@solana/spl-token#AccountLayout TypeScript Examples

The following examples show how to use @solana/spl-token#AccountLayout. 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: index.ts    From protocol-v1 with Apache License 2.0 6 votes vote down vote up
export function parseTokenAccount(data: Buffer): AccountInfo {
	const accountInfo = AccountLayout.decode(data);
	accountInfo.mint = new PublicKey(accountInfo.mint);
	accountInfo.owner = new PublicKey(accountInfo.owner);
	accountInfo.amount = u64.fromBuffer(accountInfo.amount);

	if (accountInfo.delegateOption === 0) {
		accountInfo.delegate = null;
		// eslint-disable-next-line new-cap
		accountInfo.delegatedAmount = new u64(0);
	} else {
		accountInfo.delegate = new PublicKey(accountInfo.delegate);
		accountInfo.delegatedAmount = u64.fromBuffer(accountInfo.delegatedAmount);
	}

	accountInfo.isInitialized = accountInfo.state !== 0;
	accountInfo.isFrozen = accountInfo.state === 2;

	if (accountInfo.isNativeOption === 1) {
		accountInfo.rentExemptReserve = u64.fromBuffer(accountInfo.isNative);
		accountInfo.isNative = true;
	} else {
		accountInfo.rentExemptReserve = null;
		accountInfo.isNative = false;
	}

	if (accountInfo.closeAuthorityOption === 0) {
		accountInfo.closeAuthority = null;
	} else {
		accountInfo.closeAuthority = new PublicKey(accountInfo.closeAuthority);
	}

	return accountInfo;
}
Example #2
Source File: index.ts    From zo-client with Apache License 2.0 6 votes vote down vote up
export async function createTokenAccountIxs(
  vault: Keypair,
  provider: Provider,
  mint: PublicKey,
  owner: PublicKey,
): Promise<TransactionInstruction[]> {
  return [
    SystemProgram.createAccount({
      fromPubkey: provider.wallet.publicKey,
      newAccountPubkey: vault.publicKey,
      space: AccountLayout.span,
      lamports: await Token.getMinBalanceRentForExemptAccount(
        provider.connection,
      ),
      programId: TOKEN_PROGRAM_ID,
    }),
    Token.createInitAccountInstruction(
      TOKEN_PROGRAM_ID,
      mint,
      vault.publicKey,
      owner,
    ),
  ];
}
Example #3
Source File: instructions.ts    From serum-ts with Apache License 2.0 6 votes vote down vote up
export function parseTokenAccount(data: Buffer): AccountInfo {
  const accountInfo = AccountLayout.decode(data);
  accountInfo.mint = new PublicKey(accountInfo.mint);
  accountInfo.owner = new PublicKey(accountInfo.owner);
  accountInfo.amount = u64.fromBuffer(accountInfo.amount);

  if (accountInfo.delegateOption === 0) {
    accountInfo.delegate = null;
    // eslint-disable-next-line new-cap
    accountInfo.delegatedAmount = new u64(0);
  } else {
    accountInfo.delegate = new PublicKey(accountInfo.delegate);
    accountInfo.delegatedAmount = u64.fromBuffer(accountInfo.delegatedAmount);
  }

  accountInfo.isInitialized = accountInfo.state !== 0;
  accountInfo.isFrozen = accountInfo.state === 2;

  if (accountInfo.isNativeOption === 1) {
    accountInfo.rentExemptReserve = u64.fromBuffer(accountInfo.isNative);
    accountInfo.isNative = true;
  } else {
    accountInfo.rentExemptReserve = null;
    accountInfo.isNative = false;
  }

  if (accountInfo.closeAuthorityOption === 0) {
    accountInfo.closeAuthority = null;
  } else {
    accountInfo.closeAuthority = new PublicKey(accountInfo.closeAuthority);
  }

  return accountInfo;
}
Example #4
Source File: accountParser.ts    From jet-engine with GNU Affero General Public License v3.0 6 votes vote down vote up
parseTokenAccount = (info: AccountInfo<Buffer>, address: PublicKey): Account => {
  if (!info) throw new TokenAccountNotFoundError()
  if (!info.owner.equals(TOKEN_PROGRAM_ID)) throw new TokenInvalidAccountOwnerError()
  if (info.data.length != ACCOUNT_SIZE) throw new TokenInvalidAccountSizeError()

  const rawAccount = AccountLayout.decode(info.data)

  return {
    address,
    mint: rawAccount.mint,
    owner: rawAccount.owner,
    amount: rawAccount.amount,
    delegate: rawAccount.delegateOption ? rawAccount.delegate : null,
    delegatedAmount: rawAccount.delegatedAmount,
    isInitialized: rawAccount.state !== AccountState.Uninitialized,
    isFrozen: rawAccount.state === AccountState.Frozen,
    isNative: !!rawAccount.isNativeOption,
    rentExemptReserve: rawAccount.isNativeOption ? rawAccount.isNative : null,
    closeAuthority: rawAccount.closeAuthorityOption ? rawAccount.closeAuthority : null
  }
}
Example #5
Source File: accounts.ts    From metaplex with Apache License 2.0 6 votes vote down vote up
deserializeAccount = (data: Buffer) => {
  const accountInfo = AccountLayout.decode(data);
  accountInfo.mint = new PublicKey(accountInfo.mint);
  accountInfo.owner = new PublicKey(accountInfo.owner);
  accountInfo.amount = u64.fromBuffer(accountInfo.amount);

  if (accountInfo.delegateOption === 0) {
    accountInfo.delegate = null;
    accountInfo.delegatedAmount = new u64(0);
  } else {
    accountInfo.delegate = new PublicKey(accountInfo.delegate);
    accountInfo.delegatedAmount = u64.fromBuffer(accountInfo.delegatedAmount);
  }

  accountInfo.isInitialized = accountInfo.state !== 0;
  accountInfo.isFrozen = accountInfo.state === 2;

  if (accountInfo.isNativeOption === 1) {
    accountInfo.rentExemptReserve = u64.fromBuffer(accountInfo.isNative);
    accountInfo.isNative = true;
  } else {
    accountInfo.rentExemptReserve = null;
    accountInfo.isNative = false;
  }

  if (accountInfo.closeAuthorityOption === 0) {
    accountInfo.closeAuthority = null;
  } else {
    accountInfo.closeAuthority = new PublicKey(accountInfo.closeAuthority);
  }

  return accountInfo;
}
Example #6
Source File: account.ts    From metaplex with Apache License 2.0 6 votes vote down vote up
export function createUninitializedAccount(
  instructions: TransactionInstruction[],
  payer: PublicKey,
  amount: number,
  signers: Keypair[],
) {
  const account = Keypair.generate();
  instructions.push(
    SystemProgram.createAccount({
      fromPubkey: payer,
      newAccountPubkey: account.publicKey,
      lamports: amount,
      space: AccountLayout.span,
      programId: TOKEN_PROGRAM_ID,
    }),
  );

  signers.push(account);

  return account.publicKey;
}
Example #7
Source File: index.ts    From serum-ts with Apache License 2.0 6 votes vote down vote up
export function parseTokenAccount(data: Buffer): AccountInfo {
  const accountInfo = AccountLayout.decode(data);
  accountInfo.mint = new PublicKey(accountInfo.mint);
  accountInfo.owner = new PublicKey(accountInfo.owner);
  accountInfo.amount = u64.fromBuffer(accountInfo.amount);

  if (accountInfo.delegateOption === 0) {
    accountInfo.delegate = null;
    // eslint-disable-next-line new-cap
    accountInfo.delegatedAmount = new u64(0);
  } else {
    accountInfo.delegate = new PublicKey(accountInfo.delegate);
    accountInfo.delegatedAmount = u64.fromBuffer(accountInfo.delegatedAmount);
  }

  accountInfo.isInitialized = accountInfo.state !== 0;
  accountInfo.isFrozen = accountInfo.state === 2;

  if (accountInfo.isNativeOption === 1) {
    accountInfo.rentExemptReserve = u64.fromBuffer(accountInfo.isNative);
    accountInfo.isNative = true;
  } else {
    accountInfo.rentExemptReserve = null;
    accountInfo.isNative = false;
  }

  if (accountInfo.closeAuthorityOption === 0) {
    accountInfo.closeAuthority = null;
  } else {
    accountInfo.closeAuthority = new PublicKey(accountInfo.closeAuthority);
  }

  return accountInfo;
}
Example #8
Source File: TokenAccountParser.ts    From port-sdk with MIT License 6 votes vote down vote up
function deserialize(data: Buffer): AccountInfo {
  const accountInfo = AccountLayout.decode(data);
  accountInfo.mint = new PublicKey(accountInfo.mint);
  accountInfo.owner = new PublicKey(accountInfo.owner);
  accountInfo.amount = u64.fromBuffer(accountInfo.amount);

  if (accountInfo.delegateOption === 0) {
    accountInfo.delegate = null;
    // eslint-disable-next-line new-cap
    accountInfo.delegatedAmount = new u64(0);
  } else {
    accountInfo.delegate = new PublicKey(accountInfo.delegate);
    accountInfo.delegatedAmount = u64.fromBuffer(accountInfo.delegatedAmount);
  }

  accountInfo.isInitialized = accountInfo.state !== 0;
  accountInfo.isFrozen = accountInfo.state === 2;

  if (accountInfo.isNativeOption === 1) {
    accountInfo.rentExemptReserve = u64.fromBuffer(accountInfo.isNative);
    accountInfo.isNative = true;
  } else {
    accountInfo.rentExemptReserve = null;
    accountInfo.isNative = false;
  }

  if (accountInfo.closeAuthorityOption === 0) {
    accountInfo.closeAuthority = null;
  } else {
    accountInfo.closeAuthority = new PublicKey(accountInfo.closeAuthority);
  }

  return accountInfo;
}
Example #9
Source File: deserialize.ts    From metaplex with Apache License 2.0 6 votes vote down vote up
deserializeAccount = (data: Buffer) => {
  const accountInfo = AccountLayout.decode(data);
  accountInfo.mint = new PublicKey(accountInfo.mint);
  accountInfo.owner = new PublicKey(accountInfo.owner);
  accountInfo.amount = u64.fromBuffer(accountInfo.amount);

  if (accountInfo.delegateOption === 0) {
    accountInfo.delegate = null;
    accountInfo.delegatedAmount = new u64(0);
  } else {
    accountInfo.delegate = new PublicKey(accountInfo.delegate);
    accountInfo.delegatedAmount = u64.fromBuffer(accountInfo.delegatedAmount);
  }

  accountInfo.isInitialized = accountInfo.state !== 0;
  accountInfo.isFrozen = accountInfo.state === 2;

  if (accountInfo.isNativeOption === 1) {
    accountInfo.rentExemptReserve = u64.fromBuffer(accountInfo.isNative);
    accountInfo.isNative = true;
  } else {
    accountInfo.rentExemptReserve = null;
    accountInfo.isNative = false;
  }

  if (accountInfo.closeAuthorityOption === 0) {
    accountInfo.closeAuthority = null;
  } else {
    accountInfo.closeAuthority = new PublicKey(accountInfo.closeAuthority);
  }

  return accountInfo;
}
Example #10
Source File: TokenAccount.ts    From port-sdk with MIT License 6 votes vote down vote up
public static fromRaw(raw: RawData): TokenAccount {
    const buffer = Buffer.from(raw.account.data);
    const accountInfo = AccountLayout.decode(buffer);

    accountInfo.mint = new PublicKey(accountInfo.mint);
    accountInfo.owner = new PublicKey(accountInfo.owner);
    accountInfo.amount = u64.fromBuffer(accountInfo.amount);

    return new TokenAccount(
      TokenAccountId.of(raw.pubkey),
      WalletId.of(accountInfo.owner),
      MintId.of(accountInfo.mint),
      Lamport.of(accountInfo.amount)
    );
  }
