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