Skip to main content

Quick Start

This guide will get you up and running with TokenOps SDK in under 10 minutes. We'll walk through setting up the SDK and demonstrate each major feature with working examples.

Setup

1. Install Dependencies

npm install tokenops-sdk viem

2. Environment Configuration

Create a .env file in your project root:

.env
TOKENOPS_API_KEY=your_api_key_here
RPC_URL=https://eth-sepolia.g.alchemy.com/v2/your_key
PRIVATE_KEY=your_development_private_key

3. Basic Setup

src/setup.ts
import {
ViemProviderAdapter,
TokenOpsApi
} from 'tokenops-sdk';
import {
createPublicClient,
createWalletClient,
http
} from 'viem';
import { sepolia } from 'viem/chains';
import { privateKeyToAccount } from 'viem/accounts';
import 'dotenv/config';

// Setup blockchain clients
const publicClient = createPublicClient({
chain: sepolia,
transport: http(process.env.RPC_URL)
});

const walletClient = createWalletClient({
chain: sepolia,
transport: http(process.env.RPC_URL),
account: privateKeyToAccount(process.env.PRIVATE_KEY!)
});

// Create provider adapter
export const provider = new ViemProviderAdapter(publicClient, walletClient);

// Initialize API client
export const api = new TokenOpsApi(process.env.TOKENOPS_API_KEY!);

Feature Walkthroughs

🔒 Token Vesting

Create a simple vesting schedule for team tokens:

examples/vesting.ts
import { TokenVestingManagerFactory, TokenVestingManager } from 'tokenops-sdk';
import { provider } from './setup';


// Example function to create a vesting schedule
async function createVestingSchedule() {
// Factory address (testnet)
const factoryAddress = '0x...'; // Get from TokenOps docs
const tokenAddress = '0x...'; // Your ERC20 token

// 1. Deploy vesting manager
const factory = new TokenVestingManagerFactory(factoryAddress, provider);

const result = await factory.newTokenVestingManager(
tokenAddress,
BigInt(1), // Partial funding
{
account: provider.walletClient.account!.address,
value: BigInt(0)
}
);

console.log('Vesting manager deployed:', result.tokenVestingManager);

// 2. Create vesting schedule
const manager = new TokenVestingManager(
result.tokenVestingManager,
tokenAddress,
provider
);

const now = Math.floor(Date.now() / 1000);
const vestingParams = {
recipient: '0x742d35Cc6632C0532c718F4D8c2b1D1F8a1B9F36',
startTimestamp: BigInt(now + 60), // Start in 1 minute
endTimestamp: BigInt(now + 86400), // End in 24 hours
timelock: BigInt(0), // No additional timelock
initialUnlock: BigInt(0), // No immediate unlock
cliffReleaseTimestamp: BigInt(now + 3600), // 1 hour cliff
cliffAmount: BigInt('1000000000000000000'), // 1 token
releaseIntervalSecs: BigInt(3600), // Release hourly
linearVestAmount: BigInt('10000000000000000000'), // 10 tokens total
isRevocable: true
};

const vesting = await manager.createVesting(
vestingParams.recipient,
vestingParams.startTimestamp,
vestingParams.endTimestamp,
vestingParams.timelock,
vestingParams.initialUnlock,
vestingParams.cliffReleaseTimestamp,
vestingParams.cliffAmount,
vestingParams.releaseIntervalSecs,
vestingParams.linearVestAmount,
vestingParams.isRevocable,
{
account: provider.walletClient.account!.address,
amount: BigInt('11000000000000000000') // Total amount to fund
}
);

console.log('Vesting created:', vesting.vestingId);
return vesting.vestingId;
}

// Run example
createVestingSchedule().catch(console.error);

🥩 Staking Pool

Set up a staking pool with rewards:

examples/staking.ts
import { StakingFactory, Staking } from 'tokenops-sdk';
import { provider } from './setup';

