@iotexproject/contracts
v0.2.2
Published
Addresses, ABIs and transaction builders for the IoTeX contracts used by IoTeX frontends.
Keywords
Readme
@iotexproject/contracts
Contract addresses, ABIs and transaction builders for the IoTeX contracts that IoTeX frontends send transactions to.
Frontends used to fetch calldata from the kit service and sign whatever came back, so a compromised service could swap a transaction for a different one. With this package the frontend builds the transaction itself: the target address comes from the address book shipped here, and the calldata is encoded locally from the user's own input.
Install
bun add @iotexproject/contracts viemviem (v2) is a peer dependency.
Usage
Every builder returns a TxRequest: { to, data, value? }.
import { nativeStaking, liquidStaking, mimoFarmV3, CHAIN_ID } from '@iotexproject/contracts';
const tx = nativeStaking.unstake({ bucketIndex: '123' });
await walletClient.sendTransaction({ account, ...tx });
const create = liquidStaking.createBucket({
chainId: CHAIN_ID.mainnet,
version: 'v3',
duration: 91, // days
delegate: '0x…',
value: parseEther('100'),
});
// Builders that need more than one transaction return them in order.
const [transfer, stake] = mimoFarmV3.deposit({ chainId: CHAIN_ID.mainnet, key, tokenId, account, isTransferred: false });Rules the builders rely on:
tonever comes from the caller. It is looked up fromchainId(andversionfor liquid staking). An unknown chain throws.account/recipientdecides where rewards, buckets and position NFTs go. Pass the connected wallet, never a value received from a server.- mimo farm v2 only accepts the pools listed in
MIMO_FARM_V2_POOLS. - Malformed input (non-integer amounts, bad addresses, out-of-range values) throws instead of being encoded.
- Marshall DAO calls only go to gauges in
MARSHALL_DAO_GAUGES(on testnet also gauges the user imported locally, passed asimportedGauges), and check on chain that the gauge is a FixedRewardPool. ioidcalls that need on-chain data (the ioID price, the weight NFT behind a project's gauge) take a viem public client and read it themselves, so the caller cannot pass a wrong price or target. Theprojectthey act on is the user's own project contract: take it from the user's own project list, never from a server response.
What is included
| Export | Calls |
|---|---|
| nativeStaking | createBucket, changeCandidate, depositToStake, restake, unstake, withdrawStake, transferStake, migrateStake, candidateEndorsement, intentToRevokeEndorsement, revokeEndorsement |
| liquidStaking | createBucket, changeDelegate, expandBucket, stakeLock, unstake, withdraw, migrateLegacyBucketApprove, migrateLegacyBucket |
| candidate | register, update, activate, requestDeactivation, confirmDeactivation, transferOwnership, setVoterRewardOptIn |
| delegate | claimReward, updateRewardDistribution |
| mimoFarmV2 | deposit, harvest, withdraw |
| mimoFarmV3 | deposit, harvest, batchHarvest, batchWithdraw, unstakeAndWithdraw, withdraw, poke |
| rewardForwarding | register, deregister (Hermes; mainnet only) |
| ioid | create, applyIoIDs, incrementMinterAllowance, setDeviceGauge, setProjectMetadata, setWeight |
| marshallDao | deposit, withdraw, claimRewards (FixedRewardPool gauges in MARSHALL_DAO_GAUGES) |
Address book: NATIVE_STAKING_ADDRESS, REWARDING_ADDRESS,
LIQUID_STAKING_ADDRESS, DELEGATE_PROFILE_ADDRESS, REWARD_FORWARDING_ADDRESS,
IOID_FACTORY_ADDRESS, MARSHALL_DAO_GAUGES,
MIMO_FARM_V3_ADDRESS, MIMO_FARM_V2_POOLS. ABIs for every encoded entry point are exported as well.
Mapping from kit service endpoints
The calldata is byte-identical to what these endpoints return for the same
input (see test/parity.test.ts).
| Kit service | Package |
|---|---|
| staking.createNativeBucket … staking.revokeEndorsement | nativeStaking.* (same names; createNativeBucket → createBucket) |
| staking.createNFTV2Bucket / createNFTV3Bucket | liquidStaking.createBucket({ version }) |
| staking.NFTBucketChangeDelegate | liquidStaking.changeDelegate |
| staking.NFTBucketRestake | liquidStaking.expandBucket |
| staking.NFTBucketStakeLock | liquidStaking.stakeLock |
| staking.NFTBucketUnstake | liquidStaking.unstake |
| staking.NFTBucketWithdrawStake | liquidStaking.withdraw |
| staking.migrateLegacyBucketApprove / migrateLegacyBucket | liquidStaking.* |
| staking.candidateActivate / candidateRequestDeactivation / candidateConfirmDeactivation / candidateTransferOwnership | candidate.activate / requestDeactivation / confirmDeactivation / transferOwnership |
| delegate.candidateRegister / candidateUpdate | candidate.register / candidate.update (also the post-Zanzibar PoP entry points) |
| delegate.claim | delegate.claimReward |
| delegate.upsertRewardDistribution | delegate.updateRewardDistribution |
| liquidityMining.* | mimoFarmV2.* (pass the current allowance to deposit) |
| liquidityMiningV3.* | mimoFarmV3.* (pass the position's staked incentives to harvest) |
| ioid.* | ioid.* (setGauge → setDeviceGauge; create / applyIoIDs / setWeight take a public client; setWeight takes the project instead of its gauge; applyIoIDs value is exact where the service returned e.g. 1e+21) |
| marshalldao.depositToGauge / withdrawFromGauge / getRewardFromGauge / batchGetRewardFromGauge | marshallDao.deposit (returns [approve, deposit]) / withdraw / claimRewards (one per gauge) |
| hub.registerForwardService / deregisterForwardService | rewardForwarding.register / deregister (an empty startEpoch is rejected; the service encoded it as 0) |
Development
bun install
bun run typecheck
bun test
bun run buildtest/fixtures/kit-service.json holds what the kit service's own module code
returns for every case in test/cases.ts. To refresh it, run from the
repository root (after the root bun install):
bun run packages/contracts/scripts/capture-fixtures.tsbun run check:addresses reads every chain in the address book and checks
each entry is the contract it claims to be (system contracts answer their read
calls, liquid staking is an ERC-721, the farm contracts point at the listed
position manager / staked tokens, and so on). It needs network access, so it is
not part of bun test; it runs before every publish instead. Mainnet and
testnet failures block the publish, nightly failures are only reported.
Publishing
Publishing is manual (npm 2FA). From this directory:
npm publishprepublishOnly runs the type check, the tests, the address check and the
build first.