Example #11
Source File: accounts.ts    From metaplex with Apache License 2.0 6 votes vote down vote up
getCreatorTokenAccount = async (
  walletKey: PublicKey,
  connection: Connection,
  mintKey: PublicKey,
  totalClaim: number,
) => {
  const [creatorTokenKey] = await PublicKey.findProgramAddress(
    [walletKey.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), mintKey.toBuffer()],
    SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID,
  );
  const creatorTokenAccount = await connection.getAccountInfo(creatorTokenKey);
  if (creatorTokenAccount === null) {
    throw new Error(`Could not fetch creator token account`);
  }
  if (creatorTokenAccount.data.length !== AccountLayout.span) {
    throw new Error(
      `Invalid token account size ${creatorTokenAccount.data.length}`,
    );
  }
  const creatorTokenInfo = AccountLayout.decode(
    Buffer.from(creatorTokenAccount.data),
  );
  if (new BN(creatorTokenInfo.amount, 8, 'le').toNumber() < totalClaim) {
    throw new Error(`Creator token account does not have enough tokens`);
  }
  return creatorTokenKey;
}
Example #12
Source File: getCreateTokenAccounts.ts    From metaplex with Apache License 2.0 6 votes vote down vote up
getCreateTokenAccounts = ({
  cardsToAdd,
  connection,
  walletPublicKey,
}: GetCreateTokenAccounts): Promise<TransactionInstruction[]> =>
  Promise.all(
    cardsToAdd.map(({ toAccount }) =>
      getCreateAccount({
        connection,
        walletPublicKey,
        newAccountPubkey: toAccount.publicKey,
        space: AccountLayout.span,
        programId: programIds().token,
      }),
    ),
  )