// Example function to create a staking pool
async function createStakingPool() {
const factoryAddress = '0x...'; // Get from TokenOps docs
const stakingToken = '0x...'; // Token to stake

// 1. Deploy staking contract
const factory = new StakingFactory(factoryAddress, provider);

const now = Math.floor(Date.now() / 1000);
const stakingParams = {
merkleRoot: '0x0000000000000000000000000000000000000000000000000000000000000000',
whitelistStatus: 0, // No whitelist
poolMaxCap: BigInt('1000000000000000000000'), // 1000 tokens max
stakingToken: stakingToken,
timeUnit: BigInt(86400), // Daily rewards
rewardRatioNumerator: BigInt(1), // 1% daily
rewardRatioDenominator: BigInt(100),
tierUpperBound: BigInt('100000000000000000000'), // 100 tokens
tierLowerBound: BigInt('10000000000000000000'), // 10 tokens
startStakingDate: BigInt(now + 60), // Start in 1 minute
endStakingDate: BigInt(now + 2592000) // End in 30 days
};

const result = await factory.newStaking(
stakingParams.merkleRoot,
stakingParams.whitelistStatus,
stakingParams.poolMaxCap,
stakingParams.stakingToken,
stakingParams.timeUnit,
stakingParams.rewardRatioNumerator,
stakingParams.rewardRatioDenominator,
stakingParams.tierUpperBound,
stakingParams.tierLowerBound,
stakingParams.startStakingDate,
stakingParams.endStakingDate
);

console.log('Staking pool deployed:', result.stakingContract);

// 2. Stake tokens
const staking = new Staking(result.stakingContract, stakingToken, provider);

// Stake 50 tokens
const stakeAmount = BigInt('50000000000000000000');
await staking.stake(
stakeAmount,
[], // No merkle proof needed (no whitelist)
{ account: provider.walletClient.account!.address }
);

console.log('Staked:', stakeAmount.toString(), 'tokens');
return result.stakingContract;
}

// Run example
createStakingPool().catch(console.error);

🪂 Token Airdrop

Deploy a Merkle-based airdrop:

examples/airdrop.ts
import { MerkleDistributorFactory, MerkleDistributorERC20 } from 'tokenops-sdk';
import { provider } from './setup';

// Example function to create a merkle-based airdrop
async function createAirdrop() {
const factoryAddress = '0x...'; // Get from TokenOps docs
const tokenAddress = '0x...'; // Token to distribute

// 1. Deploy airdrop contract
const factory = new MerkleDistributorFactory(factoryAddress, provider);

const now = Math.floor(Date.now() / 1000);
const airdropParams = {
tokenAddress: tokenAddress,
merkleRoot: '0x1234...', // Generate from your recipient list
startTime: now + 60, // Start in 1 minute
endTime: now + 86400, // End in 24 hours
stakingAddress: '0x0000000000000000000000000000000000000000', // No staking
rewardOwner: provider.walletClient.account!.address,
bonusPercentage: 0 // No bonus
};

const result = await factory.newMerkleDistributor(
airdropParams.tokenAddress,
airdropParams.merkleRoot,
airdropParams.startTime,
airdropParams.endTime,
airdropParams.stakingAddress,
airdropParams.rewardOwner,
airdropParams.bonusPercentage,
{
account: provider.walletClient.account!.address,
value: BigInt(0)
}
);

console.log('Airdrop deployed:', result.merkleDistributor);

// 2. Claim from airdrop (example)
const distributor = new MerkleDistributorERC20(result.merkleDistributor, provider);

// Example claim (you'll need real proof data)
const claimParams = {
index: 0,
account: provider.walletClient.account!.address,
amount: BigInt('1000000000000000000'), // 1 token
merkleProof: ['0x...'] // Generate from merkle tree
};

// Note: This will fail without valid proof
// await distributor.claim(
// claimParams.index,
// claimParams.account,
// claimParams.amount,
// claimParams.merkleProof,
// { account: provider.walletClient.account!.address }
// );

return result.merkleDistributor;
}

// Run example
createAirdrop().catch(console.error);

📤 Bulk Token Distribution

Send tokens to multiple recipients efficiently:

examples/disperse.ts
import { DisperseFactory, DisperseTokenFee } from 'tokenops-sdk';
import { provider } from './setup';

async function bulkDistribution() {
const factoryAddress = '0x...'; // Get from TokenOps docs

// 1. Deploy disperse contract
const factory = new DisperseFactory(factoryAddress, provider);

const result = await factory.newDisperseTokenFee({
account: provider.walletClient.account!.address
});

console.log('Disperse contract deployed:', result.disperse);

// 2. Distribute tokens
const disperse = new DisperseTokenFee(result.disperse, provider);

const tokenAddress = '0x...'; // Token to distribute
const recipients = [
'0x742d35Cc6632C0532c718F4D8c2b1D1f8a1B9F36',
'0x8ba1f109551bD432803012645Hac136c24F4a8E5',
'0x1234567890123456789012345678901234567890'
];
const amounts = [
BigInt('1000000000000000000'), // 1 token
BigInt('2000000000000000000'), // 2 tokens
BigInt('3000000000000000000') // 3 tokens
];

await disperse.disperseToken(
tokenAddress,
recipients,
amounts,
{ account: provider.walletClient.account!.address }
);

console.log('Bulk distribution complete!');
return result.disperse;
}

