skills/chain/interact-contract/SKILL.md
# Interact with 0G Chain Contracts ## Metadata - **Category**: chain - **SDK**: `ethers` ^6.13.0 - **Activation Triggers**: "call contract", "read contract", "interact", "write contract", "contract function" ## Purpose Read from and write to deployed smart contracts on 0G Chain using ethers v6. Covers view functions, state-changing transactions, event listening, and gas estimation. ## Prerequisites - Node.js >= 18 - `ethers` ^6.13.0 installed - Contract ABI and address - `.env` with `PRI
npx skillsauth add 0gfoundation/0g-agent-skills skills/chain/interact-contractInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
ethers ^6.13.0Read from and write to deployed smart contracts on 0G Chain using ethers v6. Covers view functions, state-changing transactions, event listening, and gas estimation.
ethers ^6.13.0 installed.env with PRIVATE_KEY, RPC_URLawait contract.getAddress() (not contract.address)await contract.waitForDeployment() (not .deployed())tx.wait()BigInt (not BigNumber).env)import { ethers } from 'ethers';
import 'dotenv/config';
const ABI = [
'function getValue() view returns (uint256)',
'function balanceOf(address) view returns (uint256)',
'function owner() view returns (address)',
];
async function readContract() {
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const contract = new ethers.Contract(process.env.CONTRACT_ADDRESS!, ABI, provider);
const value = await contract.getValue();
console.log('Value:', value.toString());
const balance = await contract.balanceOf(process.env.WALLET_ADDRESS!);
console.log('Balance:', ethers.formatEther(balance));
const owner = await contract.owner();
console.log('Owner:', owner);
}
async function writeContract() {
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
const ABI = [
'function setValue(uint256) external',
'function transfer(address, uint256) external returns (bool)',
];
const contract = new ethers.Contract(process.env.CONTRACT_ADDRESS!, ABI, wallet);
// Simple write
const tx = await contract.setValue(42);
const receipt = await tx.wait();
console.log('Tx hash:', receipt.hash);
console.log('Gas used:', receipt.gasUsed.toString());
// Write with value
const tx2 = await contract.transfer('0xRecipient...', ethers.parseEther('1.0'));
await tx2.wait();
}
async function listenForEvents() {
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const ABI = [
'event Transfer(address indexed from, address indexed to, uint256 amount)',
'event ValueChanged(uint256 newValue)',
];
const contract = new ethers.Contract(process.env.CONTRACT_ADDRESS!, ABI, provider);
// Real-time listener
contract.on('ValueChanged', (newValue) => {
console.log('Value changed to:', newValue.toString());
});
contract.on('Transfer', (from, to, amount) => {
console.log(`Transfer: ${from} → ${to}: ${ethers.formatEther(amount)}`);
});
// Query past events
const filter = contract.filters.Transfer();
const events = await contract.queryFilter(filter, -1000); // Last 1000 blocks
console.log(`Found ${events.length} transfer events`);
}
async function estimateGas() {
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
const ABI = ['function setValue(uint256) external'];
const contract = new ethers.Contract(process.env.CONTRACT_ADDRESS!, ABI, wallet);
const gasEstimate = await contract.setValue.estimateGas(42);
console.log('Estimated gas:', gasEstimate.toString());
// Execute with gas buffer
const tx = await contract.setValue(42, {
gasLimit: (gasEstimate * 120n) / 100n, // 20% buffer
});
await tx.wait();
}
import * as fs from 'fs';
async function interactWithArtifact() {
const artifact = JSON.parse(
fs.readFileSync('./artifacts/contracts/MyContract.sol/MyContract.json', 'utf8'),
);
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
const contract = new ethers.Contract(process.env.CONTRACT_ADDRESS!, artifact.abi, wallet);
// Now use any function from the contract
const value = await contract.getValue();
console.log('Value:', value.toString());
}
| Operation | v5 (DO NOT USE) | v6 (CORRECT) |
| ------------ | -------------------------------------- | ------------------------------------ |
| Parse ether | ethers.utils.parseEther("1") | ethers.parseEther("1") |
| Format ether | ethers.utils.formatEther(x) | ethers.formatEther(x) |
| Big numbers | BigNumber.from(42) | 42n (native BigInt) |
| Get address | contract.address | await contract.getAddress() |
| Wait deploy | await contract.deployed() | await contract.waitForDeployment() |
| Provider | new ethers.providers.JsonRpcProvider | new ethers.JsonRpcProvider |
// BAD: ethers v5 patterns
const value = ethers.utils.parseEther('1.0'); // v5!
const provider = new ethers.providers.JsonRpcProvider(url); // v5!
const big = BigNumber.from(42); // v5!
// BAD: Not waiting for confirmation
await contract.setValue(42); // Fire and forget — bad!
// BAD: Hardcoded addresses
const contract = new ethers.Contract('0x123...', abi, wallet);
| Error | Cause | Fix |
| ----------------------- | ------------------------ | ------------------------------ |
| execution reverted | Require/revert condition | Check function parameters |
| insufficient funds | Wallet empty | Fund wallet |
| nonce too low | Pending tx | Wait or set nonce manually |
| cannot estimate gas | Function will revert | Check args and contract state |
| call revert exception | View function reverted | Check function exists and args |
development
# Upload File to 0G Storage ## Metadata - **Category**: storage - **SDK**: `@0glabs/0g-ts-sdk` ^0.3.3, `ethers` ^6.13.0 - **Activation Triggers**: "upload file", "store on 0G", "ZgFile", "save to storage" ## Purpose Upload files to 0G decentralized storage using the ZgFile API and Indexer. Files are split into chunks, organized as a Merkle tree, and distributed across storage nodes. Returns a root hash for later retrieval. ## Prerequisites - Node.js >= 18 - `@0glabs/0g-ts-sdk` and `ethers`
development
# Merkle Verification ## Metadata - **Category**: storage - **SDK**: `@0glabs/0g-ts-sdk` ^0.3.3 - **Activation Triggers**: "verify file", "merkle proof", "data integrity", "root hash", "check file" ## Purpose Compute root hashes and verify data integrity for files stored on 0G Storage. Uses Merkle tree proofs to cryptographically verify that downloaded data matches what was originally uploaded. ## Prerequisites - Node.js >= 18 - `@0glabs/0g-ts-sdk` installed ## Quick Workflow 1. Create
development
# Download File from 0G Storage ## Metadata - **Category**: storage - **SDK**: `@0glabs/0g-ts-sdk` ^0.3.3, `ethers` ^6.13.0 - **Activation Triggers**: "download file", "retrieve from 0G", "get file", "fetch from storage" ## Purpose Download and verify files from 0G decentralized storage using a root hash. Supports verified downloads with Merkle proof validation to ensure data integrity. ## Prerequisites - Node.js >= 18 - `@0glabs/0g-ts-sdk` installed - Root hash of the file to download - `
development
# Storage + Chain Integration ## Metadata - **Category**: cross-layer - **SDK**: `@0glabs/0g-ts-sdk` ^0.3.3, `ethers` ^6.13.0 - **Activation Triggers**: "on-chain reference", "NFT metadata on 0G", "store hash on-chain", "registry contract", "chain and storage" ## Purpose Combine 0G Storage with 0G Chain smart contracts to create on-chain references to off-chain data. Common patterns include NFT metadata storage, content registries, and verifiable document systems. ## Prerequisites - Node