Example #13
Source File: pools.ts    From serum-ts with Apache License 2.0 5 votes vote down vote up
createTokenAccount = (
  owner: PublicKey,
  payer: PublicKey,
  mint: PublicKey,
  lamports: number,
) => {
  const account = new Account();
  const instructions: TransactionInstruction[] = [];
  const cleanUpInstructions: TransactionInstruction[] = [];
  const space = AccountLayout.span as number;
  instructions.push(
    SystemProgram.createAccount({
      fromPubkey: payer,
      newAccountPubkey: account.publicKey,
      lamports,
      space,
      programId: TOKEN_PROGRAM_ID,
    }),
  );

  instructions.push(
    Token.createInitAccountInstruction(
      TOKEN_PROGRAM_ID,
      mint,
      account.publicKey,
      owner,
    ),
  );
  if (mint.equals(WRAPPED_SOL_MINT)) {
    cleanUpInstructions.push(
      Token.createCloseAccountInstruction(
        TOKEN_PROGRAM_ID,
        account.publicKey,
        payer,
        owner,
        [],
      ),
    );
  }
  return { account, instructions, cleanUpInstructions };
}
Example #14
Source File: helpers.ts    From psyoptions with Apache License 2.0 5 votes vote down vote up
initNewTokenAccount = async (
  connection: Connection,
  /** The owner for the new mint account */
  owner: PublicKey,
  /** The SPL Token Mint address */
  mint: PublicKey,
  wallet: Keypair
) => {
  const tokenAccount = new Keypair();
  const transaction = new Transaction();

  const assetPoolRentBalance =
    await connection.getMinimumBalanceForRentExemption(AccountLayout.span);
  transaction.add(
    SystemProgram.createAccount({
      fromPubkey: wallet.publicKey,
      newAccountPubkey: tokenAccount.publicKey,
      lamports: assetPoolRentBalance,
      space: AccountLayout.span,
      programId: TOKEN_PROGRAM_ID,
    })
  );
  transaction.add(
    Token.createInitAccountInstruction(
      TOKEN_PROGRAM_ID,
      mint,
      tokenAccount.publicKey,
      owner
    )
  );
  await sendAndConfirmTransaction(
    connection,
    transaction,
    [wallet, tokenAccount],
    {
      commitment: "confirmed",
    }
  );
  return {
    tokenAccount,
  };
}
Example #15
Source File: index.tsx    From metaplex with Apache License 2.0 5 votes vote down vote up
async function calculateTotalCostOfRedeemingOtherPeoplesBids(
  connection: Connection,
  auctionView: AuctionView,
  bids: ParsedAccount<BidderMetadata>[],
  bidRedemptions: Record<string, ParsedAccount<BidRedemptionTicket>>,
): Promise<number> {
  const accountRentExempt = await connection.getMinimumBalanceForRentExemption(
    AccountLayout.span,
  );
  const mintRentExempt = await connection.getMinimumBalanceForRentExemption(
    MintLayout.span,
  );
  const metadataRentExempt = await connection.getMinimumBalanceForRentExemption(
    MAX_METADATA_LEN,
  );
  const editionRentExempt = await connection.getMinimumBalanceForRentExemption(
    MAX_EDITION_LEN,
  );
  const prizeTrackingTicketExempt =
    await connection.getMinimumBalanceForRentExemption(
      MAX_PRIZE_TRACKING_TICKET_SIZE,
    );

  const eligibleParticipations =
    await findEligibleParticipationBidsForRedemption(
      auctionView,
      bids,
      bidRedemptions,
    );
  const max = auctionView.auction.info.bidState.max.toNumber();
  let totalWinnerItems = 0;
  for (let i = 0; i < max; i++) {
    const winner = auctionView.auction.info.bidState.getWinnerAt(i);
    if (!winner) {
      break;
    } else {
      const bid = bids.find(b => b.info.bidderPubkey === winner);
      if (bid) {
        for (
          let j = 0;
          j < auctionView.auctionManager.safetyDepositBoxesExpected.toNumber();
          j++
        ) {
          totalWinnerItems += auctionView.auctionManager
            .getAmountForWinner(i, j)
            .toNumber();
        }
      }
    }
  }
  return (
    (mintRentExempt +
      accountRentExempt +
      metadataRentExempt +
      editionRentExempt +
      prizeTrackingTicketExempt) *
    (eligibleParticipations.length + totalWinnerItems)
  );
}
Example #16
Source File: mockAccounts.ts    From protocol-v1 with Apache License 2.0 5 votes vote down vote up
export async function mockUserUSDCAccount(
	fakeUSDCMint,
	usdcMintAmount,
	provider,
	owner?: PublicKey
): Promise<Keypair> {
	const userUSDCAccount = anchor.web3.Keypair.generate();
	const fakeUSDCTx = new Transaction();

	if (owner === undefined) {
		owner = provider.wallet.publicKey;
	}

	const createUSDCTokenAccountIx = SystemProgram.createAccount({
		fromPubkey: provider.wallet.publicKey,
		newAccountPubkey: userUSDCAccount.publicKey,
		lamports: await Token.getMinBalanceRentForExemptAccount(
			provider.connection
		),
		space: AccountLayout.span,
		programId: TOKEN_PROGRAM_ID,
	});
	fakeUSDCTx.add(createUSDCTokenAccountIx);

	const initUSDCTokenAccountIx = Token.createInitAccountInstruction(
		TOKEN_PROGRAM_ID,
		fakeUSDCMint.publicKey,
		userUSDCAccount.publicKey,
		owner
	);
	fakeUSDCTx.add(initUSDCTokenAccountIx);

	const mintToUserAccountTx = await Token.createMintToInstruction(
		TOKEN_PROGRAM_ID,
		fakeUSDCMint.publicKey,
		userUSDCAccount.publicKey,
		provider.wallet.publicKey,
		[],
		usdcMintAmount.toNumber()
	);
	fakeUSDCTx.add(mintToUserAccountTx);

	const _fakeUSDCTxResult = await sendAndConfirmTransaction(
		provider.connection,
		fakeUSDCTx,
		[provider.wallet.payer, userUSDCAccount],
		{
			skipPreflight: false,
			commitment: 'recent',
			preflightCommitment: 'recent',
		}
	);
	return userUSDCAccount;
}
Example #17
Source File: testHelpers.ts    From protocol-v1 with Apache License 2.0 5 votes vote down vote up
export async function mockUserUSDCAccount(
	fakeUSDCMint: Keypair,
	usdcMintAmount: BN,
	provider: Provider,
	owner?: PublicKey
): Promise<Keypair> {
	const userUSDCAccount = anchor.web3.Keypair.generate();
	const fakeUSDCTx = new Transaction();

	if (owner === undefined) {
		owner = provider.wallet.publicKey;
	}

	const createUSDCTokenAccountIx = SystemProgram.createAccount({
		fromPubkey: provider.wallet.publicKey,
		newAccountPubkey: userUSDCAccount.publicKey,
		lamports: await Token.getMinBalanceRentForExemptAccount(
			provider.connection
		),
		space: AccountLayout.span,
		programId: TOKEN_PROGRAM_ID,
	});
	fakeUSDCTx.add(createUSDCTokenAccountIx);

	const initUSDCTokenAccountIx = Token.createInitAccountInstruction(
		TOKEN_PROGRAM_ID,
		fakeUSDCMint.publicKey,
		userUSDCAccount.publicKey,
		owner
	);
	fakeUSDCTx.add(initUSDCTokenAccountIx);

	const mintToUserAccountTx = await Token.createMintToInstruction(
		TOKEN_PROGRAM_ID,
		fakeUSDCMint.publicKey,
		userUSDCAccount.publicKey,
		provider.wallet.publicKey,
		[],
		usdcMintAmount.toNumber()
	);
	fakeUSDCTx.add(mintToUserAccountTx);

	const _fakeUSDCTxResult = await sendAndConfirmTransaction(
		provider.connection,
		fakeUSDCTx,
		// @ts-ignore
		[provider.wallet.payer, userUSDCAccount],
		{
			skipPreflight: false,
			commitment: 'recent',
			preflightCommitment: 'recent',
		}
	);
	return userUSDCAccount;
}
Example #18
Source File: account.ts    From metaplex with Apache License 2.0 5 votes vote down vote up
export function ensureWrappedAccount(
  instructions: TransactionInstruction[],
  cleanupInstructions: TransactionInstruction[],
  toCheck: TokenAccount | undefined,
  payer: PublicKey,
  amount: number,
  signers: Keypair[],
) {
  if (toCheck && !toCheck.info.isNative) {
    return toCheck.pubkey;
  }

  const TOKEN_PROGRAM_ID = programIds().token;
  const account = Keypair.generate();
  instructions.push(
    SystemProgram.createAccount({
      fromPubkey: payer,
      newAccountPubkey: account.publicKey,
      lamports: amount,
      space: AccountLayout.span,
      programId: TOKEN_PROGRAM_ID,
    }),
  );

  instructions.push(
    Token.createInitAccountInstruction(
      TOKEN_PROGRAM_ID,
      WRAPPED_SOL_MINT,
      account.publicKey,
      payer,
    ),
  );

  cleanupInstructions.push(
    Token.createCloseAccountInstruction(
      TOKEN_PROGRAM_ID,
      account.publicKey,
      payer,
      payer,
      [],
    ),
  );

  signers.push(account);

  return account.publicKey.toBase58();
}
Example #19
Source File: Port.ts    From port-sdk with MIT License 4 votes vote down vote up
public async createReserve({
    provider,
    reserveConfig,
    transferAuthority,
    sourceTokenWallet,
    initialLiquidity,
    oracle,
    price,
  }: {
    provider: Provider;
    reserveConfig: ReserveConfigProto;
    transferAuthority: PublicKey;
    sourceTokenWallet: PublicKey;
    initialLiquidity: number | BN;
    oracle?: PublicKey;
    price?: BN;
  }): Promise<[TransactionEnvelope[], PublicKey]> {
    invariant(!!oracle !== !!price, "Oracle and price can't both be present");

    const [createReserveAccountIx, reservePubKey] = await this.createAccount({
      provider,
      space: ReserveLayout.span,
      owner: PORT_LENDING,
    });
    const [collateralMintIx, collateralMintPubKey] = await this.createAccount({
      provider,
      space: MintLayout.span,
      owner: TOKEN_PROGRAM_ID,
    });
    const [liquiditySupplyIx, liquiditySupplyPubKey] = await this.createAccount(
      {
        provider,
        space: AccountLayout.span,
        owner: TOKEN_PROGRAM_ID,
      }
    );
    const [collateralSupplyIx, collateralSupplyPubKey] =
      await this.createAccount({
        provider,
        space: AccountLayout.span,
        owner: TOKEN_PROGRAM_ID,
      });
    const [userCollateralIx, userCollateralPubKey] = await this.createAccount({
      provider,
      space: AccountLayout.span,
      owner: TOKEN_PROGRAM_ID,
    });
    const [feeReceiverIx, feeReceiverPubkey] = await this.createAccount({
      provider,
      space: AccountLayout.span,
      owner: TOKEN_PROGRAM_ID,
    });

    const tokenAccount = await getTokenAccount(provider, sourceTokenWallet);

    const initReserveIx = initReserveInstruction(
      initialLiquidity,
      oracle ? 0 : 1, // price Option
      price ?? new BN(1),
      reserveConfig,
      sourceTokenWallet,
      collateralSupplyPubKey,
      reservePubKey,
      tokenAccount.mint,
      liquiditySupplyPubKey,
      feeReceiverPubkey,
      oracle ?? Keypair.generate().publicKey,
      collateralMintPubKey,
      userCollateralPubKey,
      this.lendingMarket,
      (await this.getLendingMarketAuthority())[0],
      provider.wallet.publicKey,
      transferAuthority
    );

    let tx1 = new TransactionEnvelope(provider, []);
    tx1 = tx1.combine(createReserveAccountIx);
    tx1 = tx1.combine(collateralMintIx);
    tx1 = tx1.combine(liquiditySupplyIx);
    tx1 = tx1.combine(collateralSupplyIx);
    tx1 = tx1.combine(userCollateralIx);

    let tx2 = new TransactionEnvelope(provider, []);
    tx2 = tx2.combine(feeReceiverIx);
    tx2 = tx2.addInstructions(initReserveIx);

    return [[tx1, tx2], reservePubKey];
  }
