diff --git a/governance/xc_admin/packages/xc_admin_cli/src/index.ts b/governance/xc_admin/packages/xc_admin_cli/src/index.ts index 0a44195c0c..5fb37defc7 100644 --- a/governance/xc_admin/packages/xc_admin_cli/src/index.ts +++ b/governance/xc_admin/packages/xc_admin_cli/src/index.ts @@ -30,6 +30,12 @@ import { import { pythOracleProgram } from "@pythnetwork/client"; import { Wallet } from "@coral-xyz/anchor/dist/cjs/provider"; import { LedgerNodeWallet } from "./ledger"; +import { + createTransferInstruction, + getAssociatedTokenAddress, + getMint, +} from "@solana/spl-token"; +import { TOKEN_PROGRAM_ID } from "@coral-xyz/anchor/dist/cjs/utils/token"; export async function loadHotWalletOrLedger( wallet: string, @@ -299,4 +305,59 @@ mutlisigCommand("approve", "Approve a transaction sitting in the multisig") await squad.approveTransaction(transaction); }); +mutlisigCommand("propose-token-transfer", "Propose token transfer") + .requiredOption("-a, --amount ", "amount in dollars") + .requiredOption("-d, --destination ", "destination address") + .option( + "-m --mint ", + "mint to transfer", + "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" // default value is solana mainnet USDC SPL + ) + .action(async (options: any) => { + const wallet = await loadHotWalletOrLedger( + options.wallet, + options.ledgerDerivationAccount, + options.ledgerDerivationChange + ); + + const cluster: PythCluster = options.cluster; + const destination: PublicKey = new PublicKey(options.destination); + const mint: PublicKey = new PublicKey(options.mint); + const vault: PublicKey = new PublicKey(options.vault); + const amount: number = options.amount; + + const squad = SquadsMesh.endpoint(getPythClusterApiUrl(cluster), wallet); + const msAccount = await squad.getMultisig(vault); + const vaultAuthority = squad.getAuthorityPDA( + msAccount.publicKey, + msAccount.authorityIndex + ); + + const mintAccount = await getMint( + squad.connection, + mint, + undefined, + TOKEN_PROGRAM_ID + ); + const sourceTokenAccount = await getAssociatedTokenAddress( + mint, + vaultAuthority, + true + ); + const destinationTokenAccount = await getAssociatedTokenAddress( + mint, + destination + ); + + const proposalInstruction: TransactionInstruction = + createTransferInstruction( + sourceTokenAccount, + destinationTokenAccount, + vaultAuthority, + BigInt(amount) * BigInt(10) ** BigInt(mintAccount.decimals) + ); + + await proposeInstructions(squad, vault, [proposalInstruction], false); + }); + program.parse(); diff --git a/governance/xc_admin/packages/xc_admin_frontend/package.json b/governance/xc_admin/packages/xc_admin_frontend/package.json index 6b3d63c22f..1bc5a56583 100644 --- a/governance/xc_admin/packages/xc_admin_frontend/package.json +++ b/governance/xc_admin/packages/xc_admin_frontend/package.json @@ -12,6 +12,7 @@ "@coral-xyz/anchor": "^0.26.0", "@headlessui/react": "^1.7.7", "@pythnetwork/client": "^2.15.0", + "@solana/spl-token": "^0.3.7", "@solana/wallet-adapter-base": "^0.9.20", "@solana/wallet-adapter-react": "^0.15.28", "@solana/wallet-adapter-react-ui": "^0.9.27", diff --git a/package-lock.json b/package-lock.json index 279bfc8c33..1c3353fc3b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1416,6 +1416,7 @@ "@coral-xyz/anchor": "^0.26.0", "@headlessui/react": "^1.7.7", "@pythnetwork/client": "^2.15.0", + "@solana/spl-token": "^0.3.7", "@solana/wallet-adapter-base": "^0.9.20", "@solana/wallet-adapter-react": "^0.15.28", "@solana/wallet-adapter-react-ui": "^0.9.27", @@ -85165,6 +85166,7 @@ "@coral-xyz/anchor": "^0.26.0", "@headlessui/react": "^1.7.7", "@pythnetwork/client": "^2.15.0", + "@solana/spl-token": "*", "@solana/wallet-adapter-base": "^0.9.20", "@solana/wallet-adapter-react": "^0.15.28", "@solana/wallet-adapter-react-ui": "^0.9.27",