Skip to main content

4. Starknet.js

Estimated Time:
Score:

WTF Starknet 4: Starknet.js

Starknet.js is a JavaScript library to interact with Starknet, typically in script or a decentralized applications. Starknet.js is inspired by Ethers.js, so it's easier if you have experience with it.

If you are not familiar with Ethers.js, check WTF Ethers Tutorial.

1. Install with npm

First, get your VSCode and Node.js ready. Then open your terminal to install starknet.js with npm.

npm install starknet

2. Provider

Provider allows you to interact with the Starknet network, without signing transactions or messages.

After Starknet v0.12.3, the Starknet feeder gateway was replaced by Starknet full nodes (Pathfinder, Juno, Papyrus, etc). You can get full-nodes & RPC services here.

const provider = new RpcProvider({nodeUrl: `https://rpc.starknet-testnet.lava.build`});
console.log("ChainID:", await provider.getChainId());

3. Account

Account extends Provider and allows you to create and verify signatures. It is similar to Wallet in ethers.js, but different since all accounts are abstract on Starknet.

const privateKey = process.env.PRIVATE_KEY;
const address = process.env.ADDRESS;
const account = new Account(provider, address, privateKey);

// If this account is based on a Cairo v2 contract (for example OpenZeppelin account 0.7.0 or later), do not forget to add the parameter "1" after the privateKey parameter
// const account = new Account(provider, address, privateKey, '1');

4. Get Account Nonce

Gets the nonce of the account with respect to a specific block.

const addr = "0x06b59aEC7b1cC7248E206abfabe62062ba1aD75783E7A2Dc19E7F3f351Ac3309"
const nonce = await provider.getNonceForAddress(addr)
console.log(Number(nonce));

5. A Simple Contract

We deployed a simple contract to interact with. It has a storage variable balance, an event log_data, and 2 functions: read_balance() and set_balance() to read and set the balance. You can find the contract on starkscan here.

#[starknet::contract]
mod HelloCairo {
// storage variable: balance
#[storage]
struct Storage {
balance: felt252,
}

// event
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
LogData: LogData,
}

#[derive(Drop, starknet::Event)]
struct LogData {
#[key]
value: felt252,
}

// set balance
#[external(v0)]
fn set_balance(ref self: ContractState, amount: felt252) {
self.balance.write(amount);
self.emit(LogData { value: amount });
}

// read balance
#[external(v0)]
fn read_balance(self: @ContractState) -> felt252 {
self.balance.read()
}
}

6. Read Contract

You can create a contract instance with Contract method, and pass ABI, contract address, and provider to it. Then you can interact with the contract on Starknet.

const testAddress = "0x064bc29b6a58a30f119b4e0a8cd0a637f27207991e4d92433b2b23ae16e1002d";
// Read ABI from contract address
const { abi: testAbi } = await provider.getClassAt(testAddress);
if (testAbi === undefined) { throw new Error("no abi.") };
// create contract instance
const myTestContract = new Contract(testAbi, testAddress, provider);
// call read_balance method
const bal1 = await myTestContract.read_balance();
// you can also use call method
// const bal1 = await myTestContract.call("read_balance");
console.log("Current Balance =", bal1.toString());

7. Write Contract

To write on the blockchain, you need to connect the contract instance with account.

// Connect account with the contract
myTestContract.connect(account);
// or you can use invoke
// const result = await myTestContract.invoke("set_balance", [888]);
const result = await myTestContract.set_balance(999);
const txReceiptDeployTest = await provider.waitForTransaction(result.transaction_hash);
const bal2 = await myTestContract.read_balance();
console.log("New Balance =", bal2.toString());

8. Write Contract with Verification

If you interact with a function that needs the proof that you have the private key of the account, you have to invoke this function with account.execute, and pass following variables:

  • contractAddress: address of the contract to invoke.
  • entrypoint: name of the function to invoke.
  • calldata: array of parameters for this function.
// account.execute: when you interact with the function that needs the proof that you have the private key of the account.
const executeHash = await account.execute(
{
contractAddress: myContractAddress,
entrypoint: 'transfer',
calldata: stark.compileCalldata({
recipient: receiverAddress,
amount: ['10']
})
}
);
await provider.waitForTransaction(executeHash.transaction_hash);

9. Read Events

It is easy to read event from transaction receipt. But a transaction can contain multiple events, so you need to filter out the one you need.

// Events
// there are multiple events in the tx, because ERC20 and argent tx also emit events.
// we need to filter out the event that we care
const events = txReceiptDeployTest.events;
const event = events.find(
(it) => number.cleanHex(it.from_address) === number.cleanHex(testAddress)
) || {data: []};
console.log("event: ", event);

10. Summary

In this tutorial, we introduced how to use Starknet.js, including provider, account, read/write contract, and read events.

Start Quiz