@project-serum/anchor#web3 TypeScript Examples

The following examples show how to use @project-serum/anchor#web3. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: utilities.spec.ts    From jet-engine with GNU Affero General Public License v3.0 7 votes vote down vote up
describe("TokenAmount", () => {
  let t: TokenAmount

  test("properly instantiates", () => {
    t = new TokenAmount(new BN(10), 6, web3.PublicKey.default)
  })

  test("sets the proper mint address", () => {
    expect(t.mint.equals(web3.PublicKey.default)).toBeTruthy()
  })

  test("sets the correct token amount", () => {
    // 6 decimals
    expect(t.tokens).toStrictEqual(10 / 1e6)
  })
})
Example #2
Source File: accounts.ts    From metaplex with Apache License 2.0 6 votes vote down vote up
getMetadata = async (
  mint: anchor.web3.PublicKey,
): Promise<anchor.web3.PublicKey> => {
  return (
    await anchor.web3.PublicKey.findProgramAddress(
      [
        Buffer.from('metadata'),
        TOKEN_METADATA_PROGRAM_ID.toBuffer(),
        mint.toBuffer(),
      ],
      TOKEN_METADATA_PROGRAM_ID,
    )
  )[0];
}
Example #3
Source File: serum.ts    From psyoptions with Apache License 2.0 6 votes vote down vote up
async function setupMarket({
  provider,
  program,
  baseMint,
  quoteMint,
  marketLoader,
  optionMarket,
}: {
  provider: Provider;
  program: Program<PsyAmerican>;
  optionMarket: OptionMarketV2;
  baseMint: PublicKey;
  quoteMint: PublicKey;
  marketLoader: MarketLoader;
}): Promise<
  [
    MarketProxy,
    anchor.web3.PublicKey | anchor.BN,
    anchor.web3.PublicKey,
    number
  ]
> {
  const {
    serumMarketKey: marketAPublicKey,
    vaultOwner,
    marketAuthority,
    marketAuthorityBump,
  } = await listMarket({
    provider,
    program,
    quoteMint: quoteMint,
    dexProgramId: DEX_PID,
    feeRateBps: 0,
    optionMarket,
  });
  const MARKET_A_USDC = await marketLoader(marketAPublicKey as PublicKey);
  return [MARKET_A_USDC, vaultOwner, marketAuthority, marketAuthorityBump];
}
Example #4
Source File: accounts.ts    From metaplex with Apache License 2.0 6 votes vote down vote up
export async function loadCandyProgram(
  walletKeyPair: Keypair,
  env: string,
  customRpcUrl?: string,
) {
  if (customRpcUrl) console.log('USING CUSTOM URL', customRpcUrl);

  // @ts-ignore
  const solConnection = new anchor.web3.Connection(
    //@ts-ignore
    customRpcUrl || getCluster(env),
  );

  const walletWrapper = new anchor.Wallet(walletKeyPair);
  const provider = new anchor.Provider(solConnection, walletWrapper, {
    preflightCommitment: 'recent',
  });
  const idl = await anchor.Program.fetchIdl(CANDY_MACHINE_PROGRAM_ID, provider);
  const program = new anchor.Program(idl, CANDY_MACHINE_PROGRAM_ID, provider);
  log.debug('program id from anchor', program.programId.toBase58());
  return program;
}
Example #5
Source File: get-metadata.ts    From candy-machine-v2 with MIT License 6 votes vote down vote up
getMetadata = async (
  program: Program<Idl>,
  candyMachineId: web3.PublicKey
) => {
  const state: any = await program.account.candyMachine.fetch(candyMachineId);
  const itemsAvailable = state.data.itemsAvailable.toNumber();
  const itemsRedeemed = state.itemsRedeemed.toNumber();
  const itemsRemaining = itemsAvailable - itemsRedeemed;

  return {
    id: candyMachineId,
    program,
    state: {
      itemsAvailable,
      itemsRedeemed,
      itemsRemaining,
      isSoldOut: itemsRemaining === 0,
      isActive:
        state.data.goLiveDate.toNumber() < new Date().getTime() / 1000 &&
        (state.endSettings
          ? state.endSettings.endSettingType.date
            ? state.endSettings.number.toNumber() > new Date().getTime() / 1000
            : itemsRedeemed < state.endSettings.number.toNumber()
          : true),
      goLiveDate: state.data.goLiveDate,
      treasury: state.wallet,
      tokenMint: state.tokenMint,
      gatekeeper: state.data.gatekeeper,
      endSettings: state.data.endSettings,
      whitelistMintSettings: state.data.whitelistMintSettings,
      hiddenSettings: state.data.hiddenSettings,
      price: state.data.price,
    },
  };
}
Example #6
Source File: auction-house-cli.ts    From metaplex with Apache License 2.0 6 votes vote down vote up
export async function getAuctionHouseFromOpts(
  auctionHouse: any,
  walletKeyPair: any,
  tMintKey: any,
) {
  let auctionHouseKey;
  if (auctionHouse) {
    auctionHouseKey = new web3.PublicKey(auctionHouse);
  } else {
    log.info(
      'No auction house explicitly passed in, assuming you are creator on it and deriving key...',
    );
    auctionHouseKey = (
      await getAuctionHouse(walletKeyPair.publicKey, tMintKey)
    )[0];
  }
  return auctionHouseKey;
}
Example #7
Source File: helpers.ts    From candy-machine-v2 with MIT License 5 votes vote down vote up
CANDY_MACHINE_PROGRAM = new web3.PublicKey(
  "cndy3Z4yapfJBmL3ShUp5exZKqR3z33thTzeNMm2gRZ"
)
Example #8
Source File: token-entangler-cli.ts    From metaplex with Apache License 2.0 5 votes vote down vote up
programCommand('update_entanglement')
  .option(
    '-ep, --entangled-pair <string>',
    'Optional. Overrides mint arguments.',
  )
  .option('-na, --new-authority <string>', 'Authority, defaults to keypair')
  .option('-p, --price <string>', 'Price for a swap')
  .option(
    '-pet, --pays-every-time <string>',
    'If true, the user must pay the swapping fee each swap',
  )
  .option(
    '-ma, --mint-a <string>',
    'Mint a. You do not even need to own this token to create this entanglement.',
  )
  .option(
    '-mb, --mint-b <string>',
    'Mint b. This token will be removed from your token account right now.',
  )
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  .action(async (directory, cmd) => {
    const {
      keypair,
      env,
      price,
      paysEveryTime,
      mintA,
      mintB,
      entangledPair,
      newAuthority,
    } = cmd.opts();

    const walletKeyPair = loadWalletKey(keypair);
    const anchorProgram = await loadTokenEntanglementProgream(
      walletKeyPair,
      env,
    );

    const epKey = await getEpKeyFromArgs(
      anchorProgram,
      mintA ? new web3.PublicKey(mintA) : null,
      mintB ? new web3.PublicKey(mintB) : null,
      entangledPair,
    );

    const epObj = await anchorProgram.account.entangledPair.fetch(epKey);

    //@ts-ignore
    const authorityKey = new web3.PublicKey(
      newAuthority ? newAuthority : epObj.authority,
    );

    const priceAdjusted = price
      ? new BN(
          await getPriceWithMantissa(
            parseFloat(price),
            //@ts-ignore
            epObj.treasuryMint,
            walletKeyPair,
            anchorProgram,
          ),
        )
      : //@ts-ignore
        epObj.price;
    await anchorProgram.rpc.updateEntangledPair(
      priceAdjusted,
      paysEveryTime == 'true',
      {
        accounts: {
          newAuthority: authorityKey,
          //@ts-ignore
          authority: epObj.authority,
          entangledPair: epKey,
        },
      },
    );

    log.info('Updated entanglement', epKey.toBase58());
  });
