starknet.js SDK Skill
The starknet-js skill provides a comprehensive guide for building Starknet dApps using the starknet.js v9.x SDK. It covers providers, accounts, contracts, multicall, paymaster support, and SNIP-9/12 standards.
Installation
# Install via skills CLI
npx skills add keep-starknet-strange/starknet-agentic/skills/starknet-js
# Or clone the repo
git clone https://github.com/keep-starknet-strange/starknet-agentic.gitPrerequisites
- Node.js 18+
- TypeScript 5+
- starknet.js ^9.0.0
npm install starknet@^9.0.0Core Components
Provider Setup
The RpcProvider handles read-only operations:
import { RpcProvider } from "starknet";
// Mainnet
const provider = new RpcProvider({
nodeUrl: "https://starknet-mainnet.g.alchemy.com/v2/YOUR_KEY"
});
// Sepolia Testnet
const sepoliaProvider = new RpcProvider({
nodeUrl: "https://starknet-sepolia.g.alchemy.com/v2/YOUR_KEY"
});Account Management
Accounts require a provider, address, and signer:
import { Account, constants } from "starknet";
// Connect to existing account
const account = new Account({
provider,
address: "0x123...",
signer: privateKey,
cairoVersion: "1",
transactionVersion: constants.TRANSACTION_VERSION.V3
});V3 Transactions
V3 transactions pay fees in STRK instead of ETH. Always use TRANSACTION_VERSION.V3 for new applications.
Contract Interaction
import { Contract } from "starknet";
// Create contract instance
const contract = new Contract({
abi: tokenAbi,
address: tokenAddress,
providerOrAccount: account
});
// Read operation
const balance = await contract.balanceOf(account.address);
// Write operation
const tx = await contract.transfer(recipient, amount);
await provider.waitForTransaction(tx.transaction_hash);Advanced Patterns
Multicall / Batch Transactions
Execute multiple operations atomically:
// Batch multiple calls
const calls = [
{
contractAddress: tokenA,
entrypoint: "approve",
calldata: [spender, amountLow, amountHigh]
},
{
contractAddress: router,
entrypoint: "swap",
calldata: [tokenA, tokenB, amountLow, amountHigh, minOutLow, minOutHigh]
}
];
const { transaction_hash } = await account.execute(calls);Paymaster Support
Enable gas payment in ERC-20 tokens or sponsor transactions entirely:
import { PaymasterRpc } from "starknet";
// Create paymaster instance
const paymaster = new PaymasterRpc({
nodeUrl: "https://sepolia.paymaster.avnu.fi",
headers: {
"x-api-key": process.env.AVNU_PAYMASTER_API_KEY
}
});
// Sponsored transaction (dApp pays gas)
const result = await account.executePaymasterTransaction(
calls,
{ feeMode: { mode: "sponsored" } }
);
// User pays in alternative token
const result = await account.executePaymasterTransaction(
calls,
{
feeMode: {
mode: "default",
gasToken: "0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8" // USDC
}
}
);Message Signing (SNIP-12)
Sign typed data for off-chain verification:
import { typedData } from "starknet";
const message = {
types: {
StarkNetDomain: [
{ name: "name", type: "felt" },
{ name: "version", type: "felt" },
{ name: "chainId", type: "felt" }
],
Message: [
{ name: "content", type: "felt" }
]
},
primaryType: "Message",
domain: {
name: "MyDApp",
version: "1",
chainId: "SN_SEPOLIA"
},
message: {
content: "Hello Starknet"
}
};
const signature = await account.signMessage(message);Outside Execution (SNIP-9)
Enable delegated or gasless transactions:
// Create outside execution request
const outsideExecution = {
caller: "ANY_CALLER",
nonce: nonce,
execute_after: Math.floor(Date.now() / 1000) - 60,
execute_before: Math.floor(Date.now() / 1000) + 3600,
calls: [
{
to: tokenAddress,
selector: hash.getSelectorFromName("transfer"),
calldata: [recipient, amountLow, amountHigh]
}
]
};
// Sign the request
const signature = await account.signMessage(outsideExecutionTypedData);
// Anyone can now execute this on behalf of the account
await relayerAccount.execute({
contractAddress: account.address,
entrypoint: "execute_from_outside_v2",
calldata: [/* serialized request + signature */]
});ERC-20 Operations
BigInt Required
Always use BigInt (with n suffix like 1000n) for token amounts to prevent precision loss above 2^53.
// Reading balance
const balance = await tokenContract.balanceOf(address);
// balance is a Uint256 object with { low, high }
// Converting to BigInt
const balanceBigInt = BigInt(balance.low) + (BigInt(balance.high) << 128n);
// Formatting for display (18 decimals)
const formatted = Number(balanceBigInt) / 1e18;
// Preparing amount for transfer
const amount = 1000000000000000000n; // 1 token with 18 decimals
const { low, high } = uint256.bnToUint256(amount);Fee Estimation
// Estimate fee before execution
const estimateFee = await account.estimateInvokeFee(calls);
console.log("Overall fee:", estimateFee.overall_fee);
console.log("Gas consumed:", estimateFee.gas_consumed);
// Execute with custom resource bounds
const { transaction_hash } = await account.execute(calls, {
resourceBounds: {
l1_gas: {
max_amount: "0x1000",
max_price_per_unit: "0x100000000000"
},
l2_gas: {
max_amount: "0x0",
max_price_per_unit: "0x0"
}
}
});Wallet Integration
Connect to browser wallets:
import { connect } from "@starknet-io/get-starknet";
// Connect to wallet
const starknet = await connect();
if (starknet) {
await starknet.enable();
const account = starknet.account;
const address = starknet.selectedAddress;
// Use account for transactions
const tx = await account.execute(calls);
}Contract Deployment
Deploy contracts via Universal Deployer Contract (UDC):
import { hash, CallData } from "starknet";
// Compute class hash
const classHash = await provider.declareContract({
contract: compiledContract,
casm: compiledCasm
});
// Deploy via UDC
const { transaction_hash, contract_address } = await account.deployContract({
classHash,
constructorCalldata: CallData.compile({
owner: account.address,
initialSupply: { low: 1000000n, high: 0n }
}),
salt: hash.computeHashOnElements([Date.now()])
});
await provider.waitForTransaction(transaction_hash);Utility Functions
import { hash, ec, num, shortString } from "starknet";
// Generate keypair
const privateKey = ec.starkCurve.utils.randomPrivateKey();
const publicKey = ec.starkCurve.getPublicKey(privateKey);
// Compute selector
const selector = hash.getSelectorFromName("transfer");
// Number conversions
const felt = num.toHex(12345);
const decimal = num.toBigInt("0x3039");
// Short string encoding
const encoded = shortString.encodeShortString("hello");
const decoded = shortString.decodeShortString(encoded);
// Poseidon hash
const poseidonHash = hash.computePoseidonHash(value1, value2);Keywords
- starknet
- starknet-js
- sdk
- typescript
- smart-contracts
- account-abstraction
- paymaster
- multicall
- snip-9
- snip-12
- erc-20
- erc-721
- wallet
- rpc
- fee-estimation
Author
0xlny
Next Steps
- MCP Server Setup - Connect AI assistants to Starknet
- Cairo Coding Skill - Cairo optimization patterns
- Wallet Skill - Wallet management patterns