Skip to main content
starknet-js Reference for building Starknet applications using starknet.js v9.x SDK, including contract interaction, account management, transaction handling, fee estimation, wallet integration, and paymaster flows.
インストールへ移動 Skills Marketplace コミュニティが作成したAIスキルを発見・探索
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
直接コマンドでは確認用 Prompt が省略されます。実行前にソースを確認してください。
npx skills add https://github.com/keep-starknet-strange/starknet-agentic --skill starknet-jsコマンドは1行のまま表示されます。コピー前に横へスクロールして全体を確認してください。
ローカルで確認しますか?SkillsMP が現在取得できるファイルをダウンロードできます。
Zipをダウンロード ダウンロード中... name starknet-js description Reference for building Starknet applications using starknet.js v9.x SDK, including contract interaction, account management, transaction handling, fee estimation, wallet integration, and paymaster flows. license Apache-2.0 metadata {"author":"0xlny","version":"1.0.0","org":"keep-starknet-strange"} compatibility Node.js 18+, TypeScript 5+, npm package: starknet@^9.0.0 keywords ["starknet","starknet-js","sdk","typescript","smart-contracts","account-abstraction","paymaster","multicall","snip-9","snip-12","erc-20","erc-721","wallet","rpc","fee-estimation"] allowed-tools ["Bash","Read","Write","Glob","Grep","Task"] user-invocable true
starknet.js v9.x SDK
Related modules: skills catalog .
When to Use
Building Starknet apps with provider, account, contract, wallet, or paymaster flows.
When NOT to Use
Cairo contract authoring, deployment-only runbooks, or security audits.
Quick Start
npm install starknet
Minimal setup to read from Starknet:
import { RpcProvider , Contract } from 'starknet' ;
const provider = await RpcProvider .create ({ nodeUrl : 'https://rpc.starknet.lava.build' });
const contract = new Contract (abi, contractAddress, provider);
const result = await contract.get_balance ();
Core Architecture
Provider -> Account -> Contract
| | |
Network Identity Interaction
Provider : Read-only network connection (RpcProvider)
Account : Extends Provider with signing and transaction capabilities
Contract : Type-safe interface to deployed contracts
Use Provider for read operations, Account for write operations.
Provider Setup
import { RpcProvider } from 'starknet' ;
const provider = await RpcProvider .create ({
nodeUrl : 'https://rpc.starknet.lava.build'
});
Mainnet: https://rpc.starknet.lava.build
Sepolia: https://rpc.starknet-testnet.lava.build
const chainId = await provider.getChainId ();
const block = await provider.getBlock ('latest' );
const nonce = await provider.getNonceForAddress (accountAddress);
await provider.waitForTransaction (txHash);
const value = await provider.getStorageAt (contractAddress, storageKey);
Account Management
Account Creation (4 Steps) import { hash, ec, encode, CallData } from 'starknet' ;
const privateKey = '0x' + encode.buf2hex (ec.starkCurve .utils .randomPrivateKey ());
const publicKey = ec.starkCurve .getStarkKey (privateKey);
const classHash = '0x540d7f5ec7ecf317e68d48564934cb99259781b1ee3cedbbc37ec5337f8e688' ;
const constructorCalldata = CallData .compile ({ publicKey });
const address = hash.calculateContractAddressFromHash (publicKey, classHash, constructorCalldata, 0 );
Step 2: Fund the address with STRK before deployment.
import { Account } from 'starknet' ;
const account = new Account ({ provider, address, signer : privateKey, cairoVersion : '1' });
const { transaction_hash } = await account.deployAccount ({
classHash,
constructorCalldata,
addressSalt : publicKey
});
await provider.waitForTransaction (transaction_hash);
Step 4: Use the account for transactions.
Connect to Existing Account const account = new Account ({
provider,
address : '0x123...' ,
signer : privateKey,
cairoVersion : '1'
});
Contract Interaction
Connect to Contract import { Contract } from 'starknet' ;
const contract = new Contract (abi, contractAddress, provider);
const writeContract = new Contract (abi, contractAddress, account);
Typed Contract (Type-Safe)
const typedContract = contract.typedv2 (abi);
const balance = await typedContract.balanceOf (userAddress);
Read State const balance = await contract.get_balance ();
const userBalance = await contract.balanceOf (userAddress);
Write (Execute) const tx = await contract.increase_balance (100 );
await provider.waitForTransaction (tx.transaction_hash );
Multicall (Batch Transactions) import { CallData , cairo } from 'starknet' ;
const calls = [
{
contractAddress : tokenAddress,
entrypoint : 'approve' ,
calldata : CallData .compile ({ spender : bridgeAddress, amount : cairo.uint256 (1000n ) })
},
{
contractAddress : bridgeAddress,
entrypoint : 'deposit' ,
calldata : CallData .compile ({ amount : cairo.uint256 (1000n ) })
}
];
const tx = await account.execute (calls);
Using populate() for type-safety:
const approveCall = tokenContract.populate ('approve' , {
spender : bridgeAddress,
amount : cairo.uint256 (1000n )
});
const depositCall = bridgeContract.populate ('deposit' , { amount : cairo.uint256 (1000n ) });
const tx = await account.execute ([approveCall, depositCall]);
Parse Events const receipt = await provider.getTransactionReceipt (txHash);
const events = contract.parseEvents (receipt);
const transferEvents = contract.parseEvents (receipt, 'Transfer' );
Transaction Simulation Simulate before executing to catch reverts and inspect state changes:
const simResult = await account.simulateTransaction (
[{ type : 'INVOKE' , payload : calls }],
{ skipValidate : false }
);
console .log ('Fee estimate:' , simResult[0 ].fee_estimation );
console .log ('Trace:' , simResult[0 ].transaction_trace );
const trace = simResult[0 ].transaction_trace ;
if (trace?.state_diff ) {
console .log ('Storage changes:' , trace.state_diff .storage_diffs );
}
Fee Estimation const fee = await account.estimateInvokeFee (calls);
console .log ({
overallFee : fee.overall_fee ,
resourceBounds : fee.resourceBounds
});
Execute with custom bounds:
const tx = await account.execute (calls, {
resourceBounds : {
l1_gas : { amount : '0x2000' , price : '0x1000000000' },
l2_gas : { amount : '0x0' , price : '0x0' },
l1_data_gas : { amount : '0x1000' , price : '0x1000000000' }
}
});
const tipStats = await provider.getEstimateTip ();
const tx = await account.execute (calls, { tip : tipStats.percentile_75 });
Transaction Receipt Handling const receipt = await provider.waitForTransaction (txHash);
if (receipt.isSuccess ()) {
console .log ('Transaction succeeded' );
} else if (receipt.isReverted ()) {
console .log ('Reverted:' , receipt.revert_reason );
} else if (receipt.isRejected ()) {
console .log ('Rejected' );
} else if (receipt.isError ()) {
console .log ('Error' );
}
Wallet Integration Connect to browser wallets (ArgentX, Braavos):
import { connect } from '@starknet-io/get-starknet' ;
import { WalletAccount } from 'starknet' ;
const selectedWallet = await connect ({ modalMode : 'alwaysAsk' });
const walletAccount = await WalletAccount .connect (
{ nodeUrl : 'https://rpc.starknet.lava.build' },
selectedWallet
);
const tx = await walletAccount.execute (calls);
walletAccount.onAccountChange ((accounts ) => console .log ('New account:' , accounts[0 ]));
walletAccount.onNetworkChanged ((chainId ) => console .log ('Network changed:' , chainId));
Paymaster (Gas Sponsorship) Setup paymaster for sponsored or alternative gas token transactions:
import { PaymasterRpc , Account } from 'starknet' ;
const paymaster = new PaymasterRpc ({ nodeUrl : 'https://sepolia.paymaster.avnu.fi' });
const account = new Account ({ provider, address, signer : privateKey, paymaster });
Sponsored (dApp pays gas):
const tx = await account.executePaymasterTransaction (calls, { feeMode : { mode : 'sponsored' } });
Alternative token (e.g., USDC):
const tokens = await account.paymaster .getSupportedTokens ();
const feeDetails = { feeMode : { mode : 'default' , gasToken : USDC_ADDRESS } };
const estimate = await account.estimatePaymasterTransactionFee (calls, feeDetails);
const tx = await account.executePaymasterTransaction (calls, feeDetails, estimate.suggested_max_fee_in_gas_token );
Message Signing (SNIP-12) const typedData = {
types : {
StarknetDomain : [
{ name : 'name' , type : 'shortstring' },
{ name : 'version' , type : 'shortstring' },
{ name : 'chainId' , type : 'shortstring' },
{ name : 'revision' , type : 'shortstring' }
],
Message : [{ name : 'content' , type : 'shortstring' }]
},
primaryType : 'Message' ,
domain : { name : 'MyDapp' , version : '1' , chainId : 'SN_SEPOLIA' , revision : '1' },
message : { content : 'Hello Starknet' }
};
const signature = await account.signMessage (typedData);
const msgHash = await account.hashMessage (typedData);
const isValid = ec.starkCurve .verify (signature, msgHash, publicKey);
CallData & Cairo Types import { CallData , cairo, CairoCustomEnum , CairoOption , CairoOptionVariant } from 'starknet' ;
const calldata = new CallData (abi);
const compiled = calldata.compile ('transfer' , { recipient : '0x...' , amount : cairo.uint256 (1000n ) });
cairo.uint256 (1000n )
cairo.felt252 (1000 )
cairo.felt ('0x123' )
cairo.bool (true )
cairo.byteArray ('Hello' )
import { shortString } from 'starknet' ;
shortString.encodeShortString ('hello' )
shortString.decodeShortString ('0x...' )
const myEnum = new CairoCustomEnum ({ Variant1 : { value : 123 } });
const some = new CairoOption (CairoOptionVariant .Some , value);
Important: Always use BigInt (e.g., 1000n) for token amounts and balances. Never use Number() or parseFloat() on wei values -- JavaScript numbers lose precision above 2^53.
ERC-20 Token Operations const erc20 = new Contract (erc20Abi, tokenAddress, account);
const balance = await erc20.balanceOf (account.address );
console .log ('Balance (wei):' , balance.toString ());
const amount = cairo.uint256 (1000000000000000000n );
const tx = await erc20.transfer (recipientAddress, amount);
await provider.waitForTransaction (tx.transaction_hash );
await erc20.approve (spenderAddress, cairo.uint256 (amount));
Utility Functions import { stark, ec, encode, num, hash } from 'starknet' ;
const privateKey = '0x' + encode.buf2hex (ec.starkCurve .utils .randomPrivateKey ());
const publicKey = ec.starkCurve .getStarkKey (privateKey);
num.toHex (123 );
num.toBigInt ('0x7b' );
hash.getSelectorFromName ('transfer' );
hash.calculateContractAddressFromHash (salt, classHash, calldata, deployer);
Contract Deployment
const { transaction_hash, contract_address } = await account.deploy ({
classHash : '0x...' ,
constructorCalldata : CallData .compile ({ owner : account.address }),
salt : stark.randomAddress (),
unique : true
});
const declareResponse = await account.declare ({
contract : compiledSierra,
casm : compiledCasm
});
await provider.waitForTransaction (declareResponse.transaction_hash );
const deployResponse = await account.deploy ({
classHash : declareResponse.class_hash ,
constructorCalldata : CallData .compile ({ owner : account.address })
});
const result = await account.declareAndDeploy ({
contract : compiledContract,
casm : compiledCasm,
constructorCalldata : CallData .compile ({ owner : account.address })
});
Outside Execution (SNIP-9) Execute transactions on behalf of another account (gasless/delegated):
const version = await account.getSnip9Version ();
const outsideTransaction = await account.getOutsideTransaction (
{ caller : executorAddress, execute_after : now, execute_before : now + 3600 },
calls,
'V2'
);
const result = await executorAccount.executeFromOutside (outsideTransaction);
Error Handling import { LibraryError , RpcError } from 'starknet' ;
try {
const tx = await account.execute (calls);
} catch (error) {
if (error instanceof RpcError ) {
console .error ('RPC error:' , error.code , error.message );
} else if (error instanceof LibraryError ) {
console .error ('Library error:' , error.message );
}
}
Logging & Configuration import { config, setLogLevel } from 'starknet' ;
config.set ('transactionVersion' , '0x3' );
config.get ('transactionVersion' );
setLogLevel ('DEBUG' );