Example #20
Source File: pools.ts    From serum-ts with Apache License 2.0 4 votes vote down vote up
/**
   * Note: for seed param, this must be <= 32 characters for the txn to succeed
   */
  static async makeInitializePoolTransaction<T extends PublicKey | Account>(
    connection: Connection,
    tokenSwapProgram: PublicKey,
    owner: T,
    componentMints: PublicKey[],
    sourceTokenAccounts: {
      mint: PublicKey;
      tokenAccount: PublicKey;
      amount: number; // note this is raw amount, not decimal
    }[],
    options: PoolConfig,
    liquidityTokenPrecision = DEFAULT_LIQUIDITY_TOKEN_PRECISION,
    accounts?: {
      liquidityTokenMint?: Account;
      tokenSwapPoolAddress?: Account;
    },
    seed?: string,
  ): Promise<{
    initializeAccountsTransaction: Transaction;
    initializeAccountsSigners: Account[];
    initializePoolTransaction: Transaction;
    initializePoolSigners: Account[];
  }> {
    // @ts-ignore
    const ownerAddress: PublicKey = owner.publicKey ?? owner;
    const initializeAccountsInstructions: TransactionInstruction[] = [];
    const initializeAccountsSigners: Account[] = [];

    const liquidityTokenMintAccount = accounts?.liquidityTokenMint
      ? accounts.liquidityTokenMint
      : new Account();
    initializeAccountsInstructions.push(
      SystemProgram.createAccount({
        fromPubkey: ownerAddress,
        newAccountPubkey: liquidityTokenMintAccount.publicKey,
        lamports: await connection.getMinimumBalanceForRentExemption(
          MintLayout.span,
        ),
        space: MintLayout.span,
        programId: TOKEN_PROGRAM_ID,
      }),
    );
    initializeAccountsSigners.push(liquidityTokenMintAccount);
    let tokenSwapAccountPubkey;
    let tokenSwapAccountSigner;
    if (accounts?.tokenSwapPoolAddress) {
      tokenSwapAccountPubkey = accounts.tokenSwapPoolAddress.publicKey;
      tokenSwapAccountSigner = accounts.tokenSwapPoolAddress;
    } else if (seed) {
      // Only works when owner is of type Account
      tokenSwapAccountSigner = owner;
      tokenSwapAccountPubkey = await PublicKey.createWithSeed(ownerAddress, seed, tokenSwapProgram);
    } else {
      tokenSwapAccountSigner = new Account();
      tokenSwapAccountPubkey = tokenSwapAccountSigner.pubkey;
    }

    const [authority, nonce] = await PublicKey.findProgramAddress(
      [tokenSwapAccountPubkey.toBuffer()],
      tokenSwapProgram,
    );

    // create mint for pool liquidity token
    initializeAccountsInstructions.push(
      Token.createInitMintInstruction(
        TOKEN_PROGRAM_ID,
        liquidityTokenMintAccount.publicKey,
        liquidityTokenPrecision,
        // pass control of liquidity mint to swap program
        authority,
        // swap program can freeze liquidity token mint
        null,
      ),
    );
    const accountRentExempt = await connection.getMinimumBalanceForRentExemption(
      AccountLayout.span,
    );
    const holdingAccounts: { [mint: string]: Account } = {};
    componentMints.forEach(mint => {
      const {
        account,
        instructions: createHoldingTokenAccountInstructions,
      } = createTokenAccount(authority, ownerAddress, mint, accountRentExempt);
      initializeAccountsInstructions.push(
        ...createHoldingTokenAccountInstructions,
      );
      initializeAccountsSigners.push(account);
      holdingAccounts[mint.toBase58()] = account;
    });

    const {
      account: depositorAccount,
      instructions: createLPTokenAccountInstructions,
    } = createTokenAccount(
      ownerAddress,
      ownerAddress,
      liquidityTokenMintAccount.publicKey,
      accountRentExempt,
    );
    initializeAccountsSigners.push(depositorAccount);
    initializeAccountsInstructions.push(...createLPTokenAccountInstructions);

    const {
      account: feeAccount,
      instructions: createFeeAccountInstructions,
    } = createTokenAccount(
      SWAP_PROGRAM_OWNER_FEE_ADDRESS,
      ownerAddress,
      liquidityTokenMintAccount.publicKey,
      accountRentExempt,
    );
    initializeAccountsSigners.push(feeAccount);
    initializeAccountsInstructions.push(...createFeeAccountInstructions);
    const initializeAccountsTransaction = new Transaction();
    initializeAccountsTransaction.add(...initializeAccountsInstructions);

    // break up these into two transactions because it does not fit in a single transaction
    const initializePoolSigners: Account[] = [];
    const initializePoolInstructions: TransactionInstruction[] = [];
    const cleanupInstructions: TransactionInstruction[] = [];

    let initializeTokenSwapAccountInstruction;
    if (seed) {
      initializeTokenSwapAccountInstruction = SystemProgram.createAccountWithSeed({
        fromPubkey: ownerAddress,
        basePubkey: ownerAddress,
        newAccountPubkey: tokenSwapAccountPubkey,
        seed: seed,
        lamports: await connection.getMinimumBalanceForRentExemption(
          getLayoutForProgramId(tokenSwapProgram).span
        ),
        space: getLayoutForProgramId(tokenSwapProgram).span,
        programId: tokenSwapProgram,
      });
    } else {
      initializeTokenSwapAccountInstruction = SystemProgram.createAccount({
        fromPubkey: ownerAddress,
        newAccountPubkey: tokenSwapAccountPubkey,
        lamports: await connection.getMinimumBalanceForRentExemption(
          getLayoutForProgramId(tokenSwapProgram).span,
        ),
        space: getLayoutForProgramId(tokenSwapProgram).span,
        programId: tokenSwapProgram,
      })
    }
    initializePoolInstructions.push(initializeTokenSwapAccountInstruction);

    sourceTokenAccounts.forEach(({ mint, tokenAccount, amount }) => {
      let wrappedAccount: PublicKey;
      if (mint.equals(WRAPPED_SOL_MINT)) {
        const {
          account,
          instructions: createWrappedSolInstructions,
          cleanUpInstructions: removeWrappedSolInstructions,
        } = createTokenAccount(
          ownerAddress,
          ownerAddress,
          WRAPPED_SOL_MINT,
          amount + accountRentExempt,
        );
        wrappedAccount = account.publicKey;
        initializePoolSigners.push(account);
        initializePoolInstructions.push(...createWrappedSolInstructions);
        cleanupInstructions.push(...removeWrappedSolInstructions);
      } else {
        wrappedAccount = tokenAccount;
      }

      initializePoolInstructions.push(
        Token.createTransferInstruction(
          TOKEN_PROGRAM_ID,
          wrappedAccount,
          holdingAccounts[mint.toBase58()].publicKey,
          ownerAddress,
          [],
          amount,
        ),
      );
    });

    initializePoolInstructions.push(
      createInitSwapInstruction(
        tokenSwapAccountPubkey,
        authority,
        holdingAccounts[sourceTokenAccounts[0].mint.toBase58()].publicKey,
        holdingAccounts[sourceTokenAccounts[1].mint.toBase58()].publicKey,
        liquidityTokenMintAccount.publicKey,
        feeAccount.publicKey,
        depositorAccount.publicKey,
        TOKEN_PROGRAM_ID,
        tokenSwapProgram,
        nonce,
        options,
      ),
    );
    initializePoolSigners.push(tokenSwapAccountSigner);
    const initializePoolTransaction = new Transaction();
    initializePoolTransaction.add(
      ...initializePoolInstructions,
      ...cleanupInstructions,
    );
    return {
      initializeAccountsTransaction,
      initializeAccountsSigners,
      initializePoolTransaction,
      initializePoolSigners,
    };
  }
