import { Provider, Wallet, web3 } from '@project-serum/anchor'; import * as spl from '@solana/spl-token'; import { Connection, Keypair, PublicKey } from '@solana/web3.js'; import fs from 'fs'; import { Bank, getBank, getBankForGroupAndMint, getMintInfoForTokenIndex, registerToken, } from './accounts/types/bank'; import { createGroup, getGroupForAdmin, Group } from './accounts/types/group'; import { createMangoAccount, deposit, getMangoAccount, getMangoAccountsForGroupAndOwner, MangoAccount, withdraw, } from './accounts/types/mangoAccount'; import { createStubOracle, getStubOracleForGroupAndMint, StubOracle, } from './accounts/types/oracle'; import { getSerum3MarketForBaseAndQuote, serum3CreateOpenOrders, Serum3Market, serum3RegisterMarket, } from './accounts/types/serum3'; import { MangoClient } from './client'; import { findOrCreate } from './utils'; async function main() { // // Setup // const options = Provider.defaultOptions(); const connection = new Connection( 'https://mango.devnet.rpcpool.com', options, ); const admin = Keypair.fromSecretKey( Buffer.from( JSON.parse(fs.readFileSync(process.env.ADMIN_KEYPAIR!, 'utf-8')), ), ); const adminWallet = new Wallet(admin); console.log(`Admin ${adminWallet.publicKey.toBase58()}`); const adminProvider = new Provider(connection, adminWallet, options); const adminClient = await MangoClient.connect(adminProvider, true); const payer = Keypair.fromSecretKey( Buffer.from( JSON.parse(fs.readFileSync(process.env.PAYER_KEYPAIR!, 'utf-8')), ), ); console.log(`Payer ${payer.publicKey.toBase58()}`); // // Find existing or create a new group // const group: Group = await findOrCreate( 'group', getGroupForAdmin, [adminClient, admin.publicKey], createGroup, [adminClient, admin.publicKey, payer], ); console.log(`Group ${group.publicKey}`); // // Find existing or register new oracles // const usdcDevnetMint = new PublicKey( '8FRFC6MoGGkMFQwngccyu69VnYbzykGeez7ignHVAFSN', ); const usdcDevnetStubOracle = await findOrCreate( 'stubOracle', getStubOracleForGroupAndMint, [adminClient, group.publicKey, usdcDevnetMint], createStubOracle, [adminClient, group.publicKey, admin.publicKey, usdcDevnetMint, payer, 1], ); console.log( `usdcDevnetStubOracle ${usdcDevnetStubOracle.publicKey.toBase58()}`, ); const btcDevnetMint = new PublicKey( '3UNBZ6o52WTWwjac2kPUb4FyodhU1vFkRJheu1Sh2TvU', ); const btcDevnetOracle = new PublicKey( 'HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J', ); // // Find existing or register new tokens // // TODO: replace with 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU, // see https://developers.circle.com/docs/usdc-on-testnet#usdc-on-solana-testnet const btcBank = await findOrCreate( 'bank', getBankForGroupAndMint, [adminClient, group.publicKey, btcDevnetMint], registerToken, [ adminClient, group.publicKey, admin.publicKey, btcDevnetMint, btcDevnetOracle, payer, 0, ], ); console.log(`BtcBank ${btcBank.publicKey}`); const usdcBank = await findOrCreate( 'bank', getBankForGroupAndMint, [adminClient, group.publicKey, usdcDevnetMint], registerToken, [ adminClient, group.publicKey, admin.publicKey, usdcDevnetMint, usdcDevnetStubOracle.publicKey, payer, 1, ], ); console.log(`UsdcBank ${usdcBank.publicKey}`); // // User operations // const user = Keypair.fromSecretKey( Buffer.from( JSON.parse(fs.readFileSync(process.env.USER_KEYPAIR!, 'utf-8')), ), ); const userWallet = new Wallet(user); const userProvider = new Provider(connection, userWallet, options); const userClient = await MangoClient.connect(userProvider, true); console.log(`User ${userWallet.publicKey.toBase58()}`); // // Create mango account // const mangoAccount = await findOrCreate( 'mangoAccount', getMangoAccountsForGroupAndOwner, [userClient, group.publicKey, user.publicKey], createMangoAccount, [userClient, group.publicKey, user.publicKey, payer], ); console.log(`MangoAccount ${mangoAccount.publicKey}`); // close mango account, note: close doesnt settle/withdraw for user atm, // only use when you want to free up a mango account address for testing on not-mainnet // await closeMangoAccount(userClient, account.publicKey, user.publicKey); // accounts = await getMangoAccountsForGroupAndOwner( // userClient, // group.publicKey, // user.publicKey, // ); // if (accounts.length === 0) { // console.log(`Closed account ${account.publicKey}`); // } // // Find existing or register a new serum3 market // const serumProgramId = new web3.PublicKey( 'DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY', ); const serumMarketExternalPk = new web3.PublicKey( 'DW83EpHFywBxCHmyARxwj3nzxJd7MUdSeznmrdzZKNZB', ); const serum3Market = await findOrCreate( 'serum3Market', getSerum3MarketForBaseAndQuote, [adminClient, group.publicKey, btcBank.tokenIndex, usdcBank.tokenIndex], serum3RegisterMarket, [ adminClient, group.publicKey, admin.publicKey, serumProgramId, serumMarketExternalPk, usdcBank.publicKey, btcBank.publicKey, payer, 0, ], ); console.log(`Serum3Market ${serum3Market.publicKey}`); // // Serum3 OO // if (mangoAccount.serum3[0].marketIndex == 65535) { console.log('Creating serum3 open orders account...'); await serum3CreateOpenOrders( userClient, group.publicKey, mangoAccount.publicKey, serum3Market.publicKey, serumProgramId, serumMarketExternalPk, user.publicKey, payer, ); } // // Deposit & withdraw // console.log(`Depositing...1000`); const btcTokenAccount = await spl.getAssociatedTokenAddress( btcDevnetMint, user.publicKey, ); // Aggregate all PKs of users active assets, banks, oracles and serum OOs const healthRemainingAccounts: PublicKey[] = []; { const mintInfos = await Promise.all( mangoAccount.tokens .filter((token) => token.tokenIndex !== 65535) .map(async (token) => getMintInfoForTokenIndex( userClient, group.publicKey, token.tokenIndex, ), ), ); // banks healthRemainingAccounts.push( ...mintInfos.flatMap((mintinfos) => { return mintinfos.flatMap((mintinfo) => { return mintinfo.bank; }); }), ); // oracles healthRemainingAccounts.push( ...mintInfos.flatMap((mintinfos) => { return mintinfos.flatMap((mintinfo) => { return mintinfo.oracle; }); }), ); // serum OOs healthRemainingAccounts.push( ...mangoAccount.serum3 .filter((serum3Account) => serum3Account.marketIndex !== 65535) .map((serum3Account) => serum3Account.openOrders), ); } await deposit( userClient, group.publicKey, mangoAccount.publicKey, btcBank.publicKey, btcBank.vault, btcTokenAccount, user.publicKey, healthRemainingAccounts, 1000, ); console.log(`Witdrawing...500`); await withdraw( userClient, group.publicKey, mangoAccount.publicKey, btcBank.publicKey, btcBank.vault, btcTokenAccount, user.publicKey, healthRemainingAccounts, 500, false, ); // log const freshBank = await getBank(userClient, btcBank.publicKey); console.log(freshBank.toString()); let freshAccount = await getMangoAccount(userClient, mangoAccount.publicKey); console.log( `Mango account ${freshAccount.getNativeDeposit( freshBank, )} Deposits for bank ${freshBank.tokenIndex}`, ); // // Place serum3 order // process.exit(0); } main();