Example #9
Source File: helpers.ts    From candy-machine-v2 with MIT License 5 votes vote down vote up
TOKEN_METADATA_PROGRAM_ID = new web3.PublicKey(
  "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"
)
Example #10
Source File: auction-house-cli.ts    From metaplex with Apache License 2.0 5 votes vote down vote up
programCommand('show_escrow')
  .option('-ah, --auction-house <string>', 'Specific auction house')
  .option(
    '-w, --wallet <string>',
    'Specific wallet owner of escrow. If not present, we use your keypair.',
  )
  .action(async (directory, cmd) => {
    const { keypair, env, auctionHouse, wallet } = cmd.opts();

    const otherWallet = wallet ? new web3.PublicKey(wallet) : null;
    const walletKeyPair = loadWalletKey(keypair);
    const anchorProgram = await loadAuctionHouseProgram(walletKeyPair, env);

    const auctionHouseKey = new web3.PublicKey(auctionHouse);
    const auctionHouseObj = await anchorProgram.account.auctionHouse.fetch(
      auctionHouseKey,
    );

    if (!otherWallet) {
      log.info('No --wallet passed in, defaulting to keypair');
    }
    const escrow = (
      await getAuctionHouseBuyerEscrow(
        auctionHouseKey,
        otherWallet || walletKeyPair.publicKey,
      )
    )[0];

    const amount = await getTokenAmount(
      anchorProgram,
      escrow,
      //@ts-ignore
      auctionHouseObj.treasuryMint,
    );

    log.info(
      otherWallet.toBase58() || walletKeyPair.publicKey.toBase58(),
      'Balance:',
      amount,
    );
  });