Example #21
Source File: pools.ts    From serum-ts with Apache License 2.0 4 votes vote down vote up
async makeSwapTransaction<T extends PublicKey | Account>(
    connection: Connection,
    owner: T,
    tokenIn: {
      mint: PublicKey;
      tokenAccount: PublicKey;
      amount: number;
    },
    tokenOut: {
      mint: PublicKey;
      tokenAccount: PublicKey;
      amount: number;
    },
    slippage: number,
    hostFeeAccount?: PublicKey,
  ): Promise<{ transaction: Transaction; signers: Account[]; payer: T }> {
    // @ts-ignore
    const ownerAddress: PublicKey = owner.publicKey ?? owner;
    const [poolMint, inMint, outMint] = await Promise.all([
      this.getCachedMintAccount(connection, this._poolTokenMint, 3600_000),
      this.getCachedMintAccount(connection, tokenIn.mint, 3600_000),
      this.getCachedMintAccount(connection, tokenOut.mint, 3600_000),
    ]);
    const amountIn = Math.floor(tokenIn.amount * Math.pow(10, inMint.decimals));
    const minAmountOut = Math.floor(
      tokenOut.amount * Math.pow(10, outMint.decimals) * (1 - slippage),
    );
    const holdingA =
      this._tokenMints[0].toBase58() === tokenIn.mint.toBase58()
        ? this._holdingAccounts[0]
        : this._holdingAccounts[1];
    const holdingB = holdingA.equals(this._holdingAccounts[0])
      ? this._holdingAccounts[1]
      : this._holdingAccounts[0];

    if (!poolMint.mintAuthority || !this._feeAccount) {
      throw new Error('Mint doesnt have authority');
    }
    const authority = poolMint.mintAuthority;

    const instructions: TransactionInstruction[] = [];
    const cleanupInstructions: TransactionInstruction[] = [];
    const signers: Account[] = [];

    const accountRentExempt = await connection.getMinimumBalanceForRentExemption(
      AccountLayout.span,
    );

    let fromAccount: PublicKey;
    if (tokenIn.mint.equals(WRAPPED_SOL_MINT)) {
      const {
        account,
        instructions: createWrappedSolInstructions,
        cleanUpInstructions: removeWrappedSolInstructions,
      } = createTokenAccount(
        ownerAddress,
        ownerAddress,
        WRAPPED_SOL_MINT,
        amountIn + accountRentExempt,
      );
      fromAccount = account.publicKey;
      signers.push(account);
      instructions.push(...createWrappedSolInstructions);
      cleanupInstructions.push(...removeWrappedSolInstructions);
    } else {
      fromAccount = tokenIn.tokenAccount;
    }

    let toAccount: PublicKey;
    if (tokenOut.mint.equals(WRAPPED_SOL_MINT)) {
      const {
        account,
        instructions: createWrappedSolInstructions,
        cleanUpInstructions: removeWrappedSolInstructions,
      } = createTokenAccount(
        ownerAddress,
        ownerAddress,
        WRAPPED_SOL_MINT,
        accountRentExempt,
      );
      toAccount = account.publicKey;
      signers.push(account);
      instructions.push(...createWrappedSolInstructions);
      cleanupInstructions.push(...removeWrappedSolInstructions);
    } else {
      toAccount = tokenOut.tokenAccount;
    }

    // create approval for transfer transactions
    const transferAuthority = approveTransfer(
      instructions,
      cleanupInstructions,
      fromAccount,
      ownerAddress,
      amountIn,
      this.isLatest ? undefined : authority,
    );
    if (this.isLatest) {
      signers.push(transferAuthority);
    }

    // swap
    instructions.push(
      swapInstruction(
        this._poolAccount,
        authority,
        transferAuthority.publicKey,
        fromAccount,
        holdingA,
        holdingB,
        toAccount,
        this._poolTokenMint,
        this._feeAccount,
        this._programId,
        TOKEN_PROGRAM_ID,
        amountIn,
        minAmountOut,
        hostFeeAccount,
      ),
    );

    instructions.push(...cleanupInstructions);
    const transaction = new Transaction();
    transaction.add(...instructions);
    return { transaction, signers, payer: owner };
  }
Example #22
Source File: pools.ts    From serum-ts with Apache License 2.0 4 votes vote down vote up
async makeAddSingleSidedLiquidityTransaction<T extends PublicKey>(
    connection: Connection,
    owner: T,
    sourceTokenAccount: {
      mint: PublicKey;
      tokenAccount: PublicKey;
      amount: number; // note this is raw amount, not decimal
    },
    poolTokenAccount?: PublicKey,
  ): Promise<{ transaction: Transaction; signers: Account[]; payer: T }> {
    assert(this._decoded.curve.constantPrice, 'Only implemented for constant price pools');
    // @ts-ignore
    const ownerAddress: PublicKey = owner.publicKey ?? owner;
    const instructions: TransactionInstruction[] = [];
    const cleanupInstructions: TransactionInstruction[] = [];

    const signers: Account[] = [];
    const poolMint = await this.getCachedMintAccount(
      connection,
      this._poolTokenMint,
      0,
    );
    if (!poolMint.mintAuthority) {
      throw new Error('Mint doesnt have authority');
    }
    const authority = poolMint.mintAuthority;

    const accountRentExempt = await connection.getMinimumBalanceForRentExemption(
      AccountLayout.span,
    );
    const accountA = await this.getCachedTokenAccount(
      connection,
      this._holdingAccounts[0],
    );
    const accountB = await this.getCachedTokenAccount(
      connection,
      this._holdingAccounts[1],
    );

    const reserve0 = accountA.info.amount.toNumber();
    const reserve1 = accountB.info.amount.toNumber();
    const supply = poolMint.supply.toNumber();

    const tokenBPrice = this._decoded.curve.constantPrice.token_b_price
    let price;
    if (sourceTokenAccount.mint.equals(this.tokenMints[1])) {
      price = tokenBPrice;
    } else {
      price = 1;
    }
    const sourceAmountPostFees = sourceTokenAccount.amount - (
      Math.max(1, sourceTokenAccount.amount / 2) *
      this._decoded.fees.tradeFeeNumerator / this._decoded.fees.tradeFeeDenominator
    )
    const liquidity = Math.floor((sourceAmountPostFees * price * supply) / (reserve0 + reserve1 * tokenBPrice));

    let fromKey: PublicKey;
    if (sourceTokenAccount.mint.equals(WRAPPED_SOL_MINT)) {
      const {
        account,
        instructions: createWrappedSolInstructions,
        cleanUpInstructions: removeWrappedSolInstructions,
      } = createTokenAccount(
        ownerAddress,
        ownerAddress,
        WRAPPED_SOL_MINT,
        sourceTokenAccount.amount + accountRentExempt,
      );
      fromKey = account.publicKey;
      signers.push(account);
      instructions.push(...createWrappedSolInstructions);
      cleanupInstructions.push(...removeWrappedSolInstructions);
    } else {
      fromKey = sourceTokenAccount.tokenAccount;
    }

    let toAccount: PublicKey;
    if (!poolTokenAccount) {
      const {
        account,
        instructions: createToAccountInstructions,
        cleanUpInstructions: cleanupCreateToAccountInstructions,
      } = createTokenAccount(
        ownerAddress,
        ownerAddress,
        this._poolTokenMint,
        accountRentExempt,
      );
      toAccount = account.publicKey;
      signers.push(account);
      instructions.push(...createToAccountInstructions);
      cleanupInstructions.push(...cleanupCreateToAccountInstructions);
    } else {
      toAccount = poolTokenAccount;
    }

    const transferAuthority = approveTransfer(
      instructions,
      cleanupInstructions,
      fromKey,
      ownerAddress,
      sourceTokenAccount.amount,
      this.isLatest ? undefined : authority,
    );
    if (this.isLatest) {
      signers.push(transferAuthority);
    }

    instructions.push(
      depositExactOneInstruction(
        this._poolAccount,
        authority,
        transferAuthority.publicKey,
        sourceTokenAccount.tokenAccount,
        this._holdingAccounts[0],
        this._holdingAccounts[1],
        this._poolTokenMint,
        toAccount,
        this._programId,
        TOKEN_PROGRAM_ID,
        sourceTokenAccount.amount,
        liquidity,
        this.isLatest,
      ),
    );

    const transaction = new Transaction();
    transaction.add(...instructions);
    transaction.add(...cleanupInstructions);
    return { transaction, signers, payer: owner };
  }
