UNPKG

jito-distributor-sdk

Version:

TypeScript SDK for JITO Merkle Distributor with production-ready versioning and double-hashing support

729 lines 17.1 kB
{ "version": "0.0.1", "name": "merkle_distributor", "instructions": [ { "name": "newDistributor", "docs": [ "READ THE FOLLOWING:", "", "This instruction is susceptible to frontrunning that could result in loss of funds if not handled properly.", "", "An attack could look like:", "- A legitimate user opens a new distributor.", "- Someone observes the call to this instruction.", "- They replace the clawback_receiver, admin, or time parameters with their own.", "", "One situation that could happen here is the attacker replaces the admin and clawback_receiver with their own", "and sets the clawback_start_ts with the minimal time allowed. After clawback_start_ts has elapsed,", "the attacker can steal all funds from the distributor to their own clawback_receiver account.", "", "HOW TO AVOID:", "- When you call into this instruction, ensure your transaction succeeds.", "- To be extra safe, after your transaction succeeds, read back the state of the created MerkleDistributor account and", "assert the parameters are what you expect, most importantly the clawback_receiver and admin.", "- If your transaction fails, double check the value on-chain matches what you expect." ], "accounts": [ { "name": "distributor", "isMut": true, "isSigner": false, "docs": [ "[MerkleDistributor]." ], "pda": { "seeds": [ { "kind": "const", "type": "string", "value": "MerkleDistributor" }, { "kind": "account", "type": "publicKey", "account": "Mint", "path": "mint" }, { "kind": "arg", "type": "u64", "path": "version" } ] } }, { "name": "clawbackReceiver", "isMut": true, "isSigner": false, "docs": [ "Clawback receiver token account" ] }, { "name": "mint", "isMut": false, "isSigner": false, "docs": [ "The mint to distribute." ] }, { "name": "tokenVault", "isMut": true, "isSigner": false, "docs": [ "Token vault" ] }, { "name": "admin", "isMut": true, "isSigner": true, "docs": [ "Admin wallet, responsible for creating the distributor and paying for the transaction.", "Also has the authority to set the clawback receiver and change itself." ] }, { "name": "systemProgram", "isMut": false, "isSigner": false, "docs": [ "The [System] program." ] }, { "name": "associatedTokenProgram", "isMut": false, "isSigner": false, "docs": [ "The [Associated Token] program." ] }, { "name": "tokenProgram", "isMut": false, "isSigner": false, "docs": [ "The [Token] program." ] } ], "args": [ { "name": "version", "type": "u64" }, { "name": "root", "type": { "array": [ "u8", 32 ] } }, { "name": "maxTotalClaim", "type": "u64" }, { "name": "maxNumNodes", "type": "u64" }, { "name": "startVestingTs", "type": "i64" }, { "name": "endVestingTs", "type": "i64" }, { "name": "clawbackStartTs", "type": "i64" } ] }, { "name": "newClaim", "accounts": [ { "name": "distributor", "isMut": true, "isSigner": false, "docs": [ "The [MerkleDistributor]." ] }, { "name": "claimStatus", "isMut": true, "isSigner": false, "docs": [ "Claim status PDA" ], "pda": { "seeds": [ { "kind": "const", "type": "string", "value": "ClaimStatus" }, { "kind": "account", "type": "publicKey", "path": "claimant" }, { "kind": "account", "type": "publicKey", "account": "MerkleDistributor", "path": "distributor" } ] } }, { "name": "from", "isMut": true, "isSigner": false, "docs": [ "Distributor ATA containing the tokens to distribute." ] }, { "name": "to", "isMut": true, "isSigner": false, "docs": [ "Account to send the claimed tokens to." ] }, { "name": "claimant", "isMut": true, "isSigner": true, "docs": [ "Who is claiming the tokens." ] }, { "name": "tokenProgram", "isMut": false, "isSigner": false, "docs": [ "SPL [Token] program." ] }, { "name": "systemProgram", "isMut": false, "isSigner": false, "docs": [ "The [System] program." ] } ], "args": [ { "name": "amountUnlocked", "type": "u64" }, { "name": "amountLocked", "type": "u64" }, { "name": "proof", "type": { "vec": { "array": [ "u8", 32 ] } } } ] }, { "name": "claimLocked", "accounts": [ { "name": "distributor", "isMut": true, "isSigner": false, "docs": [ "The [MerkleDistributor]." ] }, { "name": "claimStatus", "isMut": true, "isSigner": false, "docs": [ "Claim Status PDA" ], "pda": { "seeds": [ { "kind": "const", "type": "string", "value": "ClaimStatus" }, { "kind": "account", "type": "publicKey", "path": "claimant" }, { "kind": "account", "type": "publicKey", "account": "MerkleDistributor", "path": "distributor" } ] } }, { "name": "from", "isMut": true, "isSigner": false, "docs": [ "Distributor ATA containing the tokens to distribute." ] }, { "name": "to", "isMut": true, "isSigner": false, "docs": [ "Account to send the claimed tokens to.", "Claimant must sign the transaction and can only claim on behalf of themself" ] }, { "name": "claimant", "isMut": true, "isSigner": true, "docs": [ "Who is claiming the tokens." ] }, { "name": "tokenProgram", "isMut": false, "isSigner": false, "docs": [ "SPL [Token] program." ] } ], "args": [] }, { "name": "clawback", "accounts": [ { "name": "distributor", "isMut": true, "isSigner": false, "docs": [ "The [MerkleDistributor]." ] }, { "name": "from", "isMut": true, "isSigner": false, "docs": [ "Distributor ATA containing the tokens to distribute." ] }, { "name": "to", "isMut": true, "isSigner": false, "docs": [ "The Clawback token account." ] }, { "name": "claimant", "isMut": false, "isSigner": true, "docs": [ "Claimant account", "Anyone can claw back the funds" ] }, { "name": "systemProgram", "isMut": false, "isSigner": false, "docs": [ "The [System] program." ] }, { "name": "tokenProgram", "isMut": false, "isSigner": false, "docs": [ "SPL [Token] program." ] } ], "args": [] }, { "name": "setClawbackReceiver", "accounts": [ { "name": "distributor", "isMut": true, "isSigner": false, "docs": [ "The [MerkleDistributor]." ] }, { "name": "newClawbackAccount", "isMut": false, "isSigner": false, "docs": [ "New clawback account" ] }, { "name": "admin", "isMut": true, "isSigner": true, "docs": [ "Admin signer" ] } ], "args": [] }, { "name": "setAdmin", "accounts": [ { "name": "distributor", "isMut": true, "isSigner": false, "docs": [ "The [MerkleDistributor]." ] }, { "name": "admin", "isMut": true, "isSigner": true, "docs": [ "Admin signer" ] }, { "name": "newAdmin", "isMut": true, "isSigner": false, "docs": [ "New admin account" ] } ], "args": [] } ], "accounts": [ { "name": "ClaimStatus", "docs": [ "Holds whether or not a claimant has claimed tokens." ], "type": { "kind": "struct", "fields": [ { "name": "claimant", "docs": [ "Authority that claimed the tokens." ], "type": "publicKey" }, { "name": "lockedAmount", "docs": [ "Locked amount" ], "type": "u64" }, { "name": "lockedAmountWithdrawn", "docs": [ "Locked amount withdrawn" ], "type": "u64" }, { "name": "unlockedAmount", "docs": [ "Unlocked amount" ], "type": "u64" } ] } }, { "name": "MerkleDistributor", "docs": [ "State for the account which distributes tokens." ], "type": { "kind": "struct", "fields": [ { "name": "bump", "docs": [ "Bump seed." ], "type": "u8" }, { "name": "version", "docs": [ "Version of the airdrop" ], "type": "u64" }, { "name": "root", "docs": [ "The 256-bit merkle root." ], "type": { "array": [ "u8", 32 ] } }, { "name": "mint", "docs": [ "[Mint] of the token to be distributed." ], "type": "publicKey" }, { "name": "tokenVault", "docs": [ "Token Address of the vault" ], "type": "publicKey" }, { "name": "maxTotalClaim", "docs": [ "Maximum number of tokens that can ever be claimed from this [MerkleDistributor]." ], "type": "u64" }, { "name": "maxNumNodes", "docs": [ "Maximum number of nodes in [MerkleDistributor]." ], "type": "u64" }, { "name": "totalAmountClaimed", "docs": [ "Total amount of tokens that have been claimed." ], "type": "u64" }, { "name": "numNodesClaimed", "docs": [ "Number of nodes that have been claimed." ], "type": "u64" }, { "name": "startTs", "docs": [ "Lockup time start (Unix Timestamp)" ], "type": "i64" }, { "name": "endTs", "docs": [ "Lockup time end (Unix Timestamp)" ], "type": "i64" }, { "name": "clawbackStartTs", "docs": [ "Clawback start (Unix Timestamp)" ], "type": "i64" }, { "name": "clawbackReceiver", "docs": [ "Clawback receiver" ], "type": "publicKey" }, { "name": "admin", "docs": [ "Admin wallet" ], "type": "publicKey" }, { "name": "clawedBack", "docs": [ "Whether or not the distributor has been clawed back" ], "type": "bool" } ] } } ], "events": [ { "name": "NewClaimEvent", "fields": [ { "name": "claimant", "type": "publicKey", "index": false }, { "name": "timestamp", "type": "i64", "index": false } ] }, { "name": "ClaimedEvent", "fields": [ { "name": "claimant", "type": "publicKey", "index": false }, { "name": "amount", "type": "u64", "index": false } ] } ], "errors": [ { "code": 6000, "name": "InsufficientUnlockedTokens", "msg": "Insufficient unlocked tokens" }, { "code": 6001, "name": "StartTooFarInFuture", "msg": "Deposit Start too far in future" }, { "code": 6002, "name": "InvalidProof", "msg": "Invalid Merkle proof." }, { "code": 6003, "name": "ExceededMaxClaim", "msg": "Exceeded maximum claim amount" }, { "code": 6004, "name": "MaxNodesExceeded", "msg": "Exceeded maximum node count" }, { "code": 6005, "name": "Unauthorized", "msg": "Account is not authorized to execute this instruction" }, { "code": 6006, "name": "OwnerMismatch", "msg": "Token account owner did not match intended owner" }, { "code": 6007, "name": "ClawbackDuringVesting", "msg": "Clawback cannot be before vesting ends" }, { "code": 6008, "name": "ClawbackBeforeStart", "msg": "Attempted clawback before start" }, { "code": 6009, "name": "ClawbackAlreadyClaimed", "msg": "Clawback already claimed" }, { "code": 6010, "name": "InsufficientClawbackDelay", "msg": "Clawback start must be at least one day after vesting end" }, { "code": 6011, "name": "SameClawbackReceiver", "msg": "New and old Clawback receivers are identical" }, { "code": 6012, "name": "SameAdmin", "msg": "New and old admin are identical" }, { "code": 6013, "name": "ClaimExpired", "msg": "Claim window expired" }, { "code": 6014, "name": "ArithmeticError", "msg": "Arithmetic Error (overflow/underflow)" }, { "code": 6015, "name": "StartTimestampAfterEnd", "msg": "Start Timestamp cannot be after end Timestamp" }, { "code": 6016, "name": "TimestampsNotInFuture", "msg": "Timestamps cannot be in the past" }, { "code": 6017, "name": "InvalidVersion", "msg": "Airdrop Version Mismatch" } ] }