Example #11
Source File: newOrder.ts    From psyoptions with Apache License 2.0 4 votes vote down vote up
describe("cpi_examples newOrder", () => {
  const program = anchor.workspace.CpiExamples as Program<CpiExamples>;
  const provider = program.provider;
  const americanOptionsProgram = anchor.workspace
    .PsyAmerican as Program<PsyAmerican>;

  const payer = web3.Keypair.fromSecretKey(
    Buffer.from(
      JSON.parse(
        require("fs").readFileSync(process.env.ANCHOR_WALLET, {
          encoding: "utf-8",
        })
      )
    )
  );
  const wallet = payer;
  const mintAuthority = anchor.web3.Keypair.generate();
  let underlyingToken: Token, usdcToken: Token, optionToken: Token;
  // Global PsyOptions variables
  let optionMarket: OptionMarketV2;
  // Global DEX variables
  let marketProxy: MarketProxy,
    marketAuthority: anchor.web3.PublicKey,
    marketAuthorityBump: number,
    usdcMint: anchor.web3.PublicKey,
    usdcMintInfo: MintInfo,
    referral: anchor.web3.PublicKey,
    openOrders: PublicKey,
    openOrdersBump: number,
    vault: anchor.web3.PublicKey,
    vaultBumpSeed: number,
    vaultAuthority: anchor.web3.PublicKey,
    vaultAuthBump: number;
  before(async () => {
    // Setup - Create an OptionMarket
    const {
      optionMarket: newOptionMarket,
      remainingAccounts,
      instructions,
    } = await initSetup(
      provider,
      wallet,
      mintAuthority,
      americanOptionsProgram
    );
    optionMarket = newOptionMarket;
    await initOptionMarket(
      americanOptionsProgram,
      wallet,
      optionMarket,
      remainingAccounts,
      instructions
    );
    [usdcMint] = await createMintAndVault(
      provider,
      new anchor.BN("1000000000000000000"),
      undefined,
      6
    );
    // Initialize a permissioned Serum Market
    ({ marketAuthority, marketAuthorityBump } = await getMarketAndAuthorityInfo(
      americanOptionsProgram,
      optionMarket,
      DEX_PID,
      usdcMint
    ));
    // Setup - Create a Serum market for the OptionMarket's option tokens
    ({ marketA: marketProxy } = await initMarket(
      provider,
      americanOptionsProgram,
      marketLoader(provider, program, optionMarket.key, marketAuthorityBump),
      optionMarket,
      usdcMint
    ));
    // Set the token variables for use in later tests
    underlyingToken = new Token(
      provider.connection,
      optionMarket.underlyingAssetMint,
      TOKEN_PROGRAM_ID,
      wallet
    );
    optionToken = new Token(
      provider.connection,
      optionMarket.optionMint,
      TOKEN_PROGRAM_ID,
      wallet
    );
    usdcToken = new Token(
      provider.connection,
      usdcMint,
      TOKEN_PROGRAM_ID,
      wallet
    );
    referral = await usdcToken.createAssociatedTokenAccount(FEE_OWNER_KEY);
  });

  describe("cpi_examples initNewOrderVault", () => {
    it("should create a USDC vault owned by the program", async () => {
      // Generate a PDA for the USDC vault
      [vault, vaultBumpSeed] = await anchor.web3.PublicKey.findProgramAddress(
        [usdcToken.publicKey.toBuffer(), textEncoder.encode("vault")],
        program.programId
      );
      [vaultAuthority, vaultAuthBump] =
        await anchor.web3.PublicKey.findProgramAddress(
          [vault.toBuffer(), textEncoder.encode("vaultAuthority")],
          program.programId
        );
      try {
        await program.rpc.initNewOrderVault({
          accounts: {
            authority: wallet.publicKey,
            usdcMint: usdcMint,
            vault,
            vaultAuthority,
            tokenProgram: TOKEN_PROGRAM_ID,
            rent: SYSVAR_RENT_PUBKEY,
            systemProgram: SystemProgram.programId,
          },
        });
      } catch (err) {
        console.log((err as Error).toString());
        throw err;
      }

      // validate that the vault was initialized and owned by the program
      const vaultAcct = await usdcToken.getAccountInfo(vault);
      assert.ok(vaultAcct.owner.equals(vaultAuthority));
    });
  });

  describe("place newOrder", () => {
    before(async () => {
      // Vault is already initialized because these tests run sequentially
      // transfer USDC to that vault so it can place an order
      usdcMintInfo = await usdcToken.getMintInfo();
      await usdcToken.mintTo(
        vault,
        wallet.publicKey,
        [],
        new u64(10_000_000 * usdcMintInfo.decimals)
      );
      // Get the open orders account that needs to be optionally created
      [openOrders, openOrdersBump] = await PublicKey.findProgramAddress(
        [
          openOrdersSeed,
          marketProxy.dexProgramId.toBuffer(),
          marketProxy.market.address.toBuffer(),
          // NOTE: For other developers, this should be changed to be the User or Vault that has the authority over the account.
          vaultAuthority.toBuffer(),
        ],
        americanOptionsProgram.programId
      );
    });

    it("should create an open orders account and place an order on the Serum market", async () => {
      // test the vault contains USDC
      const vaultAcct = await usdcToken.getAccountInfo(vault);
      assert.equal(
        vaultAcct.amount.toString(),
        new u64(10_000_000 * usdcMintInfo.decimals).toString()
      );
      // test the order book is blank
      let bids = await marketProxy.market.loadBids(provider.connection);
      let l2 = await bids.getL2(3);
      assert.equal(l2.length, 0);

      const price = 1;
      const size = 22;

      // Run placeOrder instruction for vault
      try {
        await program.rpc.placeOrder(
          vaultAuthBump,
          openOrdersBump,
          marketAuthorityBump,
          Side.Bid, // Side
          marketProxy.market.priceNumberToLots(price), // liimit_price
          marketProxy.market.baseSizeNumberToLots(size), // max_coin_qty
          OrderType.PostOnly, // order_type
          new anchor.BN(999), // client_order_id
          SelfTradeBehavior.AbortTransaction, // self_trade_behavior
          new anchor.BN(65535), // limit - no idea what this is
          new anchor.BN(
            // @ts-ignore: serum
            marketProxy.market._decoded.quoteLotSize.toNumber()
          ).mul(
            marketProxy.market
              .baseSizeNumberToLots(size)
              .mul(marketProxy.market.priceNumberToLots(price))
          ), // max_native_pc_qty_including_fees - no idea what exactly this is
          {
            accounts: {
              userAuthority: wallet.publicKey,
              psyAmericanProgram: americanOptionsProgram.programId,
              dexProgram: DEX_PID,
              openOrders,
              market: marketProxy.market.address,
              psyMarketAuthority: marketAuthority,
              vault,
              vaultAuthority,
              // @ts-ignore: Dumb serum stuff
              requestQueue: marketProxy.market._decoded.requestQueue,
              // @ts-ignore: Dumb serum stuff
              eventQueue: marketProxy.market._decoded.eventQueue,
              marketBids: marketProxy.market.bidsAddress,
              marketAsks: marketProxy.market.asksAddress,
              // @ts-ignore: Dumb serum stuff
              coinVault: marketProxy.market._decoded.baseVault,
              // @ts-ignore: Dumb serum stuff
              pcVault: marketProxy.market._decoded.quoteVault,

              systemProgram: SystemProgram.programId,
              tokenProgram: TOKEN_PROGRAM_ID,
              rent: SYSVAR_RENT_PUBKEY,
            },
          }
        );
      } catch (err) {
        console.log("*** error", (err as Error).toString());
        throw err;
      }
      // Test that a new open orders account was created
      const openOrdersAcct = await OpenOrders.load(
        provider.connection,
        openOrders,
        DEX_PID
      );
      assert.ok(openOrdersAcct.owner.equals(openOrders));

      // test that the order book contains the new order.
      bids = await marketProxy.market.loadBids(provider.connection);
      l2 = await bids.getL2(3);
      assert.equal(l2.length, 1);
      assert.equal(l2[0][0], price);
      assert.equal(l2[0][1], size);
    });

    describe("Open orders account exists", () => {
      it("should place the order without fail", async () => {
        // Test that the open orders account already exists
        const openOrdersAcct = await OpenOrders.load(
          provider.connection,
          openOrders,
          DEX_PID
        );
        assert.ok(openOrdersAcct.owner.equals(openOrders));
        // test that the order book contains the new order.
        let bids = await marketProxy.market.loadBids(provider.connection);
        let l2 = await bids.getL2(3);
        assert.equal(l2.length, 1);

        const price = 2;
        const size = 1;

        // Run placeOrder instruction for vault
        try {
          await program.rpc.placeOrder(
            vaultAuthBump,
            openOrdersBump,
            marketAuthorityBump,
            Side.Bid, // Side
            marketProxy.market.priceNumberToLots(price), // liimit_price
            marketProxy.market.baseSizeNumberToLots(size), // max_coin_qty
            OrderType.PostOnly, // order_type
            new anchor.BN(998), // client_order_id
            SelfTradeBehavior.AbortTransaction, // self_trade_behavior
            new anchor.BN(65535), // limit
            new anchor.BN(
              // @ts-ignore: serum
              marketProxy.market._decoded.quoteLotSize.toNumber()
            ).mul(
              marketProxy.market
                .baseSizeNumberToLots(size)
                .mul(marketProxy.market.priceNumberToLots(price))
            ), // max_native_pc_qty_including_fees
            {
              accounts: {
                userAuthority: wallet.publicKey,
                psyAmericanProgram: americanOptionsProgram.programId,
                dexProgram: DEX_PID,
                openOrders,
                market: marketProxy.market.address,
                psyMarketAuthority: marketAuthority,
                vault,
                vaultAuthority,
                // @ts-ignore: Dumb serum stuff
                requestQueue: marketProxy.market._decoded.requestQueue,
                // @ts-ignore: Dumb serum stuff
                eventQueue: marketProxy.market._decoded.eventQueue,
                marketBids: marketProxy.market.bidsAddress,
                marketAsks: marketProxy.market.asksAddress,
                // @ts-ignore: Dumb serum stuff
                coinVault: marketProxy.market._decoded.baseVault,
                // @ts-ignore: Dumb serum stuff
                pcVault: marketProxy.market._decoded.quoteVault,

                systemProgram: SystemProgram.programId,
                tokenProgram: TOKEN_PROGRAM_ID,
                rent: SYSVAR_RENT_PUBKEY,
              },
            }
          );
        } catch (err) {
          console.log("*** error", (err as Error).toString());
          throw err;
        }
        bids = await marketProxy.market.loadBids(provider.connection);
        l2 = await bids.getL2(3);
        assert.equal(l2.length, 2);
      });
    });
  });
});
Example #12
Source File: auction-house-cli.ts    From metaplex with Apache License 2.0 4 votes vote down vote up
programCommand('execute_sale')
  .option('-ah, --auction-house <string>', 'Specific auction house')
  .option(
    '-ak, --auction-house-keypair <string>',
    'If this auction house requires sign off, pass in keypair for it',
  )
  .option(
    '-aks, --auction-house-signs',
    'If you want to simulate the auction house executing the sale without another signer',
  )
  .option('-b, --buy-price <string>', 'Price you wish to sell for')
  .option('-m, --mint <string>', 'Mint of the token to purchase')
  .option('-t, --token-size <string>', 'Amount of tokens you want to sell')
  .option('-bw, --buyer-wallet <string>', 'Buyer wallet')
  .option('-sw, --seller-wallet <string>', 'Buyer wallet')
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  .action(async (directory, cmd) => {
    const {
      keypair,
      env,
      auctionHouse,
      auctionHouseKeypair,
      buyPrice,
      mint,
      tokenSize,
      auctionHouseSigns,
      buyerWallet,
      sellerWallet,
    } = cmd.opts();

    const auctionHouseKey = new web3.PublicKey(auctionHouse);
    const walletKeyPair = loadWalletKey(keypair);

    const mintKey = new web3.PublicKey(mint);

    const auctionHouseKeypairLoaded = auctionHouseKeypair
      ? loadWalletKey(auctionHouseKeypair)
      : null;
    const anchorProgram = await loadAuctionHouseProgram(
      auctionHouseSigns ? auctionHouseKeypairLoaded : walletKeyPair,
      env,
    );
    const auctionHouseObj = await anchorProgram.account.auctionHouse.fetch(
      auctionHouseKey,
    );
    const buyerWalletKey = new web3.PublicKey(buyerWallet);
    const sellerWalletKey = new web3.PublicKey(sellerWallet);

    //@ts-ignore
    const isNative = auctionHouseObj.treasuryMint.equals(WRAPPED_SOL_MINT);
    const buyPriceAdjusted = new BN(
      await getPriceWithMantissa(
        buyPrice,
        //@ts-ignore
        auctionHouseObj.treasuryMint,
        walletKeyPair,
        anchorProgram,
      ),
    );

    const tokenSizeAdjusted = new BN(
      await getPriceWithMantissa(
        tokenSize,
        mintKey,
        walletKeyPair,
        anchorProgram,
      ),
    );

    const tokenAccountKey = (await getAtaForMint(mintKey, sellerWalletKey))[0];

    const buyerTradeState = (
      await getAuctionHouseTradeState(
        auctionHouseKey,
        buyerWalletKey,
        tokenAccountKey,
        //@ts-ignore
        auctionHouseObj.treasuryMint,
        mintKey,
        tokenSizeAdjusted,
        buyPriceAdjusted,
      )
    )[0];

    const sellerTradeState = (
      await getAuctionHouseTradeState(
        auctionHouseKey,
        sellerWalletKey,
        tokenAccountKey,
        //@ts-ignore
        auctionHouseObj.treasuryMint,
        mintKey,
        tokenSizeAdjusted,
        buyPriceAdjusted,
      )
    )[0];

    const [freeTradeState, freeTradeStateBump] =
      await getAuctionHouseTradeState(
        auctionHouseKey,
        sellerWalletKey,
        tokenAccountKey,
        //@ts-ignore
        auctionHouseObj.treasuryMint,
        mintKey,
        tokenSizeAdjusted,
        new BN(0),
      );
    const [escrowPaymentAccount, bump] = await getAuctionHouseBuyerEscrow(
      auctionHouseKey,
      buyerWalletKey,
    );
    const [programAsSigner, programAsSignerBump] =
      await getAuctionHouseProgramAsSigner();
    const metadata = await getMetadata(mintKey);

    const metadataObj = await anchorProgram.provider.connection.getAccountInfo(
      metadata,
    );
    const metadataDecoded: Metadata = decodeMetadata(
      Buffer.from(metadataObj.data),
    );

    const remainingAccounts = [];

    for (let i = 0; i < metadataDecoded.data.creators.length; i++) {
      remainingAccounts.push({
        pubkey: new web3.PublicKey(metadataDecoded.data.creators[i].address),
        isWritable: true,
        isSigner: false,
      });
      if (!isNative) {
        remainingAccounts.push({
          pubkey: (
            await getAtaForMint(
              //@ts-ignore
              auctionHouseObj.treasuryMint,
              remainingAccounts[remainingAccounts.length - 1].pubkey,
            )
          )[0],
          isWritable: true,
          isSigner: false,
        });
      }
    }
    const signers = [];
    //@ts-ignore
    const tMint: web3.PublicKey = auctionHouseObj.treasuryMint;

    const instruction = await anchorProgram.instruction.executeSale(
      bump,
      freeTradeStateBump,
      programAsSignerBump,
      buyPriceAdjusted,
      tokenSizeAdjusted,
      {
        accounts: {
          buyer: buyerWalletKey,
          seller: sellerWalletKey,
          metadata,
          tokenAccount: tokenAccountKey,
          tokenMint: mintKey,
          escrowPaymentAccount,
          treasuryMint: tMint,
          sellerPaymentReceiptAccount: isNative
            ? sellerWalletKey
            : (
                await getAtaForMint(tMint, sellerWalletKey)
              )[0],
          buyerReceiptTokenAccount: (
            await getAtaForMint(mintKey, buyerWalletKey)
          )[0],
          //@ts-ignore
          authority: auctionHouseObj.authority,
          auctionHouse: auctionHouseKey,
          //@ts-ignore
          auctionHouseFeeAccount: auctionHouseObj.auctionHouseFeeAccount,
          //@ts-ignore
          auctionHouseTreasury: auctionHouseObj.auctionHouseTreasury,
          sellerTradeState,
          buyerTradeState,
          tokenProgram: TOKEN_PROGRAM_ID,
          systemProgram: web3.SystemProgram.programId,
          ataProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
          programAsSigner,
          rent: web3.SYSVAR_RENT_PUBKEY,
          freeTradeState,
        },
        remainingAccounts,
        signers,
      },
    );

    if (auctionHouseKeypairLoaded) {
      signers.push(auctionHouseKeypairLoaded);

      instruction.keys
        .filter(k => k.pubkey.equals(auctionHouseKeypairLoaded.publicKey))
        .map(k => (k.isSigner = true));
    }

    if (!auctionHouseSigns) {
      instruction.keys
        .filter(k => k.pubkey.equals(walletKeyPair.publicKey))
        .map(k => (k.isSigner = true));
    }

    await sendTransactionWithRetryWithKeypair(
      anchorProgram.provider.connection,
      auctionHouseSigns ? auctionHouseKeypairLoaded : walletKeyPair,
      [instruction],
      signers,
      'max',
    );

    log.info(
      'Accepted',
      tokenSize,
      mint,
      'sale from wallet',
      sellerWalletKey.toBase58(),
      'to',
      buyerWalletKey.toBase58(),
      'for',
      buyPrice,
      'from your account with Auction House',
      auctionHouse,
    );
  });