Example #23
Source File: pools.ts    From serum-ts with Apache License 2.0 4 votes vote down vote up
async makeAddLiquidityTransaction<T extends PublicKey | Account>(
    connection: Connection,
    owner: T,
    sourceTokenAccounts: {
      mint: PublicKey;
      tokenAccount: PublicKey;
      amount: number; // note this is raw amount, not decimal
    }[],
    poolTokenAccount?: PublicKey,
    slippageTolerance = 0.005, // allow slippage of this much between setting input amounts and on chain transaction
  ): Promise<{ transaction: Transaction; signers: Account[]; payer: T }> {
    // @ts-ignore
    const ownerAddress: PublicKey = owner.publicKey ?? owner;
    const poolMint = await this.getCachedMintAccount(
      connection,
      this._poolTokenMint,
      360000,
    );
    if (!poolMint.mintAuthority) {
      throw new Error('Mint doesnt have authority');
    }

    if (!this._feeAccount) {
      throw new Error('Invald fee account');
    }

    const accountA = await this.getCachedTokenAccount(
      connection,
      this._holdingAccounts[0],
    );
    const accountB = await this.getCachedTokenAccount(
      connection,
      this._holdingAccounts[1],
    );

    const reserve0 = accountA.info.amount.toNumber();
    const reserve1 = accountB.info.amount.toNumber();
    const [fromA, fromB] = accountA.info.mint.equals(
      sourceTokenAccounts[0].mint,
    )
      ? [sourceTokenAccounts[0], sourceTokenAccounts[1]]
      : [sourceTokenAccounts[1], sourceTokenAccounts[0]];

    if (!fromA.tokenAccount || !fromB.tokenAccount) {
      throw new Error('Missing account info.');
    }

    const supply = poolMint.supply.toNumber();
    const authority = poolMint.mintAuthority;

    // Uniswap whitepaper: https://uniswap.org/whitepaper.pdf
    // see: https://uniswap.org/docs/v2/advanced-topics/pricing/
    // as well as native uniswap v2 oracle: https://uniswap.org/docs/v2/core-concepts/oracles/
    const amount0 = fromA.amount;
    const amount1 = fromB.amount;

    const liquidity = Math.min(
      (amount0 * (1 - slippageTolerance) * supply) / reserve0,
      (amount1 * (1 - slippageTolerance) * supply) / reserve1,
    );
    const instructions: TransactionInstruction[] = [];
    const cleanupInstructions: TransactionInstruction[] = [];

    const signers: Account[] = [];

    const accountRentExempt = await connection.getMinimumBalanceForRentExemption(
      AccountLayout.span,
    );

    let fromKeyA: PublicKey;
    if (fromA.mint.equals(WRAPPED_SOL_MINT)) {
      const {
        account,
        instructions: createWrappedSolInstructions,
        cleanUpInstructions: removeWrappedSolInstructions,
      } = createTokenAccount(
        ownerAddress,
        ownerAddress,
        WRAPPED_SOL_MINT,
        fromA.amount + accountRentExempt,
      );
      fromKeyA = account.publicKey;
      signers.push(account);
      instructions.push(...createWrappedSolInstructions);
      cleanupInstructions.push(...removeWrappedSolInstructions);
    } else {
      fromKeyA = fromA.tokenAccount;
    }

    let fromKeyB: PublicKey;
    if (fromB.mint.equals(WRAPPED_SOL_MINT)) {
      const {
        account,
        instructions: createWrappedSolInstructions,
        cleanUpInstructions: removeWrappedSolInstructions,
      } = createTokenAccount(
        ownerAddress,
        ownerAddress,
        WRAPPED_SOL_MINT,
        fromB.amount + accountRentExempt,
      );
      fromKeyB = account.publicKey;
      signers.push(account);
      instructions.push(...createWrappedSolInstructions);
      cleanupInstructions.push(...removeWrappedSolInstructions);
    } else {
      fromKeyB = fromB.tokenAccount;
    }

    let toAccount: PublicKey;
    if (!poolTokenAccount) {
      const {
        account,
        instructions: createToAccountInstructions,
        cleanUpInstructions: cleanupCreateToAccountInstructions,
      } = createTokenAccount(
        ownerAddress,
        ownerAddress,
        this._poolTokenMint,
        accountRentExempt,
      );
      toAccount = account.publicKey;
      signers.push(account);
      instructions.push(...createToAccountInstructions);
      cleanupInstructions.push(...cleanupCreateToAccountInstructions);
    } else {
      toAccount = poolTokenAccount;
    }

    // create approval for transfer transactions
    const transferAuthority = approveTransfer(
      instructions,
      cleanupInstructions,
      fromKeyA,
      ownerAddress,
      amount0,
      this.isLatest ? undefined : authority,
    );
    if (this.isLatest) {
      signers.push(transferAuthority);
    }

    approveTransfer(
      instructions,
      cleanupInstructions,
      fromKeyB,
      ownerAddress,
      amount1,
      this.isLatest ? transferAuthority.publicKey : authority,
    );

    instructions.push(
      depositInstruction(
        this._poolAccount,
        authority,
        transferAuthority.publicKey,
        fromKeyA,
        fromKeyB,
        this._holdingAccounts[0],
        this._holdingAccounts[1],
        this._poolTokenMint,
        toAccount,
        this._programId,
        TOKEN_PROGRAM_ID,
        liquidity,
        amount0,
        amount1,
      ),
    );

    const transaction = new Transaction();
    transaction.add(...instructions);
    transaction.add(...cleanupInstructions);
    return { transaction, signers, payer: owner };
  }