// Run example
bulkDistribution().catch(console.error);

📊 Analytics API

Monitor your contracts and get insights:

examples/analytics.ts
import { TokenOpsApi } from 'tokenops-sdk';

async function getAnalytics() {
const api = new TokenOpsApi(process.env.TOKENOPS_API_KEY!);
// 1. Test API connection
const ping = await api.ping();
console.log('API Status:', ping);

// 2. Get vesting contract info
const chainId = 11155111; // Sepolia
const contractAddress = '0x...'; // Your vesting contract

const vestingInfo = await api.vesting(chainId, contractAddress);
console.log('Vesting Info:', vestingInfo);

// 3. Get vesting grants
const grants = await api.vestingGrants(
chainId,
contractAddress,
undefined, // tokenAddress (optional)
undefined, // recipientAddress (optional)
undefined, // eventType (optional)
1, // page
10 // size
);
console.log('Grants:', grants);

// 4. Get insights
const insights = await api.vestingInsights(
chainId,
contractAddress
);
console.log('Insights:', insights);

// 5. Subscribe to events (webhook)
await api.vestingSubscribe(
chainId,
contractAddress,
['VestingCreated', 'Claimed'],
'https://your-webhook-url.com/tokenops'
);
console.log('Webhook subscription created');
}

// Run example
getAnalytics().catch(console.error);

Complete Example Application

Here's a complete example that demonstrates multiple features:

examples/complete-example.ts
import { provider } from './setup';
import { TokenOpsApi } from 'tokenops-sdk';
import {
TokenVestingManagerFactory,
TokenVestingManager,
StakingFactory
} from 'tokenops-sdk';

const api = new TokenOpsApi(process.env.TOKENOPS_API_KEY!);

async function completeExample() {
console.log('🚀 Starting TokenOps SDK Complete Example');

try {
// 1. Test API connection
const ping = await api.ping();
console.log('✅ API Connected:', ping.message);

// 2. Deploy vesting manager
const vestingFactory = new TokenVestingManagerFactory(
'0x...', // Factory address
provider
);

const vestingResult = await vestingFactory.newTokenVestingManager(
'0x...', // Token address
BigInt(1),
{
account: provider.walletClient.account!.address,
value: BigInt(0)
}
);

console.log('✅ Vesting Manager Deployed:', vestingResult.tokenVestingManager);

// 3. Create vesting schedule
const manager = new TokenVestingManager(
vestingResult.tokenVestingManager,
'0x...', // Token address
provider
);

const now = Math.floor(Date.now() / 1000);
const vesting = await manager.createVesting(
'0x742d35Cc6632C0532c718F4D8c2b1D1f8a1B9F36', // Recipient
BigInt(now + 60), // Start
BigInt(now + 86400), // End
BigInt(0), // Timelock
BigInt(0), // Initial unlock
BigInt(now + 3600), // Cliff
BigInt('1000000000000000000'), // Cliff amount
BigInt(3600), // Release interval
BigInt('10000000000000000000'), // Linear amount
true, // Revocable
{
account: provider.walletClient.account!.address,
amount: BigInt('11000000000000000000')
}
);

console.log('✅ Vesting Schedule Created:', vesting.vestingId);

// 4. Monitor with API
setTimeout(async () => {
const vestingInfo = await api.vesting(
11155111, // Sepolia
vestingResult.tokenVestingManager
);
console.log('📊 Vesting Info:', vestingInfo);
}, 5000);

console.log('🎉 Complete example finished successfully!');

} catch (error) {
console.error('❌ Error:', error);
}
}

// Run complete example
completeExample();

Common Issues

Transaction Failures

// Always check transaction receipts
const receipt = await provider.viemClient.getTransactionReceipt({ hash: txHash });
if (receipt.status === 'reverted') {
console.error('Transaction reverted');
}

Gas Estimation

// For complex transactions, estimate gas first
const gasEstimate = await provider.viemClient.estimateGas({
account: provider.walletClient.account!.address,
to: contractAddress,
data: encodedData
});

API Rate Limits

// Handle rate limits gracefully
try {
const result = await api.vesting(chainId, contractAddress);
} catch (error) {
if (error.message.includes('rate limit')) {
// Wait and retry
await new Promise(resolve => setTimeout(resolve, 1000));
// Retry logic here
}
}

Getting Help


Ready to build more? Explore the Core Features to learn about advanced functionality!