123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508 |
- const assert = require("assert");
- const { Token } = require("@solana/spl-token");
- const anchor = require("@project-serum/anchor");
- const serumCmn = require("@project-serum/common");
- const { Market } = require("@project-serum/serum");
- const utf8 = anchor.utils.bytes.utf8;
- const { PublicKey, SystemProgram, Keypair, SYSVAR_RENT_PUBKEY } = anchor.web3;
- const utils = require("./utils");
- const { setupStakePool } = require("./utils/stake");
- const DEX_PID = new PublicKey("9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin");
- const SWAP_PID = new PublicKey("22Y43yTVxuUkoRKdm9thyRhQ3SdgQS7c7kB6UNCiaczD");
- const TOKEN_PID = new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
- const REGISTRY_PID = new PublicKey(
- "GrAkKfEpTKQuVHG2Y97Y2FF4i7y7Q5AHLK94JBy7Y5yv"
- );
- const LOCKUP_PID = new PublicKey(
- "6ebQNeTPZ1j7k3TtkCCtEPRvG7GQsucQrZ7sSEDQi9Ks"
- );
- const SYSVAR_INSTRUCTIONS_PUBKEY = new PublicKey(
- "Sysvar1nstructions1111111111111111111111111"
- );
- const FEES = "6160355581";
- describe("cfo", () => {
- anchor.setProvider(anchor.Provider.env());
- const program = anchor.workspace.Cfo;
- const sweepAuthority = program.provider.wallet.publicKey;
- let officer, srmVault, usdcVault, bVault, stake, treasury;
- let officerBump, srmBump, usdcBump, bBump, stakeBump, treasuryBump;
- let openOrders, openOrdersBump;
- let openOrdersB, openOrdersBumpB;
- let USDC_TOKEN_CLIENT, A_TOKEN_CLIENT, B_TOKEN_CLIENT;
- let officerAccount;
- let marketAClient, marketBClient;
- let marketAuth, marketAuthBump;
- let marketAuthB, marketAuthBumpB;
- let distribution;
- // Accounts used to setup the orderbook.
- let ORDERBOOK_ENV,
- // Accounts used for A -> USDC swap transactions.
- SWAP_A_USDC_ACCOUNTS,
- // Accounts used for USDC -> A swap transactions.
- SWAP_USDC_A_ACCOUNTS,
- // Serum DEX vault PDA for market A/USDC.
- marketAVaultSigner,
- // Serum DEX vault PDA for market B/USDC.
- marketBVaultSigner;
- let registrar, msrmRegistrar;
- it("BOILERPLATE: Sets up a market with funded fees", async () => {
- ORDERBOOK_ENV = await utils.initMarket({
- provider: program.provider,
- });
- console.log("Token A: ", ORDERBOOK_ENV.marketA.baseMintAddress.toString());
- console.log(
- "Token USDC: ",
- ORDERBOOK_ENV.marketA.quoteMintAddress.toString()
- );
- USDC_TOKEN_CLIENT = new Token(
- program.provider.connection,
- ORDERBOOK_ENV.usdc,
- TOKEN_PID,
- program.provider.wallet.payer
- );
- SRM_TOKEN_CLIENT = new Token(
- program.provider.connection,
- ORDERBOOK_ENV.mintA,
- TOKEN_PID,
- program.provider.wallet.payer
- );
- B_TOKEN_CLIENT = new Token(
- program.provider.connection,
- ORDERBOOK_ENV.mintB,
- TOKEN_PID,
- program.provider.wallet.payer
- );
- await USDC_TOKEN_CLIENT.transfer(
- ORDERBOOK_ENV.godUsdc,
- ORDERBOOK_ENV.marketA._decoded.quoteVault,
- program.provider.wallet.payer,
- [],
- 10000000000000
- );
- const tokenAccount = await USDC_TOKEN_CLIENT.getAccountInfo(
- ORDERBOOK_ENV.marketA._decoded.quoteVault
- );
- assert.ok(tokenAccount.amount.toString() === "10000902263700");
- });
- it("BOILERPLATE: Executes trades to generate fees", async () => {
- await utils.runTradeBot(
- ORDERBOOK_ENV.marketA._decoded.ownAddress,
- program.provider,
- 1
- );
- marketAClient = await Market.load(
- program.provider.connection,
- ORDERBOOK_ENV.marketA.address,
- { commitment: "processed" },
- DEX_PID
- );
- marketBClient = await Market.load(
- program.provider.connection,
- ORDERBOOK_ENV.marketB.address,
- { commitment: "processed" },
- DEX_PID
- );
- assert.ok(marketAClient._decoded.quoteFeesAccrued.toString() === FEES);
- });
- it("BOILERPLATE: Sets up the staking pools", async () => {
- await setupStakePool(ORDERBOOK_ENV.mintA, ORDERBOOK_ENV.godA);
- registrar = ORDERBOOK_ENV.usdc;
- msrmRegistrar = registrar;
- });
- it("BOILERPLATE: Finds PDA addresses", async () => {
- const [_officer, _officerBump] = await PublicKey.findProgramAddress(
- [DEX_PID.toBuffer()],
- program.programId
- );
- const [_openOrders, _openOrdersBump] = await PublicKey.findProgramAddress(
- [
- utf8.encode("open-orders"),
- _officer.toBuffer(),
- ORDERBOOK_ENV.marketA.address.toBuffer(),
- ],
- program.programId
- );
- const [_openOrdersB, _openOrdersBumpB] = await PublicKey.findProgramAddress(
- [
- utf8.encode("open-orders"),
- _officer.toBuffer(),
- ORDERBOOK_ENV.marketB.address.toBuffer(),
- ],
- program.programId
- );
- const [_srmVault, _srmBump] = await PublicKey.findProgramAddress(
- [
- utf8.encode("token"),
- _officer.toBuffer(),
- ORDERBOOK_ENV.mintA.toBuffer(),
- ],
- program.programId
- );
- const [_bVault, _bBump] = await PublicKey.findProgramAddress(
- [
- utf8.encode("token"),
- _officer.toBuffer(),
- ORDERBOOK_ENV.mintB.toBuffer(),
- ],
- program.programId
- );
- const [_usdcVault, _usdcBump] = await PublicKey.findProgramAddress(
- [
- utf8.encode("token"),
- _officer.toBuffer(),
- ORDERBOOK_ENV.usdc.toBuffer(),
- ],
- program.programId
- );
- const [_stake, _stakeBump] = await PublicKey.findProgramAddress(
- [utf8.encode("stake"), _officer.toBuffer()],
- program.programId
- );
- const [_treasury, _treasuryBump] = await PublicKey.findProgramAddress(
- [utf8.encode("treasury"), _officer.toBuffer()],
- program.programId
- );
- const [_marketAuth, _marketAuthBump] = await PublicKey.findProgramAddress(
- [
- utf8.encode("market-auth"),
- _officer.toBuffer(),
- ORDERBOOK_ENV.marketA.address.toBuffer(),
- ],
- program.programId
- );
- const [_marketAuthB, _marketAuthBumpB] = await PublicKey.findProgramAddress(
- [
- utf8.encode("market-auth"),
- _officer.toBuffer(),
- ORDERBOOK_ENV.marketB.address.toBuffer(),
- ],
- program.programId
- );
- officer = _officer;
- officerBump = _officerBump;
- openOrders = _openOrders;
- openOrdersBump = _openOrdersBump;
- openOrdersB = _openOrdersB;
- openOrdersBumpB = _openOrdersBumpB;
- srmVault = _srmVault;
- srmBump = _srmBump;
- usdcVault = _usdcVault;
- usdcBump = _usdcBump;
- bVault = _bVault;
- bBump = _bBump;
- stake = _stake;
- stakeBump = _stakeBump;
- treasury = _treasury;
- treasuryBump = _treasuryBump;
- marketAuth = _marketAuth;
- marketAuthBump = _marketAuthBump;
- marketAuthB = _marketAuthB;
- marketAuthBumpB = _marketAuthBumpB;
- });
- it("Creates a CFO!", async () => {
- distribution = {
- burn: 80,
- stake: 20,
- treasury: 0,
- };
- const bumps = {
- bump: officerBump,
- srm: srmBump,
- usdc: usdcBump,
- stake: stakeBump,
- treasury: treasuryBump,
- };
- await program.methods
- .createOfficer(bumps, distribution, registrar, msrmRegistrar)
- .accounts({
- officer,
- srmVault,
- usdcVault,
- stake,
- treasury,
- srmMint: ORDERBOOK_ENV.mintA,
- usdcMint: ORDERBOOK_ENV.usdc,
- authority: program.provider.wallet.publicKey,
- dexProgram: DEX_PID,
- swapProgram: SWAP_PID,
- tokenProgram: TOKEN_PID,
- systemProgram: SystemProgram.programId,
- rent: SYSVAR_RENT_PUBKEY,
- })
- .rpc();
- officerAccount = await program.account.officer.fetch(officer);
- assert.ok(
- officerAccount.authority.equals(program.provider.wallet.publicKey)
- );
- assert.ok(
- JSON.stringify(officerAccount.distribution) ===
- JSON.stringify(distribution)
- );
- });
- it("Creates a token account for the officer associated with the market", async () => {
- await program.methods
- .createOfficerToken(bBump)
- .accounts({
- officer,
- token: bVault,
- mint: ORDERBOOK_ENV.mintB,
- payer: program.provider.wallet.publicKey,
- systemProgram: SystemProgram.programId,
- tokenProgram: TOKEN_PID,
- rent: SYSVAR_RENT_PUBKEY,
- })
- .rpc();
- const tokenAccount = await B_TOKEN_CLIENT.getAccountInfo(bVault);
- assert.ok(tokenAccount.state === 1);
- assert.ok(tokenAccount.isInitialized);
- });
- it("Creates an open orders account for the officer", async () => {
- await program.methods
- .createOfficerOpenOrders(openOrdersBump)
- .accounts({
- officer,
- openOrders,
- payer: program.provider.wallet.publicKey,
- dexProgram: DEX_PID,
- systemProgram: SystemProgram.programId,
- rent: SYSVAR_RENT_PUBKEY,
- market: ORDERBOOK_ENV.marketA.address,
- })
- .rpc();
- await program.rpc.createOfficerOpenOrders(openOrdersBumpB, {
- accounts: {
- officer,
- openOrders: openOrdersB,
- payer: program.provider.wallet.publicKey,
- dexProgram: DEX_PID,
- systemProgram: SystemProgram.programId,
- rent: SYSVAR_RENT_PUBKEY,
- market: ORDERBOOK_ENV.marketB.address,
- },
- });
- });
- it("Sweeps fees", async () => {
- const [sweepVault, bump] = await PublicKey.findProgramAddress(
- [utf8.encode("token"), officer.toBuffer(), ORDERBOOK_ENV.usdc.toBuffer()],
- program.programId
- );
- const beforeTokenAccount = await serumCmn.getTokenAccount(
- program.provider,
- sweepVault
- );
- await program.methods
- .sweepFees()
- .accounts({
- officer,
- sweepVault,
- mint: ORDERBOOK_ENV.usdc,
- dex: {
- market: ORDERBOOK_ENV.marketA._decoded.ownAddress,
- pcVault: ORDERBOOK_ENV.marketA._decoded.quoteVault,
- sweepAuthority,
- vaultSigner: ORDERBOOK_ENV.marketAVaultSigner,
- dexProgram: DEX_PID,
- tokenProgram: TOKEN_PID,
- },
- })
- .rpc();
- const afterTokenAccount = await serumCmn.getTokenAccount(
- program.provider,
- sweepVault
- );
- assert.ok(
- afterTokenAccount.amount.sub(beforeTokenAccount.amount).toString() ===
- FEES
- );
- });
- it("Creates a market auth token", async () => {
- await program.methods
- .authorizeMarket(marketAuthBump)
- .accounts({
- officer,
- authority: program.provider.wallet.publicKey,
- marketAuth,
- payer: program.provider.wallet.publicKey,
- market: ORDERBOOK_ENV.marketA.address,
- systemProgram: SystemProgram.programId,
- })
- .rpc();
- await program.methods
- .authorizeMarket(marketAuthBumpB)
- .accounts({
- officer,
- authority: program.provider.wallet.publicKey,
- marketAuth: marketAuthB,
- payer: program.provider.wallet.publicKey,
- market: ORDERBOOK_ENV.marketB.address,
- systemProgram: SystemProgram.programId,
- })
- .rpc();
- });
- it("Transfers into the mintB vault", async () => {
- await B_TOKEN_CLIENT.transfer(
- ORDERBOOK_ENV.godB,
- bVault,
- program.provider.wallet.payer,
- [],
- 616035558100
- );
- });
- it("Swaps from B token to USDC", async () => {
- const bVaultBefore = await B_TOKEN_CLIENT.getAccountInfo(bVault);
- const usdcVaultBefore = await USDC_TOKEN_CLIENT.getAccountInfo(usdcVault);
- const minExchangeRate = {
- rate: new anchor.BN(0),
- fromDecimals: 6,
- quoteDecimals: 6,
- strict: false,
- };
- await program.methods
- .swapToUsdc(minExchangeRate)
- .accounts({
- officer,
- market: {
- market: marketBClient.address,
- openOrders: openOrdersB,
- requestQueue: marketBClient.decoded.requestQueue,
- eventQueue: marketBClient.decoded.eventQueue,
- bids: marketBClient.decoded.bids,
- asks: marketBClient.decoded.asks,
- orderPayerTokenAccount: bVault,
- coinVault: marketBClient.decoded.baseVault,
- pcVault: marketBClient.decoded.quoteVault,
- vaultSigner: ORDERBOOK_ENV.marketBVaultSigner,
- },
- marketAuth: marketAuthB,
- usdcVault,
- fromVault: bVault,
- usdcMint: ORDERBOOK_ENV.usdc,
- swapProgram: SWAP_PID,
- dexProgram: DEX_PID,
- tokenProgram: TOKEN_PID,
- instructions: SYSVAR_INSTRUCTIONS_PUBKEY,
- rent: SYSVAR_RENT_PUBKEY,
- })
- .rpc();
- const bVaultAfter = await B_TOKEN_CLIENT.getAccountInfo(bVault);
- const usdcVaultAfter = await USDC_TOKEN_CLIENT.getAccountInfo(usdcVault);
- assert.ok(bVaultBefore.amount.toNumber() === 616035558100);
- assert.ok(usdcVaultBefore.amount.toNumber() === 6160355581);
- assert.ok(bVaultAfter.amount.toNumber() === 615884458100);
- assert.ok(usdcVaultAfter.amount.toNumber() === 7060634298);
- });
- it("Swaps to SRM", async () => {
- const srmVaultBefore = await SRM_TOKEN_CLIENT.getAccountInfo(srmVault);
- const usdcVaultBefore = await USDC_TOKEN_CLIENT.getAccountInfo(usdcVault);
- const minExchangeRate = {
- rate: new anchor.BN(0),
- fromDecimals: 6,
- quoteDecimals: 6,
- strict: false,
- };
- await program.methods
- .swapToSrm(minExchangeRate)
- .accounts({
- officer,
- market: {
- market: marketAClient.address,
- openOrders,
- requestQueue: marketAClient.decoded.requestQueue,
- eventQueue: marketAClient.decoded.eventQueue,
- bids: marketAClient.decoded.bids,
- asks: marketAClient.decoded.asks,
- orderPayerTokenAccount: usdcVault,
- coinVault: marketAClient.decoded.baseVault,
- pcVault: marketAClient.decoded.quoteVault,
- vaultSigner: ORDERBOOK_ENV.marketAVaultSigner,
- },
- marketAuth,
- usdcVault,
- srmVault,
- usdcMint: ORDERBOOK_ENV.usdc,
- srmMint: ORDERBOOK_ENV.mintA,
- swapProgram: SWAP_PID,
- dexProgram: DEX_PID,
- tokenProgram: TOKEN_PID,
- instructions: SYSVAR_INSTRUCTIONS_PUBKEY,
- rent: SYSVAR_RENT_PUBKEY,
- })
- .rpc();
- const srmVaultAfter = await SRM_TOKEN_CLIENT.getAccountInfo(srmVault);
- const usdcVaultAfter = await USDC_TOKEN_CLIENT.getAccountInfo(usdcVault);
- assert.ok(srmVaultBefore.amount.toNumber() === 0);
- assert.ok(srmVaultAfter.amount.toNumber() === 1152000000);
- assert.ok(usdcVaultBefore.amount.toNumber() === 7060634298);
- assert.ok(usdcVaultAfter.amount.toNumber() === 530863);
- });
- it("Distributes the tokens to categories", async () => {
- const srmVaultBefore = await SRM_TOKEN_CLIENT.getAccountInfo(srmVault);
- const treasuryBefore = await SRM_TOKEN_CLIENT.getAccountInfo(treasury);
- const stakeBefore = await SRM_TOKEN_CLIENT.getAccountInfo(stake);
- const mintInfoBefore = await SRM_TOKEN_CLIENT.getMintInfo();
- await program.methods
- .distribute()
- .accounts({
- officer,
- treasury,
- stake,
- srmVault,
- srmMint: ORDERBOOK_ENV.mintA,
- tokenProgram: TOKEN_PID,
- dexProgram: DEX_PID,
- })
- .rpc();
- const srmVaultAfter = await SRM_TOKEN_CLIENT.getAccountInfo(srmVault);
- const treasuryAfter = await SRM_TOKEN_CLIENT.getAccountInfo(treasury);
- const stakeAfter = await SRM_TOKEN_CLIENT.getAccountInfo(stake);
- const mintInfoAfter = await SRM_TOKEN_CLIENT.getMintInfo();
- const beforeAmount = 1152000000;
- assert.ok(srmVaultBefore.amount.toNumber() === beforeAmount);
- assert.ok(srmVaultAfter.amount.toNumber() === 0); // Fully distributed.
- assert.ok(
- stakeAfter.amount.toNumber() ===
- beforeAmount * (distribution.stake / 100.0)
- );
- assert.ok(
- treasuryAfter.amount.toNumber() ===
- beforeAmount * (distribution.treasury / 100.0)
- );
- // Check burn amount.
- assert.ok(mintInfoBefore.supply.toString() === "1000000000000000000");
- assert.ok(
- mintInfoBefore.supply.sub(mintInfoAfter.supply).toNumber() ===
- beforeAmount * (distribution.burn / 100.0)
- );
- });
- });
|