Example #24
Source File: pools.ts    From serum-ts with Apache License 2.0 4 votes vote down vote up
async makeRemoveLiquidityTransaction<T extends PublicKey | Account>(
    connection: Connection,
    owner: T,
    liquidityAmount: number,
    poolAccount: TokenAccount,
    tokenAccounts: TokenAccount[],
  ): Promise<{ transaction: Transaction; signers: Account[]; payer: T }> {
    // @ts-ignore
    const ownerAddress: PublicKey = owner.publicKey ?? owner;

    // TODO get min amounts based on total supply and liquidity
    const minAmount0 = 0;
    const minAmount1 = 0;

    const poolMint = await this.getCachedMintAccount(
      connection,
      this._poolTokenMint,
      3600000,
    );
    const accountA = await this.getCachedTokenAccount(
      connection,
      this._holdingAccounts[0],
      3600000,
    );
    const accountB = await this.getCachedTokenAccount(
      connection,
      this._holdingAccounts[1],
      3600000,
    );
    if (!poolMint.mintAuthority) {
      throw new Error('Mint doesnt have authority');
    }
    const authority = poolMint.mintAuthority;

    const signers: Account[] = [];
    const instructions: TransactionInstruction[] = [];
    const cleanUpInstructions: TransactionInstruction[] = [];

    let tokenAccountA: PublicKey | undefined;
    let tokenAccountB: PublicKey | undefined;
    if (accountA.info.mint.equals(WRAPPED_SOL_MINT)) {
      const accountRentExempt = await connection.getMinimumBalanceForRentExemption(
        AccountLayout.span,
      );
      const {
        account,
        instructions: createWrappedSolInstructions,
        cleanUpInstructions: removeWrappedSolInstructions,
      } = createTokenAccount(
        ownerAddress,
        ownerAddress,
        WRAPPED_SOL_MINT,
        accountRentExempt,
      );
      tokenAccountA = account.publicKey;
      signers.push(account);
      instructions.push(...createWrappedSolInstructions);
      cleanUpInstructions.push(...removeWrappedSolInstructions)
    } else {
      tokenAccountA = tokenAccounts.find(a =>
        a.info.mint.equals(accountA.info.mint),
      )?.pubkey;
    }
    if (accountB.info.mint.equals(WRAPPED_SOL_MINT)) {
      const accountRentExempt = await connection.getMinimumBalanceForRentExemption(
        AccountLayout.span,
      );
      const {
        account,
        instructions: createWrappedSolInstructions,
        cleanUpInstructions: removeWrappedSolInstructions,
      } = createTokenAccount(
        ownerAddress,
        ownerAddress,
        WRAPPED_SOL_MINT,
        accountRentExempt,
      );
      tokenAccountB = account.publicKey;
      signers.push(account);
      instructions.push(...createWrappedSolInstructions);
      cleanUpInstructions.push(...removeWrappedSolInstructions)
    } else {
      tokenAccountB = tokenAccounts.find(a =>
        a.info.mint.equals(accountB.info.mint),
      )?.pubkey;
    }
    assert(
      !!tokenAccountA,
      `Token account for mint ${accountA.info.mint.toBase58()} not provided`,
    );
    assert(
      !!tokenAccountB,
      `Token account for mint ${accountB.info.mint.toBase58()} not provided`,
    );

    const transferAuthority = approveTransfer(
      instructions,
      cleanUpInstructions,
      poolAccount.pubkey,
      ownerAddress,
      liquidityAmount,
      this.isLatest ? undefined : authority,
    );

    if (this.isLatest) {
      signers.push(transferAuthority);
    }

    instructions.push(
      withdrawInstruction(
        this._poolAccount,
        authority,
        transferAuthority.publicKey,
        this._poolTokenMint,
        this._feeAccount,
        poolAccount.pubkey,
        this._holdingAccounts[0],
        this._holdingAccounts[1],
        tokenAccountA,
        tokenAccountB,
        this._programId,
        TOKEN_PROGRAM_ID,
        liquidityAmount,
        minAmount0,
        minAmount1,
      ),
    );
    const transaction = new Transaction();
    transaction.add(...instructions, ...cleanUpInstructions);
    return { transaction, signers, payer: owner };
  }