Example #13
Source File: famine.spec.ts    From quarry with GNU Affero General Public License v3.0 4 votes vote down vote up
describe("Famine", () => {
  let sdk: QuarrySDK;
  let provider: Provider;
  let mintWrapper: MintWrapper;
  let mine: MineWrapper;

  before("Initialize SDK", () => {
    sdk = makeSDK();
    provider = sdk.provider;
    mintWrapper = sdk.mintWrapper;
    mine = sdk.mine;
  });

  const stakeAmount = 1_000_000000;
  let stakedMintAuthority: web3.Keypair;
  let stakeTokenMint: web3.PublicKey;
  let stakeToken: Token;

  let rewardsMint: web3.PublicKey;
  let token: Token;
  let mintWrapperKey: web3.PublicKey;
  let hardCap: TokenAmount;

  beforeEach("Initialize rewards and stake mint", async () => {
    await doesNotReject(async () => {
      stakedMintAuthority = web3.Keypair.generate();
      stakeTokenMint = await createMint(
        provider,
        stakedMintAuthority.publicKey,
        DEFAULT_DECIMALS
      );
    });

    stakeToken = Token.fromMint(stakeTokenMint, DEFAULT_DECIMALS, {
      name: "stake token",
    });
    const rewardsMintKP = web3.Keypair.generate();
    rewardsMint = rewardsMintKP.publicKey;
    token = Token.fromMint(rewardsMint, DEFAULT_DECIMALS);
    hardCap = TokenAmount.parse(token, DEFAULT_HARD_CAP.toString());
    const { tx, mintWrapper: wrapperKey } = await mintWrapper.newWrapper({
      hardcap: hardCap.toU64(),
      tokenMint: rewardsMint,
    });

    await expectTX(
      await createInitMintInstructions({
        provider,
        mintKP: rewardsMintKP,
        decimals: DEFAULT_DECIMALS,
        mintAuthority: wrapperKey,
        freezeAuthority: wrapperKey,
      })
    ).to.be.fulfilled;

    mintWrapperKey = wrapperKey;
    await expectTX(tx, "Initialize mint").to.be.fulfilled;
  });

  let rewarderWrapper: RewarderWrapper;
  const dailyRewardsRate = new BN(1_000_000 * DEFAULT_DECIMALS);
  const annualRewardsRate = dailyRewardsRate.mul(new BN(365));

  beforeEach("Set up rewarder and minter", async () => {
    const { tx, key: rewarder } = await mine.createRewarder({
      mintWrapper: mintWrapperKey,
      authority: provider.wallet.publicKey,
    });
    await expectTX(tx, "Create new rewarder").to.be.fulfilled;
    rewarderWrapper = await mine.loadRewarderWrapper(rewarder);

    // Set annual rewards rate
    await expectTX(
      rewarderWrapper.setAnnualRewards({
        newAnnualRate: annualRewardsRate,
      }),
      "Set annual rewards rate"
    ).to.be.fulfilled;

    // whitelist rewarder
    await expectTX(
      mintWrapper.newMinterWithAllowance(
        mintWrapperKey,
        rewarder,
        new u64(100_000_000_000000)
      ),
      "Minter add"
    ).to.be.fulfilled;
  });

  let quarryWrapper: QuarryWrapper;

  beforeEach("Set up quarry and miner", async () => {
    const { quarry, tx: tx1 } = await rewarderWrapper.createQuarry({
      token: stakeToken,
    });
    await expectTX(tx1, "Create new quarry").to.be.fulfilled;
    quarryWrapper = await QuarryWrapper.load({
      sdk,
      token: stakeToken,
      key: quarry,
    });

    // mint test tokens
    await newUserStakeTokenAccount(
      sdk,
      quarryWrapper,
      stakeToken,
      stakedMintAuthority,
      stakeAmount
    );

    await expectTX(
      quarryWrapper.setRewardsShare(new u64(100)),
      "Set rewards share"
    ).to.be.fulfilled;

    const { tx: tx2 } = await quarryWrapper.createMiner();
    await expectTX(tx2, "Create new miner").to.be.fulfilled;
  });

  it("Stake and claim after famine", async () => {
    const famine = new BN(Date.now() / 1000 - 5); // Rewards stopped 5 seconds ago
    await expectTX(quarryWrapper.setFamine(famine), "Set famine").to.be
      .fulfilled;

    const minerActions = await quarryWrapper.getMinerActions(
      provider.wallet.publicKey
    );
    await expectTX(
      minerActions.stake(new TokenAmount(stakeToken, stakeAmount)),
      "Stake into the quarry"
    ).to.be.fulfilled;

    // Sleep for 5 seconds
    await sleep(5000);

    const tx = await minerActions.claim();
    await expectTX(tx, "Claim from the quarry").to.be.fulfilled;

    const rewardsTokenAccount = await getATAAddress({
      mint: rewardsMint,
      owner: provider.wallet.publicKey,
    });
    const rewardsTokenAccountInfo = await getTokenAccount(
      provider,
      rewardsTokenAccount
    );
    expect(rewardsTokenAccountInfo.amount.toString()).to.equal(ZERO.toString());
  });

  it("Stake before famine and claim after famine", async () => {
    const minerActions = await quarryWrapper.getMinerActions(
      provider.wallet.publicKey
    );

    const rewardsDuration = 5; // 5 seconds
    const famine = new BN(Date.now() / 1_000 + rewardsDuration);
    await expectTX(
      minerActions
        .stake(new TokenAmount(stakeToken, stakeAmount))
        .combine(quarryWrapper.setFamine(famine)),
      "Set famine then stake tokens"
    ).to.be.fulfilled;

    // Sleep for 8 seconds
    await sleep(8_000);

    const tx = await minerActions.claim();
    const claimSent = await tx.send();
    await expectTX(claimSent, "Claim from the quarry").to.be.fulfilled;
    const receipt = await claimSent.wait();
    receipt.printLogs();

    const claimEvent = QUARRY_CODERS.Mine.parseProgramLogEvents(
      receipt.response.meta?.logMessages ?? []
    ).find((ev) => ev.name === "ClaimEvent");
    invariant(
      claimEvent && claimEvent.name === "ClaimEvent",
      "claim event not found"
    );

    const expectedRewards = dailyRewardsRate
      .div(new BN(86400))
      .mul(new BN(rewardsDuration))
      .add(new BN(2)); // error epsilon
    expect(claimEvent.data.amount.toString()).to.be.oneOf([
      expectedRewards.toString(),
      "416", // XXX: Figure out this flaky case
    ]);

    console.log("Claiming again after 5 seconds ...");
    // Sleep for 5 seconds
    await sleep(5_000);

    const claim2 = await minerActions.claim();
    const claim2Sent = await claim2.send();
    await expectTX(claim2Sent, "Claim again from the quarry").to.be.fulfilled;
    const claim2Receipt = await claim2Sent.wait();
    claim2Receipt.printLogs();

    const claim2Event = QUARRY_CODERS.Mine.parseProgramLogEvents(
      claim2Receipt.response.meta?.logMessages ?? []
    )[0];
    expect(claim2Event).to.be.undefined; // No claim event
  });
});
Example #14
Source File: auction-house-cli.ts    From metaplex with Apache License 2.0 4 votes vote down vote up
programCommand('update_auction_house')
  .option(
    '-tm, --treasury-mint <string>',
    'Mint address of treasury used during creation. If not used, default to SOL. Ignored if providing -ah arg',
  )
  .option(
    '-ah, --auction-house <string>',
    'Specific auction house(if not provided, we assume you are asking for your own)',
  )
  .option(
    '-a, --new-authority <string>',
    'New authority of auction house - defaults to current authority',
  )
  .option('-f, --force', 'Cannot set authority without this flag being set.')
  .option(
    '-sfbp, --seller-fee-basis-points <string>',
    'Auction house cut of each txn, 10000 = 100%',
  )
  .option(
    '-ccsp, --can-change-sale-price <string>',
    'if true, and user initially places item for sale for 0, then AH can make new sell prices without consent(off chain price matching). Should only be used in concert with requires-sign-off, so AH is controlling every txn hitting the system.',
  )
  .option(
    '-rso, --requires-sign-off <string>',
    'if true, no txn can occur against this Auction House without AH authority as signer. Good if you are doing all txns through a pass-through GCP or something.',
  )
  .option(
    '-twd, --treasury-withdrawal-destination <string>',
    'if you wish to empty the treasury account, this is where it will land, default is your keypair. Pass in a wallet, not an ATA - ATA will be made for you if not present.',
  )
  .option(
    '-fwd, --fee-withdrawal-destination <string>',
    'if you wish to empty the fee paying account, this is where it will land, default is your keypair',
  )
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  .action(async (directory, cmd) => {
    const {
      keypair,
      env,
      sellerFeeBasisPoints,
      canChangeSalePrice,
      requiresSignOff,
      treasuryWithdrawalDestination,
      feeWithdrawalDestination,
      treasuryMint,
      auctionHouse,
      newAuthority,
      force,
    } = cmd.opts();

    const walletKeyPair = loadWalletKey(keypair);
    const anchorProgram = await loadAuctionHouseProgram(walletKeyPair, env);

    let tMintKey: web3.PublicKey;
    if (!treasuryMint) {
      log.info('No treasury mint detected, using SOL.');
      tMintKey = WRAPPED_SOL_MINT;
    } else {
      tMintKey = new web3.PublicKey(treasuryMint);
    }

    const auctionHouseKey = await getAuctionHouseFromOpts(
      auctionHouse,
      walletKeyPair,
      tMintKey,
    );
    const auctionHouseObj = await anchorProgram.account.auctionHouse.fetch(
      auctionHouseKey,
    );
    //@ts-ignore
    tMintKey = auctionHouseObj.treasuryMint;

    let twdKey: web3.PublicKey, fwdKey: web3.PublicKey;
    if (!treasuryWithdrawalDestination) {
      log.info('No treasury withdrawal dest detected, using original value');
      twdKey = tMintKey.equals(WRAPPED_SOL_MINT)
        ? //@ts-ignore
          auctionHouseObj.treasuryWithdrawalDestination
        : deserializeAccount(
            Buffer.from(
              (
                await anchorProgram.provider.connection.getAccountInfo(
                  //@ts-ignore
                  auctionHouseObj.treasuryWithdrawalDestination,
                )
              ).data,
            ),
          ).owner;
    } else {
      twdKey = new web3.PublicKey(treasuryWithdrawalDestination);
    }
    if (!feeWithdrawalDestination) {
      log.info('No fee withdrawal dest detected, using original value');
      //@ts-ignore
      fwdKey = auctionHouseObj.feeWithdrawalDestination;
    } else {
      fwdKey = new web3.PublicKey(feeWithdrawalDestination);
    }
    const twdAta = tMintKey.equals(WRAPPED_SOL_MINT)
      ? twdKey
      : (await getAtaForMint(tMintKey, twdKey))[0];

    let sfbp;
    if (sellerFeeBasisPoints != undefined && sellerFeeBasisPoints != null) {
      sfbp = parseInt(sellerFeeBasisPoints);
    } else {
      log.info('No sfbp passed in, using original value');
      //@ts-ignore
      sfbp = auctionHouseObj.sellerFeeBasisPoints;
    }

    let newAuth;
    if (newAuthority != undefined && newAuthority != null) {
      if (!force) {
        throw Error(
          'Cannot change authority without additional force flag. Are you sure you want to do this?',
        );
      }
      newAuth = newAuthority;
    } else {
      log.info('No authority passed in, using original value');
      //@ts-ignore
      newAuth = auctionHouseObj.authority;
    }

    let ccsp;
    if (canChangeSalePrice != undefined && canChangeSalePrice != null) {
      ccsp = canChangeSalePrice == 'true';
    } else {
      log.info('No can change sale price passed in, using original value');
      //@ts-ignore
      ccsp = auctionHouseObj.canChangeSalePrice;
    }

    let rso;
    if (requiresSignOff != undefined && requiresSignOff != null) {
      rso = requiresSignOff == 'true';
    } else {
      log.info('No requires sign off passed in, using original value');
      //@ts-ignore
      rso = auctionHouseObj.requiresSignOff;
    }
    await anchorProgram.rpc.updateAuctionHouse(sfbp, rso, ccsp, {
      accounts: {
        treasuryMint: tMintKey,
        payer: walletKeyPair.publicKey,
        authority: walletKeyPair.publicKey,
        // extra safety here even though newAuth should be right
        //@ts-ignore
        newAuthority: force ? newAuth : auctionHouseObj.authority,
        feeWithdrawalDestination: fwdKey,
        treasuryWithdrawalDestination: twdAta,
        treasuryWithdrawalDestinationOwner: twdKey,
        auctionHouse: auctionHouseKey,
        //@ts-ignore
        auctionHouseFeeAccount: auctionHouseObj.feePayer,
        //@ts-ignore
        auctionHouseTreasury: auctionHouseObj.treasury,
        tokenProgram: TOKEN_PROGRAM_ID,
        systemProgram: web3.SystemProgram.programId,
        ataProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
        rent: web3.SYSVAR_RENT_PUBKEY,
      },
    });
    log.info('Updated auction house', auctionHouseKey.toBase58());
  });