From 252658edef72fea60bc278a2edf3e513e1823ef3 Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Tue, 29 Aug 2023 14:28:53 +0530 Subject: [PATCH 01/32] need to fix mintAmericanOptions --- .../helpers.ts | 118 ++++++++++++------ .../helpers.ts | 75 +++++++---- packages/js/src/utils/ata.ts | 17 ++- .../integration/psyoptionsAmerican.spec.ts | 15 ++- 4 files changed, 153 insertions(+), 72 deletions(-) diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts index 3e6499227..8faaf7da0 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts @@ -1,16 +1,17 @@ import * as psyoptionsAmerican from '@mithraic-labs/psy-american'; import { BN } from 'bn.js'; -import { PublicKey } from '@solana/web3.js'; +import { PublicKey, TransactionInstruction } from '@solana/web3.js'; import { Convergence } from '../../Convergence'; -import { ATAExistence, getOrCreateATA } from '../../utils/ata'; +import { + ATAExistence, + getOrCreateATA, + getOrCreateATAInx, +} from '../../utils/ata'; import { Mint } from '../tokenModule/models'; import { CvgWallet } from '../../utils/Wallets'; -import { - InstructionWithSigners, - TransactionBuilder, -} from '../../utils/TransactionBuilder'; +import { TransactionBuilder } from '../../utils/TransactionBuilder'; import { PsyoptionsAmericanInstrument } from './types'; import { createAmericanProgram } from './instrument'; @@ -28,12 +29,15 @@ export const mintAmericanOptions = async ( .findRfqByAddress({ address: response.rfq }); const callerSide = caller.equals(rfq.taker) ? 'taker' : 'maker'; - const instructionWithSigners: InstructionWithSigners[] = []; - const { legs } = await convergence.rfqs().getSettlementResult({ + + const { legs } = convergence.rfqs().getSettlementResult({ response, rfq, }); + + const txBuilderArray: TransactionBuilder[] = []; for (const [index, leg] of rfq.legs.entries()) { + const instructions: TransactionInstruction[] = []; if (leg instanceof PsyoptionsAmericanInstrument) { const { receiver } = legs[index]; if (receiver !== callerSide) { @@ -44,23 +48,43 @@ export const mintAmericanOptions = async ( leg.optionMetaPubKey ); if (optionMarket) { - const optionToken = await getOrCreateATA( - convergence, - optionMarket.optionMint, - caller - ); - - const writerToken = await getOrCreateATA( - convergence, - optionMarket!.writerTokenMint, - caller - ); - - const underlyingToken = await getOrCreateATA( - convergence, - optionMarket!.underlyingAssetMint, - caller - ); + const { ataPubKey: optionToken, instruction: optionTokenIx } = + await getOrCreateATAInx( + convergence, + optionMarket.optionMint, + caller + ); + if (optionTokenIx) { + instructions.push(optionTokenIx); + } + + const { ataPubKey: writerToken, instruction: writerTokenIx } = + await getOrCreateATAInx( + convergence, + optionMarket!.writerTokenMint, + caller + ); + if (writerTokenIx) { + // instructionWithSigners.push({ + // instruction: writerTokenIx, + // signers: [], + // }); + instructions.push(writerTokenIx); + } + + const { ataPubKey: underlyingToken, instruction: underlyingTokenIx } = + await getOrCreateATAInx( + convergence, + optionMarket!.underlyingAssetMint, + caller + ); + if (underlyingTokenIx) { + // instructionWithSigners.push({ + // instruction: underlyingTokenIx, + // signers: [], + // }); + instructions.push(underlyingTokenIx); + } const ixWithSigners = await psyoptionsAmerican.instructions.mintOptionV2Instruction( @@ -76,23 +100,43 @@ export const mintAmericanOptions = async ( isSigner: true, isWritable: false, }; - instructionWithSigners.push({ - instruction: ixWithSigners.ix, - signers: ixWithSigners.signers, - }); + // instructionWithSigners.push({ + // instruction: ixWithSigners.ix, + // signers: ixWithSigners.signers, + // }); + instructions.push(ixWithSigners.ix); } } } + if (instructions.length > 0) { + const txBuilder = TransactionBuilder.make().setFeePayer( + convergence.rpc().getDefaultFeePayer() + ); + instructions.forEach((ins) => { + txBuilder.add({ + instruction: ins, + signers: [convergence.identity()], + }); + }); + // txBuilder.add(...instructionWithSigners); + txBuilderArray.push(txBuilder); + } } - if (instructionWithSigners.length > 0) { - const payer = convergence.rpc().getDefaultFeePayer(); - const txBuilder = TransactionBuilder.make().setFeePayer(payer); - - txBuilder.add(...instructionWithSigners); - const sig = await txBuilder.sendAndConfirm(convergence); - return sig; + if (txBuilderArray.length > 0) { + const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); + const signedTxs = await convergence + .identity() + .signAllTransactions( + txBuilderArray.map((b) => b.toTransaction(lastValidBlockHeight)) + ); + await Promise.all( + signedTxs.map((signedTx) => + convergence + .rpc() + .serializeAndSendTransaction(signedTx, lastValidBlockHeight) + ) + ); } - return null; }; export const initializeNewAmericanOption = async ( diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts index d3c021a2a..ae73f4f31 100644 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts @@ -3,7 +3,11 @@ import * as anchor from '@project-serum/anchor'; import { Keypair, PublicKey } from '@solana/web3.js'; import { BN } from 'bn.js'; import { Mint } from '../tokenModule'; -import { ATAExistence, getOrCreateATA } from '../../utils/ata'; +import { + ATAExistence, + getOrCreateATA, + getOrCreateATAInx, +} from '../../utils/ata'; import { addDecimals } from '../../utils/conversions'; import { TransactionBuilder } from '../../utils/TransactionBuilder'; import { Convergence } from '../../Convergence'; @@ -130,14 +134,15 @@ export const mintEuropeanOptions = async ( .rfqs() .findRfqByAddress({ address: response.rfq }); - const callerIsTaker = caller.toBase58() === rfq.taker.toBase58(); - const callerSide = callerIsTaker ? 'taker' : 'maker'; - const instructions: anchor.web3.TransactionInstruction[] = []; - const { legs } = await convergence.rfqs().getSettlementResult({ + const callerSide = caller.equals(rfq.taker) ? 'taker' : 'maker'; + + const { legs } = convergence.rfqs().getSettlementResult({ response, rfq, }); + const txBuilderArray: TransactionBuilder[] = []; for (const [index, leg] of rfq.legs.entries()) { + const instructions: anchor.web3.TransactionInstruction[] = []; if (leg instanceof PsyoptionsEuropeanInstrument) { const { receiver } = legs[index]; @@ -166,20 +171,33 @@ export const mintEuropeanOptions = async ( ? stableMintToken : underlyingMintToken; - const optionDestination = await getOrCreateATA( + const { + ataPubKey: optionDestination, + instruction: optionDestinationAtaIx, + } = await getOrCreateATAInx( convergence, leg.optionType == psyoptionsEuropean.OptionType.PUT ? euroMeta.putOptionMint : euroMeta.callOptionMint, caller ); - const writerDestination = await getOrCreateATA( + + if (optionDestinationAtaIx) { + instructions.push(optionDestinationAtaIx); + } + const { + ataPubKey: writerDestination, + instruction: writerDestinationAtaInx, + } = await getOrCreateATAInx( convergence, leg.optionType == psyoptionsEuropean.OptionType.PUT ? euroMeta.putWriterMint : euroMeta.callWriterMint, caller ); + if (writerDestinationAtaInx) { + instructions.push(writerDestinationAtaInx); + } const { instruction: ix } = psyoptionsEuropean.instructions.mintOptions( europeanProgram, leg.optionMetaPubKey, @@ -200,27 +218,34 @@ export const mintEuropeanOptions = async ( instructions.push(ix); } } + if (instructions.length > 0) { + const txBuilder = TransactionBuilder.make().setFeePayer( + convergence.rpc().getDefaultFeePayer() + ); + instructions.forEach((ins) => { + txBuilder.add({ + instruction: ins, + signers: [convergence.identity()], + }); + }); + txBuilderArray.push(txBuilder); + } } - if (instructions.length > 0) { - const txBuilder = TransactionBuilder.make().setFeePayer( - convergence.rpc().getDefaultFeePayer() + if (txBuilderArray.length > 0) { + const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); + const signedTxs = await convergence + .identity() + .signAllTransactions( + txBuilderArray.map((b) => b.toTransaction(lastValidBlockHeight)) + ); + await Promise.all( + signedTxs.map((signedTx) => + convergence + .rpc() + .serializeAndSendTransaction(signedTx, lastValidBlockHeight) + ) ); - - instructions.forEach((ins) => { - txBuilder.add({ - instruction: ins, - signers: [convergence.identity()], - }); - }); - - const confirmOptions = makeConfirmOptionsFinalizedOnMainnet(convergence, { - skipPreflight: true, - }); - - const sig = await txBuilder.sendAndConfirm(convergence, confirmOptions); - return sig; } - return null; }; export const getOrCreateEuropeanOptionATAs = async ( diff --git a/packages/js/src/utils/ata.ts b/packages/js/src/utils/ata.ts index 7478b4fce..763c773c8 100644 --- a/packages/js/src/utils/ata.ts +++ b/packages/js/src/utils/ata.ts @@ -35,31 +35,36 @@ export const getOrCreateATA = async ( return ata; }; +interface GetOrCreateATAInxReturnType { + ataPubKey: PublicKey; + instruction?: TransactionInstruction; +} + export const getOrCreateATAInx = async ( convergence: Convergence, mint: PublicKey, owner: PublicKey, programs?: Program[] -): Promise => { +): Promise => { const pda = convergence.tokens().pdas().associatedTokenAccount({ mint, owner, programs, }); const account = await convergence.rpc().getAccount(pda); - let ix: TransactionInstruction; + const payer = convergence.rpc().getDefaultFeePayer(); if (!account.exists) { - ix = Spl.createAssociatedTokenAccountInstruction( - owner, + const ix = Spl.createAssociatedTokenAccountInstruction( + payer.publicKey, pda, owner, mint, Spl.TOKEN_PROGRAM_ID, Spl.ASSOCIATED_TOKEN_PROGRAM_ID ); - return ix; + return { ataPubKey: pda, instruction: ix }; } - return pda; + return { ataPubKey: pda }; }; export const devnetAirdrops = async ( diff --git a/packages/js/tests/integration/psyoptionsAmerican.spec.ts b/packages/js/tests/integration/psyoptionsAmerican.spec.ts index 0e32836a9..a4f7b48a5 100644 --- a/packages/js/tests/integration/psyoptionsAmerican.spec.ts +++ b/packages/js/tests/integration/psyoptionsAmerican.spec.ts @@ -10,6 +10,7 @@ import { setupAmerican, createAmericanOpenSizeCallSpdOptionRfq, createAmericanFixedBaseStraddle, + fetchTokenAmount, } from '../helpers'; import { BASE_MINT_BTC_PK, QUOTE_MINT_PK } from '../constants'; @@ -71,7 +72,7 @@ describe('integration.psyoptionsAmerican', () => { }); it('fixed-size american straddle [buy]', async () => { - const { rfq } = await createAmericanFixedBaseStraddle( + const { rfq, optionMarket } = await createAmericanFixedBaseStraddle( takerCvg, 'buy', baseMint, @@ -95,13 +96,19 @@ describe('integration.psyoptionsAmerican', () => { expect(confirmResponse).toHaveProperty('signature'); await setupAmerican(takerCvg, rfqResponse); await setupAmerican(makerCvg, rfqResponse); + const refreshedResponse = await takerCvg.rfqs().findResponseByAddress({ + address: rfqResponse.address, + }); + const res = takerCvg.rfqs().getSettlementResult({ + rfq, + response: refreshedResponse, + }); const takerResponse = await prepareRfqSettlement( takerCvg, rfq, rfqResponse ); expect(takerResponse.response).toHaveProperty('signature'); - const makerResponse = await prepareRfqSettlement( makerCvg, rfq, @@ -114,7 +121,7 @@ describe('integration.psyoptionsAmerican', () => { }); it('fixed-size american straddle [sell]', async () => { - const { rfq } = await createAmericanFixedBaseStraddle( + const { rfq, optionMarket } = await createAmericanFixedBaseStraddle( takerCvg, 'sell', baseMint, @@ -138,13 +145,13 @@ describe('integration.psyoptionsAmerican', () => { expect(confirmResponse).toHaveProperty('signature'); await setupAmerican(takerCvg, rfqResponse); await setupAmerican(makerCvg, rfqResponse); + const takerResponse = await prepareRfqSettlement( takerCvg, rfq, rfqResponse ); expect(takerResponse.response).toHaveProperty('signature'); - const makerResponse = await prepareRfqSettlement( makerCvg, rfq, From 6ad852c3b6e4c1323a5c814a52381fddb5cb487c Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Tue, 29 Aug 2023 18:19:21 +0530 Subject: [PATCH 02/32] add logs to find error --- .../helpers.ts | 4 +--- .../helpers.ts | 2 +- .../integration/psyoptionsAmerican.spec.ts | 20 +++++++++++++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts index 8faaf7da0..566f005c6 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts @@ -39,10 +39,8 @@ export const mintAmericanOptions = async ( for (const [index, leg] of rfq.legs.entries()) { const instructions: TransactionInstruction[] = []; if (leg instanceof PsyoptionsAmericanInstrument) { - const { receiver } = legs[index]; + const { receiver, amount } = legs[index]; if (receiver !== callerSide) { - const { amount } = legs[index]; - const optionMarket = await psyoptionsAmerican.getOptionByKey( americanProgram, leg.optionMetaPubKey diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts index ae73f4f31..f83d5309b 100644 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts @@ -205,7 +205,7 @@ export const mintEuropeanOptions = async ( minterCollateralKey, optionDestination, writerDestination, - new BN(addDecimals(amount, PsyoptionsEuropeanInstrument.decimals)), + addDecimals(amount, PsyoptionsEuropeanInstrument.decimals), leg.optionType ); diff --git a/packages/js/tests/integration/psyoptionsAmerican.spec.ts b/packages/js/tests/integration/psyoptionsAmerican.spec.ts index a4f7b48a5..525ff88e7 100644 --- a/packages/js/tests/integration/psyoptionsAmerican.spec.ts +++ b/packages/js/tests/integration/psyoptionsAmerican.spec.ts @@ -11,6 +11,7 @@ import { createAmericanOpenSizeCallSpdOptionRfq, createAmericanFixedBaseStraddle, fetchTokenAmount, + sleep, } from '../helpers'; import { BASE_MINT_BTC_PK, QUOTE_MINT_PK } from '../constants'; @@ -96,6 +97,7 @@ describe('integration.psyoptionsAmerican', () => { expect(confirmResponse).toHaveProperty('signature'); await setupAmerican(takerCvg, rfqResponse); await setupAmerican(makerCvg, rfqResponse); + const refreshedResponse = await takerCvg.rfqs().findResponseByAddress({ address: rfqResponse.address, }); @@ -103,11 +105,21 @@ describe('integration.psyoptionsAmerican', () => { rfq, response: refreshedResponse, }); + console.log(res); + await sleep(3); + const [takerOpAfter, makerOpAfter] = await Promise.all([ + fetchTokenAmount(takerCvg, optionMarket.optionMint), + fetchTokenAmount(makerCvg, optionMarket.optionMint), + ]); + + console.log('maker', makerOpAfter); + console.log('taker', takerOpAfter); const takerResponse = await prepareRfqSettlement( takerCvg, rfq, rfqResponse ); + expect(takerResponse.response).toHaveProperty('signature'); const makerResponse = await prepareRfqSettlement( makerCvg, @@ -146,6 +158,14 @@ describe('integration.psyoptionsAmerican', () => { await setupAmerican(takerCvg, rfqResponse); await setupAmerican(makerCvg, rfqResponse); + const [takerOpAfter, makerOpAfter] = await Promise.all([ + fetchTokenAmount(takerCvg, optionMarket.optionMint), + fetchTokenAmount(makerCvg, optionMarket.optionMint), + ]); + + console.log('maker', makerOpAfter); + console.log('taker', takerOpAfter); + const takerResponse = await prepareRfqSettlement( takerCvg, rfq, From b4140d4ce422aaae12431abd4b45dd422f298e73 Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Thu, 31 Aug 2023 13:39:57 +0530 Subject: [PATCH 03/32] testing --- .../psyoptionsAmericanInstrumentModule/helpers.ts | 13 ------------- packages/js/tests/helpers.ts | 6 ------ 2 files changed, 19 deletions(-) diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts index 566f005c6..6f7990b16 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts @@ -63,10 +63,6 @@ export const mintAmericanOptions = async ( caller ); if (writerTokenIx) { - // instructionWithSigners.push({ - // instruction: writerTokenIx, - // signers: [], - // }); instructions.push(writerTokenIx); } @@ -77,10 +73,6 @@ export const mintAmericanOptions = async ( caller ); if (underlyingTokenIx) { - // instructionWithSigners.push({ - // instruction: underlyingTokenIx, - // signers: [], - // }); instructions.push(underlyingTokenIx); } @@ -98,10 +90,6 @@ export const mintAmericanOptions = async ( isSigner: true, isWritable: false, }; - // instructionWithSigners.push({ - // instruction: ixWithSigners.ix, - // signers: ixWithSigners.signers, - // }); instructions.push(ixWithSigners.ix); } } @@ -116,7 +104,6 @@ export const mintAmericanOptions = async ( signers: [convergence.identity()], }); }); - // txBuilder.add(...instructionWithSigners); txBuilderArray.push(txBuilder); } } diff --git a/packages/js/tests/helpers.ts b/packages/js/tests/helpers.ts index 2800eed64..20a8d66ca 100644 --- a/packages/js/tests/helpers.ts +++ b/packages/js/tests/helpers.ts @@ -653,12 +653,6 @@ export const createPythPriceFeed = async ( export const setupAmerican = async (cvg: Convergence, response: Response) => { const americanProgram = createAmericanProgram(cvg); - await getOrCreateAmericanOptionATAs( - cvg, - response.address, - cvg.identity().publicKey, - americanProgram - ); await mintAmericanOptions( cvg, response.address, From c1e9a55608ec5f3aba9a83f9683a95a6d5efa39a Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Mon, 4 Sep 2023 10:10:35 +0530 Subject: [PATCH 04/32] add mintOptions logic to prepareSettlement operation --- .../helpers.ts | 150 +++++++++++------- .../classes.ts | 49 ++++++ .../helpers.ts | 89 ++++++----- .../index.ts | 1 + .../rfqModule/operations/prepareSettlement.ts | 37 ++++- .../prepareSettlementAndPrepareMoreLegs.ts | 12 +- packages/js/src/utils/ata.ts | 11 +- packages/js/tests/helpers.ts | 32 ++-- .../integration/psyoptionsAmerican.spec.ts | 46 +----- .../integration/psyoptionsEuropean.spec.ts | 27 ++-- 10 files changed, 267 insertions(+), 187 deletions(-) create mode 100644 packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/classes.ts diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts index 6f7990b16..69d3fd35e 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts @@ -18,9 +18,9 @@ import { createAmericanProgram } from './instrument'; export const mintAmericanOptions = async ( convergence: Convergence, responseAddress: PublicKey, - caller: PublicKey, - americanProgram: any + caller: PublicKey ) => { + const americanProgram = createAmericanProgram(convergence); const response = await convergence .rfqs() .findResponseByAddress({ address: responseAddress }); @@ -35,9 +35,9 @@ export const mintAmericanOptions = async ( rfq, }); - const txBuilderArray: TransactionBuilder[] = []; + // const ataInstructions: TransactionInstruction[] = []; + const mintInstructions: TransactionInstruction[] = []; for (const [index, leg] of rfq.legs.entries()) { - const instructions: TransactionInstruction[] = []; if (leg instanceof PsyoptionsAmericanInstrument) { const { receiver, amount } = legs[index]; if (receiver !== callerSide) { @@ -46,36 +46,30 @@ export const mintAmericanOptions = async ( leg.optionMetaPubKey ); if (optionMarket) { - const { ataPubKey: optionToken, instruction: optionTokenIx } = - await getOrCreateATAInx( - convergence, - optionMarket.optionMint, - caller - ); - if (optionTokenIx) { - instructions.push(optionTokenIx); - } - - const { ataPubKey: writerToken, instruction: writerTokenIx } = - await getOrCreateATAInx( - convergence, - optionMarket!.writerTokenMint, - caller - ); - if (writerTokenIx) { - instructions.push(writerTokenIx); - } - - const { ataPubKey: underlyingToken, instruction: underlyingTokenIx } = - await getOrCreateATAInx( - convergence, - optionMarket!.underlyingAssetMint, - caller - ); - if (underlyingTokenIx) { - instructions.push(underlyingTokenIx); - } - + const optionToken = await getOrCreateATA( + convergence, + optionMarket.optionMint, + caller + ); + // if (optionTokenIx) { + // ataInstructions.push(optionTokenIx); + // } + const writerToken = await getOrCreateATA( + convergence, + optionMarket!.writerTokenMint, + caller + ); + // if (writerTokenIx) { + // ataInstructions.push(writerTokenIx); + // } + const underlyingToken = await getOrCreateATA( + convergence, + optionMarket!.underlyingAssetMint, + caller + ); + // if (underlyingTokenIx) { + // ataInstructions.push(underlyingTokenIx); + // } const ixWithSigners = await psyoptionsAmerican.instructions.mintOptionV2Instruction( americanProgram, @@ -90,37 +84,75 @@ export const mintAmericanOptions = async ( isSigner: true, isWritable: false, }; - instructions.push(ixWithSigners.ix); + mintInstructions.push(ixWithSigners.ix); } } } - if (instructions.length > 0) { - const txBuilder = TransactionBuilder.make().setFeePayer( - convergence.rpc().getDefaultFeePayer() - ); - instructions.forEach((ins) => { - txBuilder.add({ - instruction: ins, - signers: [convergence.identity()], - }); - }); - txBuilderArray.push(txBuilder); - } + // if (mintInstructions.length > 0) { + // const txBuilder = TransactionBuilder.make().setFeePayer( + // convergence.rpc().getDefaultFeePayer() + // ); + // mintInstructions.forEach((ins) => { + // txBuilder.add({ + // instruction: ins, + // signers: [convergence.identity()], + // }); + // }); + // mintTxBuilderArray.push(txBuilder); + // } } - if (txBuilderArray.length > 0) { + // if (mintTxBuilderArray.length > 0) { + // const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); + // const signedTxs = await convergence + // .identity() + // .signAllTransactions( + // mintTxBuilderArray.map((b) => b.toTransaction(lastValidBlockHeight)) + // ); + // signedTxs.forEach((signedTx) => + // convergence + // .rpc() + // .serializeAndSendTransaction(signedTx, lastValidBlockHeight) + // ); + // } + + // if (ataInstructions.length > 0) { + // const txBuilder = TransactionBuilder.make().setFeePayer( + // convergence.rpc().getDefaultFeePayer() + // ); + // ataInstructions.forEach((ins) => { + // txBuilder.add({ + // instruction: ins, + // signers: [convergence.identity()], + // }); + // }); + // const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); + // const signedTx = await convergence + // .identity() + // .signTransaction(txBuilder.toTransaction(lastValidBlockHeight)); + + // await convergence + // .rpc() + // .serializeAndSendTransaction(signedTx, lastValidBlockHeight); + // } + + if (mintInstructions.length > 0) { + const txBuilder = TransactionBuilder.make().setFeePayer( + convergence.rpc().getDefaultFeePayer() + ); + mintInstructions.forEach((ins) => { + txBuilder.add({ + instruction: ins, + signers: [convergence.identity()], + }); + }); const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); - const signedTxs = await convergence + const signedTx = await convergence .identity() - .signAllTransactions( - txBuilderArray.map((b) => b.toTransaction(lastValidBlockHeight)) - ); - await Promise.all( - signedTxs.map((signedTx) => - convergence - .rpc() - .serializeAndSendTransaction(signedTx, lastValidBlockHeight) - ) - ); + .signTransaction(txBuilder.toTransaction(lastValidBlockHeight)); + + await convergence + .rpc() + .serializeAndSendTransaction(signedTx, lastValidBlockHeight); } }; diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/classes.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/classes.ts new file mode 100644 index 000000000..96f7ef5a0 --- /dev/null +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/classes.ts @@ -0,0 +1,49 @@ +import { AccountMeta, TransactionInstruction } from '@solana/web3.js'; + +export class InstructionUniquenessTracker { + constructor(public readonly IxArray: TransactionInstruction[]) { + this.IxArray = IxArray; + } + + private matchKeys = ( + keys: AccountMeta[], + keysToMatch: AccountMeta[] + ): boolean => { + let matching = true; + if (keys.length !== keysToMatch.length) { + return false; + } + for (let i = 0; i < keys.length; i++) { + if ( + keys[i].isSigner !== keysToMatch[i].isSigner || + keys[i].isWritable !== keysToMatch[i].isWritable || + !keys[i].pubkey.equals(keysToMatch[i].pubkey) + ) { + matching = false; + break; + } + } + return matching; + }; + private matchInstruction = (ixToBeAdded: TransactionInstruction): boolean => { + let match = false; + this.IxArray.forEach((ix) => { + if ( + this.matchKeys(ix.keys, ixToBeAdded.keys) && + ix.programId.equals(ixToBeAdded.programId) && + ix.data.equals(ixToBeAdded.data) + ) { + match = true; + return match; + } + }); + return match; + }; + checkedAdd(ix: TransactionInstruction): boolean { + if (!this.matchInstruction(ix)) { + this.IxArray.push(ix); + return true; + } + return false; + } +} diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts index f83d5309b..e4ae57b9e 100644 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts @@ -1,6 +1,6 @@ import * as psyoptionsEuropean from '@mithraic-labs/tokenized-euros'; import * as anchor from '@project-serum/anchor'; -import { Keypair, PublicKey } from '@solana/web3.js'; +import { Keypair, PublicKey, Transaction } from '@solana/web3.js'; import { BN } from 'bn.js'; import { Mint } from '../tokenModule'; import { @@ -12,12 +12,12 @@ import { addDecimals } from '../../utils/conversions'; import { TransactionBuilder } from '../../utils/TransactionBuilder'; import { Convergence } from '../../Convergence'; import { PsyoptionsEuropeanInstrument } from './instrument'; -import { Pda } from '@/types/Pda'; -import { makeConfirmOptionsFinalizedOnMainnet } from '@/types/Operation'; +import { InstructionUniquenessTracker } from './classes'; import { toBigNumber } from '@/types/BigNumber'; export const initializeNewEuropeanOption = async ( convergence: Convergence, + ixTracker: InstructionUniquenessTracker, oracle: PublicKey, europeanProgram: anchor.Program, underlyingMint: Mint, @@ -29,7 +29,7 @@ export const initializeNewEuropeanOption = async ( ) => { const expirationTimestamp = new BN(Date.now() / 1_000 + expiration); - let { instructions: initializeIxs } = + const { instructions: initializeIxs } = await psyoptionsEuropean.instructions.initializeAllAccountsInstructions( europeanProgram, underlyingMint.address, @@ -40,41 +40,45 @@ export const initializeNewEuropeanOption = async ( oracleProviderId ); - const tx = TransactionBuilder.make(); + const tx = new Transaction(); - const underlyingPoolKey = Pda.find(europeanProgram.programId, [ - underlyingMint.address.toBuffer(), - Buffer.from('underlyingPool', 'utf-8'), - ]); - // TODO: Use retry method - const underlyingPoolAccount = await convergence.connection.getAccountInfo( - underlyingPoolKey - ); - if (underlyingPoolAccount && initializeIxs.length === 3) { - initializeIxs = initializeIxs.slice(1); - } - const stablePoolKey = Pda.find(europeanProgram.programId, [ - stableMint.address.toBuffer(), - Buffer.from('stablePool', 'utf-8'), - ]); - // TODO: Use retry method - const stablePoolAccount = await convergence.connection.getAccountInfo( - stablePoolKey - ); - if (stablePoolAccount && initializeIxs.length === 2) { - initializeIxs = initializeIxs.slice(1); - } else if (stablePoolAccount && initializeIxs.length === 3) { - initializeIxs.splice(1, 1); - } + // const underlyingPoolKey = Pda.find(europeanProgram.programId, [ + // underlyingMint.address.toBuffer(), + // Buffer.from('underlyingPool', 'utf-8'), + // ]); + // // TODO: Use retry method + // const underlyingPoolAccount = await convergence.connection.getAccountInfo( + // underlyingPoolKey + // ); + // if (underlyingPoolAccount && initializeIxs.length === 3) { + // initializeIxs = initializeIxs.slice(1); + // } + // const stablePoolKey = Pda.find(europeanProgram.programId, [ + // stableMint.address.toBuffer(), + // Buffer.from('stablePool', 'utf-8'), + // ]); + // // TODO: Use retry method + // const stablePoolAccount = await convergence.connection.getAccountInfo( + // stablePoolKey + // ); + // if (stablePoolAccount && initializeIxs.length === 2) { + // initializeIxs = initializeIxs.slice(1); + // } else if (stablePoolAccount && initializeIxs.length === 3) { + // initializeIxs.splice(1, 1); + // } initializeIxs.forEach((ix) => { - tx.add({ instruction: ix, signers: [] }); + if (ixTracker.checkedAdd(ix)) tx.add(ix); }); - const confirmOptions = makeConfirmOptionsFinalizedOnMainnet(convergence); + // const confirmOptions = makeConfirmOptionsFinalizedOnMainnet(convergence); - if (initializeIxs.length > 0) { - await tx.sendAndConfirm(convergence, confirmOptions); + if (tx.instructions.length > 0) { + const latestBlockHash = await convergence.rpc().getLatestBlockhash(); + tx.recentBlockhash = latestBlockHash.blockhash; + tx.feePayer = convergence.rpc().getDefaultFeePayer().publicKey; + await convergence.identity().signTransaction(tx); + await convergence.rpc().serializeAndSendTransaction(tx, latestBlockHash); } const strikePriceSize = addDecimals(strikePrice, stableMint.decimals); @@ -102,9 +106,16 @@ export const initializeNewEuropeanOption = async ( oracleProviderId ); - await TransactionBuilder.make() - .add({ instruction: createIx, signers: [] }) - .sendAndConfirm(convergence); + if (ixTracker.checkedAdd(createIx)) { + const createTx = new Transaction().add(createIx); + const latestBlockHash = await convergence.rpc().getLatestBlockhash(); + createTx.recentBlockhash = latestBlockHash.blockhash; + createTx.feePayer = convergence.rpc().getDefaultFeePayer().publicKey; + const signedTx = await convergence.identity().signTransaction(createTx); + await convergence + .rpc() + .serializeAndSendTransaction(signedTx, latestBlockHash); + } return { euroMeta, @@ -124,9 +135,9 @@ export const createEuropeanProgram = async (convergence: Convergence) => { export const mintEuropeanOptions = async ( convergence: Convergence, responseAddress: PublicKey, - caller: PublicKey, - europeanProgram: any + caller: PublicKey ) => { + const europeanProgram = await createEuropeanProgram(convergence); const response = await convergence .rfqs() .findResponseByAddress({ address: responseAddress }); @@ -263,7 +274,7 @@ export const getOrCreateEuropeanOptionATAs = async ( const callerIsTaker = caller.toBase58() === rfq.taker.toBase58(); const callerSide = callerIsTaker ? 'taker' : 'maker'; - const { legs } = await convergence.rfqs().getSettlementResult({ + const { legs } = convergence.rfqs().getSettlementResult({ response, rfq, }); diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/index.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/index.ts index 401a3592d..494a78f01 100644 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/index.ts +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/index.ts @@ -3,3 +3,4 @@ export * from './plugin'; export * from './types'; export * from './programs'; export * from './helpers'; +export * from './classes'; diff --git a/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts b/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts index d016c5989..dcb132973 100644 --- a/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts +++ b/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts @@ -24,10 +24,16 @@ import { TransactionBuilder, TransactionBuilderOptions, } from '../../../utils/TransactionBuilder'; -import { getOrCreateATA } from '../../../utils/ata'; +import { Rfq } from '../../rfqModule'; +import { getOrCreateATA, getOrCreateATAInx } from '../../../utils/ata'; import { Mint } from '../../tokenModule'; import { InstrumentPdasClient } from '../../instrumentModule'; import { legToBaseAssetMint } from '@/plugins/instrumentModule'; +import { + mintAmericanOptions, + psyoptionsAmericanInstrumentProgram, +} from '@/plugins/psyoptionsAmericanInstrumentModule'; +import { mintEuropeanOptions } from '@/plugins/psyoptionsEuropeanInstrumentModule'; const Key = 'PrepareSettlementOperation' as const; @@ -112,8 +118,18 @@ export const prepareSettlementOperationHandler: OperationHandler => { + const { + response, + rfq, + caller = convergence.identity(), + } = operation.input; + + const rfqModel = await convergence + .rfqs() + .findRfqByAddress({ address: rfq }); const builder = await prepareSettlementBuilder( convergence, + rfqModel, { ...operation.input, }, @@ -125,6 +141,12 @@ export const prepareSettlementOperationHandler: OperationHandler => { @@ -166,7 +189,7 @@ export const prepareSettlementBuilder = async ( const rfqProgram = convergence.programs().getRfq(programs); - const rfqModel = await convergence.rfqs().findRfqByAddress({ address: rfq }); + // const rfqModel = await convergence.rfqs().findRfqByAddress({ address: rfq }); const responseModel = await convergence .rfqs() .findResponseByAddress({ address: response }); @@ -308,3 +331,13 @@ export const prepareSettlementBuilder = async ( } ); }; + +const findOptionStyle = (rfq: Rfq) => { + const american = rfq.legs.every((leg) => + leg.getProgramId().equals(psyoptionsAmericanInstrumentProgram.address) + ); + if (american) { + return 'american'; + } + return 'european'; +}; diff --git a/packages/js/src/plugins/rfqModule/operations/prepareSettlementAndPrepareMoreLegs.ts b/packages/js/src/plugins/rfqModule/operations/prepareSettlementAndPrepareMoreLegs.ts index e3a3c89fd..0fe7ffe36 100644 --- a/packages/js/src/plugins/rfqModule/operations/prepareSettlementAndPrepareMoreLegs.ts +++ b/packages/js/src/plugins/rfqModule/operations/prepareSettlementAndPrepareMoreLegs.ts @@ -96,13 +96,20 @@ export const prepareSettlementAndPrepareMoreLegsOperationHandler: OperationHandl convergence: Convergence, scope: OperationScope ): Promise => { - const { caller = convergence.identity(), legAmountToPrepare } = - operation.input; + const { + caller = convergence.identity(), + legAmountToPrepare, + rfq, + } = operation.input; const MAX_TX_SIZE = 1232; + const rfqModel = await convergence.rfqs().findRfqByAddress({ + address: rfq, + }); let prepareBuilder = await prepareSettlementBuilder( convergence, + rfqModel, { ...operation.input, }, @@ -124,6 +131,7 @@ export const prepareSettlementAndPrepareMoreLegsOperationHandler: OperationHandl prepareBuilder = await prepareSettlementBuilder( convergence, + rfqModel, { ...operation.input, legAmountToPrepare: halvedLegAmount, diff --git a/packages/js/src/utils/ata.ts b/packages/js/src/utils/ata.ts index 763c773c8..fda367120 100644 --- a/packages/js/src/utils/ata.ts +++ b/packages/js/src/utils/ata.ts @@ -52,17 +52,14 @@ export const getOrCreateATAInx = async ( programs, }); const account = await convergence.rpc().getAccount(pda); - const payer = convergence.rpc().getDefaultFeePayer(); if (!account.exists) { - const ix = Spl.createAssociatedTokenAccountInstruction( - payer.publicKey, + const instruction = Spl.createAssociatedTokenAccountInstruction( + owner, pda, owner, - mint, - Spl.TOKEN_PROGRAM_ID, - Spl.ASSOCIATED_TOKEN_PROGRAM_ID + mint ); - return { ataPubKey: pda, instruction: ix }; + return { ataPubKey: pda, instruction }; } return { ataPubKey: pda }; }; diff --git a/packages/js/tests/helpers.ts b/packages/js/tests/helpers.ts index 20a8d66ca..1422c3dc1 100644 --- a/packages/js/tests/helpers.ts +++ b/packages/js/tests/helpers.ts @@ -10,10 +10,8 @@ import { PsyoptionsAmericanInstrument, initializeNewAmericanOption, toBigNumber, - createAmericanProgram, Rfq, Response, - getOrCreateAmericanOptionATAs, mintAmericanOptions, SpotQuoteInstrument, SpotLegInstrument, @@ -25,8 +23,8 @@ import { CvgWallet, PsyoptionsEuropeanInstrument, initializeNewEuropeanOption, - getOrCreateEuropeanOptionATAs, mintEuropeanOptions, + InstructionUniquenessTracker, } from '../src'; import { getUserKp, RPC_ENDPOINT } from '../../validator'; import { IDL as PseudoPythIdl } from '../../validator/fixtures/programs/pseudo_pyth_idl'; @@ -165,9 +163,10 @@ export const createEuropeanCoveredCallRfq = async ( ); const min = 3_600; const randomExpiry = min + Math.random(); - + const ixTracker = new InstructionUniquenessTracker([]); const { euroMeta, euroMetaKey } = await initializeNewEuropeanOption( cvg, + ixTracker, oracle, europeanProgram, baseMint, @@ -214,11 +213,13 @@ export const createEuropeanOpenSizeCallSpdOptionRfq = async ( 17_000, quoteMint.decimals * -1 ); + const ixTracker = new InstructionUniquenessTracker([]); const min = 3_600; const randomExpiry = min + Math.random(); const { euroMeta: euroMeta1, euroMetaKey: euroMetaKey1 } = await initializeNewEuropeanOption( cvg, + ixTracker, oracle, europeanProgram, baseMint, @@ -231,6 +232,7 @@ export const createEuropeanOpenSizeCallSpdOptionRfq = async ( const { euroMeta: euroMeta2, euroMetaKey: euroMetaKey2 } = await initializeNewEuropeanOption( cvg, + ixTracker, oracle, europeanProgram, baseMint, @@ -334,9 +336,11 @@ export const createEuropeanFixedBaseStraddle = async ( ); const min = 3_600; const randomExpiry = min + Math.random(); + const ixTracker = new InstructionUniquenessTracker([]); const { euroMeta: euroMeta, euroMetaKey: euroMetaKey } = await initializeNewEuropeanOption( cvg, + ixTracker, oracle, europeanProgram, baseMint, @@ -593,7 +597,7 @@ export const prepareRfqSettlement = async ( response: Response ) => { return await cvg.rfqs().prepareSettlement({ - caller: cvg.rpc().getDefaultFeePayer(), + caller: cvg.identity(), rfq: rfq.address, response: response.address, legAmountToPrepare: rfq.legs.length, @@ -652,27 +656,13 @@ export const createPythPriceFeed = async ( }; export const setupAmerican = async (cvg: Convergence, response: Response) => { - const americanProgram = createAmericanProgram(cvg); - await mintAmericanOptions( - cvg, - response.address, - cvg.identity().publicKey, - americanProgram - ); + await mintAmericanOptions(cvg, response.address, cvg.identity().publicKey); }; export const setupEuropean = async (cvg: Convergence, response: Response) => { - const europeanProgram = await createEuropeanProgram(cvg); - - await getOrCreateEuropeanOptionATAs( - cvg, - response.address, - cvg.rpc().getDefaultFeePayer().publicKey - ); await mintEuropeanOptions( cvg, response.address, - cvg.rpc().getDefaultFeePayer().publicKey, - europeanProgram + cvg.rpc().getDefaultFeePayer().publicKey ); }; diff --git a/packages/js/tests/integration/psyoptionsAmerican.spec.ts b/packages/js/tests/integration/psyoptionsAmerican.spec.ts index 525ff88e7..49ce2e5e1 100644 --- a/packages/js/tests/integration/psyoptionsAmerican.spec.ts +++ b/packages/js/tests/integration/psyoptionsAmerican.spec.ts @@ -7,11 +7,8 @@ import { prepareRfqSettlement, settleRfq, createUserCvg, - setupAmerican, createAmericanOpenSizeCallSpdOptionRfq, createAmericanFixedBaseStraddle, - fetchTokenAmount, - sleep, } from '../helpers'; import { BASE_MINT_BTC_PK, QUOTE_MINT_PK } from '../constants'; @@ -50,8 +47,6 @@ describe('integration.psyoptionsAmerican', () => { side: 'bid', }); expect(confirmResponse).toHaveProperty('signature'); - await setupAmerican(takerCvg, rfqResponse); - const takerResponse = await prepareRfqSettlement( takerCvg, rfq, @@ -73,12 +68,13 @@ describe('integration.psyoptionsAmerican', () => { }); it('fixed-size american straddle [buy]', async () => { - const { rfq, optionMarket } = await createAmericanFixedBaseStraddle( + const { rfq } = await createAmericanFixedBaseStraddle( takerCvg, 'buy', baseMint, quoteMint ); + expect(rfq).toHaveProperty('address'); const { rfqResponse } = await respondToRfq( makerCvg, @@ -95,25 +91,6 @@ describe('integration.psyoptionsAmerican', () => { side: 'ask', }); expect(confirmResponse).toHaveProperty('signature'); - await setupAmerican(takerCvg, rfqResponse); - await setupAmerican(makerCvg, rfqResponse); - - const refreshedResponse = await takerCvg.rfqs().findResponseByAddress({ - address: rfqResponse.address, - }); - const res = takerCvg.rfqs().getSettlementResult({ - rfq, - response: refreshedResponse, - }); - console.log(res); - await sleep(3); - const [takerOpAfter, makerOpAfter] = await Promise.all([ - fetchTokenAmount(takerCvg, optionMarket.optionMint), - fetchTokenAmount(makerCvg, optionMarket.optionMint), - ]); - - console.log('maker', makerOpAfter); - console.log('taker', takerOpAfter); const takerResponse = await prepareRfqSettlement( takerCvg, rfq, @@ -133,7 +110,7 @@ describe('integration.psyoptionsAmerican', () => { }); it('fixed-size american straddle [sell]', async () => { - const { rfq, optionMarket } = await createAmericanFixedBaseStraddle( + const { rfq } = await createAmericanFixedBaseStraddle( takerCvg, 'sell', baseMint, @@ -155,17 +132,6 @@ describe('integration.psyoptionsAmerican', () => { side: 'bid', }); expect(confirmResponse).toHaveProperty('signature'); - await setupAmerican(takerCvg, rfqResponse); - await setupAmerican(makerCvg, rfqResponse); - - const [takerOpAfter, makerOpAfter] = await Promise.all([ - fetchTokenAmount(takerCvg, optionMarket.optionMint), - fetchTokenAmount(makerCvg, optionMarket.optionMint), - ]); - - console.log('maker', makerOpAfter); - console.log('taker', takerOpAfter); - const takerResponse = await prepareRfqSettlement( takerCvg, rfq, @@ -201,8 +167,6 @@ describe('integration.psyoptionsAmerican', () => { side: 'ask', }); expect(confirmResponse).toHaveProperty('signature'); - await setupAmerican(takerCvg, rfqResponse); - await setupAmerican(makerCvg, rfqResponse); const takerResponse = await prepareRfqSettlement( takerCvg, rfq, @@ -247,8 +211,6 @@ describe('integration.psyoptionsAmerican', () => { overrideLegMultiplier: 4, }); expect(confirmResponse).toHaveProperty('signature'); - await setupAmerican(takerCvg, rfqResponse); - await setupAmerican(makerCvg, rfqResponse); const takerResponse = await prepareRfqSettlement( takerCvg, rfq, @@ -293,8 +255,6 @@ describe('integration.psyoptionsAmerican', () => { overrideLegMultiplier: 4, }); expect(confirmResponse).toHaveProperty('signature'); - await setupAmerican(takerCvg, rfqResponse); - await setupAmerican(makerCvg, rfqResponse); const takerResponse = await prepareRfqSettlement( takerCvg, rfq, diff --git a/packages/js/tests/integration/psyoptionsEuropean.spec.ts b/packages/js/tests/integration/psyoptionsEuropean.spec.ts index 54ee6ea70..be67b374d 100644 --- a/packages/js/tests/integration/psyoptionsEuropean.spec.ts +++ b/packages/js/tests/integration/psyoptionsEuropean.spec.ts @@ -8,7 +8,6 @@ import { createUserCvg, createEuropeanCoveredCallRfq, createEuropeanOpenSizeCallSpdOptionRfq, - setupEuropean, createEuropeanFixedBaseStraddle, } from '../helpers'; import { BASE_MINT_BTC_PK, QUOTE_MINT_PK } from '../constants'; @@ -46,7 +45,7 @@ describe('integration.psyoptionsEuropean', () => { side: 'bid', }); - await setupEuropean(takerCvg, rfqResponse); + // await setupEuropean(takerCvg, rfqResponse); await prepareRfqSettlement(makerCvg, rfq, rfqResponse); await prepareRfqSettlement(takerCvg, rfq, rfqResponse); @@ -76,8 +75,8 @@ describe('integration.psyoptionsEuropean', () => { side: 'ask', }); expect(confirmResponse).toHaveProperty('signature'); - await setupEuropean(takerCvg, rfqResponse); - await setupEuropean(makerCvg, rfqResponse); + // await setupEuropean(takerCvg, rfqResponse); + // await setupEuropean(makerCvg, rfqResponse); const takerResponse = await prepareRfqSettlement( takerCvg, rfq, @@ -119,8 +118,8 @@ describe('integration.psyoptionsEuropean', () => { side: 'bid', }); expect(confirmResponse).toHaveProperty('signature'); - await setupEuropean(takerCvg, rfqResponse); - await setupEuropean(makerCvg, rfqResponse); + // await setupEuropean(takerCvg, rfqResponse); + // await setupEuropean(makerCvg, rfqResponse); const takerResponse = await prepareRfqSettlement( takerCvg, rfq, @@ -157,8 +156,8 @@ describe('integration.psyoptionsEuropean', () => { side: 'ask', }); expect(confirmResponse).toHaveProperty('signature'); - await setupEuropean(takerCvg, rfqResponse); - await setupEuropean(makerCvg, rfqResponse); + // await setupEuropean(takerCvg, rfqResponse); + // await setupEuropean(makerCvg, rfqResponse); const takerResponse = await prepareRfqSettlement( takerCvg, rfq, @@ -203,8 +202,8 @@ describe('integration.psyoptionsEuropean', () => { overrideLegMultiplier: 4, }); expect(confirmResponse).toHaveProperty('signature'); - await setupEuropean(takerCvg, rfqResponse); - await setupEuropean(makerCvg, rfqResponse); + // await setupEuropean(takerCvg, rfqResponse); + // await setupEuropean(makerCvg, rfqResponse); const takerResponse = await prepareRfqSettlement( takerCvg, rfq, @@ -249,8 +248,8 @@ describe('integration.psyoptionsEuropean', () => { overrideLegMultiplier: 4, }); expect(confirmResponse).toHaveProperty('signature'); - await setupEuropean(takerCvg, rfqResponse); - await setupEuropean(makerCvg, rfqResponse); + // await setupEuropean(takerCvg, rfqResponse); + // await setupEuropean(makerCvg, rfqResponse); const takerResponse = await prepareRfqSettlement( takerCvg, rfq, @@ -295,8 +294,8 @@ describe('integration.psyoptionsEuropean', () => { overrideLegMultiplier: 4, }); expect(confirmResponse).toHaveProperty('signature'); - await setupEuropean(takerCvg, rfqResponse); - await setupEuropean(makerCvg, rfqResponse); + // await setupEuropean(takerCvg, rfqResponse); + // await setupEuropean(makerCvg, rfqResponse); const takerResponse = await prepareRfqSettlement( takerCvg, From abebda03262f2653d74e998a906a4725f8efb5f7 Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Mon, 4 Sep 2023 14:39:06 +0530 Subject: [PATCH 05/32] american mintOptions not working --- .../helpers.ts | 71 ++++++++++--------- .../rfqModule/operations/prepareSettlement.ts | 13 ++-- packages/js/tests/helpers.ts | 13 ++-- .../integration/psyoptionsEuropean.spec.ts | 34 +++++---- .../js/tests/unit/settlementResult.spec.ts | 6 +- 5 files changed, 70 insertions(+), 67 deletions(-) diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts index 69d3fd35e..d1689dc1d 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts @@ -34,8 +34,9 @@ export const mintAmericanOptions = async ( response, rfq, }); - - // const ataInstructions: TransactionInstruction[] = []; + console.log('caller', caller.toBase58()); + console.log('identity', convergence.identity().publicKey.toBase58()); + const ataInstructions: TransactionInstruction[] = []; const mintInstructions: TransactionInstruction[] = []; for (const [index, leg] of rfq.legs.entries()) { if (leg instanceof PsyoptionsAmericanInstrument) { @@ -46,36 +47,36 @@ export const mintAmericanOptions = async ( leg.optionMetaPubKey ); if (optionMarket) { - const optionToken = await getOrCreateATA( + const optionToken = await getOrCreateATAInx( convergence, optionMarket.optionMint, caller ); - // if (optionTokenIx) { - // ataInstructions.push(optionTokenIx); - // } - const writerToken = await getOrCreateATA( + if (optionToken.instruction) { + ataInstructions.push(optionToken.instruction); + } + const writerToken = await getOrCreateATAInx( convergence, optionMarket!.writerTokenMint, caller ); - // if (writerTokenIx) { - // ataInstructions.push(writerTokenIx); - // } - const underlyingToken = await getOrCreateATA( + if (writerToken.instruction) { + ataInstructions.push(writerToken.instruction); + } + const underlyingToken = await getOrCreateATAInx( convergence, optionMarket!.underlyingAssetMint, caller ); - // if (underlyingTokenIx) { - // ataInstructions.push(underlyingTokenIx); - // } + if (underlyingToken.instruction) { + ataInstructions.push(underlyingToken.instruction); + } const ixWithSigners = await psyoptionsAmerican.instructions.mintOptionV2Instruction( americanProgram, - optionToken, - writerToken, - underlyingToken, + optionToken.ataPubKey, + writerToken.ataPubKey, + underlyingToken.ataPubKey, new BN(amount!), optionMarket as psyoptionsAmerican.OptionMarketWithKey ); @@ -115,25 +116,25 @@ export const mintAmericanOptions = async ( // ); // } - // if (ataInstructions.length > 0) { - // const txBuilder = TransactionBuilder.make().setFeePayer( - // convergence.rpc().getDefaultFeePayer() - // ); - // ataInstructions.forEach((ins) => { - // txBuilder.add({ - // instruction: ins, - // signers: [convergence.identity()], - // }); - // }); - // const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); - // const signedTx = await convergence - // .identity() - // .signTransaction(txBuilder.toTransaction(lastValidBlockHeight)); + if (ataInstructions.length > 0) { + const txBuilder = TransactionBuilder.make().setFeePayer( + convergence.rpc().getDefaultFeePayer() + ); + ataInstructions.forEach((ins) => { + txBuilder.add({ + instruction: ins, + signers: [convergence.identity()], + }); + }); + const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); + const signedTx = await convergence + .identity() + .signTransaction(txBuilder.toTransaction(lastValidBlockHeight)); - // await convergence - // .rpc() - // .serializeAndSendTransaction(signedTx, lastValidBlockHeight); - // } + await convergence + .rpc() + .serializeAndSendTransaction(signedTx, lastValidBlockHeight); + } if (mintInstructions.length > 0) { const txBuilder = TransactionBuilder.make().setFeePayer( diff --git a/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts b/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts index dcb132973..c2128bd30 100644 --- a/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts +++ b/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts @@ -127,6 +127,13 @@ export const prepareSettlementOperationHandler: OperationHandler { const europeanProgram = await createEuropeanProgram(cvg); const oracle = await createPythPriceFeed( @@ -163,7 +164,6 @@ export const createEuropeanCoveredCallRfq = async ( ); const min = 3_600; const randomExpiry = min + Math.random(); - const ixTracker = new InstructionUniquenessTracker([]); const { euroMeta, euroMetaKey } = await initializeNewEuropeanOption( cvg, ixTracker, @@ -201,7 +201,8 @@ export const createEuropeanOpenSizeCallSpdOptionRfq = async ( cvg: Convergence, orderType: OrderType, baseMint: any, - quoteMint: any + quoteMint: any, + ixTracker: InstructionUniquenessTracker ) => { const europeanProgram = await createEuropeanProgram(cvg); const oracle = await createPythPriceFeed( @@ -213,7 +214,6 @@ export const createEuropeanOpenSizeCallSpdOptionRfq = async ( 17_000, quoteMint.decimals * -1 ); - const ixTracker = new InstructionUniquenessTracker([]); const min = 3_600; const randomExpiry = min + Math.random(); const { euroMeta: euroMeta1, euroMetaKey: euroMetaKey1 } = @@ -322,7 +322,8 @@ export const createEuropeanFixedBaseStraddle = async ( cvg: Convergence, orderType: OrderType, baseMint: any, - quoteMint: any + quoteMint: any, + ixTracker: InstructionUniquenessTracker ) => { const europeanProgram = await createEuropeanProgram(cvg); const oracle = await createPythPriceFeed( @@ -336,7 +337,7 @@ export const createEuropeanFixedBaseStraddle = async ( ); const min = 3_600; const randomExpiry = min + Math.random(); - const ixTracker = new InstructionUniquenessTracker([]); + const { euroMeta: euroMeta, euroMetaKey: euroMetaKey } = await initializeNewEuropeanOption( cvg, diff --git a/packages/js/tests/integration/psyoptionsEuropean.spec.ts b/packages/js/tests/integration/psyoptionsEuropean.spec.ts index be67b374d..94b760656 100644 --- a/packages/js/tests/integration/psyoptionsEuropean.spec.ts +++ b/packages/js/tests/integration/psyoptionsEuropean.spec.ts @@ -11,13 +11,14 @@ import { createEuropeanFixedBaseStraddle, } from '../helpers'; import { BASE_MINT_BTC_PK, QUOTE_MINT_PK } from '../constants'; +import { InstructionUniquenessTracker } from '../../src'; describe('integration.psyoptionsEuropean', () => { const takerCvg = createUserCvg('taker'); const makerCvg = createUserCvg('maker'); let baseMint: Mint; let quoteMint: Mint; - + const ixTracker = new InstructionUniquenessTracker([]); before(async () => { baseMint = await takerCvg .tokens() @@ -32,7 +33,8 @@ describe('integration.psyoptionsEuropean', () => { takerCvg, 'sell', baseMint, - quoteMint + quoteMint, + ixTracker ); expect(rfq).toHaveProperty('address'); @@ -57,7 +59,8 @@ describe('integration.psyoptionsEuropean', () => { takerCvg, 'buy', baseMint, - quoteMint + quoteMint, + ixTracker ); expect(rfq).toHaveProperty('address'); const { rfqResponse } = await respondToRfq( @@ -100,7 +103,8 @@ describe('integration.psyoptionsEuropean', () => { takerCvg, 'sell', baseMint, - quoteMint + quoteMint, + ixTracker ); expect(rfq).toHaveProperty('address'); const { rfqResponse } = await respondToRfq( @@ -118,8 +122,6 @@ describe('integration.psyoptionsEuropean', () => { side: 'bid', }); expect(confirmResponse).toHaveProperty('signature'); - // await setupEuropean(takerCvg, rfqResponse); - // await setupEuropean(makerCvg, rfqResponse); const takerResponse = await prepareRfqSettlement( takerCvg, rfq, @@ -143,7 +145,8 @@ describe('integration.psyoptionsEuropean', () => { takerCvg, 'two-way', baseMint, - quoteMint + quoteMint, + ixTracker ); expect(rfq).toHaveProperty('address'); const { rfqResponse } = await respondToRfq(makerCvg, rfq, 61_222, 60_123); @@ -156,8 +159,6 @@ describe('integration.psyoptionsEuropean', () => { side: 'ask', }); expect(confirmResponse).toHaveProperty('signature'); - // await setupEuropean(takerCvg, rfqResponse); - // await setupEuropean(makerCvg, rfqResponse); const takerResponse = await prepareRfqSettlement( takerCvg, rfq, @@ -181,7 +182,8 @@ describe('integration.psyoptionsEuropean', () => { takerCvg, 'buy', baseMint, - quoteMint + quoteMint, + ixTracker ); expect(rfq).toHaveProperty('address'); const { rfqResponse } = await respondToRfq( @@ -202,8 +204,6 @@ describe('integration.psyoptionsEuropean', () => { overrideLegMultiplier: 4, }); expect(confirmResponse).toHaveProperty('signature'); - // await setupEuropean(takerCvg, rfqResponse); - // await setupEuropean(makerCvg, rfqResponse); const takerResponse = await prepareRfqSettlement( takerCvg, rfq, @@ -227,7 +227,8 @@ describe('integration.psyoptionsEuropean', () => { takerCvg, 'two-way', baseMint, - quoteMint + quoteMint, + ixTracker ); expect(rfq).toHaveProperty('address'); const { rfqResponse } = await respondToRfq( @@ -248,8 +249,6 @@ describe('integration.psyoptionsEuropean', () => { overrideLegMultiplier: 4, }); expect(confirmResponse).toHaveProperty('signature'); - // await setupEuropean(takerCvg, rfqResponse); - // await setupEuropean(makerCvg, rfqResponse); const takerResponse = await prepareRfqSettlement( takerCvg, rfq, @@ -273,7 +272,8 @@ describe('integration.psyoptionsEuropean', () => { takerCvg, 'sell', baseMint, - quoteMint + quoteMint, + ixTracker ); expect(rfq).toHaveProperty('address'); const { rfqResponse } = await respondToRfq( @@ -294,8 +294,6 @@ describe('integration.psyoptionsEuropean', () => { overrideLegMultiplier: 4, }); expect(confirmResponse).toHaveProperty('signature'); - // await setupEuropean(takerCvg, rfqResponse); - // await setupEuropean(makerCvg, rfqResponse); const takerResponse = await prepareRfqSettlement( takerCvg, diff --git a/packages/js/tests/unit/settlementResult.spec.ts b/packages/js/tests/unit/settlementResult.spec.ts index d784c36bc..e9e7ba902 100644 --- a/packages/js/tests/unit/settlementResult.spec.ts +++ b/packages/js/tests/unit/settlementResult.spec.ts @@ -12,13 +12,14 @@ import { QUOTE_MINT_DECIMALS, QUOTE_MINT_PK, } from '../constants'; +import { InstructionUniquenessTracker } from '../../src'; describe('unit.settlementResult', () => { const takerCvg = createUserCvg('taker'); const makerCvg = createUserCvg('maker'); let baseMint: Mint; let quoteMint: Mint; - + const ixTracker = new InstructionUniquenessTracker([]); before(async () => { baseMint = await takerCvg .tokens() @@ -371,7 +372,8 @@ describe('unit.settlementResult', () => { takerCvg, 'sell', baseMint, - quoteMint + quoteMint, + ixTracker ); expect(rfq).toHaveProperty('address'); expect(response.signature).toBeDefined(); From 76fe7a845201f82d1ceb1a3d4693e631113d1bba Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Tue, 5 Sep 2023 10:44:27 +0530 Subject: [PATCH 06/32] testing --- .../helpers.ts | 105 ++++++------------ .../helpers.ts | 14 ++- .../rfqModule/operations/prepareSettlement.ts | 2 +- packages/js/tests/helpers.ts | 12 +- .../integration/psyoptionsAmerican.spec.ts | 29 ++++- 5 files changed, 74 insertions(+), 88 deletions(-) diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts index d1689dc1d..9deadf72e 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts @@ -20,7 +20,8 @@ export const mintAmericanOptions = async ( responseAddress: PublicKey, caller: PublicKey ) => { - const americanProgram = createAmericanProgram(convergence); + const cvgWallet = new CvgWallet(convergence); + const americanProgram = createAmericanProgram(convergence, cvgWallet); const response = await convergence .rfqs() .findResponseByAddress({ address: responseAddress }); @@ -34,18 +35,13 @@ export const mintAmericanOptions = async ( response, rfq, }); - console.log('caller', caller.toBase58()); - console.log('identity', convergence.identity().publicKey.toBase58()); - const ataInstructions: TransactionInstruction[] = []; - const mintInstructions: TransactionInstruction[] = []; + const txBuilderArray: TransactionBuilder[] = []; for (const [index, leg] of rfq.legs.entries()) { + const instructions: TransactionInstruction[] = []; if (leg instanceof PsyoptionsAmericanInstrument) { const { receiver, amount } = legs[index]; if (receiver !== callerSide) { - const optionMarket = await psyoptionsAmerican.getOptionByKey( - americanProgram, - leg.optionMetaPubKey - ); + const optionMarket = await leg.getOptionMeta(); if (optionMarket) { const optionToken = await getOrCreateATAInx( convergence, @@ -53,7 +49,7 @@ export const mintAmericanOptions = async ( caller ); if (optionToken.instruction) { - ataInstructions.push(optionToken.instruction); + instructions.push(optionToken.instruction); } const writerToken = await getOrCreateATAInx( convergence, @@ -61,7 +57,7 @@ export const mintAmericanOptions = async ( caller ); if (writerToken.instruction) { - ataInstructions.push(writerToken.instruction); + instructions.push(writerToken.instruction); } const underlyingToken = await getOrCreateATAInx( convergence, @@ -69,7 +65,7 @@ export const mintAmericanOptions = async ( caller ); if (underlyingToken.instruction) { - ataInstructions.push(underlyingToken.instruction); + instructions.push(underlyingToken.instruction); } const ixWithSigners = await psyoptionsAmerican.instructions.mintOptionV2Instruction( @@ -85,75 +81,36 @@ export const mintAmericanOptions = async ( isSigner: true, isWritable: false, }; - mintInstructions.push(ixWithSigners.ix); + instructions.push(ixWithSigners.ix); } } } - // if (mintInstructions.length > 0) { - // const txBuilder = TransactionBuilder.make().setFeePayer( - // convergence.rpc().getDefaultFeePayer() - // ); - // mintInstructions.forEach((ins) => { - // txBuilder.add({ - // instruction: ins, - // signers: [convergence.identity()], - // }); - // }); - // mintTxBuilderArray.push(txBuilder); - // } - } - // if (mintTxBuilderArray.length > 0) { - // const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); - // const signedTxs = await convergence - // .identity() - // .signAllTransactions( - // mintTxBuilderArray.map((b) => b.toTransaction(lastValidBlockHeight)) - // ); - // signedTxs.forEach((signedTx) => - // convergence - // .rpc() - // .serializeAndSendTransaction(signedTx, lastValidBlockHeight) - // ); - // } - - if (ataInstructions.length > 0) { - const txBuilder = TransactionBuilder.make().setFeePayer( - convergence.rpc().getDefaultFeePayer() - ); - ataInstructions.forEach((ins) => { - txBuilder.add({ - instruction: ins, - signers: [convergence.identity()], + if (instructions.length > 0) { + const txBuilder = TransactionBuilder.make().setFeePayer( + convergence.rpc().getDefaultFeePayer() + ); + instructions.forEach((ins) => { + txBuilder.add({ + instruction: ins, + signers: [convergence.identity()], + }); }); - }); - const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); - const signedTx = await convergence - .identity() - .signTransaction(txBuilder.toTransaction(lastValidBlockHeight)); - - await convergence - .rpc() - .serializeAndSendTransaction(signedTx, lastValidBlockHeight); + txBuilderArray.push(txBuilder); + } } - - if (mintInstructions.length > 0) { - const txBuilder = TransactionBuilder.make().setFeePayer( - convergence.rpc().getDefaultFeePayer() - ); - mintInstructions.forEach((ins) => { - txBuilder.add({ - instruction: ins, - signers: [convergence.identity()], - }); - }); + if (txBuilderArray.length > 0) { const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); - const signedTx = await convergence + const signedTxs = await convergence .identity() - .signTransaction(txBuilder.toTransaction(lastValidBlockHeight)); - - await convergence - .rpc() - .serializeAndSendTransaction(signedTx, lastValidBlockHeight); + .signAllTransactions( + txBuilderArray.map((b) => b.toTransaction(lastValidBlockHeight)) + ); + signedTxs.map( + async (signedTx) => + await convergence + .rpc() + .serializeAndSendTransaction(signedTx, lastValidBlockHeight) + ); } }; diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts index e4ae57b9e..1adcb3022 100644 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts @@ -1,6 +1,11 @@ import * as psyoptionsEuropean from '@mithraic-labs/tokenized-euros'; import * as anchor from '@project-serum/anchor'; -import { Keypair, PublicKey, Transaction } from '@solana/web3.js'; +import { + Keypair, + PublicKey, + Transaction, + TransactionInstruction, +} from '@solana/web3.js'; import { BN } from 'bn.js'; import { Mint } from '../tokenModule'; import { @@ -153,13 +158,10 @@ export const mintEuropeanOptions = async ( }); const txBuilderArray: TransactionBuilder[] = []; for (const [index, leg] of rfq.legs.entries()) { - const instructions: anchor.web3.TransactionInstruction[] = []; + const instructions: TransactionInstruction[] = []; if (leg instanceof PsyoptionsEuropeanInstrument) { - const { receiver } = legs[index]; - + const { receiver, amount } = legs[index]; if (receiver !== callerSide) { - const { amount } = legs[index]; - const euroMeta = await leg.getOptionMeta(); const { stableMint } = euroMeta; const { underlyingMint } = euroMeta; diff --git a/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts b/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts index c2128bd30..7877e51c4 100644 --- a/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts +++ b/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts @@ -25,7 +25,7 @@ import { TransactionBuilderOptions, } from '../../../utils/TransactionBuilder'; import { Rfq } from '../../rfqModule'; -import { getOrCreateATA, getOrCreateATAInx } from '../../../utils/ata'; +import { getOrCreateATA } from '../../../utils/ata'; import { Mint } from '../../tokenModule'; import { InstrumentPdasClient } from '../../instrumentModule'; import { legToBaseAssetMint } from '@/plugins/instrumentModule'; diff --git a/packages/js/tests/helpers.ts b/packages/js/tests/helpers.ts index 42790b8fe..0d93d9946 100644 --- a/packages/js/tests/helpers.ts +++ b/packages/js/tests/helpers.ts @@ -118,14 +118,14 @@ export const createAmericanCoveredCallRfq = async ( cvg, baseMint, quoteMint, - 27_000, + 44_000, 1, - 3_600 + Math.random() + 3_600 + Math.random() * 10 ); const { rfq, response } = await cvg.rfqs().createAndFinalize({ instruments: [ - await SpotLegInstrument.create(cvg, baseMint, 1.0, 'long'), + await SpotLegInstrument.create(cvg, baseMint, 0.00118, 'short'), await PsyoptionsAmericanInstrument.create( cvg, baseMint, @@ -163,7 +163,7 @@ export const createEuropeanCoveredCallRfq = async ( quoteMint.decimals * -1 ); const min = 3_600; - const randomExpiry = min + Math.random(); + const randomExpiry = min + Math.random() * 10; const { euroMeta, euroMetaKey } = await initializeNewEuropeanOption( cvg, ixTracker, @@ -307,7 +307,7 @@ export const createAmericanFixedBaseStraddle = async ( optionMarket, optionMarketKey, 1, - 'long' + 'short' ), ], orderType, @@ -598,7 +598,7 @@ export const prepareRfqSettlement = async ( response: Response ) => { return await cvg.rfqs().prepareSettlement({ - caller: cvg.identity(), + caller: cvg.rpc().getDefaultFeePayer(), rfq: rfq.address, response: response.address, legAmountToPrepare: rfq.legs.length, diff --git a/packages/js/tests/integration/psyoptionsAmerican.spec.ts b/packages/js/tests/integration/psyoptionsAmerican.spec.ts index 49ce2e5e1..565bdf94b 100644 --- a/packages/js/tests/integration/psyoptionsAmerican.spec.ts +++ b/packages/js/tests/integration/psyoptionsAmerican.spec.ts @@ -11,6 +11,7 @@ import { createAmericanFixedBaseStraddle, } from '../helpers'; import { BASE_MINT_BTC_PK, QUOTE_MINT_PK } from '../constants'; +import { getOrCreateATAInx } from '../../src'; describe('integration.psyoptionsAmerican', () => { const takerCvg = createUserCvg('taker'); @@ -27,7 +28,7 @@ describe('integration.psyoptionsAmerican', () => { .findMintByAddress({ address: QUOTE_MINT_PK }); }); - it('covered call [sell]', async () => { + it('american covered call [sell]', async () => { const { rfq } = await createAmericanCoveredCallRfq( takerCvg, 'sell', @@ -46,7 +47,32 @@ describe('integration.psyoptionsAmerican', () => { response: rfqResponse.address, side: 'bid', }); + + const refreshedRfq = await takerCvg.rfqs().findRfqByAddress({ + address: rfq.address, + }); + + const refreshedResponse = await takerCvg.rfqs().findResponseByAddress({ + address: rfqResponse.address, + }); + + const bal = await getOrCreateATAInx( + takerCvg, + baseMint.address, + takerCvg.identity().publicKey + ); + const acc = await takerCvg.tokens().findTokenByAddress({ + address: bal.ataPubKey, + }); + console.log('acc', Number(acc.amount.basisPoints) / Math.pow(10, 9)); + + const result = takerCvg.rfqs().getSettlementResult({ + rfq: refreshedRfq, + response: refreshedResponse, + }); + console.log('res', result); expect(confirmResponse).toHaveProperty('signature'); + const takerResponse = await prepareRfqSettlement( takerCvg, rfq, @@ -132,6 +158,7 @@ describe('integration.psyoptionsAmerican', () => { side: 'bid', }); expect(confirmResponse).toHaveProperty('signature'); + const takerResponse = await prepareRfqSettlement( takerCvg, rfq, From f54300f5750154112a6f00cf0812e90e4a4ca04c Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Tue, 5 Sep 2023 10:53:23 +0530 Subject: [PATCH 07/32] fix build errors --- .../src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts index 9deadf72e..1d9e97c54 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts @@ -92,7 +92,7 @@ export const mintAmericanOptions = async ( instructions.forEach((ins) => { txBuilder.add({ instruction: ins, - signers: [convergence.identity()], + signers: [convergence.rpc().getDefaultFeePayer()], }); }); txBuilderArray.push(txBuilder); From 4c0c659ea826bcbf04b636b6eb09bf34b8d3fccf Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Tue, 5 Sep 2023 11:03:20 +0530 Subject: [PATCH 08/32] fix more build errors --- .../psyoptionsAmericanInstrumentModule/helpers.ts | 9 ++------- packages/js/tests/helpers.ts | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts index 1d9e97c54..2c3c8dace 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts @@ -10,7 +10,6 @@ import { getOrCreateATAInx, } from '../../utils/ata'; import { Mint } from '../tokenModule/models'; -import { CvgWallet } from '../../utils/Wallets'; import { TransactionBuilder } from '../../utils/TransactionBuilder'; import { PsyoptionsAmericanInstrument } from './types'; import { createAmericanProgram } from './instrument'; @@ -20,8 +19,7 @@ export const mintAmericanOptions = async ( responseAddress: PublicKey, caller: PublicKey ) => { - const cvgWallet = new CvgWallet(convergence); - const americanProgram = createAmericanProgram(convergence, cvgWallet); + const americanProgram = createAmericanProgram(convergence); const response = await convergence .rfqs() .findResponseByAddress({ address: responseAddress }); @@ -131,10 +129,7 @@ export const initializeNewAmericanOption = async ( Number(underlyingAmountPerContract) * Math.pow(10, underlyingMint.decimals) ); - const americanProgram = createAmericanProgram( - convergence, - new CvgWallet(convergence) - ); + const americanProgram = createAmericanProgram(convergence); const { optionMarketKey, optionMintKey, writerMintKey } = await psyoptionsAmerican.instructions.initializeMarket(americanProgram, { diff --git a/packages/js/tests/helpers.ts b/packages/js/tests/helpers.ts index 0d93d9946..17f9d964f 100644 --- a/packages/js/tests/helpers.ts +++ b/packages/js/tests/helpers.ts @@ -598,7 +598,7 @@ export const prepareRfqSettlement = async ( response: Response ) => { return await cvg.rfqs().prepareSettlement({ - caller: cvg.rpc().getDefaultFeePayer(), + caller: cvg.identity(), rfq: rfq.address, response: response.address, legAmountToPrepare: rfq.legs.length, From 9c3c6bca4223385490722f9b0291bd333bb28b8e Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Tue, 5 Sep 2023 11:21:00 +0530 Subject: [PATCH 09/32] add cvgWallet --- .../plugins/psyoptionsAmericanInstrumentModule/helpers.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts index 2c3c8dace..fd3998772 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts @@ -13,13 +13,15 @@ import { Mint } from '../tokenModule/models'; import { TransactionBuilder } from '../../utils/TransactionBuilder'; import { PsyoptionsAmericanInstrument } from './types'; import { createAmericanProgram } from './instrument'; +import { CvgWallet } from '@/index'; export const mintAmericanOptions = async ( convergence: Convergence, responseAddress: PublicKey, caller: PublicKey ) => { - const americanProgram = createAmericanProgram(convergence); + const cvgWallet = new CvgWallet(convergence); + const americanProgram = createAmericanProgram(convergence, cvgWallet); const response = await convergence .rfqs() .findResponseByAddress({ address: responseAddress }); @@ -129,7 +131,8 @@ export const initializeNewAmericanOption = async ( Number(underlyingAmountPerContract) * Math.pow(10, underlyingMint.decimals) ); - const americanProgram = createAmericanProgram(convergence); + const cvgWallet = new CvgWallet(convergence); + const americanProgram = createAmericanProgram(convergence, cvgWallet); const { optionMarketKey, optionMintKey, writerMintKey } = await psyoptionsAmerican.instructions.initializeMarket(americanProgram, { From 5f8f6f35b38022571ad99782a853901e29cd7bfa Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Tue, 5 Sep 2023 11:28:12 +0530 Subject: [PATCH 10/32] fix circular deps --- .../src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts index fd3998772..ba580e07a 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts @@ -11,9 +11,9 @@ import { } from '../../utils/ata'; import { Mint } from '../tokenModule/models'; import { TransactionBuilder } from '../../utils/TransactionBuilder'; +import { CvgWallet } from '../../utils/Wallets'; import { PsyoptionsAmericanInstrument } from './types'; import { createAmericanProgram } from './instrument'; -import { CvgWallet } from '@/index'; export const mintAmericanOptions = async ( convergence: Convergence, From 32ab68aa17e97ec168325d614218e6b5e3c16b5e Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Tue, 5 Sep 2023 11:34:38 +0530 Subject: [PATCH 11/32] change defaultFeePayer to identity in CvgWallet --- packages/js/src/utils/Wallets.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/js/src/utils/Wallets.ts b/packages/js/src/utils/Wallets.ts index 23bfe096b..7117a4d2b 100644 --- a/packages/js/src/utils/Wallets.ts +++ b/packages/js/src/utils/Wallets.ts @@ -15,7 +15,7 @@ export class CvgWallet implements Wallet { constructor(convergence: Convergence) { this.convergence = convergence; this.payer = convergence.rpc().getDefaultFeePayer() as Keypair; - this.publicKey = convergence.rpc().getDefaultFeePayer().publicKey; + this.publicKey = convergence.identity().publicKey; } signTransaction = (tx: Transaction): Promise => { From d498542a21566fd1385631802165c0ed043e9ce5 Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Tue, 5 Sep 2023 11:37:08 +0530 Subject: [PATCH 12/32] add convergence.identity() as signer --- packages/js/src/utils/Wallets.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/js/src/utils/Wallets.ts b/packages/js/src/utils/Wallets.ts index 7117a4d2b..965c5d73a 100644 --- a/packages/js/src/utils/Wallets.ts +++ b/packages/js/src/utils/Wallets.ts @@ -19,13 +19,15 @@ export class CvgWallet implements Wallet { } signTransaction = (tx: Transaction): Promise => { - return this.convergence.rpc().signTransaction(tx, [this.payer as Signer]); + return this.convergence + .rpc() + .signTransaction(tx, [this.convergence.identity() as Signer]); }; signAllTransactions = (txs: Transaction[]): Promise => { return this.convergence .rpc() - .signAllTransactions(txs, [this.payer as Signer]); + .signAllTransactions(txs, [this.convergence.identity() as Signer]); }; } From 22e1227d1879d8eb047f292ae75f366825d9c6ad Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Tue, 5 Sep 2023 13:54:10 +0530 Subject: [PATCH 13/32] fixed --- .../helpers.ts | 68 ++++++++++------ .../instrument.ts | 3 +- .../helpers.ts | 69 ++++++++++------- .../rfqModule/operations/prepareSettlement.ts | 37 +++++++-- packages/js/src/utils/ata.ts | 23 +++--- packages/js/tests/helpers.ts | 6 +- .../integration/psyoptionsAmerican.spec.ts | 77 +++++++------------ .../integration/psyoptionsEuropean.spec.ts | 60 +++++++-------- 8 files changed, 186 insertions(+), 157 deletions(-) diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts index ba580e07a..e2ed194f2 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts @@ -1,13 +1,17 @@ import * as psyoptionsAmerican from '@mithraic-labs/psy-american'; import { BN } from 'bn.js'; -import { PublicKey, TransactionInstruction } from '@solana/web3.js'; +import { + PublicKey, + Transaction, + TransactionInstruction, +} from '@solana/web3.js'; import { Convergence } from '../../Convergence'; import { ATAExistence, getOrCreateATA, - getOrCreateATAInx, + getOrCreateATAtxBuilder, } from '../../utils/ata'; import { Mint } from '../tokenModule/models'; import { TransactionBuilder } from '../../utils/TransactionBuilder'; @@ -35,37 +39,39 @@ export const mintAmericanOptions = async ( response, rfq, }); - const txBuilderArray: TransactionBuilder[] = []; + + const ataTxBuilderArray: TransactionBuilder[] = []; + const mintTxBuilderArray: TransactionBuilder[] = []; for (const [index, leg] of rfq.legs.entries()) { - const instructions: TransactionInstruction[] = []; + const mintInstructions: TransactionInstruction[] = []; if (leg instanceof PsyoptionsAmericanInstrument) { const { receiver, amount } = legs[index]; if (receiver !== callerSide) { const optionMarket = await leg.getOptionMeta(); if (optionMarket) { - const optionToken = await getOrCreateATAInx( + const optionToken = await getOrCreateATAtxBuilder( convergence, optionMarket.optionMint, caller ); - if (optionToken.instruction) { - instructions.push(optionToken.instruction); + if (optionToken.txBuilder) { + ataTxBuilderArray.push(optionToken.txBuilder); } - const writerToken = await getOrCreateATAInx( + const writerToken = await getOrCreateATAtxBuilder( convergence, optionMarket!.writerTokenMint, caller ); - if (writerToken.instruction) { - instructions.push(writerToken.instruction); + if (writerToken.txBuilder) { + ataTxBuilderArray.push(writerToken.txBuilder); } - const underlyingToken = await getOrCreateATAInx( + const underlyingToken = await getOrCreateATAtxBuilder( convergence, optionMarket!.underlyingAssetMint, caller ); - if (underlyingToken.instruction) { - instructions.push(underlyingToken.instruction); + if (underlyingToken.txBuilder) { + ataTxBuilderArray.push(underlyingToken.txBuilder); } const ixWithSigners = await psyoptionsAmerican.instructions.mintOptionV2Instruction( @@ -81,31 +87,49 @@ export const mintAmericanOptions = async ( isSigner: true, isWritable: false, }; - instructions.push(ixWithSigners.ix); + mintInstructions.push(ixWithSigners.ix); } } } - if (instructions.length > 0) { + if (mintInstructions.length > 0) { const txBuilder = TransactionBuilder.make().setFeePayer( convergence.rpc().getDefaultFeePayer() ); - instructions.forEach((ins) => { + mintInstructions.forEach((ins) => { txBuilder.add({ instruction: ins, - signers: [convergence.rpc().getDefaultFeePayer()], + signers: [convergence.identity()], }); }); - txBuilderArray.push(txBuilder); + mintTxBuilderArray.push(txBuilder); } } - if (txBuilderArray.length > 0) { + let signedTxs: Transaction[] = []; + if (ataTxBuilderArray.length > 0 || mintTxBuilderArray.length > 0) { + const mergedTxBuilderArray = ataTxBuilderArray.concat(mintTxBuilderArray); const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); - const signedTxs = await convergence + signedTxs = await convergence .identity() .signAllTransactions( - txBuilderArray.map((b) => b.toTransaction(lastValidBlockHeight)) + mergedTxBuilderArray.map((b) => b.toTransaction(lastValidBlockHeight)) ); - signedTxs.map( + } + + const ataSignedTx = signedTxs.slice(0, ataTxBuilderArray.length); + const mintSignedTx = signedTxs.slice(ataTxBuilderArray.length); + + if (ataSignedTx.length > 0) { + const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); + ataSignedTx.map( + async (signedTx) => + await convergence + .rpc() + .serializeAndSendTransaction(signedTx, lastValidBlockHeight) + ); + } + if (mintSignedTx.length > 0) { + const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); + mintSignedTx.map( async (signedTx) => await convergence .rpc() diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/instrument.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/instrument.ts index ad226fc03..ec4882198 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/instrument.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/instrument.ts @@ -113,7 +113,8 @@ export class PsyoptionsAmericanInstrument implements LegInstrument { convergence: Convergence, metaKey: PublicKey ): Promise { - const americanProgram = createAmericanProgram(convergence); + const cvgWallet = new CvgWallet(convergence); + const americanProgram = createAmericanProgram(convergence, cvgWallet); const optionMarket = (await psyoptionsAmerican.getOptionByKey( americanProgram, metaKey diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts index 1adcb3022..0dc5ccaeb 100644 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts @@ -11,7 +11,7 @@ import { Mint } from '../tokenModule'; import { ATAExistence, getOrCreateATA, - getOrCreateATAInx, + getOrCreateATAtxBuilder, } from '../../utils/ata'; import { addDecimals } from '../../utils/conversions'; import { TransactionBuilder } from '../../utils/TransactionBuilder'; @@ -156,9 +156,10 @@ export const mintEuropeanOptions = async ( response, rfq, }); - const txBuilderArray: TransactionBuilder[] = []; + const mintTxBuilderArray: TransactionBuilder[] = []; + const ataTxBuilderArray: TransactionBuilder[] = []; for (const [index, leg] of rfq.legs.entries()) { - const instructions: TransactionInstruction[] = []; + const mintInstructions: TransactionInstruction[] = []; if (leg instanceof PsyoptionsEuropeanInstrument) { const { receiver, amount } = legs[index]; if (receiver !== callerSide) { @@ -184,10 +185,7 @@ export const mintEuropeanOptions = async ( ? stableMintToken : underlyingMintToken; - const { - ataPubKey: optionDestination, - instruction: optionDestinationAtaIx, - } = await getOrCreateATAInx( + const optionDestination = await getOrCreateATAtxBuilder( convergence, leg.optionType == psyoptionsEuropean.OptionType.PUT ? euroMeta.putOptionMint @@ -195,29 +193,26 @@ export const mintEuropeanOptions = async ( caller ); - if (optionDestinationAtaIx) { - instructions.push(optionDestinationAtaIx); + if (optionDestination.txBuilder) { + ataTxBuilderArray.push(optionDestination.txBuilder); } - const { - ataPubKey: writerDestination, - instruction: writerDestinationAtaInx, - } = await getOrCreateATAInx( + const writerDestination = await getOrCreateATAtxBuilder( convergence, leg.optionType == psyoptionsEuropean.OptionType.PUT ? euroMeta.putWriterMint : euroMeta.callWriterMint, caller ); - if (writerDestinationAtaInx) { - instructions.push(writerDestinationAtaInx); + if (writerDestination.txBuilder) { + ataTxBuilderArray.push(writerDestination.txBuilder); } const { instruction: ix } = psyoptionsEuropean.instructions.mintOptions( europeanProgram, leg.optionMetaPubKey, euroMeta as psyoptionsEuropean.EuroMeta, minterCollateralKey, - optionDestination, - writerDestination, + optionDestination.ataPubKey, + writerDestination.ataPubKey, addDecimals(amount, PsyoptionsEuropeanInstrument.decimals), leg.optionType ); @@ -228,35 +223,53 @@ export const mintEuropeanOptions = async ( isWritable: false, }; - instructions.push(ix); + mintInstructions.push(ix); } } - if (instructions.length > 0) { + if (mintInstructions.length > 0) { const txBuilder = TransactionBuilder.make().setFeePayer( convergence.rpc().getDefaultFeePayer() ); - instructions.forEach((ins) => { + mintInstructions.forEach((ins) => { txBuilder.add({ instruction: ins, signers: [convergence.identity()], }); }); - txBuilderArray.push(txBuilder); + mintTxBuilderArray.push(txBuilder); } } - if (txBuilderArray.length > 0) { + + let signedTxs: Transaction[] = []; + if (ataTxBuilderArray.length > 0 || mintTxBuilderArray.length > 0) { + const mergedTxBuilderArray = ataTxBuilderArray.concat(mintTxBuilderArray); const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); - const signedTxs = await convergence + signedTxs = await convergence .identity() .signAllTransactions( - txBuilderArray.map((b) => b.toTransaction(lastValidBlockHeight)) + mergedTxBuilderArray.map((b) => b.toTransaction(lastValidBlockHeight)) ); - await Promise.all( - signedTxs.map((signedTx) => - convergence + } + + const ataSignedTx = signedTxs.slice(0, ataTxBuilderArray.length); + const mintSignedTx = signedTxs.slice(ataTxBuilderArray.length); + + if (ataSignedTx.length > 0) { + const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); + ataSignedTx.map( + async (signedTx) => + await convergence + .rpc() + .serializeAndSendTransaction(signedTx, lastValidBlockHeight) + ); + } + if (mintSignedTx.length > 0) { + const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); + mintSignedTx.map( + async (signedTx) => + await convergence .rpc() .serializeAndSendTransaction(signedTx, lastValidBlockHeight) - ) ); } }; diff --git a/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts b/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts index 7877e51c4..ee68b0c5a 100644 --- a/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts +++ b/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts @@ -25,7 +25,7 @@ import { TransactionBuilderOptions, } from '../../../utils/TransactionBuilder'; import { Rfq } from '../../rfqModule'; -import { getOrCreateATA } from '../../../utils/ata'; +import { getOrCreateATAtxBuilder } from '../../../utils/ata'; import { Mint } from '../../tokenModule'; import { InstrumentPdasClient } from '../../instrumentModule'; import { legToBaseAssetMint } from '@/plugins/instrumentModule'; @@ -251,6 +251,7 @@ export const prepareSettlementBuilder = async ( anchorRemainingAccounts.push(spotInstrumentProgramAccount, ...quoteAccounts); + const ataTxBuilderArray: TransactionBuilder[] = []; for (let legIndex = 0; legIndex < legAmountToPrepare; legIndex++) { const instrumentProgramAccount: AccountMeta = { pubkey: rfqModel.legs[legIndex].getProgramId(), @@ -266,6 +267,16 @@ export const prepareSettlementBuilder = async ( rfqModel, }); + const { ataPubKey, txBuilder } = await getOrCreateATAtxBuilder( + convergence, + baseAssetMints[legIndex].address, + caller.publicKey, + programs + ); + if (txBuilder) { + ataTxBuilderArray.push(txBuilder); + } + const legAccounts: AccountMeta[] = [ // `caller` { @@ -275,12 +286,7 @@ export const prepareSettlementBuilder = async ( }, // `caller_token_account` { - pubkey: await getOrCreateATA( - convergence, - baseAssetMints[legIndex].address, - caller.publicKey, - programs - ), + pubkey: ataPubKey, isSigner: false, isWritable: true, }, @@ -303,6 +309,21 @@ export const prepareSettlementBuilder = async ( anchorRemainingAccounts.push(instrumentProgramAccount, ...legAccounts); } + if (ataTxBuilderArray.length > 0) { + const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); + const signedTxs = await convergence + .identity() + .signAllTransactions( + ataTxBuilderArray.map((b) => b.toTransaction(lastValidBlockHeight)) + ); + signedTxs.map( + async (signedTx) => + await convergence + .rpc() + .serializeAndSendTransaction(signedTx, lastValidBlockHeight) + ); + } + return TransactionBuilder.make() .setFeePayer(payer) .add( @@ -334,7 +355,7 @@ export const prepareSettlementBuilder = async ( }; const findOptionStyle = (rfq: Rfq) => { - const american = rfq.legs.every((leg) => + const american = rfq.legs.some((leg) => leg.getProgramId().equals(psyoptionsAmericanInstrumentProgram.address) ); if (american) { diff --git a/packages/js/src/utils/ata.ts b/packages/js/src/utils/ata.ts index fda367120..86fe5b384 100644 --- a/packages/js/src/utils/ata.ts +++ b/packages/js/src/utils/ata.ts @@ -1,9 +1,10 @@ -import * as Spl from '@solana/spl-token'; -import { Keypair, PublicKey, TransactionInstruction } from '@solana/web3.js'; +import { Keypair, PublicKey } from '@solana/web3.js'; import { Convergence } from '../Convergence'; import { token } from '../types/Amount'; import { Program } from '../types'; +import { TransactionBuilder } from '../utils/TransactionBuilder'; import { collateralMintCache } from '@/plugins/collateralModule/cache'; +import { createTokenBuilder } from '@/plugins/tokenModule/operations/createToken'; export enum ATAExistence { EXISTS, @@ -35,17 +36,17 @@ export const getOrCreateATA = async ( return ata; }; -interface GetOrCreateATAInxReturnType { +interface GetOrCreateATAtxBuilderReturnType { ataPubKey: PublicKey; - instruction?: TransactionInstruction; + txBuilder?: TransactionBuilder; } -export const getOrCreateATAInx = async ( +export const getOrCreateATAtxBuilder = async ( convergence: Convergence, mint: PublicKey, owner: PublicKey, programs?: Program[] -): Promise => { +): Promise => { const pda = convergence.tokens().pdas().associatedTokenAccount({ mint, owner, @@ -53,13 +54,11 @@ export const getOrCreateATAInx = async ( }); const account = await convergence.rpc().getAccount(pda); if (!account.exists) { - const instruction = Spl.createAssociatedTokenAccountInstruction( + const txBuilder = await createTokenBuilder(convergence, { + mint, owner, - pda, - owner, - mint - ); - return { ataPubKey: pda, instruction }; + }); + return { ataPubKey: pda, txBuilder }; } return { ataPubKey: pda }; }; diff --git a/packages/js/tests/helpers.ts b/packages/js/tests/helpers.ts index 17f9d964f..ff7ea173a 100644 --- a/packages/js/tests/helpers.ts +++ b/packages/js/tests/helpers.ts @@ -125,7 +125,7 @@ export const createAmericanCoveredCallRfq = async ( const { rfq, response } = await cvg.rfqs().createAndFinalize({ instruments: [ - await SpotLegInstrument.create(cvg, baseMint, 0.00118, 'short'), + await SpotLegInstrument.create(cvg, baseMint, 1.0, 'long'), await PsyoptionsAmericanInstrument.create( cvg, baseMint, @@ -277,7 +277,7 @@ export const createAmericanFixedBaseStraddle = async ( baseMint: any, quoteMint: any ) => { - const expiration = 3_600 + Math.random(); + const expiration = 3_600 + Math.random() * 100; const { optionMarketKey, optionMarket } = await initializeNewAmericanOption( cvg, baseMint, @@ -336,7 +336,7 @@ export const createEuropeanFixedBaseStraddle = async ( quoteMint.decimals * -1 ); const min = 3_600; - const randomExpiry = min + Math.random(); + const randomExpiry = min + Math.random() * 100; const { euroMeta: euroMeta, euroMetaKey: euroMetaKey } = await initializeNewEuropeanOption( diff --git a/packages/js/tests/integration/psyoptionsAmerican.spec.ts b/packages/js/tests/integration/psyoptionsAmerican.spec.ts index 565bdf94b..96bf368f8 100644 --- a/packages/js/tests/integration/psyoptionsAmerican.spec.ts +++ b/packages/js/tests/integration/psyoptionsAmerican.spec.ts @@ -11,7 +11,6 @@ import { createAmericanFixedBaseStraddle, } from '../helpers'; import { BASE_MINT_BTC_PK, QUOTE_MINT_PK } from '../constants'; -import { getOrCreateATAInx } from '../../src'; describe('integration.psyoptionsAmerican', () => { const takerCvg = createUserCvg('taker'); @@ -48,29 +47,6 @@ describe('integration.psyoptionsAmerican', () => { side: 'bid', }); - const refreshedRfq = await takerCvg.rfqs().findRfqByAddress({ - address: rfq.address, - }); - - const refreshedResponse = await takerCvg.rfqs().findResponseByAddress({ - address: rfqResponse.address, - }); - - const bal = await getOrCreateATAInx( - takerCvg, - baseMint.address, - takerCvg.identity().publicKey - ); - const acc = await takerCvg.tokens().findTokenByAddress({ - address: bal.ataPubKey, - }); - console.log('acc', Number(acc.amount.basisPoints) / Math.pow(10, 9)); - - const result = takerCvg.rfqs().getSettlementResult({ - rfq: refreshedRfq, - response: refreshedResponse, - }); - console.log('res', result); expect(confirmResponse).toHaveProperty('signature'); const takerResponse = await prepareRfqSettlement( @@ -100,7 +76,6 @@ describe('integration.psyoptionsAmerican', () => { baseMint, quoteMint ); - expect(rfq).toHaveProperty('address'); const { rfqResponse } = await respondToRfq( makerCvg, @@ -135,10 +110,10 @@ describe('integration.psyoptionsAmerican', () => { expect(settlementResponse.response).toHaveProperty('signature'); }); - it('fixed-size american straddle [sell]', async () => { - const { rfq } = await createAmericanFixedBaseStraddle( + it('open size american call Spread [buy]', async () => { + const { rfq } = await createAmericanOpenSizeCallSpdOptionRfq( takerCvg, - 'sell', + 'buy', baseMint, quoteMint ); @@ -146,25 +121,28 @@ describe('integration.psyoptionsAmerican', () => { const { rfqResponse } = await respondToRfq( makerCvg, rfq, - 55_133, - undefined + undefined, + 150_123, + 5 ); expect(rfqResponse).toHaveProperty('address'); + const { response: confirmResponse } = await takerCvg .rfqs() .confirmResponse({ rfq: rfq.address, response: rfqResponse.address, - side: 'bid', + side: 'ask', + overrideLegMultiplier: 4, }); expect(confirmResponse).toHaveProperty('signature'); - const takerResponse = await prepareRfqSettlement( takerCvg, rfq, rfqResponse ); expect(takerResponse.response).toHaveProperty('signature'); + const makerResponse = await prepareRfqSettlement( makerCvg, rfq, @@ -176,31 +154,36 @@ describe('integration.psyoptionsAmerican', () => { expect(settlementResponse.response).toHaveProperty('signature'); }); - it('fixed-size american straddle [2-way]', async () => { + it('fixed-size american straddle [sell]', async () => { const { rfq } = await createAmericanFixedBaseStraddle( takerCvg, - 'two-way', + 'sell', baseMint, quoteMint ); expect(rfq).toHaveProperty('address'); - const { rfqResponse } = await respondToRfq(makerCvg, rfq, 61_222, 60_123); + const { rfqResponse } = await respondToRfq( + makerCvg, + rfq, + 55_133, + undefined + ); expect(rfqResponse).toHaveProperty('address'); const { response: confirmResponse } = await takerCvg .rfqs() .confirmResponse({ rfq: rfq.address, response: rfqResponse.address, - side: 'ask', + side: 'bid', }); expect(confirmResponse).toHaveProperty('signature'); + const takerResponse = await prepareRfqSettlement( takerCvg, rfq, rfqResponse ); expect(takerResponse.response).toHaveProperty('signature'); - const makerResponse = await prepareRfqSettlement( makerCvg, rfq, @@ -212,10 +195,10 @@ describe('integration.psyoptionsAmerican', () => { expect(settlementResponse.response).toHaveProperty('signature'); }); - it('open size american call Spread [buy]', async () => { + it('open size american call Spread [2-way]', async () => { const { rfq } = await createAmericanOpenSizeCallSpdOptionRfq( takerCvg, - 'buy', + 'two-way', baseMint, quoteMint ); @@ -223,7 +206,7 @@ describe('integration.psyoptionsAmerican', () => { const { rfqResponse } = await respondToRfq( makerCvg, rfq, - undefined, + 220_111, 150_123, 5 ); @@ -256,30 +239,22 @@ describe('integration.psyoptionsAmerican', () => { expect(settlementResponse.response).toHaveProperty('signature'); }); - it('open size american call Spread [2-way]', async () => { - const { rfq } = await createAmericanOpenSizeCallSpdOptionRfq( + it('fixed-size american straddle [2-way]', async () => { + const { rfq } = await createAmericanFixedBaseStraddle( takerCvg, 'two-way', baseMint, quoteMint ); expect(rfq).toHaveProperty('address'); - const { rfqResponse } = await respondToRfq( - makerCvg, - rfq, - 220_111, - 150_123, - 5 - ); + const { rfqResponse } = await respondToRfq(makerCvg, rfq, 61_222, 60_123); expect(rfqResponse).toHaveProperty('address'); - const { response: confirmResponse } = await takerCvg .rfqs() .confirmResponse({ rfq: rfq.address, response: rfqResponse.address, side: 'ask', - overrideLegMultiplier: 4, }); expect(confirmResponse).toHaveProperty('signature'); const takerResponse = await prepareRfqSettlement( diff --git a/packages/js/tests/integration/psyoptionsEuropean.spec.ts b/packages/js/tests/integration/psyoptionsEuropean.spec.ts index 94b760656..7d5781898 100644 --- a/packages/js/tests/integration/psyoptionsEuropean.spec.ts +++ b/packages/js/tests/integration/psyoptionsEuropean.spec.ts @@ -10,7 +10,7 @@ import { createEuropeanOpenSizeCallSpdOptionRfq, createEuropeanFixedBaseStraddle, } from '../helpers'; -import { BASE_MINT_BTC_PK, QUOTE_MINT_PK } from '../constants'; +import { BASE_MINT_SOL_PK, QUOTE_MINT_PK } from '../constants'; import { InstructionUniquenessTracker } from '../../src'; describe('integration.psyoptionsEuropean', () => { @@ -22,13 +22,13 @@ describe('integration.psyoptionsEuropean', () => { before(async () => { baseMint = await takerCvg .tokens() - .findMintByAddress({ address: BASE_MINT_BTC_PK }); + .findMintByAddress({ address: BASE_MINT_SOL_PK }); quoteMint = await takerCvg .tokens() .findMintByAddress({ address: QUOTE_MINT_PK }); }); - it('covered call [sell]', async () => { + it('european covered call [sell]', async () => { const { rfq, response } = await createEuropeanCoveredCallRfq( takerCvg, 'sell', @@ -46,14 +46,12 @@ describe('integration.psyoptionsEuropean', () => { response: rfqResponse.address, side: 'bid', }); - - // await setupEuropean(takerCvg, rfqResponse); - await prepareRfqSettlement(makerCvg, rfq, rfqResponse); await prepareRfqSettlement(takerCvg, rfq, rfqResponse); await settleRfq(takerCvg, rfq, rfqResponse); }); + it('fixed-size european straddle [buy]', async () => { const { rfq } = await createEuropeanFixedBaseStraddle( takerCvg, @@ -78,8 +76,6 @@ describe('integration.psyoptionsEuropean', () => { side: 'ask', }); expect(confirmResponse).toHaveProperty('signature'); - // await setupEuropean(takerCvg, rfqResponse); - // await setupEuropean(makerCvg, rfqResponse); const takerResponse = await prepareRfqSettlement( takerCvg, rfq, @@ -98,10 +94,10 @@ describe('integration.psyoptionsEuropean', () => { expect(settlementResponse.response).toHaveProperty('signature'); }); - it('fixed-size european straddle [sell]', async () => { - const { rfq } = await createEuropeanFixedBaseStraddle( + it('open size european call Spread [buy]', async () => { + const { rfq } = await createEuropeanOpenSizeCallSpdOptionRfq( takerCvg, - 'sell', + 'buy', baseMint, quoteMint, ixTracker @@ -110,16 +106,19 @@ describe('integration.psyoptionsEuropean', () => { const { rfqResponse } = await respondToRfq( makerCvg, rfq, - 55_133, - undefined + undefined, + 150_123, + 5 ); expect(rfqResponse).toHaveProperty('address'); + const { response: confirmResponse } = await takerCvg .rfqs() .confirmResponse({ rfq: rfq.address, response: rfqResponse.address, - side: 'bid', + side: 'ask', + overrideLegMultiplier: 4, }); expect(confirmResponse).toHaveProperty('signature'); const takerResponse = await prepareRfqSettlement( @@ -140,23 +139,28 @@ describe('integration.psyoptionsEuropean', () => { expect(settlementResponse.response).toHaveProperty('signature'); }); - it('fixed-size european straddle [2-way]', async () => { + it('fixed-size european straddle [sell]', async () => { const { rfq } = await createEuropeanFixedBaseStraddle( takerCvg, - 'two-way', + 'sell', baseMint, quoteMint, ixTracker ); expect(rfq).toHaveProperty('address'); - const { rfqResponse } = await respondToRfq(makerCvg, rfq, 61_222, 60_123); + const { rfqResponse } = await respondToRfq( + makerCvg, + rfq, + 55_133, + undefined + ); expect(rfqResponse).toHaveProperty('address'); const { response: confirmResponse } = await takerCvg .rfqs() .confirmResponse({ rfq: rfq.address, response: rfqResponse.address, - side: 'ask', + side: 'bid', }); expect(confirmResponse).toHaveProperty('signature'); const takerResponse = await prepareRfqSettlement( @@ -177,10 +181,10 @@ describe('integration.psyoptionsEuropean', () => { expect(settlementResponse.response).toHaveProperty('signature'); }); - it('open size european call Spread [buy]', async () => { + it('open size european call Spread [2-way]', async () => { const { rfq } = await createEuropeanOpenSizeCallSpdOptionRfq( takerCvg, - 'buy', + 'two-way', baseMint, quoteMint, ixTracker @@ -189,7 +193,7 @@ describe('integration.psyoptionsEuropean', () => { const { rfqResponse } = await respondToRfq( makerCvg, rfq, - undefined, + 220_111, 150_123, 5 ); @@ -222,8 +226,8 @@ describe('integration.psyoptionsEuropean', () => { expect(settlementResponse.response).toHaveProperty('signature'); }); - it('open size european call Spread [2-way]', async () => { - const { rfq } = await createEuropeanOpenSizeCallSpdOptionRfq( + it('fixed-size european straddle [2-way]', async () => { + const { rfq } = await createEuropeanFixedBaseStraddle( takerCvg, 'two-way', baseMint, @@ -231,22 +235,14 @@ describe('integration.psyoptionsEuropean', () => { ixTracker ); expect(rfq).toHaveProperty('address'); - const { rfqResponse } = await respondToRfq( - makerCvg, - rfq, - 220_111, - 150_123, - 5 - ); + const { rfqResponse } = await respondToRfq(makerCvg, rfq, 61_222, 60_123); expect(rfqResponse).toHaveProperty('address'); - const { response: confirmResponse } = await takerCvg .rfqs() .confirmResponse({ rfq: rfq.address, response: rfqResponse.address, side: 'ask', - overrideLegMultiplier: 4, }); expect(confirmResponse).toHaveProperty('signature'); const takerResponse = await prepareRfqSettlement( From a3e4ac603507959037d183b048f12646a47b9792 Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Tue, 5 Sep 2023 14:02:14 +0530 Subject: [PATCH 14/32] reduce expiry --- packages/js/tests/helpers.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/js/tests/helpers.ts b/packages/js/tests/helpers.ts index ff7ea173a..28fc3c50c 100644 --- a/packages/js/tests/helpers.ts +++ b/packages/js/tests/helpers.ts @@ -163,7 +163,7 @@ export const createEuropeanCoveredCallRfq = async ( quoteMint.decimals * -1 ); const min = 3_600; - const randomExpiry = min + Math.random() * 10; + const randomExpiry = min + Math.random(); const { euroMeta, euroMetaKey } = await initializeNewEuropeanOption( cvg, ixTracker, @@ -336,7 +336,7 @@ export const createEuropeanFixedBaseStraddle = async ( quoteMint.decimals * -1 ); const min = 3_600; - const randomExpiry = min + Math.random() * 100; + const randomExpiry = min + Math.random(); const { euroMeta: euroMeta, euroMetaKey: euroMetaKey } = await initializeNewEuropeanOption( From 7fbacd86f302f02350b7e69f10bb3e8d46fdc607 Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Tue, 5 Sep 2023 19:28:58 +0530 Subject: [PATCH 15/32] replace sol with btc mint --- packages/js/tests/integration/psyoptionsEuropean.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/js/tests/integration/psyoptionsEuropean.spec.ts b/packages/js/tests/integration/psyoptionsEuropean.spec.ts index 7d5781898..6ac0760cc 100644 --- a/packages/js/tests/integration/psyoptionsEuropean.spec.ts +++ b/packages/js/tests/integration/psyoptionsEuropean.spec.ts @@ -10,7 +10,7 @@ import { createEuropeanOpenSizeCallSpdOptionRfq, createEuropeanFixedBaseStraddle, } from '../helpers'; -import { BASE_MINT_SOL_PK, QUOTE_MINT_PK } from '../constants'; +import { BASE_MINT_BTC_PK, QUOTE_MINT_PK } from '../constants'; import { InstructionUniquenessTracker } from '../../src'; describe('integration.psyoptionsEuropean', () => { @@ -22,7 +22,7 @@ describe('integration.psyoptionsEuropean', () => { before(async () => { baseMint = await takerCvg .tokens() - .findMintByAddress({ address: BASE_MINT_SOL_PK }); + .findMintByAddress({ address: BASE_MINT_BTC_PK }); quoteMint = await takerCvg .tokens() .findMintByAddress({ address: QUOTE_MINT_PK }); From cc61a70051f5a7e84eb0ef606c9c86775ad3c3e2 Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Tue, 5 Sep 2023 19:35:35 +0530 Subject: [PATCH 16/32] add long and short legs to straddle test --- packages/js/tests/helpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/js/tests/helpers.ts b/packages/js/tests/helpers.ts index 28fc3c50c..b5f2d295c 100644 --- a/packages/js/tests/helpers.ts +++ b/packages/js/tests/helpers.ts @@ -370,7 +370,7 @@ export const createEuropeanFixedBaseStraddle = async ( euroMeta, euroMetaKey, 1, - 'long' + 'short' ), ], orderType, From 85e9a7130d040901a2631755ac83b376b2b2f806 Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Tue, 5 Sep 2023 19:49:51 +0530 Subject: [PATCH 17/32] add more randomness to expiry --- packages/js/tests/helpers.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/js/tests/helpers.ts b/packages/js/tests/helpers.ts index b5f2d295c..d09c342da 100644 --- a/packages/js/tests/helpers.ts +++ b/packages/js/tests/helpers.ts @@ -120,7 +120,7 @@ export const createAmericanCoveredCallRfq = async ( quoteMint, 44_000, 1, - 3_600 + Math.random() * 10 + 3_600 + Math.random() * 100 ); const { rfq, response } = await cvg.rfqs().createAndFinalize({ @@ -163,7 +163,7 @@ export const createEuropeanCoveredCallRfq = async ( quoteMint.decimals * -1 ); const min = 3_600; - const randomExpiry = min + Math.random(); + const randomExpiry = min + Math.random() * 100; const { euroMeta, euroMetaKey } = await initializeNewEuropeanOption( cvg, ixTracker, @@ -215,7 +215,7 @@ export const createEuropeanOpenSizeCallSpdOptionRfq = async ( quoteMint.decimals * -1 ); const min = 3_600; - const randomExpiry = min + Math.random(); + const randomExpiry = min + Math.random() * 100; const { euroMeta: euroMeta1, euroMetaKey: euroMetaKey1 } = await initializeNewEuropeanOption( cvg, @@ -336,7 +336,7 @@ export const createEuropeanFixedBaseStraddle = async ( quoteMint.decimals * -1 ); const min = 3_600; - const randomExpiry = min + Math.random(); + const randomExpiry = min + Math.random() * 100; const { euroMeta: euroMeta, euroMetaKey: euroMetaKey } = await initializeNewEuropeanOption( @@ -387,7 +387,7 @@ export const createAmericanOpenSizeCallSpdOptionRfq = async ( baseMint: any, quoteMint: any ) => { - const expiration = 3_600 + Math.random(); + const expiration = 3_600 + Math.random() * 100; const { optionMarketKey: optionMarketKey1, optionMarket: optionMarket1 } = await initializeNewAmericanOption( cvg, From ba41ad91d16cbf488bf830e6fcdfd1d5974a0b31 Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Tue, 5 Sep 2023 20:04:07 +0530 Subject: [PATCH 18/32] use Promise.all --- .../helpers.ts | 21 ++++++++++++------- .../helpers.ts | 14 +++++++------ .../rfqModule/operations/prepareSettlement.ts | 7 ++++--- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts index e2ed194f2..93603482e 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts @@ -120,20 +120,25 @@ export const mintAmericanOptions = async ( if (ataSignedTx.length > 0) { const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); - ataSignedTx.map( - async (signedTx) => - await convergence + + await Promise.all( + ataSignedTx.map((signedTx) => + convergence .rpc() .serializeAndSendTransaction(signedTx, lastValidBlockHeight) + ) ); } if (mintSignedTx.length > 0) { const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); - mintSignedTx.map( - async (signedTx) => - await convergence - .rpc() - .serializeAndSendTransaction(signedTx, lastValidBlockHeight) + + await Promise.all( + mintSignedTx.map( + async (signedTx) => + await convergence + .rpc() + .serializeAndSendTransaction(signedTx, lastValidBlockHeight) + ) ); } }; diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts index 0dc5ccaeb..95b0f8edc 100644 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts @@ -256,20 +256,22 @@ export const mintEuropeanOptions = async ( if (ataSignedTx.length > 0) { const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); - ataSignedTx.map( - async (signedTx) => - await convergence + await Promise.all( + ataSignedTx.map((signedTx) => + convergence .rpc() .serializeAndSendTransaction(signedTx, lastValidBlockHeight) + ) ); } if (mintSignedTx.length > 0) { const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); - mintSignedTx.map( - async (signedTx) => - await convergence + await Promise.all( + mintSignedTx.map((signedTx) => + convergence .rpc() .serializeAndSendTransaction(signedTx, lastValidBlockHeight) + ) ); } }; diff --git a/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts b/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts index ee68b0c5a..ebdad6870 100644 --- a/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts +++ b/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts @@ -316,11 +316,12 @@ export const prepareSettlementBuilder = async ( .signAllTransactions( ataTxBuilderArray.map((b) => b.toTransaction(lastValidBlockHeight)) ); - signedTxs.map( - async (signedTx) => - await convergence + await Promise.all( + signedTxs.map((signedTx) => + convergence .rpc() .serializeAndSendTransaction(signedTx, lastValidBlockHeight) + ) ); } From 3b384c66466435ef7c8740bd1b77b511082a3745 Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Tue, 5 Sep 2023 20:32:48 +0530 Subject: [PATCH 19/32] fix promise.all --- .../helpers.ts | 27 ++++++++++--------- .../helpers.ts | 20 ++++++++------ 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts index 93603482e..e9a3b8acb 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts @@ -119,26 +119,27 @@ export const mintAmericanOptions = async ( const mintSignedTx = signedTxs.slice(ataTxBuilderArray.length); if (ataSignedTx.length > 0) { - const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); - await Promise.all( - ataSignedTx.map((signedTx) => + ataSignedTx.map(async (signedTx) => { + const lastValidBlockHeight = await convergence + .rpc() + .getLatestBlockhash(); convergence .rpc() - .serializeAndSendTransaction(signedTx, lastValidBlockHeight) - ) + .serializeAndSendTransaction(signedTx, lastValidBlockHeight); + }) ); } if (mintSignedTx.length > 0) { - const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); - await Promise.all( - mintSignedTx.map( - async (signedTx) => - await convergence - .rpc() - .serializeAndSendTransaction(signedTx, lastValidBlockHeight) - ) + mintSignedTx.map(async (signedTx) => { + const lastValidBlockHeight = await convergence + .rpc() + .getLatestBlockhash(); + convergence + .rpc() + .serializeAndSendTransaction(signedTx, lastValidBlockHeight); + }) ); } }; diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts index 95b0f8edc..40057bc2a 100644 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts @@ -255,23 +255,27 @@ export const mintEuropeanOptions = async ( const mintSignedTx = signedTxs.slice(ataTxBuilderArray.length); if (ataSignedTx.length > 0) { - const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); await Promise.all( - ataSignedTx.map((signedTx) => + ataSignedTx.map(async (signedTx) => { + const lastValidBlockHeight = await convergence + .rpc() + .getLatestBlockhash(); convergence .rpc() - .serializeAndSendTransaction(signedTx, lastValidBlockHeight) - ) + .serializeAndSendTransaction(signedTx, lastValidBlockHeight); + }) ); } if (mintSignedTx.length > 0) { - const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); await Promise.all( - mintSignedTx.map((signedTx) => + mintSignedTx.map(async (signedTx) => { + const lastValidBlockHeight = await convergence + .rpc() + .getLatestBlockhash(); convergence .rpc() - .serializeAndSendTransaction(signedTx, lastValidBlockHeight) - ) + .serializeAndSendTransaction(signedTx, lastValidBlockHeight); + }) ); } }; From d627b602a27d10701a1e1dda8ba98333d61408a4 Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Tue, 5 Sep 2023 20:41:23 +0530 Subject: [PATCH 20/32] cleanup --- .../helpers.ts | 142 ++++++------------ .../helpers.ts | 75 +-------- packages/js/src/utils/ata.ts | 5 - 3 files changed, 49 insertions(+), 173 deletions(-) diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts index e9a3b8acb..2ffbcaf84 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts @@ -8,17 +8,60 @@ import { } from '@solana/web3.js'; import { Convergence } from '../../Convergence'; -import { - ATAExistence, - getOrCreateATA, - getOrCreateATAtxBuilder, -} from '../../utils/ata'; +import { getOrCreateATAtxBuilder } from '../../utils/ata'; import { Mint } from '../tokenModule/models'; import { TransactionBuilder } from '../../utils/TransactionBuilder'; import { CvgWallet } from '../../utils/Wallets'; import { PsyoptionsAmericanInstrument } from './types'; import { createAmericanProgram } from './instrument'; +export const initializeNewAmericanOption = async ( + convergence: Convergence, + underlyingMint: Mint, + quoteMint: Mint, + quoteAmountPerContract: number, + underlyingAmountPerContract: number, + expiration: number +) => { + const expirationUnixTimestamp = new BN(Date.now() / 1_000 + expiration); + + const quoteAmountPerContractBN = new BN( + Number(quoteAmountPerContract) * Math.pow(10, quoteMint.decimals) + ); + const underlyingAmountPerContractBN = new BN( + Number(underlyingAmountPerContract) * Math.pow(10, underlyingMint.decimals) + ); + + const cvgWallet = new CvgWallet(convergence); + const americanProgram = createAmericanProgram(convergence, cvgWallet); + + const { optionMarketKey, optionMintKey, writerMintKey } = + await psyoptionsAmerican.instructions.initializeMarket(americanProgram, { + expirationUnixTimestamp, + quoteAmountPerContract: quoteAmountPerContractBN, + quoteMint: quoteMint.address, + underlyingAmountPerContract: underlyingAmountPerContractBN, + underlyingMint: underlyingMint.address, + }); + + const optionMarket = (await psyoptionsAmerican.getOptionByKey( + americanProgram, + optionMarketKey + )) as psyoptionsAmerican.OptionMarketWithKey; + + const optionMint = await convergence + .tokens() + .findMintByAddress({ address: optionMintKey }); + + return { + optionMarketKey, + optionMarket, + optionMintKey, + writerMintKey, + optionMint, + }; +}; + export const mintAmericanOptions = async ( convergence: Convergence, responseAddress: PublicKey, @@ -143,92 +186,3 @@ export const mintAmericanOptions = async ( ); } }; - -export const initializeNewAmericanOption = async ( - convergence: Convergence, - underlyingMint: Mint, - quoteMint: Mint, - quoteAmountPerContract: number, - underlyingAmountPerContract: number, - expiration: number -) => { - const expirationUnixTimestamp = new BN(Date.now() / 1_000 + expiration); - - const quoteAmountPerContractBN = new BN( - Number(quoteAmountPerContract) * Math.pow(10, quoteMint.decimals) - ); - const underlyingAmountPerContractBN = new BN( - Number(underlyingAmountPerContract) * Math.pow(10, underlyingMint.decimals) - ); - - const cvgWallet = new CvgWallet(convergence); - const americanProgram = createAmericanProgram(convergence, cvgWallet); - - const { optionMarketKey, optionMintKey, writerMintKey } = - await psyoptionsAmerican.instructions.initializeMarket(americanProgram, { - expirationUnixTimestamp, - quoteAmountPerContract: quoteAmountPerContractBN, - quoteMint: quoteMint.address, - underlyingAmountPerContract: underlyingAmountPerContractBN, - underlyingMint: underlyingMint.address, - }); - - const optionMarket = (await psyoptionsAmerican.getOptionByKey( - americanProgram, - optionMarketKey - )) as psyoptionsAmerican.OptionMarketWithKey; - - const optionMint = await convergence - .tokens() - .findMintByAddress({ address: optionMintKey }); - - return { - optionMarketKey, - optionMarket, - optionMintKey, - writerMintKey, - optionMint, - }; -}; - -// used in UI -export const getOrCreateAmericanOptionATAs = async ( - convergence: Convergence, - responseAddress: PublicKey, - caller: PublicKey, - americanProgram: any -): Promise => { - let flag = false; - const response = await convergence - .rfqs() - .findResponseByAddress({ address: responseAddress }); - const rfq = await convergence - .rfqs() - .findRfqByAddress({ address: response.rfq }); - - const callerSide = caller.equals(rfq.taker) ? 'taker' : 'maker'; - const { legs } = await convergence.rfqs().getSettlementResult({ - response, - rfq, - }); - for (const [index, leg] of rfq.legs.entries()) { - if (leg instanceof PsyoptionsAmericanInstrument) { - const { receiver } = legs[index]; - if (receiver !== callerSide) { - flag = true; - - const optionMarket = await psyoptionsAmerican.getOptionByKey( - americanProgram, - leg.optionMetaPubKey - ); - if (optionMarket) { - await getOrCreateATA(convergence, optionMarket.optionMint, caller); - } - } - } - } - if (flag === true) { - return ATAExistence.EXISTS; - } - return ATAExistence.NOTEXISTS; -}; diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts index 40057bc2a..dc3478698 100644 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts @@ -8,11 +8,7 @@ import { } from '@solana/web3.js'; import { BN } from 'bn.js'; import { Mint } from '../tokenModule'; -import { - ATAExistence, - getOrCreateATA, - getOrCreateATAtxBuilder, -} from '../../utils/ata'; +import { getOrCreateATAtxBuilder } from '../../utils/ata'; import { addDecimals } from '../../utils/conversions'; import { TransactionBuilder } from '../../utils/TransactionBuilder'; import { Convergence } from '../../Convergence'; @@ -47,37 +43,10 @@ export const initializeNewEuropeanOption = async ( const tx = new Transaction(); - // const underlyingPoolKey = Pda.find(europeanProgram.programId, [ - // underlyingMint.address.toBuffer(), - // Buffer.from('underlyingPool', 'utf-8'), - // ]); - // // TODO: Use retry method - // const underlyingPoolAccount = await convergence.connection.getAccountInfo( - // underlyingPoolKey - // ); - // if (underlyingPoolAccount && initializeIxs.length === 3) { - // initializeIxs = initializeIxs.slice(1); - // } - // const stablePoolKey = Pda.find(europeanProgram.programId, [ - // stableMint.address.toBuffer(), - // Buffer.from('stablePool', 'utf-8'), - // ]); - // // TODO: Use retry method - // const stablePoolAccount = await convergence.connection.getAccountInfo( - // stablePoolKey - // ); - // if (stablePoolAccount && initializeIxs.length === 2) { - // initializeIxs = initializeIxs.slice(1); - // } else if (stablePoolAccount && initializeIxs.length === 3) { - // initializeIxs.splice(1, 1); - // } - initializeIxs.forEach((ix) => { if (ixTracker.checkedAdd(ix)) tx.add(ix); }); - // const confirmOptions = makeConfirmOptionsFinalizedOnMainnet(convergence); - if (tx.instructions.length > 0) { const latestBlockHash = await convergence.rpc().getLatestBlockhash(); tx.recentBlockhash = latestBlockHash.blockhash; @@ -279,45 +248,3 @@ export const mintEuropeanOptions = async ( ); } }; - -export const getOrCreateEuropeanOptionATAs = async ( - convergence: Convergence, - responseAddress: PublicKey, - caller: PublicKey -): Promise => { - let flag = false; - const response = await convergence - .rfqs() - .findResponseByAddress({ address: responseAddress }); - const rfq = await convergence - .rfqs() - .findRfqByAddress({ address: response.rfq }); - - const callerIsTaker = caller.toBase58() === rfq.taker.toBase58(); - const callerSide = callerIsTaker ? 'taker' : 'maker'; - const { legs } = convergence.rfqs().getSettlementResult({ - response, - rfq, - }); - for (const [index, leg] of rfq.legs.entries()) { - if (leg instanceof PsyoptionsEuropeanInstrument) { - const { receiver } = legs[index]; - if (receiver !== callerSide) { - flag = true; - const euroMeta = await leg.getOptionMeta(); - const { optionType } = leg; - await getOrCreateATA( - convergence, - optionType === psyoptionsEuropean.OptionType.PUT - ? euroMeta.putOptionMint - : euroMeta.callOptionMint, - caller - ); - } - } - } - if (flag === true) { - return ATAExistence.EXISTS; - } - return ATAExistence.NOTEXISTS; -}; diff --git a/packages/js/src/utils/ata.ts b/packages/js/src/utils/ata.ts index 86fe5b384..e0851f235 100644 --- a/packages/js/src/utils/ata.ts +++ b/packages/js/src/utils/ata.ts @@ -6,11 +6,6 @@ import { TransactionBuilder } from '../utils/TransactionBuilder'; import { collateralMintCache } from '@/plugins/collateralModule/cache'; import { createTokenBuilder } from '@/plugins/tokenModule/operations/createToken'; -export enum ATAExistence { - EXISTS, - NOTEXISTS, -} - export const getOrCreateATA = async ( convergence: Convergence, mint: PublicKey, From ae5ae1c5c78c40d88c1584e73aaff41092fbd411 Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Thu, 7 Sep 2023 15:51:22 +0530 Subject: [PATCH 21/32] optimise and cleanup --- .../helpers.ts | 148 +++++++------- .../classes.ts | 49 ----- .../helpers.ts | 188 ++++++++---------- .../index.ts | 1 - .../rfqModule/operations/prepareSettlement.ts | 31 +-- packages/js/src/utils/classes.ts | 55 +++++ packages/js/src/utils/index.ts | 1 + packages/js/tests/helpers.ts | 23 ++- .../integration/psyoptionsEuropean.spec.ts | 30 ++- 9 files changed, 269 insertions(+), 257 deletions(-) delete mode 100644 packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/classes.ts create mode 100644 packages/js/src/utils/classes.ts diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts index 2ffbcaf84..ee0b867bf 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts @@ -1,17 +1,14 @@ import * as psyoptionsAmerican from '@mithraic-labs/psy-american'; import { BN } from 'bn.js'; -import { - PublicKey, - Transaction, - TransactionInstruction, -} from '@solana/web3.js'; +import { PublicKey, Transaction } from '@solana/web3.js'; import { Convergence } from '../../Convergence'; import { getOrCreateATAtxBuilder } from '../../utils/ata'; import { Mint } from '../tokenModule/models'; import { TransactionBuilder } from '../../utils/TransactionBuilder'; import { CvgWallet } from '../../utils/Wallets'; +import { InstructionUniquenessTracker } from '../../utils/classes'; import { PsyoptionsAmericanInstrument } from './types'; import { createAmericanProgram } from './instrument'; @@ -61,12 +58,13 @@ export const initializeNewAmericanOption = async ( optionMint, }; }; - -export const mintAmericanOptions = async ( +//create American Options ATAs and mint Options +export const prepareAmericanOptions = async ( convergence: Convergence, responseAddress: PublicKey, caller: PublicKey ) => { + const ixTracker = new InstructionUniquenessTracker([]); const cvgWallet = new CvgWallet(convergence); const americanProgram = createAmericanProgram(convergence, cvgWallet); const response = await convergence @@ -86,71 +84,77 @@ export const mintAmericanOptions = async ( const ataTxBuilderArray: TransactionBuilder[] = []; const mintTxBuilderArray: TransactionBuilder[] = []; for (const [index, leg] of rfq.legs.entries()) { - const mintInstructions: TransactionInstruction[] = []; - if (leg instanceof PsyoptionsAmericanInstrument) { - const { receiver, amount } = legs[index]; - if (receiver !== callerSide) { - const optionMarket = await leg.getOptionMeta(); - if (optionMarket) { - const optionToken = await getOrCreateATAtxBuilder( - convergence, - optionMarket.optionMint, - caller - ); - if (optionToken.txBuilder) { - ataTxBuilderArray.push(optionToken.txBuilder); - } - const writerToken = await getOrCreateATAtxBuilder( - convergence, - optionMarket!.writerTokenMint, - caller - ); - if (writerToken.txBuilder) { - ataTxBuilderArray.push(writerToken.txBuilder); - } - const underlyingToken = await getOrCreateATAtxBuilder( - convergence, - optionMarket!.underlyingAssetMint, - caller - ); - if (underlyingToken.txBuilder) { - ataTxBuilderArray.push(underlyingToken.txBuilder); - } - const ixWithSigners = - await psyoptionsAmerican.instructions.mintOptionV2Instruction( - americanProgram, - optionToken.ataPubKey, - writerToken.ataPubKey, - underlyingToken.ataPubKey, - new BN(amount!), - optionMarket as psyoptionsAmerican.OptionMarketWithKey - ); - ixWithSigners.ix.keys[0] = { - pubkey: caller, - isSigner: true, - isWritable: false, - }; - mintInstructions.push(ixWithSigners.ix); - } - } + const { receiver, amount } = legs[index]; + if ( + !(leg instanceof PsyoptionsAmericanInstrument) || + receiver === callerSide + ) { + continue; } - if (mintInstructions.length > 0) { - const txBuilder = TransactionBuilder.make().setFeePayer( + + const optionMarket = await leg.getOptionMeta(); + if (optionMarket) { + const optionToken = await getOrCreateATAtxBuilder( + convergence, + optionMarket.optionMint, + caller + ); + if ( + optionToken.txBuilder && + ixTracker.checkedAdd(optionToken.txBuilder) + ) { + ataTxBuilderArray.push(optionToken.txBuilder); + } + const writerToken = await getOrCreateATAtxBuilder( + convergence, + optionMarket!.writerTokenMint, + caller + ); + if ( + writerToken.txBuilder && + ixTracker.checkedAdd(writerToken.txBuilder) + ) { + ataTxBuilderArray.push(writerToken.txBuilder); + } + const underlyingToken = await getOrCreateATAtxBuilder( + convergence, + optionMarket!.underlyingAssetMint, + caller + ); + if ( + underlyingToken.txBuilder && + ixTracker.checkedAdd(underlyingToken.txBuilder) + ) { + ataTxBuilderArray.push(underlyingToken.txBuilder); + } + const ixWithSigners = + await psyoptionsAmerican.instructions.mintOptionInstruction( + americanProgram, + optionToken.ataPubKey, + writerToken.ataPubKey, + underlyingToken.ataPubKey, + new BN(amount!), + optionMarket as psyoptionsAmerican.OptionMarketWithKey + ); + ixWithSigners.ix.keys[0] = { + pubkey: caller, + isSigner: true, + isWritable: false, + }; + const mintTxBuilder = TransactionBuilder.make().setFeePayer( convergence.rpc().getDefaultFeePayer() ); - mintInstructions.forEach((ins) => { - txBuilder.add({ - instruction: ins, - signers: [convergence.identity()], - }); + mintTxBuilder.add({ + instruction: ixWithSigners.ix, + signers: [convergence.identity()], }); - mintTxBuilderArray.push(txBuilder); + mintTxBuilderArray.push(mintTxBuilder); } } let signedTxs: Transaction[] = []; + const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); if (ataTxBuilderArray.length > 0 || mintTxBuilderArray.length > 0) { const mergedTxBuilderArray = ataTxBuilderArray.concat(mintTxBuilderArray); - const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); signedTxs = await convergence .identity() .signAllTransactions( @@ -163,26 +167,20 @@ export const mintAmericanOptions = async ( if (ataSignedTx.length > 0) { await Promise.all( - ataSignedTx.map(async (signedTx) => { - const lastValidBlockHeight = await convergence - .rpc() - .getLatestBlockhash(); + ataSignedTx.map((signedTx) => convergence .rpc() - .serializeAndSendTransaction(signedTx, lastValidBlockHeight); - }) + .serializeAndSendTransaction(signedTx, lastValidBlockHeight) + ) ); } if (mintSignedTx.length > 0) { await Promise.all( - mintSignedTx.map(async (signedTx) => { - const lastValidBlockHeight = await convergence - .rpc() - .getLatestBlockhash(); + mintSignedTx.map((signedTx) => convergence .rpc() - .serializeAndSendTransaction(signedTx, lastValidBlockHeight); - }) + .serializeAndSendTransaction(signedTx, lastValidBlockHeight) + ) ); } }; diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/classes.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/classes.ts deleted file mode 100644 index 96f7ef5a0..000000000 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/classes.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { AccountMeta, TransactionInstruction } from '@solana/web3.js'; - -export class InstructionUniquenessTracker { - constructor(public readonly IxArray: TransactionInstruction[]) { - this.IxArray = IxArray; - } - - private matchKeys = ( - keys: AccountMeta[], - keysToMatch: AccountMeta[] - ): boolean => { - let matching = true; - if (keys.length !== keysToMatch.length) { - return false; - } - for (let i = 0; i < keys.length; i++) { - if ( - keys[i].isSigner !== keysToMatch[i].isSigner || - keys[i].isWritable !== keysToMatch[i].isWritable || - !keys[i].pubkey.equals(keysToMatch[i].pubkey) - ) { - matching = false; - break; - } - } - return matching; - }; - private matchInstruction = (ixToBeAdded: TransactionInstruction): boolean => { - let match = false; - this.IxArray.forEach((ix) => { - if ( - this.matchKeys(ix.keys, ixToBeAdded.keys) && - ix.programId.equals(ixToBeAdded.programId) && - ix.data.equals(ixToBeAdded.data) - ) { - match = true; - return match; - } - }); - return match; - }; - checkedAdd(ix: TransactionInstruction): boolean { - if (!this.matchInstruction(ix)) { - this.IxArray.push(ix); - return true; - } - return false; - } -} diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts index dc3478698..76ec58c0c 100644 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts @@ -1,19 +1,14 @@ import * as psyoptionsEuropean from '@mithraic-labs/tokenized-euros'; import * as anchor from '@project-serum/anchor'; -import { - Keypair, - PublicKey, - Transaction, - TransactionInstruction, -} from '@solana/web3.js'; +import { Keypair, PublicKey, Transaction } from '@solana/web3.js'; import { BN } from 'bn.js'; import { Mint } from '../tokenModule'; import { getOrCreateATAtxBuilder } from '../../utils/ata'; import { addDecimals } from '../../utils/conversions'; import { TransactionBuilder } from '../../utils/TransactionBuilder'; import { Convergence } from '../../Convergence'; +import { InstructionUniquenessTracker } from '../../utils/classes'; import { PsyoptionsEuropeanInstrument } from './instrument'; -import { InstructionUniquenessTracker } from './classes'; import { toBigNumber } from '@/types/BigNumber'; export const initializeNewEuropeanOption = async ( @@ -46,9 +41,8 @@ export const initializeNewEuropeanOption = async ( initializeIxs.forEach((ix) => { if (ixTracker.checkedAdd(ix)) tx.add(ix); }); - + const latestBlockHash = await convergence.rpc().getLatestBlockhash(); if (tx.instructions.length > 0) { - const latestBlockHash = await convergence.rpc().getLatestBlockhash(); tx.recentBlockhash = latestBlockHash.blockhash; tx.feePayer = convergence.rpc().getDefaultFeePayer().publicKey; await convergence.identity().signTransaction(tx); @@ -82,7 +76,6 @@ export const initializeNewEuropeanOption = async ( if (ixTracker.checkedAdd(createIx)) { const createTx = new Transaction().add(createIx); - const latestBlockHash = await convergence.rpc().getLatestBlockhash(); createTx.recentBlockhash = latestBlockHash.blockhash; createTx.feePayer = convergence.rpc().getDefaultFeePayer().publicKey; const signedTx = await convergence.identity().signTransaction(createTx); @@ -106,11 +99,13 @@ export const createEuropeanProgram = async (convergence: Convergence) => { ); }; -export const mintEuropeanOptions = async ( +// create European Option ATAs and mint options +export const prepareEuropeanOptions = async ( convergence: Convergence, responseAddress: PublicKey, caller: PublicKey ) => { + const ixTracker = new InstructionUniquenessTracker([]); const europeanProgram = await createEuropeanProgram(convergence); const response = await convergence .rfqs() @@ -128,91 +123,90 @@ export const mintEuropeanOptions = async ( const mintTxBuilderArray: TransactionBuilder[] = []; const ataTxBuilderArray: TransactionBuilder[] = []; for (const [index, leg] of rfq.legs.entries()) { - const mintInstructions: TransactionInstruction[] = []; - if (leg instanceof PsyoptionsEuropeanInstrument) { - const { receiver, amount } = legs[index]; - if (receiver !== callerSide) { - const euroMeta = await leg.getOptionMeta(); - const { stableMint } = euroMeta; - const { underlyingMint } = euroMeta; - const stableMintToken = convergence - .tokens() - .pdas() - .associatedTokenAccount({ - mint: stableMint, - owner: caller, - }); - const underlyingMintToken = convergence - .tokens() - .pdas() - .associatedTokenAccount({ - mint: underlyingMint, - owner: caller, - }); - const minterCollateralKey = - leg.optionType == psyoptionsEuropean.OptionType.PUT - ? stableMintToken - : underlyingMintToken; - - const optionDestination = await getOrCreateATAtxBuilder( - convergence, - leg.optionType == psyoptionsEuropean.OptionType.PUT - ? euroMeta.putOptionMint - : euroMeta.callOptionMint, - caller - ); - - if (optionDestination.txBuilder) { - ataTxBuilderArray.push(optionDestination.txBuilder); - } - const writerDestination = await getOrCreateATAtxBuilder( - convergence, - leg.optionType == psyoptionsEuropean.OptionType.PUT - ? euroMeta.putWriterMint - : euroMeta.callWriterMint, - caller - ); - if (writerDestination.txBuilder) { - ataTxBuilderArray.push(writerDestination.txBuilder); - } - const { instruction: ix } = psyoptionsEuropean.instructions.mintOptions( - europeanProgram, - leg.optionMetaPubKey, - euroMeta as psyoptionsEuropean.EuroMeta, - minterCollateralKey, - optionDestination.ataPubKey, - writerDestination.ataPubKey, - addDecimals(amount, PsyoptionsEuropeanInstrument.decimals), - leg.optionType - ); - - ix.keys[0] = { - pubkey: caller, - isSigner: true, - isWritable: false, - }; - - mintInstructions.push(ix); - } + const { receiver, amount } = legs[index]; + if ( + !(leg instanceof PsyoptionsEuropeanInstrument) || + receiver === callerSide + ) { + continue; } - if (mintInstructions.length > 0) { - const txBuilder = TransactionBuilder.make().setFeePayer( - convergence.rpc().getDefaultFeePayer() - ); - mintInstructions.forEach((ins) => { - txBuilder.add({ - instruction: ins, - signers: [convergence.identity()], - }); + const euroMeta = await leg.getOptionMeta(); + const { stableMint } = euroMeta; + const { underlyingMint } = euroMeta; + const stableMintToken = convergence.tokens().pdas().associatedTokenAccount({ + mint: stableMint, + owner: caller, + }); + const underlyingMintToken = convergence + .tokens() + .pdas() + .associatedTokenAccount({ + mint: underlyingMint, + owner: caller, }); - mintTxBuilderArray.push(txBuilder); + const minterCollateralKey = + leg.optionType == psyoptionsEuropean.OptionType.PUT + ? stableMintToken + : underlyingMintToken; + + const optionDestination = await getOrCreateATAtxBuilder( + convergence, + leg.optionType == psyoptionsEuropean.OptionType.PUT + ? euroMeta.putOptionMint + : euroMeta.callOptionMint, + caller + ); + + if ( + optionDestination.txBuilder && + ixTracker.checkedAdd(optionDestination.txBuilder) + ) { + ataTxBuilderArray.push(optionDestination.txBuilder); } + const writerDestination = await getOrCreateATAtxBuilder( + convergence, + leg.optionType == psyoptionsEuropean.OptionType.PUT + ? euroMeta.putWriterMint + : euroMeta.callWriterMint, + caller + ); + if ( + writerDestination.txBuilder && + ixTracker.checkedAdd(writerDestination.txBuilder) + ) { + ataTxBuilderArray.push(writerDestination.txBuilder); + } + const { instruction: ix } = psyoptionsEuropean.instructions.mintOptions( + europeanProgram, + leg.optionMetaPubKey, + euroMeta as psyoptionsEuropean.EuroMeta, + minterCollateralKey, + optionDestination.ataPubKey, + writerDestination.ataPubKey, + addDecimals(amount, PsyoptionsEuropeanInstrument.decimals), + leg.optionType + ); + + ix.keys[0] = { + pubkey: caller, + isSigner: true, + isWritable: false, + }; + + const mintTxBuilder = TransactionBuilder.make().setFeePayer( + convergence.rpc().getDefaultFeePayer() + ); + mintTxBuilder.add({ + instruction: ix, + signers: [convergence.identity()], + }); + mintTxBuilderArray.push(mintTxBuilder); } let signedTxs: Transaction[] = []; + const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); if (ataTxBuilderArray.length > 0 || mintTxBuilderArray.length > 0) { const mergedTxBuilderArray = ataTxBuilderArray.concat(mintTxBuilderArray); - const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); signedTxs = await convergence .identity() .signAllTransactions( @@ -225,26 +219,20 @@ export const mintEuropeanOptions = async ( if (ataSignedTx.length > 0) { await Promise.all( - ataSignedTx.map(async (signedTx) => { - const lastValidBlockHeight = await convergence - .rpc() - .getLatestBlockhash(); + ataSignedTx.map((signedTx) => convergence .rpc() - .serializeAndSendTransaction(signedTx, lastValidBlockHeight); - }) + .serializeAndSendTransaction(signedTx, lastValidBlockHeight) + ) ); } if (mintSignedTx.length > 0) { await Promise.all( - mintSignedTx.map(async (signedTx) => { - const lastValidBlockHeight = await convergence - .rpc() - .getLatestBlockhash(); + mintSignedTx.map((signedTx) => convergence .rpc() - .serializeAndSendTransaction(signedTx, lastValidBlockHeight); - }) + .serializeAndSendTransaction(signedTx, lastValidBlockHeight) + ) ); } }; diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/index.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/index.ts index 494a78f01..401a3592d 100644 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/index.ts +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/index.ts @@ -3,4 +3,3 @@ export * from './plugin'; export * from './types'; export * from './programs'; export * from './helpers'; -export * from './classes'; diff --git a/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts b/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts index ebdad6870..03272f574 100644 --- a/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts +++ b/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts @@ -30,10 +30,13 @@ import { Mint } from '../../tokenModule'; import { InstrumentPdasClient } from '../../instrumentModule'; import { legToBaseAssetMint } from '@/plugins/instrumentModule'; import { - mintAmericanOptions, + prepareAmericanOptions, psyoptionsAmericanInstrumentProgram, } from '@/plugins/psyoptionsAmericanInstrumentModule'; -import { mintEuropeanOptions } from '@/plugins/psyoptionsEuropeanInstrumentModule'; +import { + prepareEuropeanOptions, + psyoptionsEuropeanInstrumentProgram, +} from '@/plugins/psyoptionsEuropeanInstrumentModule'; const Key = 'PrepareSettlementOperation' as const; @@ -128,11 +131,11 @@ export const prepareSettlementOperationHandler: OperationHandler { - const american = rfq.legs.some((leg) => +const doesRfqLegContainsPsyoptionsAmerican = (rfq: Rfq) => { + return rfq.legs.some((leg) => leg.getProgramId().equals(psyoptionsAmericanInstrumentProgram.address) ); - if (american) { - return 'american'; - } - return 'european'; +}; + +const doesRfqLegContainsPsyoptionsEuropean = (rfq: Rfq) => { + return rfq.legs.some((leg) => + leg.getProgramId().equals(psyoptionsEuropeanInstrumentProgram.address) + ); }; diff --git a/packages/js/src/utils/classes.ts b/packages/js/src/utils/classes.ts new file mode 100644 index 000000000..1107ae50f --- /dev/null +++ b/packages/js/src/utils/classes.ts @@ -0,0 +1,55 @@ +import { AccountMeta, TransactionInstruction } from '@solana/web3.js'; +import { TransactionBuilder } from './TransactionBuilder'; + +export class InstructionUniquenessTracker { + constructor(public readonly IxArray: TransactionInstruction[]) { + this.IxArray = IxArray; + } + + private matchKeys = ( + keys: AccountMeta[], + keysToMatch: AccountMeta[] + ): boolean => { + if (keys.length !== keysToMatch.length) { + return false; + } + return keys.every( + (key, index) => + key.isSigner === keysToMatch[index].isSigner && + key.isWritable === keysToMatch[index].isWritable && + key.pubkey.equals(keysToMatch[index].pubkey) + ); + }; + private matchInstruction = (ixToBeAdded: TransactionInstruction): boolean => { + this.IxArray.forEach((ix) => { + if ( + this.matchKeys(ix.keys, ixToBeAdded.keys) && + ix.programId.equals(ixToBeAdded.programId) && + ix.data.equals(ixToBeAdded.data) + ) + return true; + }); + return false; + }; + checkedAdd(ix: TransactionInstruction | TransactionBuilder): boolean { + if (ix instanceof TransactionBuilder) { + const instructions = ix.getInstructions(); + const ixLength = instructions.length; + let checked = 0; + instructions.forEach((ix) => { + if (!this.matchInstruction(ix)) { + this.IxArray.push(ix); + checked++; + } + }); + return checked === ixLength; + } else if (ix instanceof TransactionInstruction) { + if (!this.matchInstruction(ix)) { + this.IxArray.push(ix); + return true; + } + return false; + } + throw new Error('Invalid Instruction type'); + } +} diff --git a/packages/js/src/utils/index.ts b/packages/js/src/utils/index.ts index c6caca0ba..47ca604ba 100644 --- a/packages/js/src/utils/index.ts +++ b/packages/js/src/utils/index.ts @@ -12,3 +12,4 @@ export * from './Wallets'; export * from './cache'; export * from './conversions'; export * from './ata'; +export * from './classes'; diff --git a/packages/js/tests/helpers.ts b/packages/js/tests/helpers.ts index d09c342da..6fd6e68bb 100644 --- a/packages/js/tests/helpers.ts +++ b/packages/js/tests/helpers.ts @@ -3,6 +3,7 @@ import { PROGRAM_ID } from '@convergence-rfq/rfq'; import { v4 as uuidv4 } from 'uuid'; import { Program, web3 } from '@project-serum/anchor'; import * as anchor from '@project-serum/anchor'; +import { EuroPrimitive } from '@mithraic-labs/tokenized-euros'; import { Convergence, OrderType, @@ -12,18 +13,17 @@ import { toBigNumber, Rfq, Response, - mintAmericanOptions, + prepareAmericanOptions, SpotQuoteInstrument, SpotLegInstrument, keypairIdentity, PublicKey, removeDecimals, useCache, - createEuropeanProgram, CvgWallet, PsyoptionsEuropeanInstrument, initializeNewEuropeanOption, - mintEuropeanOptions, + prepareEuropeanOptions, InstructionUniquenessTracker, } from '../src'; import { getUserKp, RPC_ENDPOINT } from '../../validator'; @@ -150,9 +150,9 @@ export const createEuropeanCoveredCallRfq = async ( orderType: OrderType, baseMint: any, quoteMint: any, - ixTracker: InstructionUniquenessTracker + ixTracker: InstructionUniquenessTracker, + europeanProgram: Program ) => { - const europeanProgram = await createEuropeanProgram(cvg); const oracle = await createPythPriceFeed( new anchor.Program( PseudoPythIdl, @@ -202,9 +202,9 @@ export const createEuropeanOpenSizeCallSpdOptionRfq = async ( orderType: OrderType, baseMint: any, quoteMint: any, - ixTracker: InstructionUniquenessTracker + ixTracker: InstructionUniquenessTracker, + europeanProgram: Program ) => { - const europeanProgram = await createEuropeanProgram(cvg); const oracle = await createPythPriceFeed( new anchor.Program( PseudoPythIdl, @@ -229,6 +229,7 @@ export const createEuropeanOpenSizeCallSpdOptionRfq = async ( randomExpiry, 0 ); + await sleep(2); const { euroMeta: euroMeta2, euroMetaKey: euroMetaKey2 } = await initializeNewEuropeanOption( cvg, @@ -323,9 +324,9 @@ export const createEuropeanFixedBaseStraddle = async ( orderType: OrderType, baseMint: any, quoteMint: any, - ixTracker: InstructionUniquenessTracker + ixTracker: InstructionUniquenessTracker, + europeanProgram: Program ) => { - const europeanProgram = await createEuropeanProgram(cvg); const oracle = await createPythPriceFeed( new anchor.Program( PseudoPythIdl, @@ -657,11 +658,11 @@ export const createPythPriceFeed = async ( }; export const setupAmerican = async (cvg: Convergence, response: Response) => { - await mintAmericanOptions(cvg, response.address, cvg.identity().publicKey); + await prepareAmericanOptions(cvg, response.address, cvg.identity().publicKey); }; export const setupEuropean = async (cvg: Convergence, response: Response) => { - await mintEuropeanOptions( + await prepareEuropeanOptions( cvg, response.address, cvg.rpc().getDefaultFeePayer().publicKey diff --git a/packages/js/tests/integration/psyoptionsEuropean.spec.ts b/packages/js/tests/integration/psyoptionsEuropean.spec.ts index 6ac0760cc..0bbd2bca9 100644 --- a/packages/js/tests/integration/psyoptionsEuropean.spec.ts +++ b/packages/js/tests/integration/psyoptionsEuropean.spec.ts @@ -1,6 +1,8 @@ import { expect } from 'expect'; import { Mint } from '@solana/spl-token'; +import { Program } from '@project-serum/anchor'; +import { EuroPrimitive } from '@mithraic-labs/tokenized-euros'; import { prepareRfqSettlement, respondToRfq, @@ -9,15 +11,18 @@ import { createEuropeanCoveredCallRfq, createEuropeanOpenSizeCallSpdOptionRfq, createEuropeanFixedBaseStraddle, + sleep, } from '../helpers'; import { BASE_MINT_BTC_PK, QUOTE_MINT_PK } from '../constants'; -import { InstructionUniquenessTracker } from '../../src'; +import { InstructionUniquenessTracker } from '../../src/utils/'; +import { createEuropeanProgram } from '../../src'; describe('integration.psyoptionsEuropean', () => { const takerCvg = createUserCvg('taker'); const makerCvg = createUserCvg('maker'); let baseMint: Mint; let quoteMint: Mint; + let europeanProgram: Program; const ixTracker = new InstructionUniquenessTracker([]); before(async () => { baseMint = await takerCvg @@ -26,6 +31,7 @@ describe('integration.psyoptionsEuropean', () => { quoteMint = await takerCvg .tokens() .findMintByAddress({ address: QUOTE_MINT_PK }); + europeanProgram = await createEuropeanProgram(takerCvg); }); it('european covered call [sell]', async () => { @@ -34,7 +40,8 @@ describe('integration.psyoptionsEuropean', () => { 'sell', baseMint, quoteMint, - ixTracker + ixTracker, + europeanProgram ); expect(rfq).toHaveProperty('address'); @@ -50,6 +57,7 @@ describe('integration.psyoptionsEuropean', () => { await prepareRfqSettlement(takerCvg, rfq, rfqResponse); await settleRfq(takerCvg, rfq, rfqResponse); + await sleep(1); }); it('fixed-size european straddle [buy]', async () => { @@ -58,7 +66,8 @@ describe('integration.psyoptionsEuropean', () => { 'buy', baseMint, quoteMint, - ixTracker + ixTracker, + europeanProgram ); expect(rfq).toHaveProperty('address'); const { rfqResponse } = await respondToRfq( @@ -100,7 +109,8 @@ describe('integration.psyoptionsEuropean', () => { 'buy', baseMint, quoteMint, - ixTracker + ixTracker, + europeanProgram ); expect(rfq).toHaveProperty('address'); const { rfqResponse } = await respondToRfq( @@ -145,7 +155,8 @@ describe('integration.psyoptionsEuropean', () => { 'sell', baseMint, quoteMint, - ixTracker + ixTracker, + europeanProgram ); expect(rfq).toHaveProperty('address'); const { rfqResponse } = await respondToRfq( @@ -187,7 +198,8 @@ describe('integration.psyoptionsEuropean', () => { 'two-way', baseMint, quoteMint, - ixTracker + ixTracker, + europeanProgram ); expect(rfq).toHaveProperty('address'); const { rfqResponse } = await respondToRfq( @@ -232,7 +244,8 @@ describe('integration.psyoptionsEuropean', () => { 'two-way', baseMint, quoteMint, - ixTracker + ixTracker, + europeanProgram ); expect(rfq).toHaveProperty('address'); const { rfqResponse } = await respondToRfq(makerCvg, rfq, 61_222, 60_123); @@ -269,7 +282,8 @@ describe('integration.psyoptionsEuropean', () => { 'sell', baseMint, quoteMint, - ixTracker + ixTracker, + europeanProgram ); expect(rfq).toHaveProperty('address'); const { rfqResponse } = await respondToRfq( From 2dfa4f7057903a3ee6a17e1fcc4f99242cd62533 Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Thu, 7 Sep 2023 17:04:20 +0530 Subject: [PATCH 22/32] fix createEuropeanProgram --- .../psyoptionsEuropeanInstrumentModule/helpers.ts | 11 ++++++++--- packages/js/tests/helpers.ts | 1 - .../js/tests/integration/psyoptionsEuropean.spec.ts | 2 -- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts index 76ec58c0c..396c062a0 100644 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts @@ -10,6 +10,7 @@ import { Convergence } from '../../Convergence'; import { InstructionUniquenessTracker } from '../../utils/classes'; import { PsyoptionsEuropeanInstrument } from './instrument'; import { toBigNumber } from '@/types/BigNumber'; +import { CvgWallet } from '@/index'; export const initializeNewEuropeanOption = async ( convergence: Convergence, @@ -92,9 +93,13 @@ export const initializeNewEuropeanOption = async ( }; export const createEuropeanProgram = async (convergence: Convergence) => { - return psyoptionsEuropean.createProgram( - convergence.rpc().getDefaultFeePayer() as Keypair, - convergence.connection.rpcEndpoint, + const cvgWallet = new CvgWallet(convergence); + return psyoptionsEuropean.createProgramFromProvider( + new anchor.AnchorProvider( + convergence.connection, + cvgWallet, + anchor.AnchorProvider.defaultOptions() + ), new PublicKey(psyoptionsEuropean.programId) ); }; diff --git a/packages/js/tests/helpers.ts b/packages/js/tests/helpers.ts index 6fd6e68bb..daa1c2a97 100644 --- a/packages/js/tests/helpers.ts +++ b/packages/js/tests/helpers.ts @@ -229,7 +229,6 @@ export const createEuropeanOpenSizeCallSpdOptionRfq = async ( randomExpiry, 0 ); - await sleep(2); const { euroMeta: euroMeta2, euroMetaKey: euroMetaKey2 } = await initializeNewEuropeanOption( cvg, diff --git a/packages/js/tests/integration/psyoptionsEuropean.spec.ts b/packages/js/tests/integration/psyoptionsEuropean.spec.ts index 0bbd2bca9..878fa3697 100644 --- a/packages/js/tests/integration/psyoptionsEuropean.spec.ts +++ b/packages/js/tests/integration/psyoptionsEuropean.spec.ts @@ -11,7 +11,6 @@ import { createEuropeanCoveredCallRfq, createEuropeanOpenSizeCallSpdOptionRfq, createEuropeanFixedBaseStraddle, - sleep, } from '../helpers'; import { BASE_MINT_BTC_PK, QUOTE_MINT_PK } from '../constants'; import { InstructionUniquenessTracker } from '../../src/utils/'; @@ -57,7 +56,6 @@ describe('integration.psyoptionsEuropean', () => { await prepareRfqSettlement(takerCvg, rfq, rfqResponse); await settleRfq(takerCvg, rfq, rfqResponse); - await sleep(1); }); it('fixed-size european straddle [buy]', async () => { From c769c1f91c9bb05cc6ad5ec9b389cadcab661302 Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Thu, 7 Sep 2023 17:10:44 +0530 Subject: [PATCH 23/32] cleanup --- .../src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts index 396c062a0..ce4407bf2 100644 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts @@ -1,6 +1,6 @@ import * as psyoptionsEuropean from '@mithraic-labs/tokenized-euros'; import * as anchor from '@project-serum/anchor'; -import { Keypair, PublicKey, Transaction } from '@solana/web3.js'; +import { PublicKey, Transaction } from '@solana/web3.js'; import { BN } from 'bn.js'; import { Mint } from '../tokenModule'; import { getOrCreateATAtxBuilder } from '../../utils/ata'; @@ -8,9 +8,9 @@ import { addDecimals } from '../../utils/conversions'; import { TransactionBuilder } from '../../utils/TransactionBuilder'; import { Convergence } from '../../Convergence'; import { InstructionUniquenessTracker } from '../../utils/classes'; +import { CvgWallet } from '../../utils/Wallets'; import { PsyoptionsEuropeanInstrument } from './instrument'; import { toBigNumber } from '@/types/BigNumber'; -import { CvgWallet } from '@/index'; export const initializeNewEuropeanOption = async ( convergence: Convergence, From fa7b6d3f4f5fc417b5281f9e4db32d5da19c56e4 Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Thu, 7 Sep 2023 17:18:55 +0530 Subject: [PATCH 24/32] fix settlementResult tests --- packages/js/tests/unit/settlementResult.spec.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/js/tests/unit/settlementResult.spec.ts b/packages/js/tests/unit/settlementResult.spec.ts index e9e7ba902..4d9d37b1c 100644 --- a/packages/js/tests/unit/settlementResult.spec.ts +++ b/packages/js/tests/unit/settlementResult.spec.ts @@ -1,5 +1,7 @@ import expect from 'expect'; import { Mint } from '@solana/spl-token'; +import { EuroPrimitive } from '@mithraic-labs/tokenized-euros'; +import { Program } from '@project-serum/anchor'; import { createAmericanCoveredCallRfq, createEuropeanCoveredCallRfq, @@ -12,13 +14,14 @@ import { QUOTE_MINT_DECIMALS, QUOTE_MINT_PK, } from '../constants'; -import { InstructionUniquenessTracker } from '../../src'; +import { InstructionUniquenessTracker, createEuropeanProgram } from '../../src'; describe('unit.settlementResult', () => { const takerCvg = createUserCvg('taker'); const makerCvg = createUserCvg('maker'); let baseMint: Mint; let quoteMint: Mint; + let europeanProgram: Program; const ixTracker = new InstructionUniquenessTracker([]); before(async () => { baseMint = await takerCvg @@ -27,6 +30,7 @@ describe('unit.settlementResult', () => { quoteMint = await takerCvg .tokens() .findMintByAddress({ address: QUOTE_MINT_PK }); + europeanProgram = await createEuropeanProgram(takerCvg); }); it('fixed-base buy', async () => { @@ -373,7 +377,8 @@ describe('unit.settlementResult', () => { 'sell', baseMint, quoteMint, - ixTracker + ixTracker, + europeanProgram ); expect(rfq).toHaveProperty('address'); expect(response.signature).toBeDefined(); From 6937fb71c39f3c0e5ce4c829002b63b1e3906d27 Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Fri, 8 Sep 2023 20:44:41 +0530 Subject: [PATCH 25/32] resolve comments --- .../helpers.ts | 107 +++++++++--------- .../helpers.ts | 3 +- packages/js/src/utils/classes.ts | 7 +- 3 files changed, 57 insertions(+), 60 deletions(-) diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts index ee0b867bf..c869c4379 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts @@ -93,63 +93,58 @@ export const prepareAmericanOptions = async ( } const optionMarket = await leg.getOptionMeta(); - if (optionMarket) { - const optionToken = await getOrCreateATAtxBuilder( - convergence, - optionMarket.optionMint, - caller - ); - if ( - optionToken.txBuilder && - ixTracker.checkedAdd(optionToken.txBuilder) - ) { - ataTxBuilderArray.push(optionToken.txBuilder); - } - const writerToken = await getOrCreateATAtxBuilder( - convergence, - optionMarket!.writerTokenMint, - caller - ); - if ( - writerToken.txBuilder && - ixTracker.checkedAdd(writerToken.txBuilder) - ) { - ataTxBuilderArray.push(writerToken.txBuilder); - } - const underlyingToken = await getOrCreateATAtxBuilder( - convergence, - optionMarket!.underlyingAssetMint, - caller - ); - if ( - underlyingToken.txBuilder && - ixTracker.checkedAdd(underlyingToken.txBuilder) - ) { - ataTxBuilderArray.push(underlyingToken.txBuilder); - } - const ixWithSigners = - await psyoptionsAmerican.instructions.mintOptionInstruction( - americanProgram, - optionToken.ataPubKey, - writerToken.ataPubKey, - underlyingToken.ataPubKey, - new BN(amount!), - optionMarket as psyoptionsAmerican.OptionMarketWithKey - ); - ixWithSigners.ix.keys[0] = { - pubkey: caller, - isSigner: true, - isWritable: false, - }; - const mintTxBuilder = TransactionBuilder.make().setFeePayer( - convergence.rpc().getDefaultFeePayer() - ); - mintTxBuilder.add({ - instruction: ixWithSigners.ix, - signers: [convergence.identity()], - }); - mintTxBuilderArray.push(mintTxBuilder); + if (!optionMarket) { + continue; + } + const optionToken = await getOrCreateATAtxBuilder( + convergence, + optionMarket.optionMint, + caller + ); + if (optionToken.txBuilder && ixTracker.checkedAdd(optionToken.txBuilder)) { + ataTxBuilderArray.push(optionToken.txBuilder); + } + const writerToken = await getOrCreateATAtxBuilder( + convergence, + optionMarket!.writerTokenMint, + caller + ); + if (writerToken.txBuilder && ixTracker.checkedAdd(writerToken.txBuilder)) { + ataTxBuilderArray.push(writerToken.txBuilder); + } + const underlyingToken = await getOrCreateATAtxBuilder( + convergence, + optionMarket!.underlyingAssetMint, + caller + ); + if ( + underlyingToken.txBuilder && + ixTracker.checkedAdd(underlyingToken.txBuilder) + ) { + ataTxBuilderArray.push(underlyingToken.txBuilder); } + const ixWithSigners = + await psyoptionsAmerican.instructions.mintOptionInstruction( + americanProgram, + optionToken.ataPubKey, + writerToken.ataPubKey, + underlyingToken.ataPubKey, + new BN(amount!), + optionMarket as psyoptionsAmerican.OptionMarketWithKey + ); + ixWithSigners.ix.keys[0] = { + pubkey: caller, + isSigner: true, + isWritable: false, + }; + const mintTxBuilder = TransactionBuilder.make().setFeePayer( + convergence.rpc().getDefaultFeePayer() + ); + mintTxBuilder.add({ + instruction: ixWithSigners.ix, + signers: [convergence.identity()], + }); + mintTxBuilderArray.push(mintTxBuilder); } let signedTxs: Transaction[] = []; const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts index ce4407bf2..faaf4c734 100644 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts @@ -136,8 +136,7 @@ export const prepareEuropeanOptions = async ( continue; } const euroMeta = await leg.getOptionMeta(); - const { stableMint } = euroMeta; - const { underlyingMint } = euroMeta; + const { stableMint, underlyingMint } = euroMeta; const stableMintToken = convergence.tokens().pdas().associatedTokenAccount({ mint: stableMint, owner: caller, diff --git a/packages/js/src/utils/classes.ts b/packages/js/src/utils/classes.ts index 1107ae50f..03ba7a744 100644 --- a/packages/js/src/utils/classes.ts +++ b/packages/js/src/utils/classes.ts @@ -38,11 +38,14 @@ export class InstructionUniquenessTracker { let checked = 0; instructions.forEach((ix) => { if (!this.matchInstruction(ix)) { - this.IxArray.push(ix); checked++; } }); - return checked === ixLength; + if (checked === ixLength) { + this.IxArray.push(...instructions); + return true; + } + return false; } else if (ix instanceof TransactionInstruction) { if (!this.matchInstruction(ix)) { this.IxArray.push(ix); From 85aa4532ff1aadecefb0814e786a2337433db23f Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Mon, 11 Sep 2023 17:06:19 +0530 Subject: [PATCH 26/32] resolve comments --- .../helpers.ts | 3 --- packages/js/src/utils/classes.ts | 21 ++++++++++--------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts index c869c4379..1bf7aecd0 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts @@ -93,9 +93,6 @@ export const prepareAmericanOptions = async ( } const optionMarket = await leg.getOptionMeta(); - if (!optionMarket) { - continue; - } const optionToken = await getOrCreateATAtxBuilder( convergence, optionMarket.optionMint, diff --git a/packages/js/src/utils/classes.ts b/packages/js/src/utils/classes.ts index 8b9282e45..fed8ecb1e 100644 --- a/packages/js/src/utils/classes.ts +++ b/packages/js/src/utils/classes.ts @@ -22,25 +22,26 @@ export class InstructionUniquenessTracker { ); }; private matchInstruction = (ixToBeAdded: TransactionInstruction): boolean => { - this.IxArray.forEach((ix) => { - if ( - this.matchKeys(ix.keys, ixToBeAdded.keys) && - ix.programId.equals(ixToBeAdded.programId) && - ix.data.equals(ixToBeAdded.data) - ) - return true; - }); - return false; + return !this.IxArray.every( + (ix) => + !( + this.matchKeys(ix.keys, ixToBeAdded.keys) && + ix.programId.equals(ixToBeAdded.programId) && + ix.data.equals(ixToBeAdded.data) + ) + ); }; checkedAdd(ix: TransactionInstruction | TransactionBuilder): boolean { if (ix instanceof TransactionBuilder) { const instructions = ix.getInstructions(); const ixLength = instructions.length; let checked = 0; - instructions.forEach((ix) => { + instructions.every((ix) => { if (!this.matchInstruction(ix)) { checked++; + return true; } + return false; }); if (checked === ixLength) { this.IxArray.push(...instructions); From df69c67b1737c84f6e3b97d2c1b05f6c01484f13 Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Mon, 11 Sep 2023 17:33:07 +0530 Subject: [PATCH 27/32] add sendAndConfirmTx fn when signing individual txs --- .../plugins/psyoptionsEuropeanInstrumentModule/helpers.ts | 8 ++++---- packages/js/src/plugins/rpcModule/RpcClient.ts | 4 ++-- packages/js/src/utils/TransactionBuilder.ts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts index faaf4c734..7e9d5ca61 100644 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts @@ -46,8 +46,9 @@ export const initializeNewEuropeanOption = async ( if (tx.instructions.length > 0) { tx.recentBlockhash = latestBlockHash.blockhash; tx.feePayer = convergence.rpc().getDefaultFeePayer().publicKey; - await convergence.identity().signTransaction(tx); - await convergence.rpc().serializeAndSendTransaction(tx, latestBlockHash); + await convergence + .rpc() + .sendAndConfirmTransaction(tx, [convergence.identity()]); } const strikePriceSize = addDecimals(strikePrice, stableMint.decimals); @@ -79,10 +80,9 @@ export const initializeNewEuropeanOption = async ( const createTx = new Transaction().add(createIx); createTx.recentBlockhash = latestBlockHash.blockhash; createTx.feePayer = convergence.rpc().getDefaultFeePayer().publicKey; - const signedTx = await convergence.identity().signTransaction(createTx); await convergence .rpc() - .serializeAndSendTransaction(signedTx, latestBlockHash); + .sendAndConfirmTransaction(createTx, [convergence.identity()]); } return { diff --git a/packages/js/src/plugins/rpcModule/RpcClient.ts b/packages/js/src/plugins/rpcModule/RpcClient.ts index a89551491..9f3501632 100644 --- a/packages/js/src/plugins/rpcModule/RpcClient.ts +++ b/packages/js/src/plugins/rpcModule/RpcClient.ts @@ -283,8 +283,8 @@ export class RpcClient { async sendAndConfirmTransaction( transaction: Transaction | TransactionBuilder, - confirmOptions?: ConfirmOptions, - signers: Signer[] = [] + signers: Signer[] = [], + confirmOptions?: ConfirmOptions ): Promise { const prepared = await this.prepareTransaction(transaction, signers); const { blockhashWithExpiryBlockHeight } = prepared; diff --git a/packages/js/src/utils/TransactionBuilder.ts b/packages/js/src/utils/TransactionBuilder.ts index 04be4161e..54d51f00a 100644 --- a/packages/js/src/utils/TransactionBuilder.ts +++ b/packages/js/src/utils/TransactionBuilder.ts @@ -196,7 +196,7 @@ export class TransactionBuilder { ): Promise<{ response: SendAndConfirmTransactionResponse } & C> { const response = await convergence .rpc() - .sendAndConfirmTransaction(this, confirmOptions); + .sendAndConfirmTransaction(this, [], confirmOptions); return { response, From ba5afa622bcfb982e53781f8ed400e77237dfc9b Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Mon, 11 Sep 2023 17:38:39 +0530 Subject: [PATCH 28/32] remove convergence.identity() as explicit signer --- .../plugins/psyoptionsEuropeanInstrumentModule/helpers.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts index 7e9d5ca61..45634e029 100644 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts @@ -46,9 +46,7 @@ export const initializeNewEuropeanOption = async ( if (tx.instructions.length > 0) { tx.recentBlockhash = latestBlockHash.blockhash; tx.feePayer = convergence.rpc().getDefaultFeePayer().publicKey; - await convergence - .rpc() - .sendAndConfirmTransaction(tx, [convergence.identity()]); + await convergence.rpc().sendAndConfirmTransaction(tx); } const strikePriceSize = addDecimals(strikePrice, stableMint.decimals); @@ -80,9 +78,7 @@ export const initializeNewEuropeanOption = async ( const createTx = new Transaction().add(createIx); createTx.recentBlockhash = latestBlockHash.blockhash; createTx.feePayer = convergence.rpc().getDefaultFeePayer().publicKey; - await convergence - .rpc() - .sendAndConfirmTransaction(createTx, [convergence.identity()]); + await convergence.rpc().sendAndConfirmTransaction(createTx); } return { From d28abd939c39959c0cedf903974b0ab6444a4c62 Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Mon, 11 Sep 2023 19:03:59 +0530 Subject: [PATCH 29/32] fix signature verification error --- .../helpers.ts | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts index 45634e029..0c3b95b2e 100644 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/helpers.ts @@ -37,16 +37,20 @@ export const initializeNewEuropeanOption = async ( oracleProviderId ); - const tx = new Transaction(); + const inititalizeTxBuilder = TransactionBuilder.make().setFeePayer( + convergence.rpc().getDefaultFeePayer() + ); initializeIxs.forEach((ix) => { - if (ixTracker.checkedAdd(ix)) tx.add(ix); + if (ixTracker.checkedAdd(ix)) + inititalizeTxBuilder.add({ + instruction: ix, + signers: [convergence.identity()], + }); }); - const latestBlockHash = await convergence.rpc().getLatestBlockhash(); - if (tx.instructions.length > 0) { - tx.recentBlockhash = latestBlockHash.blockhash; - tx.feePayer = convergence.rpc().getDefaultFeePayer().publicKey; - await convergence.rpc().sendAndConfirmTransaction(tx); + + if (inititalizeTxBuilder.getInstructions().length > 0) { + await inititalizeTxBuilder.sendAndConfirm(convergence); } const strikePriceSize = addDecimals(strikePrice, stableMint.decimals); @@ -75,10 +79,14 @@ export const initializeNewEuropeanOption = async ( ); if (ixTracker.checkedAdd(createIx)) { - const createTx = new Transaction().add(createIx); - createTx.recentBlockhash = latestBlockHash.blockhash; - createTx.feePayer = convergence.rpc().getDefaultFeePayer().publicKey; - await convergence.rpc().sendAndConfirmTransaction(createTx); + const createTxBuilder = TransactionBuilder.make().setFeePayer( + convergence.rpc().getDefaultFeePayer() + ); + createTxBuilder.add({ + instruction: createIx, + signers: [convergence.identity()], + }); + await createTxBuilder.sendAndConfirm(convergence); } return { From c7c16dcf1a4f327abfd7681b53f50c96cabcdead Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Mon, 11 Sep 2023 19:33:34 +0530 Subject: [PATCH 30/32] add more randomness to expiry --- packages/js/tests/helpers.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/js/tests/helpers.ts b/packages/js/tests/helpers.ts index daa1c2a97..7429cf3f3 100644 --- a/packages/js/tests/helpers.ts +++ b/packages/js/tests/helpers.ts @@ -118,7 +118,7 @@ export const createAmericanCoveredCallRfq = async ( cvg, baseMint, quoteMint, - 44_000, + 44_000 + Math.random() * 100, 1, 3_600 + Math.random() * 100 ); @@ -163,7 +163,7 @@ export const createEuropeanCoveredCallRfq = async ( quoteMint.decimals * -1 ); const min = 3_600; - const randomExpiry = min + Math.random() * 100; + const randomExpiry = min + Math.random() * 1000; const { euroMeta, euroMetaKey } = await initializeNewEuropeanOption( cvg, ixTracker, @@ -215,7 +215,7 @@ export const createEuropeanOpenSizeCallSpdOptionRfq = async ( quoteMint.decimals * -1 ); const min = 3_600; - const randomExpiry = min + Math.random() * 100; + const randomExpiry = min + Math.random() * 1000; const { euroMeta: euroMeta1, euroMetaKey: euroMetaKey1 } = await initializeNewEuropeanOption( cvg, @@ -224,7 +224,7 @@ export const createEuropeanOpenSizeCallSpdOptionRfq = async ( europeanProgram, baseMint, quoteMint, - 23_354, + 23_822, 1, randomExpiry, 0 @@ -237,7 +237,7 @@ export const createEuropeanOpenSizeCallSpdOptionRfq = async ( europeanProgram, baseMint, quoteMint, - 25_354, + 28_822, 1, randomExpiry, 0 @@ -277,12 +277,12 @@ export const createAmericanFixedBaseStraddle = async ( baseMint: any, quoteMint: any ) => { - const expiration = 3_600 + Math.random() * 100; + const expiration = 3_600 + Math.random() * 1000; const { optionMarketKey, optionMarket } = await initializeNewAmericanOption( cvg, baseMint, quoteMint, - 27_000, + 29_210, 1, expiration ); @@ -336,7 +336,7 @@ export const createEuropeanFixedBaseStraddle = async ( quoteMint.decimals * -1 ); const min = 3_600; - const randomExpiry = min + Math.random() * 100; + const randomExpiry = min + Math.random() * 1000; const { euroMeta: euroMeta, euroMetaKey: euroMetaKey } = await initializeNewEuropeanOption( @@ -387,7 +387,7 @@ export const createAmericanOpenSizeCallSpdOptionRfq = async ( baseMint: any, quoteMint: any ) => { - const expiration = 3_600 + Math.random() * 100; + const expiration = 3_600 + Math.random() * 1000; const { optionMarketKey: optionMarketKey1, optionMarket: optionMarket1 } = await initializeNewAmericanOption( cvg, From 344a83202efca23724e7c76fd3c4a8b8b88e12df Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Thu, 14 Sep 2023 14:27:56 +0530 Subject: [PATCH 31/32] simplify UniqueInstructionTracker logic --- packages/js/src/utils/classes.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/js/src/utils/classes.ts b/packages/js/src/utils/classes.ts index fed8ecb1e..2f4b45e45 100644 --- a/packages/js/src/utils/classes.ts +++ b/packages/js/src/utils/classes.ts @@ -34,16 +34,10 @@ export class InstructionUniquenessTracker { checkedAdd(ix: TransactionInstruction | TransactionBuilder): boolean { if (ix instanceof TransactionBuilder) { const instructions = ix.getInstructions(); - const ixLength = instructions.length; - let checked = 0; - instructions.every((ix) => { - if (!this.matchInstruction(ix)) { - checked++; - return true; - } - return false; + const uniqueIxs = instructions.every((ix) => { + return !this.matchInstruction(ix); }); - if (checked === ixLength) { + if (uniqueIxs) { this.IxArray.push(...instructions); return true; } From b655a68fed4fb39e908745ab1d2e424c50997926 Mon Sep 17 00:00:00 2001 From: Nagaprasadvr Date: Thu, 14 Sep 2023 14:54:45 +0530 Subject: [PATCH 32/32] optimize UnqueInstructionTracker code --- packages/js/src/utils/classes.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/js/src/utils/classes.ts b/packages/js/src/utils/classes.ts index 2f4b45e45..198f3c407 100644 --- a/packages/js/src/utils/classes.ts +++ b/packages/js/src/utils/classes.ts @@ -34,10 +34,10 @@ export class InstructionUniquenessTracker { checkedAdd(ix: TransactionInstruction | TransactionBuilder): boolean { if (ix instanceof TransactionBuilder) { const instructions = ix.getInstructions(); - const uniqueIxs = instructions.every((ix) => { - return !this.matchInstruction(ix); - }); - if (uniqueIxs) { + const areAllUnique = instructions.every( + (ix) => !this.matchInstruction(ix) + ); + if (areAllUnique) { this.IxArray.push(...instructions); return true; }