Example #25
Source File: accounts.tsx    From metaplex with Apache License 2.0 4 votes vote down vote up
export function AccountsProvider({
  children = null,
}: {
  children: React.ReactNode;
}) {
  const connection = useConnection();
  const { publicKey } = useWallet();
  const [tokenAccounts, setTokenAccounts] = useState<TokenAccount[]>([]);
  const [userAccounts, setUserAccounts] = useState<TokenAccount[]>([]);
  const { nativeAccount } = UseNativeAccount();
  const walletKey = publicKey?.toBase58();

  const selectUserAccounts = useCallback(() => {
    return cache
      .byParser(TokenAccountParser)
      .map(id => cache.get(id))
      .filter(a => a && a.info.owner.toBase58() === walletKey)
      .map(a => a as TokenAccount);
  }, [walletKey, nativeAccount]);

  useEffect(() => {
    const accounts = selectUserAccounts().filter(
      a => a !== undefined,
    ) as TokenAccount[];
    setUserAccounts(accounts);
  }, [nativeAccount, tokenAccounts, selectUserAccounts]);

  useEffect(() => {
    const subs: number[] = [];
    cache.emitter.onCache(args => {
      if (args.isNew && args.isActive) {
        const id = args.id;
        const deserialize = args.parser;
        connection.onAccountChange(new PublicKey(id), info => {
          cache.add(id, info, deserialize);
        });
      }
    });

    return () => {
      subs.forEach(id => connection.removeAccountChangeListener(id));
    };
  }, [connection]);

  useEffect(() => {
    if (!connection || !publicKey) {
      setTokenAccounts([]);
    } else {
      precacheUserTokenAccounts(connection, publicKey).then(() => {
        setTokenAccounts(selectUserAccounts());
      });

      // This can return different types of accounts: token-account, mint, multisig
      // TODO: web3.js expose ability to filter.
      // this should use only filter syntax to only get accounts that are owned by user
      const tokenSubID = connection.onProgramAccountChange(
        programIds().token,
        info => {
          // TODO: fix type in web3.js
          const id = info.accountId as unknown as string;
          // TODO: do we need a better way to identify layout (maybe a enum identifing type?)
          if (info.accountInfo.data.length === AccountLayout.span) {
            const data = deserializeAccount(info.accountInfo.data);

            if (PRECACHED_OWNERS.has(data.owner.toBase58())) {
              cache.add(id, info.accountInfo, TokenAccountParser);
              setTokenAccounts(selectUserAccounts());
            }
          }
        },
        'singleGossip',
      );

      return () => {
        connection.removeProgramAccountChangeListener(tokenSubID);
      };
    }
  }, [connection, publicKey, selectUserAccounts]);

  return (
    <AccountsContext.Provider
      value={{
        userAccounts,
        nativeAccount,
      }}
    >
      {children}
    </AccountsContext.Provider>
  );
}
Example #26
Source File: token.ts    From metaplex with Apache License 2.0 4 votes vote down vote up
mintNFT = async (
  connection: Connection,
  wallet: WalletSigner,
  // SOL account
  owner: PublicKey,
) => {
  if (!wallet.publicKey) throw new WalletNotConnectedError();

  const TOKEN_PROGRAM_ID = new PublicKey(
    'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',
  );
  //const SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID = new PublicKey(
  //  'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL',
  //);
  const mintAccount = new Account();
  const tokenAccount = new Account();

  // Allocate memory for the account
  const mintRent = await connection.getMinimumBalanceForRentExemption(
    MintLayout.span,
  );

  const accountRent = await connection.getMinimumBalanceForRentExemption(
    AccountLayout.span,
  );

  let transaction = new Transaction();
  const signers = [mintAccount, tokenAccount];
  transaction.recentBlockhash = (
    await connection.getRecentBlockhash('max')
  ).blockhash;

  transaction.add(
    SystemProgram.createAccount({
      fromPubkey: wallet.publicKey,
      newAccountPubkey: mintAccount.publicKey,
      lamports: mintRent,
      space: MintLayout.span,
      programId: TOKEN_PROGRAM_ID,
    }),
  );

  transaction.add(
    SystemProgram.createAccount({
      fromPubkey: wallet.publicKey,
      newAccountPubkey: tokenAccount.publicKey,
      lamports: accountRent,
      space: AccountLayout.span,
      programId: TOKEN_PROGRAM_ID,
    }),
  );

  transaction.add(
    Token.createInitMintInstruction(
      TOKEN_PROGRAM_ID,
      mintAccount.publicKey,
      0,
      wallet.publicKey,
      wallet.publicKey,
    ),
  );
  transaction.add(
    Token.createInitAccountInstruction(
      TOKEN_PROGRAM_ID,
      mintAccount.publicKey,
      tokenAccount.publicKey,
      owner,
    ),
  );
  transaction.add(
    Token.createMintToInstruction(
      TOKEN_PROGRAM_ID,
      mintAccount.publicKey,
      tokenAccount.publicKey,
      wallet.publicKey,
      [],
      1,
    ),
  );
  transaction.add(
    Token.createSetAuthorityInstruction(
      TOKEN_PROGRAM_ID,
      mintAccount.publicKey,
      null,
      'MintTokens',
      wallet.publicKey,
      [],
    ),
  );

  transaction.setSigners(wallet.publicKey, ...signers.map(s => s.publicKey));
  if (signers.length > 0) {
    transaction.partialSign(...signers);
  }
  transaction = await wallet.signTransaction(transaction);
  const rawTransaction = transaction.serialize();
  const options = {
    skipPreflight: true,
    commitment: 'singleGossip',
  };

  const txid = await connection.sendRawTransaction(rawTransaction, options);

  return { txid, mint: mintAccount.publicKey, account: tokenAccount.publicKey };
}
Example #27
Source File: closeVault.ts    From metaplex with Apache License 2.0 4 votes vote down vote up
// This command "closes" the vault, by activating & combining it in one go, handing it over to the auction manager
// authority (that may or may not exist yet.)
export async function closeVault(
  connection: Connection,
  wallet: WalletSigner,
  vault: StringPublicKey,
  fractionMint: StringPublicKey,
  fractionTreasury: StringPublicKey,
  redeemTreasury: StringPublicKey,
  priceMint: StringPublicKey,
  externalPriceAccount: StringPublicKey,
): Promise<{
  instructions: TransactionInstruction[];
  signers: Keypair[];
}> {
  if (!wallet.publicKey) throw new WalletNotConnectedError();

  const accountRentExempt = await connection.getMinimumBalanceForRentExemption(
    AccountLayout.span,
  );
  const signers: Keypair[] = [];
  const instructions: TransactionInstruction[] = [];

  await activateVault(
    new BN(0),
    vault,
    fractionMint,
    fractionTreasury,
    wallet.publicKey.toBase58(),
    instructions,
  );

  const outstandingShareAccount = createTokenAccount(
    instructions,
    wallet.publicKey,
    accountRentExempt,
    toPublicKey(fractionMint),
    wallet.publicKey,
    signers,
  );

  const payingTokenAccount = createTokenAccount(
    instructions,
    wallet.publicKey,
    accountRentExempt,
    toPublicKey(priceMint),
    wallet.publicKey,
    signers,
  );

  const transferAuthority = Keypair.generate();

  // Shouldn't need to pay anything since we activated vault with 0 shares, but we still
  // need this setup anyway.
  approve(
    instructions,
    [],
    payingTokenAccount,
    wallet.publicKey,
    0,
    false,
    undefined,
    transferAuthority,
  );

  approve(
    instructions,
    [],
    outstandingShareAccount,
    wallet.publicKey,
    0,
    false,
    undefined,
    transferAuthority,
  );

  signers.push(transferAuthority);

  await combineVault(
    vault,
    outstandingShareAccount.toBase58(),
    payingTokenAccount.toBase58(),
    fractionMint,
    fractionTreasury,
    redeemTreasury,
    wallet.publicKey.toBase58(),
    wallet.publicKey.toBase58(),
    transferAuthority.publicKey.toBase58(),
    externalPriceAccount,
    instructions,
  );

  return { instructions, signers };
}
Example #28
Source File: helpers.ts    From psyoptions with Apache License 2.0 4 votes vote down vote up
createExerciser = async (
  connection: Connection,
  exerciser: Keypair,
  mintAuthority: Keypair,
  quoteToken: Token,
  quoteAmount: number,
  optionMint: PublicKey,
  underlyingTokenMint: PublicKey
) => {
  const transaction = new Transaction();

  const quoteAccount = new Keypair();
  const assetPoolRentBalance =
    await connection.getMinimumBalanceForRentExemption(AccountLayout.span);
  transaction.add(
    SystemProgram.createAccount({
      fromPubkey: exerciser.publicKey,
      newAccountPubkey: quoteAccount.publicKey,
      lamports: assetPoolRentBalance,
      space: AccountLayout.span,
      programId: TOKEN_PROGRAM_ID,
    })
  );
  transaction.add(
    Token.createInitAccountInstruction(
      TOKEN_PROGRAM_ID,
      quoteToken.publicKey,
      quoteAccount.publicKey,
      exerciser.publicKey
    )
  );

  // create an associated token account to hold the options
  const optionAccount = new Keypair();
  transaction.add(
    SystemProgram.createAccount({
      fromPubkey: exerciser.publicKey,
      newAccountPubkey: optionAccount.publicKey,
      lamports: assetPoolRentBalance,
      space: AccountLayout.span,
      programId: TOKEN_PROGRAM_ID,
    })
  );
  transaction.add(
    Token.createInitAccountInstruction(
      TOKEN_PROGRAM_ID,
      optionMint,
      optionAccount.publicKey,
      exerciser.publicKey
    )
  );

  // create an associated token account to hold the underlying tokens
  const underlyingAccount = new Keypair();
  transaction.add(
    SystemProgram.createAccount({
      fromPubkey: exerciser.publicKey,
      newAccountPubkey: underlyingAccount.publicKey,
      lamports: assetPoolRentBalance,
      space: AccountLayout.span,
      programId: TOKEN_PROGRAM_ID,
    })
  );
  transaction.add(
    Token.createInitAccountInstruction(
      TOKEN_PROGRAM_ID,
      underlyingTokenMint,
      underlyingAccount.publicKey,
      exerciser.publicKey
    )
  );
  await sendAndConfirmTransaction(
    connection,
    transaction,
    [exerciser, quoteAccount, optionAccount, underlyingAccount],
    {
      commitment: "confirmed",
    }
  );

  // mint underlying tokens to the minter's account
  await quoteToken.mintTo(
    quoteAccount.publicKey,
    mintAuthority,
    [],
    quoteAmount
  );
  return { optionAccount, quoteAccount, underlyingAccount };
}
Example #29
Source File: helpers.ts    From psyoptions with Apache License 2.0 4 votes vote down vote up
createMinter = async (
  connection: Connection,
  minter: Keypair,
  mintAuthority: Keypair,
  underlyingToken: Token,
  underlyingAmount: number,
  optionMint: PublicKey,
  writerTokenMint: PublicKey,
  quoteToken: Token,
  quoteAmount: number = 0
) => {
  const transaction = new Transaction();

  const underlyingAccount = new Keypair();
  const assetPoolRentBalance =
    await connection.getMinimumBalanceForRentExemption(AccountLayout.span);
  transaction.add(
    SystemProgram.createAccount({
      fromPubkey: minter.publicKey,
      newAccountPubkey: underlyingAccount.publicKey,
      lamports: assetPoolRentBalance,
      space: AccountLayout.span,
      programId: TOKEN_PROGRAM_ID,
    })
  );
  transaction.add(
    Token.createInitAccountInstruction(
      TOKEN_PROGRAM_ID,
      underlyingToken.publicKey,
      underlyingAccount.publicKey,
      minter.publicKey
    )
  );

  const quoteAccount = new Keypair();
  transaction.add(
    SystemProgram.createAccount({
      fromPubkey: minter.publicKey,
      newAccountPubkey: quoteAccount.publicKey,
      lamports: assetPoolRentBalance,
      space: AccountLayout.span,
      programId: TOKEN_PROGRAM_ID,
    })
  );
  transaction.add(
    Token.createInitAccountInstruction(
      TOKEN_PROGRAM_ID,
      quoteToken.publicKey,
      quoteAccount.publicKey,
      minter.publicKey
    )
  );

  // create an associated token account to hold the options
  const optionAccount = new Keypair();
  transaction.add(
    SystemProgram.createAccount({
      fromPubkey: minter.publicKey,
      newAccountPubkey: optionAccount.publicKey,
      lamports: assetPoolRentBalance,
      space: AccountLayout.span,
      programId: TOKEN_PROGRAM_ID,
    })
  );
  transaction.add(
    Token.createInitAccountInstruction(
      TOKEN_PROGRAM_ID,
      optionMint,
      optionAccount.publicKey,
      minter.publicKey
    )
  );

  // create an associated token account to hold the writer tokens
  const writerTokenAccount = new Keypair();
  transaction.add(
    SystemProgram.createAccount({
      fromPubkey: minter.publicKey,
      newAccountPubkey: writerTokenAccount.publicKey,
      lamports: assetPoolRentBalance,
      space: AccountLayout.span,
      programId: TOKEN_PROGRAM_ID,
    })
  );
  transaction.add(
    Token.createInitAccountInstruction(
      TOKEN_PROGRAM_ID,
      writerTokenMint,
      writerTokenAccount.publicKey,
      minter.publicKey
    )
  );

  await sendAndConfirmTransaction(
    connection,
    transaction,
    [
      minter,
      underlyingAccount,
      quoteAccount,
      optionAccount,
      writerTokenAccount,
    ],
    {
      commitment: "confirmed",
    }
  );

  // mint underlying tokens to the minter's account
  await underlyingToken.mintTo(
    underlyingAccount.publicKey,
    mintAuthority,
    [],
    underlyingAmount
  );

  if (quoteAmount > 0) {
    await quoteToken.mintTo(
      quoteAccount.publicKey,
      mintAuthority,
      [],
      quoteAmount
    );
  }
  return { optionAccount, quoteAccount, underlyingAccount, writerTokenAccount };
}