diff --git a/src/components/Multisig.tsx b/src/components/Multisig.tsx index b824d63..70ae23f 100644 --- a/src/components/Multisig.tsx +++ b/src/components/Multisig.tsx @@ -44,6 +44,7 @@ import CheckCircleIcon from "@material-ui/icons/CheckCircle"; import BN from "bn.js"; import { Account, + Keypair, PublicKey, SYSVAR_RENT_PUBKEY, SYSVAR_CLOCK_PUBKEY, @@ -53,7 +54,8 @@ import { useWallet } from "./WalletProvider"; import { ViewTransactionOnExplorerButton } from "./Notification"; import * as idl from "../utils/idl"; import { networks } from "../store/reducer"; - +import { TOKEN_PROGRAM_ID } from "@solana/spl-token"; +import { createMint, createTokenAccount, findAssociatedTokenAddress } from "../utils/uxd_helper"; export default function Multisig({ multisig }: { multisig?: PublicKey }) { return (
@@ -257,7 +259,7 @@ export function NewMultisigDialog({ const multisig = new Account(); // Disc. + threshold + nonce. const baseSize = 8 + 8 + 1 + 4; - // Add enough for 2 more participants, in case the user changes one's + // Add enough for 2 more participants, in case the user changes one"s /// mind later. const fudge = 64; // Can only grow the participant set by 2x the initialized value. @@ -455,6 +457,7 @@ function TxListItem({ [multisig.toBuffer()], multisigClient.programId ); + console.log({tx: tx.publicKey}) await multisigClient.rpc.executeTransaction({ accounts: { multisig, @@ -762,12 +765,514 @@ function AddTransactionDialog({ multisig={multisig} onClose={onClose} /> + + ); } + + +function InitializeIdoPoolListItem({ + multisig, + onClose, + didAddTransaction, +}: { + multisig: PublicKey; + onClose: Function; + didAddTransaction: (tx: PublicKey) => void; + }) { + const [open, setOpen] = useState(false); + return ( + <> + setOpen((open) => !open)}> + + + + + {open ? : } + + + + + + ); +} + +function WithdrawIdoPoolListItem({ + multisig, + onClose, + didAddTransaction, +}: { + multisig: PublicKey; + onClose: Function; + didAddTransaction: (tx: PublicKey) => void; +}) { + const [open, setOpen] = useState(false); + return ( + <> + setOpen((open) => !open)}> + + + + + {open ? : } + + + + + + ); +} + +// UXD MULTISIG instance AFBx8bHKmfqVxaHxgL8hLmrxJip8Dq8fZckngpQzVVG3 +// its PDA 35F3GaWyShU5N5ygYAFWDw6bGVNHnAHSe8RKzqRD2RkT (The one owning shits) +const IdoProgramAddress = new PublicKey("UXDJHLPFr8qjLqZs8ejW24zFTq174g1wQHQ4LFhTXxz"); +const multisigPDA = new PublicKey("35F3GaWyShU5N5ygYAFWDw6bGVNHnAHSe8RKzqRD2RkT"); //? Can we actually get that from the multisigClient? +const uxpMint = new PublicKey('MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey');//new PublicKey("UXPhBoR3qG4UCiGNJfV7MqhHyFqKN68g45GoYvAeL2M"); +const usdcMint = new PublicKey("2wmVCSfPxGPjrnMMn7rchp4uaeoTqN39mXFC2zhPdri9"); //* That"s the mainnet one +const multisigUxpTokenAccount = new PublicKey("4BWt4xZ5okZRfd3KtXujjHJaHCLfjekJPLMdUzhFmSQW")//new PublicKey("GJgkVjjsYZeY2RLKcd7346A2dreykurTxkeNw6ysVQkc"); //! We should be able to get it from chain + + + +function InitializeIdoPoolListItemDetails({ + multisig, + onClose, + didAddTransaction, +}: { + multisig: PublicKey; + onClose: Function; + didAddTransaction: (tx: PublicKey) => void; + }) { + + const [num_ido_tokens, setNum_ido_tokens] = useState(3); + const [start_ido_ts, setStart_ido_ts] = useState((Date.now()/1000) + 60 * 5); + const [end_deposits_ts, setEnd_deposits_ts] = useState((Date.now()/1000) + 60 * 7); + const [end_ido_ts, setEnd_ido_ts] = useState((Date.now()/1000) + 60 * 10); + const { multisigClient, idoClient } = useWallet(); + // @ts-ignore + const { enqueueSnackbar } = useSnackbar(); + const initializeIdoPool = async () => { + enqueueSnackbar("Creating IDO pool initialization transaction", { + variant: "info", + }); + const [,nonce] = await PublicKey.findProgramAddress([IdoProgramAddress.toBuffer()], IdoProgramAddress); + const [multisigSigner] = await PublicKey.findProgramAddress( + [multisig.toBuffer()], + multisigClient.programId + ); + + const itxs = []; + const poolAccount = Keypair.generate(); + console.log("poolAccount: ", poolAccount.publicKey.toBase58()) + console.log("redeemableMint: "); + const {mint: redeemableMint, instructions: redeemableMintItxs} = await createMint(multisigClient.provider, multisigSigner); + console.log("poolUxp: "); + const {account: poolUxp, instructions: poolUxpItxs} = await createTokenAccount(multisigClient.provider, uxpMint, multisigSigner); + console.log("poolUsdc: "); + + const {account: poolUsdc, instructions: poolUsdcItxs} = await createTokenAccount( + multisigClient.provider, + usdcMint, + multisigSigner + ); + itxs.push(...redeemableMintItxs, ...poolUxpItxs, ...poolUsdcItxs); + // We use the uxp mint address as the seed, could use something else though. + const [_poolSigner] = await anchor.web3.PublicKey.findProgramAddress( + [uxpMint.toBuffer()], + IdoProgramAddress + ); + const poolSigner = _poolSigner; + const distributionAuthority = multisigPDA; + const accounts = [ + + // HERE NEED TO ADD THE RIGHT ACCOUNTS -- Not sure what can be hardcoded or not your call for now. + // Accounts expected can be found here https://github.com/UXDProtocol/uxd_ido/blob/main/programs/uxd_ido/src/lib.rs#L281 + + // pool_account -- can be created arbitrarily - then will need to be referenced in the other operations and used on the front end (THE POINTER TO OUR IDO) + { + pubkey: poolAccount.publicKey, + isWritable: true, + isSigner: true, + }, + // pool_signer -- this is the multisig PDA : 35F3GaWyShU5N5ygYAFWDw6bGVNHnAHSe8RKzqRD2RkT + //? While testing we used to use a derivation from the uxp mint for creating this account + { + pubkey: poolSigner, + isWritable: false, + isSigner: false, + }, + // redeemable_mint -- Wrapped sollet USDC? which one do we use https://solscan.io/token/BXXkv6z8ykpG1yuvUDPgh732wzVHB69RnB9YgSYh3itW + // apparently we do not have to give a shit, jsute create a random mint account + { + pubkey: redeemableMint.publicKey, + isWritable: false, + isSigner: false, + }, + // uxp_mint -- This is UXP UXPhBoR3qG4UCiGNJfV7MqhHyFqKN68g45GoYvAeL2M token () https://solscan.io/token/UXPhBoR3qG4UCiGNJfV7MqhHyFqKN68g45GoYvAeL2M () + { + pubkey: uxpMint, + isWritable: false, + isSigner: false, + }, + // pool_uxp -- + { + pubkey: poolUxp.publicKey, + isWritable: true, + isSigner: false, + }, + // pool_usdc -- + { + pubkey: poolUsdc.publicKey, + isWritable: false, + isSigner: false, + }, + // distribution_authority -- should be the multisig PDA - might have an issue with the program cause it"s also a payer + // 35F3GaWyShU5N5ygYAFWDw6bGVNHnAHSe8RKzqRD2RkT + // NGMI if we discover issues last minute, this need to be done asap for our mental wellbeing, sorry to be lame but it"s super important + { + pubkey: distributionAuthority, + isWritable: true, + isSigner: false, + }, + // creator_uxp -- Not sure what is this what was used before + //* It is the token account that holds the UXP that will be transfered to the uxpPool at initialization + { + pubkey: multisigUxpTokenAccount, + isWritable: true, + isSigner: false, + }, + // token_program + { + pubkey: TOKEN_PROGRAM_ID, + isWritable: false, + isSigner: false, + }, + // system_program + { + pubkey: anchor.web3.SystemProgram.programId, + isWritable: false, + isSigner: false, + }, + // rent + { + pubkey: anchor.web3.SYSVAR_RENT_PUBKEY, + isWritable: false, + isSigner: false, + }, + // clock + { + pubkey: anchor.web3.SYSVAR_CLOCK_PUBKEY, + isWritable: false, + isSigner: false, + }, + ]; + + const data = initializeIdoPoolData(idoClient, num_ido_tokens, nonce, start_ido_ts, end_deposits_ts, end_ido_ts, + { + poolAccount: poolAccount.publicKey, + poolSigner, + distributionAuthority: multisigPDA, + redeemableMint: redeemableMint.publicKey, + usdcMint, + uxpMint, + poolUxp: poolUxp.publicKey, + poolUsdc: poolUsdc.publicKey, + creatorUxp: multisigUxpTokenAccount, + tokenProgram: TOKEN_PROGRAM_ID, + systemProgram: anchor.web3.SystemProgram.programId, + rent: anchor.web3.SYSVAR_RENT_PUBKEY, + clock: anchor.web3.SYSVAR_CLOCK_PUBKEY, + }, + poolAccount, + itxs + ); + + const transaction = new Keypair(); + const txSize = 1000; // todo + const txItx = (await multisigClient.account.transaction.createInstruction( + transaction, + // @ts-ignore + txSize + )); + + + const tx = await multisigClient.rpc.createTransaction( + idoClient.programId, + accounts, + data, + { + accounts: { + multisig, + transaction: transaction.publicKey, + proposer: multisigClient.provider.wallet.publicKey, + rent: SYSVAR_RENT_PUBKEY, + }, + signers: [transaction, poolAccount], + instructions: [ + txItx + ], + } + ); + enqueueSnackbar("Transaction created", { + variant: "success", + action: , + }); + didAddTransaction(transaction.publicKey); + onClose(); + }; + return ( +
+ { + // @ts-ignore + setNum_ido_tokens(e.target.value); + }} + /> + { + // @ts-ignore + setStart_ido_ts(e.target.value); + }} + /> + { + // @ts-ignore + setEnd_deposits_ts(e.target.value); + }} + /> + { + // @ts-ignore + setEnd_ido_ts(e.target.value); + }} + /> +
+ +
+
+ ); +} + +function WithdrawIdoPoolListItemDetails({ + multisig, + onClose, + didAddTransaction, +}: { + multisig: PublicKey; + onClose: Function; + didAddTransaction: (tx: PublicKey) => void; +}) { + const [poolAccountAddr, setPoolAccountAddr] = useState(""); + const [poolUsdcAddr, setPoolUsdcAddr] = useState(""); + const { multisigClient, idoClient } = useWallet(); + + const { enqueueSnackbar } = useSnackbar(); + const withdrawIdoPool = async () => { + const itxs: anchor.web3.TransactionInstruction[] = []; + let multisigUsdcTokenAccount = findAssociatedTokenAddress(multisigPDA, usdcMint) + if (!multisigUsdcTokenAccount) { + const { account: multisigUsdcAcc, instructions: createmultisigUsdcItxs} = await createTokenAccount(multisigClient.provider, usdcMint, multisigPDA); + multisigUsdcTokenAccount = multisigUsdcAcc.publicKey + itxs.push(...createmultisigUsdcItxs); + } + // We use the uxp mint address as the seed, could use something else though. + const [_poolSigner] = await anchor.web3.PublicKey.findProgramAddress( + [uxpMint.toBuffer()], + IdoProgramAddress + ); + const poolSigner = _poolSigner; + // @ts-ignore + enqueueSnackbar("Creating USDC pool withdraw transaction", { + variant: "info", + }); + + const poolAccountKey = new PublicKey(poolAccountAddr) + const poolUsdcKey = new PublicKey(poolUsdcAddr) + const distributionAuthority = multisigPDA; + const accounts = [ + // HERE NEED TO ADD THE RIGHT ACCOUNTS -- Not sure what can be hardcoded or not your call for now. + // Accounts expected can be found here https://github.com/UXDProtocol/uxd_ido/blob/main/programs/uxd_ido/src/lib.rs#L281 + + // pool_account -- can be created arbitrarily - then will need to be referenced in the other operations and used on the front end (THE POINTER TO OUR IDO) + { + pubkey: poolAccountKey, + isWritable: false, + isSigner: false, + }, + // pool_signer -- this is the multisig PDA : 35F3GaWyShU5N5ygYAFWDw6bGVNHnAHSe8RKzqRD2RkT + //? While testing we used to use a derivation from the uxp mint for creating this account + { + pubkey: poolSigner, + isWritable: false, + isSigner: false, + }, + + // pool_usdc -- + { + pubkey: poolUsdcKey, + isWritable: true, + isSigner: false, + }, + // distribution_authority -- should be the multisig PDA - might have an issue with the program cause it"s also a payer + // 35F3GaWyShU5N5ygYAFWDw6bGVNHnAHSe8RKzqRD2RkT + // NGMI if we discover issues last minute, this need to be done asap for our mental wellbeing, sorry to be lame but it"s super important + { + pubkey: distributionAuthority, + isWritable: false, + isSigner: true, + }, + // creator_usdc -- is actually the token account that will receive the usdc + { + pubkey: multisigUsdcTokenAccount, + isWritable: true, + isSigner: false, + }, + // token_program + { + pubkey: TOKEN_PROGRAM_ID, + isWritable: false, + isSigner: false, + }, + + // clock + { + pubkey: anchor.web3.SYSVAR_CLOCK_PUBKEY, + isWritable: false, + isSigner: false, + }, + ]; + + const data = withdrawIdoUsdcPoolData( + idoClient, + { + poolAccount: poolAccountKey, + poolSigner, + distributionAuthority: multisigPDA, + creatorUsdc: multisigUsdcTokenAccount, + poolUsdc: poolUsdcKey, + tokenProgram: TOKEN_PROGRAM_ID, + clock: anchor.web3.SYSVAR_CLOCK_PUBKEY, + }, + itxs + ); + + + const transaction = new Keypair(); + const txSize = 1000; // todo + const txItx = await multisigClient.account.transaction.createInstruction( + transaction, + // @ts-ignore + txSize + ); + + const tx = await multisigClient.rpc.createTransaction( + idoClient.programId, + accounts, + data, + { + accounts: { + multisig, + transaction: transaction.publicKey, + proposer: multisigClient.provider.wallet.publicKey, + rent: SYSVAR_RENT_PUBKEY, + }, + signers: [transaction], + instructions: [ + + txItx + ], + } + ); + enqueueSnackbar("Transaction created", { + variant: "success", + action: , + }); + didAddTransaction(transaction.publicKey); + onClose(); + }; + return ( +
+ { + // @ts-ignore + setPoolAccountAddr(e.target.value); + }} + /> + { + // @ts-ignore + setPoolUsdcAddr(e.target.value); + }} + /> +
+ +
+
+ ); +} + + function ChangeThresholdListItem({ multisig, onClose, @@ -806,7 +1311,7 @@ function ChangeThresholdListItemDetails({ multisig: PublicKey; onClose: Function; didAddTransaction: (tx: PublicKey) => void; -}) { + }) { const [threshold, setThreshold] = useState(2); const { multisigClient } = useWallet(); // @ts-ignore @@ -1355,6 +1860,46 @@ function changeThresholdData(multisigClient, threshold) { }); } +// @ts-ignore +function initializeIdoPoolData(idoClient: anchor.Program, + num_ido_tokens: number, + nonce: number, + start_ido_ts: number, + end_deposits_ts: number, + end_ido_ts: number, + accounts: any, + signer: Keypair, + itxs: anchor.web3.TransactionInstruction[] +) { + return idoClient.coder.instruction.encode( + "initialize_pool", + idoClient.instruction.initializePool( + new BN(num_ido_tokens), + new BN(nonce), + new BN(start_ido_ts), + new BN(end_deposits_ts), + new BN(end_ido_ts), + { + accounts, + signers: [signer], + instructions: [...itxs] + } + )); +} + + +// @ts-ignore +function withdrawIdoUsdcPoolData(idoClient: anchor.Program, accounts: any, itxs: anchor.web3.TransactionInstruction[]) { + return idoClient.coder.instruction.encode( + "withdraw_pool_usdc", + idoClient.instruction.withdrawPoolUsdc( + { + accounts, + instructions: [...itxs] + } + )); +} + // @ts-ignore function setOwnersData(multisigClient, owners) { return multisigClient.coder.instruction.encode("set_owners", { diff --git a/src/components/WalletProvider.tsx b/src/components/WalletProvider.tsx index 3b07d0c..b07852c 100644 --- a/src/components/WalletProvider.tsx +++ b/src/components/WalletProvider.tsx @@ -9,9 +9,10 @@ import { useSelector } from "react-redux"; import { Connection, ConfirmOptions } from "@solana/web3.js"; // @ts-ignore import Wallet from "@project-serum/sol-wallet-adapter"; -import { Program, Provider } from "@project-serum/anchor"; +import { Program, Provider, web3 } from "@project-serum/anchor"; import { State as StoreState } from "../store/reducer"; import MultisigIdl from "../idl"; +import idoIdl from "../idl/idoIdl"; export function useWallet(): WalletContextValues { const w = useContext(WalletContext); @@ -27,6 +28,7 @@ const WalletContext = React.createContext(null); type WalletContextValues = { wallet: Wallet; multisigClient: Program; + idoClient: Program }; export default function WalletProvider( @@ -39,7 +41,7 @@ export default function WalletProvider( }; }); - const { wallet, multisigClient } = useMemo(() => { + const { wallet, multisigClient, idoClient } = useMemo(() => { const opts: ConfirmOptions = { preflightCommitment: "recent", commitment: "recent", @@ -54,14 +56,23 @@ export default function WalletProvider( provider ); + const UXDIDOProgramAdress = new web3.PublicKey("UXDJHLPFr8qjLqZs8ejW24zFTq174g1wQHQ4LFhTXxz"); + + const idoClient = new Program( + idoIdl, + UXDIDOProgramAdress, + provider + ) + return { wallet, multisigClient, + idoClient }; }, [walletProvider, network]); return ( - + {props.children} ); diff --git a/src/idl/idoIdl.ts b/src/idl/idoIdl.ts new file mode 100644 index 0000000..0884a81 --- /dev/null +++ b/src/idl/idoIdl.ts @@ -0,0 +1,441 @@ +import { Idl } from "@project-serum/anchor"; + +const uxdIdl: Idl = { + "version": "0.0.0", + "name": "uxd_ido", + "instructions": [ + { + "name": "initializePool", + "accounts": [ + { + "name": "poolAccount", + "isMut": true, + "isSigner": true + }, + { + "name": "poolSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "redeemableMint", + "isMut": false, + "isSigner": false + }, + { + "name": "uxpMint", + "isMut": false, + "isSigner": false + }, + { + "name": "usdcMint", + "isMut": false, + "isSigner": false + }, + { + "name": "poolUxp", + "isMut": true, + "isSigner": false + }, + { + "name": "poolUsdc", + "isMut": false, + "isSigner": false + }, + { + "name": "distributionAuthority", + "isMut": true, + "isSigner": true + }, + { + "name": "creatorUxp", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "numIdoTokens", + "type": "u64" + }, + { + "name": "nonce", + "type": "u8" + }, + { + "name": "startIdoTs", + "type": "i64" + }, + { + "name": "endDepositsTs", + "type": "i64" + }, + { + "name": "endIdoTs", + "type": "i64" + } + ] + }, + { + "name": "exchangeUsdcForRedeemable", + "accounts": [ + { + "name": "poolAccount", + "isMut": false, + "isSigner": false + }, + { + "name": "poolSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "redeemableMint", + "isMut": true, + "isSigner": false + }, + { + "name": "poolUsdc", + "isMut": true, + "isSigner": false + }, + { + "name": "userAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "userUsdc", + "isMut": true, + "isSigner": false + }, + { + "name": "userRedeemable", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "exchangeRedeemableForUsdc", + "accounts": [ + { + "name": "poolAccount", + "isMut": false, + "isSigner": false + }, + { + "name": "poolSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "redeemableMint", + "isMut": true, + "isSigner": false + }, + { + "name": "poolUsdc", + "isMut": true, + "isSigner": false + }, + { + "name": "userAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "userUsdc", + "isMut": true, + "isSigner": false + }, + { + "name": "userRedeemable", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "exchangeRedeemableForUxp", + "accounts": [ + { + "name": "poolAccount", + "isMut": false, + "isSigner": false + }, + { + "name": "poolSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "redeemableMint", + "isMut": true, + "isSigner": false + }, + { + "name": "poolUxp", + "isMut": true, + "isSigner": false + }, + { + "name": "userAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "userUxp", + "isMut": true, + "isSigner": false + }, + { + "name": "userRedeemable", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "withdrawPoolUsdc", + "accounts": [ + { + "name": "poolAccount", + "isMut": false, + "isSigner": false + }, + { + "name": "poolSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "poolUsdc", + "isMut": true, + "isSigner": false + }, + { + "name": "distributionAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "creatorUsdc", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + } + ], + "args": [] + } + ], + "accounts": [ + { + "name": "PoolAccount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "redeemableMint", + "type": "publicKey" + }, + { + "name": "poolUxp", + "type": "publicKey" + }, + { + "name": "uxpMint", + "type": "publicKey" + }, + { + "name": "poolUsdc", + "type": "publicKey" + }, + { + "name": "usdcMint", + "type": "publicKey" + }, + { + "name": "distributionAuthority", + "type": "publicKey" + }, + { + "name": "nonce", + "type": "u8" + }, + { + "name": "numIdoTokens", + "type": "u64" + }, + { + "name": "startIdoTs", + "type": "i64" + }, + { + "name": "endDepositsTs", + "type": "i64" + }, + { + "name": "endIdoTs", + "type": "i64" + } + ] + } + } + ], + "errors": [ + { + "code": 300, + "name": "IdoFuture", + "msg": "IDO must start in the future" + }, + { + "code": 301, + "name": "SeqTimes", + "msg": "IDO times are non-sequential" + }, + { + "code": 302, + "name": "StartIdoTime", + "msg": "IDO has not started" + }, + { + "code": 303, + "name": "EndDepositsTime", + "msg": "Deposits period has ended" + }, + { + "code": 304, + "name": "EndIdoTime", + "msg": "IDO has ended" + }, + { + "code": 305, + "name": "IdoNotOver", + "msg": "IDO has not finished yet" + }, + { + "code": 306, + "name": "InvalidAmount", + "msg": "Invalid amount passed to instruction. Should be not zero." + }, + { + "code": 307, + "name": "LowUsdc", + "msg": "Insufficient USDC" + }, + { + "code": 308, + "name": "LowRedeemable", + "msg": "Insufficient redeemable tokens" + }, + { + "code": 309, + "name": "UsdcNotEqRedeem", + "msg": "USDC total and redeemable total don't match" + }, + { + "code": 310, + "name": "InvalidNonce", + "msg": "Given nonce is invalid" + }, + { + "code": 311, + "name": "InvalidParam", + "msg": "Invalid param" + }, + { + "code": 312, + "name": "InvalidIdoAmount", + "msg": "Invalid Ido amount. There must be a positive amount of IDO token to distribute." + }, + { + "code": 313, + "name": "InvalidIdoEndTime", + "msg": "IDO cannot end before it starts." + }, + { + "code": 314, + "name": "InvalidIdoDepositEndTime", + "msg": "IDO cannot end before it starts." + } + ] + }; +export default uxdIdl; diff --git a/src/utils/uxd_helper.ts b/src/utils/uxd_helper.ts new file mode 100644 index 0000000..f6421bf --- /dev/null +++ b/src/utils/uxd_helper.ts @@ -0,0 +1,105 @@ +// TODO: use the `@solana/spl-token` package instead of utils here. +import * as anchor from '@project-serum/anchor'; +import { TokenInstructions } from '@project-serum/serum'; + +// TODO: remove this constant once @project-serum/serum uses the same version +// of @solana/web3.js as anchor (or switch packages). +const TOKEN_PROGRAM_ID = TokenInstructions.TOKEN_PROGRAM_ID; + +const ASSOC_TOKEN_PROGRAM_ID = new anchor.web3.PublicKey('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'); + + + +export async function createMint(provider: anchor.Provider, authority: anchor.web3.PublicKey) { + if (authority === undefined) { + authority = provider.wallet.publicKey; + } + const mint = anchor.web3.Keypair.generate(); + console.log(mint.publicKey.toBase58()) + const instructions = await createMintInstructions(provider, authority, mint.publicKey); + return { mint, instructions}; + // const tx = new anchor.web3.Transaction(); + // tx.add(...instructions); + + // await provider.send(tx, [mint]); + + // return mint.publicKey; +} + +async function createMintInstructions( + provider: anchor.Provider, + authority: anchor.web3.PublicKey, + mint: anchor.web3.PublicKey +) { + console.log("TOKEN_PROGRAM_ID", TOKEN_PROGRAM_ID) + let instructions = [ + anchor.web3.SystemProgram.createAccount({ + fromPubkey: provider.wallet.publicKey, + newAccountPubkey: mint, + space: 82, + lamports: await provider.connection.getMinimumBalanceForRentExemption(82), + programId: TOKEN_PROGRAM_ID, + }), + TokenInstructions.initializeMint({ + mint, + decimals: 6, + mintAuthority: authority, + }), + ]; + return instructions; +} + +export async function createTokenAccount( + provider: anchor.Provider, + mint: anchor.web3.PublicKey, + owner: anchor.web3.PublicKey +) { + const vault = anchor.web3.Keypair.generate(); + console.log(vault.publicKey.toBase58()) + //const tx = new anchor.web3.Transaction(); + const instructions = await createTokenAccountInstrs(provider, vault.publicKey, mint, owner); + return { account: vault, instructions} + // await provider.send(tx, [vault]); + // return vault.publicKey; +} + +async function createTokenAccountInstrs( + provider: anchor.Provider, + newAccountPubkey: anchor.web3.PublicKey, + mint: anchor.web3.PublicKey, + owner: anchor.web3.PublicKey, + lamports?: number +) { + if (lamports === undefined) { + lamports = await provider.connection.getMinimumBalanceForRentExemption(165); + } + return [ + anchor.web3.SystemProgram.createAccount({ + fromPubkey: provider.wallet.publicKey, + newAccountPubkey, + space: 165, + lamports, + programId: TOKEN_PROGRAM_ID, + }), + TokenInstructions.initializeAccount({ + account: newAccountPubkey, + mint, + owner, + }), + ]; +} + + +// derives the canonical token account address for a given wallet and mint +export function findAssociatedTokenAddress(walletKey: anchor.web3.PublicKey, mintKey: anchor.web3.PublicKey,) { + if (!walletKey || !mintKey) return; + return findAddr( + [walletKey.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), mintKey.toBuffer()], + ASSOC_TOKEN_PROGRAM_ID + ); +} + +// simple shorthand +function findAddr(seeds: (Buffer | Uint8Array)[], programId: anchor.web3.PublicKey) { + return anchor.utils.publicKey.findProgramAddressSync(seeds, programId)[0]; +} \ No newline at end of file