diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts index 1bf7aecd0..41901640c 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts @@ -120,13 +120,20 @@ export const prepareAmericanOptions = async ( ) { ataTxBuilderArray.push(underlyingToken.txBuilder); } + const { tokenBalance } = await convergence.tokens().getTokenBalance({ + mintAddress: optionMarket.optionMint, + owner: caller, + mintDecimals: PsyoptionsAmericanInstrument.decimals, + }); + + const tokensToMint = amount - tokenBalance; const ixWithSigners = await psyoptionsAmerican.instructions.mintOptionInstruction( americanProgram, optionToken.ataPubKey, writerToken.ataPubKey, underlyingToken.ataPubKey, - new BN(amount!), + new BN(tokensToMint!), optionMarket as psyoptionsAmerican.OptionMarketWithKey ); ixWithSigners.ix.keys[0] = { diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts index 0c3b95b2e..d27b78e8a 100644 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts @@ -184,6 +184,18 @@ export const prepareEuropeanOptions = async ( ) { ataTxBuilderArray.push(writerDestination.txBuilder); } + + const { tokenBalance } = await convergence.tokens().getTokenBalance({ + mintAddress: + leg.optionType == psyoptionsEuropean.OptionType.PUT + ? euroMeta.putWriterMint + : euroMeta.callWriterMint, + owner: caller, + mintDecimals: PsyoptionsEuropeanInstrument.decimals, + }); + + const tokensToMint = amount - tokenBalance; + const { instruction: ix } = psyoptionsEuropean.instructions.mintOptions( europeanProgram, leg.optionMetaPubKey, @@ -191,7 +203,7 @@ export const prepareEuropeanOptions = async ( minterCollateralKey, optionDestination.ataPubKey, writerDestination.ataPubKey, - addDecimals(amount, PsyoptionsEuropeanInstrument.decimals), + addDecimals(tokensToMint, PsyoptionsEuropeanInstrument.decimals), leg.optionType ); diff --git a/packages/js/src/plugins/tokenModule/TokenClient.ts b/packages/js/src/plugins/tokenModule/TokenClient.ts index 9f4aacc0c..ad0587bf4 100644 --- a/packages/js/src/plugins/tokenModule/TokenClient.ts +++ b/packages/js/src/plugins/tokenModule/TokenClient.ts @@ -17,6 +17,8 @@ import { findTokenWithMintByMintOperation, FreezeTokensInput, freezeTokensOperation, + GetTokenBalanceInput, + getTokenBalanceOperation, MintTokensInput, mintTokensOperation, RevokeTokenDelegateAuthorityInput, @@ -233,4 +235,11 @@ export class TokenClient { .operations() .execute(revokeTokenDelegateAuthorityOperation(input), options); } + + /** {@inheritDoc getTokenBalanceOperation } */ + getTokenBalance(input: GetTokenBalanceInput, options?: OperationOptions) { + return this.convergence + .operations() + .execute(getTokenBalanceOperation(input), options); + } } diff --git a/packages/js/src/plugins/tokenModule/operations/getTokenBalance.ts b/packages/js/src/plugins/tokenModule/operations/getTokenBalance.ts new file mode 100644 index 000000000..4dda8d08a --- /dev/null +++ b/packages/js/src/plugins/tokenModule/operations/getTokenBalance.ts @@ -0,0 +1,91 @@ +import { PublicKey } from '@solana/web3.js'; + +import BN from 'bn.js'; +import type { Convergence } from '../../../Convergence'; +import { Operation, OperationHandler, useOperation } from '../../../types'; + +const Key = 'GetTokenBalance' as const; + +/** + * Get token Balance. + * + * ```ts + * await convergence + * .tokens() + * .getTokenBalance({ + * mintAddress, + * owner, + * mintDecimals + * }; + * ``` + * + * @group Operations + * @category Constructors + */ +export const getTokenBalanceOperation = + useOperation(Key); + +/** + * @group Operations + * @category Types + */ +export type GetTokenBalanceOperation = Operation< + typeof Key, + GetTokenBalanceInput, + GetTokenBalanceOutput +>; + +/** + * @group Operations + * @category Inputs + */ +export type GetTokenBalanceInput = { + /** The address of the mint account. */ + mintAddress: PublicKey; + /** The address of ATA owner */ + owner: PublicKey; + /** mint decimals*/ + mintDecimals: number; +}; + +/** + * @group Operations + * @category Outputs + */ +export type GetTokenBalanceOutput = { + /** The blockchain response from sending and confirming the transaction. */ + tokenBalance: number; +}; + +/** + * @group Operations + * @category Handlers + */ +export const getTokenBalanceOperationHandler: OperationHandler = + { + async handle( + operation: GetTokenBalanceOperation, + convergence: Convergence + ): Promise { + const { mintAddress, owner, mintDecimals } = operation.input; + + const ataAddress = convergence.tokens().pdas().associatedTokenAccount({ + mint: mintAddress, + owner, + }); + try { + const ata = await convergence + .tokens() + .findTokenByAddress({ address: ataAddress }); + return { + tokenBalance: ata.amount.basisPoints + .div(new BN(Math.pow(10, mintDecimals))) + .toNumber(), + }; + } catch (e) { + return { + tokenBalance: 0, + }; + } + }, + }; diff --git a/packages/js/src/plugins/tokenModule/operations/index.ts b/packages/js/src/plugins/tokenModule/operations/index.ts index 126c7f4a1..2a3ea8a8f 100644 --- a/packages/js/src/plugins/tokenModule/operations/index.ts +++ b/packages/js/src/plugins/tokenModule/operations/index.ts @@ -11,3 +11,4 @@ export * from './mintTokens'; export * from './revokeTokenDelegateAuthority'; export * from './sendTokens'; export * from './thawTokens'; +export * from './getTokenBalance'; diff --git a/packages/js/src/plugins/tokenModule/plugin.ts b/packages/js/src/plugins/tokenModule/plugin.ts index 7f7555483..77544a77c 100644 --- a/packages/js/src/plugins/tokenModule/plugin.ts +++ b/packages/js/src/plugins/tokenModule/plugin.ts @@ -18,6 +18,8 @@ import { findTokenWithMintByMintOperationHandler, freezeTokensOperation, freezeTokensOperationHandler, + getTokenBalanceOperationHandler, + getTokenBalanceOperation, mintTokensOperation, mintTokensOperationHandler, revokeTokenDelegateAuthorityOperation, @@ -94,6 +96,8 @@ export const tokenModule = (): ConvergencePlugin => ({ op.register(sendTokensOperation, sendTokensOperationHandler); op.register(thawTokensOperation, thawTokensOperationHandler); + op.register(getTokenBalanceOperation, getTokenBalanceOperationHandler); + convergence.tokens = function () { return new TokenClient(this); };