From 198b69381c482e33d3c6b719724e207e45c2caea Mon Sep 17 00:00:00 2001 From: blaineheffron Date: Tue, 28 May 2024 11:08:34 -0400 Subject: [PATCH 01/14] add auto restore functionality for contract client --- src/contract/assembled_transaction.ts | 21 +++++++++++++++++++++ src/contract/sent_transaction.ts | 6 ++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/contract/assembled_transaction.ts b/src/contract/assembled_transaction.ts index 6003de128..6a82e336d 100644 --- a/src/contract/assembled_transaction.ts +++ b/src/contract/assembled_transaction.ts @@ -416,6 +416,21 @@ export class AssembledTransaction { }); } + private static async getAccount( + options: AssembledTransactionOptions, + server?: Server + ): Promise { + if (!server) { + server = new Server(options.rpcUrl, { + allowHttp: options.allowHttp ?? false, + }); + } + const account = options.publicKey + ? await server.getAccount(options.publicKey) + : new Account(NULL_ACCOUNT, "0"); + return account; + } + /** * Construct a new AssembledTransaction. This is the only way to create a new * AssembledTransaction; the main constructor is private. @@ -604,6 +619,7 @@ export class AssembledTransaction { signAndSend = async ({ force = false, signTransaction = this.options.signTransaction, + updateTimeout = true, }: { /** * If `true`, sign and send the transaction even if it is a read call @@ -613,6 +629,11 @@ export class AssembledTransaction { * You must provide this here if you did not provide one before */ signTransaction?: ClientOptions["signTransaction"]; + /** + * Whether or not to update the timeout value before signing + * and sending the transaction + */ + updateTimeout?: boolean; } = {}): Promise> => { if (!this.built) { throw new Error("Transaction has not yet been simulated"); diff --git a/src/contract/sent_transaction.ts b/src/contract/sent_transaction.ts index 8d033e648..6a4249df9 100644 --- a/src/contract/sent_transaction.ts +++ b/src/contract/sent_transaction.ts @@ -66,6 +66,7 @@ export class SentTransaction { }); } + /** * Initialize a `SentTransaction` from an existing `AssembledTransaction` and * a `signTransaction` function. This will also send the transaction to the @@ -76,13 +77,14 @@ export class SentTransaction { signTransaction: ClientOptions["signTransaction"], /** {@link AssembledTransaction} from which this SentTransaction was initialized */ assembled: AssembledTransaction, + updateTimeout: boolean = true, ): Promise> => { const tx = new SentTransaction(signTransaction, assembled); - const sent = await tx.send(); + const sent = await tx.send(updateTimeout); return sent; }; - private send = async (): Promise => { + private send = async (updateTimeout: boolean = true): Promise => { const timeoutInSeconds = this.assembled.options.timeoutInSeconds ?? DEFAULT_TIMEOUT; this.assembled.built = TransactionBuilder.cloneFrom(this.assembled.built!, { From def2953aec63a60fbd1edae87e3f61200c606f72 Mon Sep 17 00:00:00 2001 From: blaineheffron Date: Wed, 29 May 2024 17:20:25 -0400 Subject: [PATCH 02/14] extract getAccount to utils --- src/contract/assembled_transaction.ts | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/contract/assembled_transaction.ts b/src/contract/assembled_transaction.ts index 6a82e336d..79d004a5c 100644 --- a/src/contract/assembled_transaction.ts +++ b/src/contract/assembled_transaction.ts @@ -416,20 +416,7 @@ export class AssembledTransaction { }); } - private static async getAccount( - options: AssembledTransactionOptions, - server?: Server - ): Promise { - if (!server) { - server = new Server(options.rpcUrl, { - allowHttp: options.allowHttp ?? false, - }); - } - const account = options.publicKey - ? await server.getAccount(options.publicKey) - : new Account(NULL_ACCOUNT, "0"); - return account; - } + /** * Construct a new AssembledTransaction. This is the only way to create a new From a2dc474948d21345da61982faee54643ac6bdc97 Mon Sep 17 00:00:00 2001 From: blaineheffron Date: Wed, 29 May 2024 17:39:56 -0400 Subject: [PATCH 03/14] remove bald booleans --- src/contract/sent_transaction.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/contract/sent_transaction.ts b/src/contract/sent_transaction.ts index 6a4249df9..97f142a94 100644 --- a/src/contract/sent_transaction.ts +++ b/src/contract/sent_transaction.ts @@ -66,7 +66,6 @@ export class SentTransaction { }); } - /** * Initialize a `SentTransaction` from an existing `AssembledTransaction` and * a `signTransaction` function. This will also send the transaction to the @@ -80,11 +79,11 @@ export class SentTransaction { updateTimeout: boolean = true, ): Promise> => { const tx = new SentTransaction(signTransaction, assembled); - const sent = await tx.send(updateTimeout); + const sent = await tx.send({ updateTimeout }); return sent; }; - private send = async (updateTimeout: boolean = true): Promise => { + private send = async ({ updateTimeout }: {updateTimeout?: boolean } = { updateTimeout: true }): Promise => { const timeoutInSeconds = this.assembled.options.timeoutInSeconds ?? DEFAULT_TIMEOUT; this.assembled.built = TransactionBuilder.cloneFrom(this.assembled.built!, { From 813078e0df09214bab29bdebf975fb7359ff4eb3 Mon Sep 17 00:00:00 2001 From: blaineheffron Date: Wed, 5 Jun 2024 17:30:33 -0400 Subject: [PATCH 04/14] cleanup, remove updateTimeout workaround, dont rebuild sorobandata --- src/contract/assembled_transaction.ts | 16 ++++------------ src/contract/sent_transaction.ts | 5 ++--- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/contract/assembled_transaction.ts b/src/contract/assembled_transaction.ts index 79d004a5c..7e270ca20 100644 --- a/src/contract/assembled_transaction.ts +++ b/src/contract/assembled_transaction.ts @@ -330,8 +330,8 @@ export class AssembledTransaction { method: this.options.method, tx: this.built?.toXDR(), simulationResult: { - auth: this.simulationData.result.auth.map((a) => a.toXDR("base64")), - retval: this.simulationData.result.retval.toXDR("base64"), + auth: this.simulationData.result?.auth.map((a) => a.toXDR("base64")), + retval: this.simulationData.result?.retval.toXDR("base64"), }, simulationTransactionData: this.simulationData.transactionData.toXDR("base64"), @@ -416,8 +416,6 @@ export class AssembledTransaction { }); } - - /** * Construct a new AssembledTransaction. This is the only way to create a new * AssembledTransaction; the main constructor is private. @@ -535,7 +533,7 @@ export class AssembledTransaction { }; get simulationData(): { - result: Api.SimulateHostFunctionResult; + result?: Api.SimulateHostFunctionResult; transactionData: xdr.SorobanTransactionData; } { if (this.simulationResult && this.simulationTransactionData) { @@ -606,7 +604,6 @@ export class AssembledTransaction { signAndSend = async ({ force = false, signTransaction = this.options.signTransaction, - updateTimeout = true, }: { /** * If `true`, sign and send the transaction even if it is a read call @@ -616,11 +613,6 @@ export class AssembledTransaction { * You must provide this here if you did not provide one before */ signTransaction?: ClientOptions["signTransaction"]; - /** - * Whether or not to update the timeout value before signing - * and sending the transaction - */ - updateTimeout?: boolean; } = {}): Promise> => { if (!this.built) { throw new Error("Transaction has not yet been simulated"); @@ -836,7 +828,7 @@ export class AssembledTransaction { * returns `false`, then you need to call `signAndSend` on this transaction. */ get isReadCall(): boolean { - const authsCount = this.simulationData.result.auth.length; + const authsCount = this.simulationData.result?.auth.length; const writeLength = this.simulationData.transactionData .resources() .footprint() diff --git a/src/contract/sent_transaction.ts b/src/contract/sent_transaction.ts index 97f142a94..8d033e648 100644 --- a/src/contract/sent_transaction.ts +++ b/src/contract/sent_transaction.ts @@ -76,14 +76,13 @@ export class SentTransaction { signTransaction: ClientOptions["signTransaction"], /** {@link AssembledTransaction} from which this SentTransaction was initialized */ assembled: AssembledTransaction, - updateTimeout: boolean = true, ): Promise> => { const tx = new SentTransaction(signTransaction, assembled); - const sent = await tx.send({ updateTimeout }); + const sent = await tx.send(); return sent; }; - private send = async ({ updateTimeout }: {updateTimeout?: boolean } = { updateTimeout: true }): Promise => { + private send = async (): Promise => { const timeoutInSeconds = this.assembled.options.timeoutInSeconds ?? DEFAULT_TIMEOUT; this.assembled.built = TransactionBuilder.cloneFrom(this.assembled.built!, { From 0c32d1cc3b6f93c6e466e1c6a290ca7d2da7e90c Mon Sep 17 00:00:00 2001 From: blaineheffron Date: Wed, 5 Jun 2024 18:16:19 -0400 Subject: [PATCH 05/14] add changelog entry for auto restore functionality --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04e0d5df0..5afdca448 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,12 @@ interface LedgerEntryChange { } ``` +- `contract.AssembledTransaction` now has a `restoreFootprint` method which accepts the +`restorePreamble` returned when a simulation call fails due to some contract state that +has expired. When invoking a contract function, one can now set `restore` to `true` in the +`MethodOptions`. When enabled, a `restoreFootprint` transaction will be created and await +signing whenever contract state is required to be restored before a contract function can +be invoked. ## [v12.0.0-rc.3](https://github.com/stellar/js-stellar-sdk/compare/v11.3.0...v12.0.0-rc.3) From 2690f1679ae5270c32b1cb3e786426be969fe57d Mon Sep 17 00:00:00 2001 From: blaineheffron Date: Wed, 5 Jun 2024 18:27:35 -0400 Subject: [PATCH 06/14] simpler wording --- CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5afdca448..35c94e951 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,8 +40,7 @@ interface LedgerEntryChange { `restorePreamble` returned when a simulation call fails due to some contract state that has expired. When invoking a contract function, one can now set `restore` to `true` in the `MethodOptions`. When enabled, a `restoreFootprint` transaction will be created and await -signing whenever contract state is required to be restored before a contract function can -be invoked. +signing when required. ## [v12.0.0-rc.3](https://github.com/stellar/js-stellar-sdk/compare/v11.3.0...v12.0.0-rc.3) From 0d4e6832a3422c6feb1dcb3bc1b576f29ee2fefe Mon Sep 17 00:00:00 2001 From: blaineheffron Date: Wed, 5 Jun 2024 18:46:15 -0400 Subject: [PATCH 07/14] fixed position of changelog entry --- CHANGELOG.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35c94e951..04e0d5df0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,11 +36,6 @@ interface LedgerEntryChange { } ``` -- `contract.AssembledTransaction` now has a `restoreFootprint` method which accepts the -`restorePreamble` returned when a simulation call fails due to some contract state that -has expired. When invoking a contract function, one can now set `restore` to `true` in the -`MethodOptions`. When enabled, a `restoreFootprint` transaction will be created and await -signing when required. ## [v12.0.0-rc.3](https://github.com/stellar/js-stellar-sdk/compare/v11.3.0...v12.0.0-rc.3) From 2253ce0078cfce932cf673353936cac84da088eb Mon Sep 17 00:00:00 2001 From: Chad Ostrowski <221614+chadoh@users.noreply.github.com> Date: Thu, 13 Jun 2024 18:02:45 -0400 Subject: [PATCH 08/14] add stub result when simulation returns blank --- src/contract/assembled_transaction.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/contract/assembled_transaction.ts b/src/contract/assembled_transaction.ts index 7e270ca20..6003de128 100644 --- a/src/contract/assembled_transaction.ts +++ b/src/contract/assembled_transaction.ts @@ -330,8 +330,8 @@ export class AssembledTransaction { method: this.options.method, tx: this.built?.toXDR(), simulationResult: { - auth: this.simulationData.result?.auth.map((a) => a.toXDR("base64")), - retval: this.simulationData.result?.retval.toXDR("base64"), + auth: this.simulationData.result.auth.map((a) => a.toXDR("base64")), + retval: this.simulationData.result.retval.toXDR("base64"), }, simulationTransactionData: this.simulationData.transactionData.toXDR("base64"), @@ -533,7 +533,7 @@ export class AssembledTransaction { }; get simulationData(): { - result?: Api.SimulateHostFunctionResult; + result: Api.SimulateHostFunctionResult; transactionData: xdr.SorobanTransactionData; } { if (this.simulationResult && this.simulationTransactionData) { @@ -828,7 +828,7 @@ export class AssembledTransaction { * returns `false`, then you need to call `signAndSend` on this transaction. */ get isReadCall(): boolean { - const authsCount = this.simulationData.result?.auth.length; + const authsCount = this.simulationData.result.auth.length; const writeLength = this.simulationData.transactionData .resources() .footprint() From 73d147bd37496496b119e62f9209bea5e544e05f Mon Sep 17 00:00:00 2001 From: Blaine Heffron Date: Mon, 10 Jun 2024 15:23:18 -0400 Subject: [PATCH 09/14] rebase on top of AutoRestore --- src/contract/assembled_transaction.ts | 77 +++++++++++++++++++++++---- src/contract/sent_transaction.ts | 46 ++++------------ 2 files changed, 76 insertions(+), 47 deletions(-) diff --git a/src/contract/assembled_transaction.ts b/src/contract/assembled_transaction.ts index 6003de128..f81d89702 100644 --- a/src/contract/assembled_transaction.ts +++ b/src/contract/assembled_transaction.ts @@ -303,6 +303,11 @@ export class AssembledTransaction { */ private server: Server; + /** + * The signed transaction. + */ + private signed?: Tx; + /** * A list of the most important errors that various AssembledTransaction * methods can throw. Feel free to catch specific errors in your application @@ -597,11 +602,9 @@ export class AssembledTransaction { /** * Sign the transaction with the `wallet`, included previously. If you did * not previously include one, you need to include one now that at least - * includes the `signTransaction` method. After signing, this method will - * send the transaction to the network and return a `SentTransaction` that - * keeps track of all the attempts to fetch the transaction. + * includes the `signTransaction` method. */ - signAndSend = async ({ + sign = async ({ force = false, signTransaction = this.options.signTransaction, }: { @@ -613,7 +616,7 @@ export class AssembledTransaction { * You must provide this here if you did not provide one before */ signTransaction?: ClientOptions["signTransaction"]; - } = {}): Promise> => { + } = {}): Promise => { if (!this.built) { throw new Error("Transaction has not yet been simulated"); } @@ -635,16 +638,70 @@ export class AssembledTransaction { if (this.needsNonInvokerSigningBy().length) { throw new AssembledTransaction.Errors.NeedsMoreSignatures( "Transaction requires more signatures. " + - "See `needsNonInvokerSigningBy` for details." + "See `needsNonInvokerSigningBy` for details.", ); } - const typeChecked: AssembledTransaction = this; - const sent = await SentTransaction.init( - signTransaction, - typeChecked, + const timeoutInSeconds = + this.options.timeoutInSeconds ?? DEFAULT_TIMEOUT; + this.built = TransactionBuilder.cloneFrom(this.built!, { + fee: this.built!.fee, + timebounds: undefined, + sorobanData: this.simulationData.transactionData, + }) + .setTimeout(timeoutInSeconds) + .build(); + + const signature = await signTransaction( + this.built.toXDR(), + { + networkPassphrase: this.options.networkPassphrase, + }, ); + + this.signed = TransactionBuilder.fromXDR( + signature, + this.options.networkPassphrase, + ) as Tx; + }; + + /** + * Sends the transaction to the network to return a `SentTransaction` that + * keeps track of all the attempts to fetch the transaction. + */ + async send(){ + if(!this.signed){ + throw new Error("The transaction has not yet been signed. Run `sign` first."); + } + const typeChecked: AssembledTransaction = this; + const sent = await SentTransaction.init(typeChecked, this.signed); return sent; + } + + /** + * Sign the transaction with the `wallet`, included previously. If you did + * not previously include one, you need to include one now that at least + * includes the `signTransaction` method. After signing, this method will + * send the transaction to the network and return a `SentTransaction` that + * keeps track of all the attempts to fetch the transaction. + */ + signAndSend = async ({ + force = false, + signTransaction = this.options.signTransaction, + }: { + /** + * If `true`, sign and send the transaction even if it is a read call + */ + force?: boolean; + /** + * You must provide this here if you did not provide one before + */ + signTransaction?: ClientOptions["signTransaction"]; + } = {}): Promise> => { + if(!this.signed){ + await this.sign({ force, signTransaction }); + } + return this.send(); }; private getStorageExpiration = async () => { diff --git a/src/contract/sent_transaction.ts b/src/contract/sent_transaction.ts index 8d033e648..960f842f7 100644 --- a/src/contract/sent_transaction.ts +++ b/src/contract/sent_transaction.ts @@ -1,7 +1,6 @@ /* disable max-classes rule, because extending error shouldn't count! */ /* eslint max-classes-per-file: 0 */ -import { TransactionBuilder } from "@stellar/stellar-base"; -import type { ClientOptions, MethodOptions, Tx } from "./types"; +import type { MethodOptions, Tx } from "./types"; import { Server } from "../rpc/server" import { Api } from "../rpc/api" import { DEFAULT_TIMEOUT, withExponentialBackoff } from "./utils"; @@ -24,8 +23,6 @@ import type { AssembledTransaction } from "./assembled_transaction"; export class SentTransaction { public server: Server; - public signed?: Tx; - /** * The result of calling `sendTransaction` to broadcast the transaction to the * network. @@ -53,14 +50,10 @@ export class SentTransaction { }; constructor( - public signTransaction: ClientOptions["signTransaction"], public assembled: AssembledTransaction, + + public signed: Tx, ) { - if (!signTransaction) { - throw new Error( - "You must provide a `signTransaction` function to send a transaction", - ); - } this.server = new Server(this.assembled.options.rpcUrl, { allowHttp: this.assembled.options.allowHttp ?? false, }); @@ -68,44 +61,21 @@ export class SentTransaction { /** * Initialize a `SentTransaction` from an existing `AssembledTransaction` and - * a `signTransaction` function. This will also send the transaction to the + * a `signed` AssembledTransaction. This will also send the transaction to the * network. */ static init = async ( - /** More info in {@link MethodOptions} */ - signTransaction: ClientOptions["signTransaction"], /** {@link AssembledTransaction} from which this SentTransaction was initialized */ assembled: AssembledTransaction, + /** The signed transaction to send to the network */ + signed: Tx, ): Promise> => { - const tx = new SentTransaction(signTransaction, assembled); + const tx = new SentTransaction(assembled, signed); const sent = await tx.send(); return sent; }; private send = async (): Promise => { - const timeoutInSeconds = - this.assembled.options.timeoutInSeconds ?? DEFAULT_TIMEOUT; - this.assembled.built = TransactionBuilder.cloneFrom(this.assembled.built!, { - fee: this.assembled.built!.fee, - timebounds: undefined, // intentionally don't clone timebounds - sorobanData: this.assembled.simulationData.transactionData - }) - .setTimeout(timeoutInSeconds) - .build(); - - const signature = await this.signTransaction!( - // `signAndSend` checks for `this.built` before calling `SentTransaction.init` - this.assembled.built!.toXDR(), - { - networkPassphrase: this.assembled.options.networkPassphrase, - }, - ); - - this.signed = TransactionBuilder.fromXDR( - signature, - this.assembled.options.networkPassphrase, - ) as Tx; - this.sendTransactionResponse = await this.server.sendTransaction( this.signed, ); @@ -122,6 +92,8 @@ export class SentTransaction { const { hash } = this.sendTransactionResponse; + const timeoutInSeconds = + this.assembled.options.timeoutInSeconds ?? DEFAULT_TIMEOUT; this.getTransactionResponseAll = await withExponentialBackoff( () => this.server.getTransaction(hash), (resp) => resp.status === Api.GetTransactionStatus.NOT_FOUND, From 16623b4b7ef1cff904b664d7fb26a0a2306355e6 Mon Sep 17 00:00:00 2001 From: Blaine Heffron Date: Mon, 10 Jun 2024 16:02:49 -0400 Subject: [PATCH 10/14] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04e0d5df0..ba30bfcb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ A breaking change will get clearly marked in this log. - `contract.AssembledTransaction` now has: - `toXDR` and `fromXDR` methods for serializing the transaction to and from XDR. Additionally, `contract.Client` now has a `txFromXDR`. These methods should be used in place of `AssembledTransaction.toJSON`, `AssembledTransaction.fromJSON`, and `Client.txFromJSON` for multi-auth signing. The JSON methods are now deprecated. **Note you must now call `simulate` on the transaction before the final `signAndSend` call after all required signatures are gathered when using the XDR methods. - a `restoreFootprint` method which accepts the `restorePreamble` returned when a simulation call fails due to some contract state that has expired. When invoking a contract function, one can now set `restore` to `true` in the `MethodOptions`. When enabled, a `restoreFootprint` transaction will be created and await signing when required. + - separate `sign` and `send` methods so that you can sign a transaction without sending it. You can continue to use `signAndSend` if you prefer. ### Deprecated - In `contract.AssembledTransaction`, `toJSON` and `fromJSON` should be replaced with `toXDR` and From c1e9347539a031ee55399e5c4a774bdedf95fe17 Mon Sep 17 00:00:00 2001 From: Blaine Heffron Date: Tue, 11 Jun 2024 14:57:14 -0400 Subject: [PATCH 11/14] Update src/contract/assembled_transaction.ts better user instructions Co-authored-by: Chad Ostrowski <221614+chadoh@users.noreply.github.com> --- src/contract/assembled_transaction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/contract/assembled_transaction.ts b/src/contract/assembled_transaction.ts index f81d89702..98cf38f12 100644 --- a/src/contract/assembled_transaction.ts +++ b/src/contract/assembled_transaction.ts @@ -671,7 +671,7 @@ export class AssembledTransaction { */ async send(){ if(!this.signed){ - throw new Error("The transaction has not yet been signed. Run `sign` first."); + throw new Error("The transaction has not yet been signed. Run `sign` first, or use `signAndSend` instead."); } const typeChecked: AssembledTransaction = this; const sent = await SentTransaction.init(typeChecked, this.signed); From fedd1a0c54023571bccbf9bf67035e03a862861d Mon Sep 17 00:00:00 2001 From: Blaine Heffron Date: Tue, 11 Jun 2024 15:25:30 -0400 Subject: [PATCH 12/14] remove assembled argument from init --- src/contract/assembled_transaction.ts | 3 +-- src/contract/sent_transaction.ts | 22 ++++++++++------------ src/contract/types.ts | 7 +++++++ 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/contract/assembled_transaction.ts b/src/contract/assembled_transaction.ts index 98cf38f12..433328a00 100644 --- a/src/contract/assembled_transaction.ts +++ b/src/contract/assembled_transaction.ts @@ -673,8 +673,7 @@ export class AssembledTransaction { if(!this.signed){ throw new Error("The transaction has not yet been signed. Run `sign` first, or use `signAndSend` instead."); } - const typeChecked: AssembledTransaction = this; - const sent = await SentTransaction.init(typeChecked, this.signed); + const sent = await SentTransaction.init(this.options, this.signed); return sent; } diff --git a/src/contract/sent_transaction.ts b/src/contract/sent_transaction.ts index 960f842f7..366e00259 100644 --- a/src/contract/sent_transaction.ts +++ b/src/contract/sent_transaction.ts @@ -1,10 +1,9 @@ /* disable max-classes rule, because extending error shouldn't count! */ /* eslint max-classes-per-file: 0 */ -import type { MethodOptions, Tx } from "./types"; +import type { MethodOptions, SentTransactionOptions, Tx } from "./types"; import { Server } from "../rpc/server" import { Api } from "../rpc/api" import { DEFAULT_TIMEOUT, withExponentialBackoff } from "./utils"; -import type { AssembledTransaction } from "./assembled_transaction"; /** * A transaction that has been sent to the Soroban network. This happens in two steps: @@ -50,12 +49,11 @@ export class SentTransaction { }; constructor( - public assembled: AssembledTransaction, - + public options: SentTransactionOptions, public signed: Tx, ) { - this.server = new Server(this.assembled.options.rpcUrl, { - allowHttp: this.assembled.options.allowHttp ?? false, + this.server = new Server(this.options.rpcUrl, { + allowHttp: this.options.allowHttp ?? false, }); } @@ -65,12 +63,12 @@ export class SentTransaction { * network. */ static init = async ( - /** {@link AssembledTransaction} from which this SentTransaction was initialized */ - assembled: AssembledTransaction, + /** {@link SentTransactionOptions} from which this SentTransaction was initialized */ + options: SentTransactionOptions, /** The signed transaction to send to the network */ signed: Tx, ): Promise> => { - const tx = new SentTransaction(assembled, signed); + const tx = new SentTransaction(options, signed); const sent = await tx.send(); return sent; }; @@ -93,7 +91,7 @@ export class SentTransaction { const { hash } = this.sendTransactionResponse; const timeoutInSeconds = - this.assembled.options.timeoutInSeconds ?? DEFAULT_TIMEOUT; + this.options.timeoutInSeconds ?? DEFAULT_TIMEOUT; this.getTransactionResponseAll = await withExponentialBackoff( () => this.server.getTransaction(hash), (resp) => resp.status === Api.GetTransactionStatus.NOT_FOUND, @@ -130,7 +128,7 @@ export class SentTransaction { if ("getTransactionResponse" in this && this.getTransactionResponse) { // getTransactionResponse has a `returnValue` field unless it failed if ("returnValue" in this.getTransactionResponse) { - return this.assembled.options.parseResultXdr( + return this.options.parseResultXdr( this.getTransactionResponse.returnValue!, ); } @@ -155,7 +153,7 @@ export class SentTransaction { // 3. finally, if neither of those are present, throw an error throw new Error( - `Sending transaction failed: ${JSON.stringify(this.assembled)}`, + `Sending transaction failed: ${JSON.stringify(this.signed)}`, ); } } diff --git a/src/contract/types.ts b/src/contract/types.ts index d329bd0da..339f896ca 100644 --- a/src/contract/types.ts +++ b/src/contract/types.ts @@ -123,3 +123,10 @@ export type AssembledTransactionOptions = MethodOptions & args?: any[]; parseResultXdr: (xdr: xdr.ScVal) => T; }; + +export type SentTransactionOptions = { + timeoutInSeconds?: number, + rpcUrl: string, + allowHttp?: boolean, + parseResultXdr: (xdr: xdr.ScVal) => T, +}; From 039c6dbbb734b015091ec077ed50ffaec7f20bab Mon Sep 17 00:00:00 2001 From: Blaine Heffron Date: Tue, 11 Jun 2024 15:35:12 -0400 Subject: [PATCH 13/14] docstring fixes --- src/contract/assembled_transaction.ts | 14 ++++++-------- src/contract/sent_transaction.ts | 15 +++++++++++---- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/contract/assembled_transaction.ts b/src/contract/assembled_transaction.ts index 433328a00..9602a0dd3 100644 --- a/src/contract/assembled_transaction.ts +++ b/src/contract/assembled_transaction.ts @@ -600,9 +600,8 @@ export class AssembledTransaction { } /** - * Sign the transaction with the `wallet`, included previously. If you did - * not previously include one, you need to include one now that at least - * includes the `signTransaction` method. + * Sign the transaction with the signTransaction function included previously. + * If you did not previously include one, you need to include one now. */ sign = async ({ force = false, @@ -678,11 +677,10 @@ export class AssembledTransaction { } /** - * Sign the transaction with the `wallet`, included previously. If you did - * not previously include one, you need to include one now that at least - * includes the `signTransaction` method. After signing, this method will - * send the transaction to the network and return a `SentTransaction` that - * keeps track of all the attempts to fetch the transaction. + * Sign the transaction with the `signTransaction` function included previously. + * If you did not previously include one, you need to include one now. + * After signing, this method will send the transaction to the network and + * return a `SentTransaction` that keeps track * of all the attempts to fetch the transaction. */ signAndSend = async ({ force = false, diff --git a/src/contract/sent_transaction.ts b/src/contract/sent_transaction.ts index 366e00259..98bbb56b6 100644 --- a/src/contract/sent_transaction.ts +++ b/src/contract/sent_transaction.ts @@ -58,12 +58,19 @@ export class SentTransaction { } /** - * Initialize a `SentTransaction` from an existing `AssembledTransaction` and - * a `signed` AssembledTransaction. This will also send the transaction to the - * network. + * Initialize a `SentTransaction` from `options` and a `signed` + * AssembledTransaction. This will also send the transaction to the network. */ static init = async ( - /** {@link SentTransactionOptions} from which this SentTransaction was initialized */ + /** + * Configuration options for initializing the SentTransaction. + * + * @typedef {Object} SentTransactionOptions + * @property {number} [timeoutInSeconds] - Optional timeout duration in seconds for the transaction. + * @property {string} rpcUrl - The RPC URL of the network to which the transaction will be sent. + * @property {boolean} [allowHttp] - Optional flag to allow HTTP connections (default is false, HTTPS is preferred). + * @property {(xdr: xdr.ScVal) => U} parseResultXdr - Function to parse the XDR result returned by the network. + */ options: SentTransactionOptions, /** The signed transaction to send to the network */ signed: Tx, From 845bc2390145c2553e996e4e568b00cb2bd0dd3a Mon Sep 17 00:00:00 2001 From: Chad Ostrowski <221614+chadoh@users.noreply.github.com> Date: Thu, 13 Jun 2024 16:42:16 -0400 Subject: [PATCH 14/14] build: remove breaking change --- src/contract/assembled_transaction.ts | 4 +-- src/contract/sent_transaction.ts | 37 +++++++++++---------------- src/contract/types.ts | 7 ----- 3 files changed, 17 insertions(+), 31 deletions(-) diff --git a/src/contract/assembled_transaction.ts b/src/contract/assembled_transaction.ts index 9602a0dd3..e87de33b7 100644 --- a/src/contract/assembled_transaction.ts +++ b/src/contract/assembled_transaction.ts @@ -306,7 +306,7 @@ export class AssembledTransaction { /** * The signed transaction. */ - private signed?: Tx; + public signed?: Tx; /** * A list of the most important errors that various AssembledTransaction @@ -672,7 +672,7 @@ export class AssembledTransaction { if(!this.signed){ throw new Error("The transaction has not yet been signed. Run `sign` first, or use `signAndSend` instead."); } - const sent = await SentTransaction.init(this.options, this.signed); + const sent = await SentTransaction.init(undefined, this); return sent; } diff --git a/src/contract/sent_transaction.ts b/src/contract/sent_transaction.ts index 98bbb56b6..0a449ab3e 100644 --- a/src/contract/sent_transaction.ts +++ b/src/contract/sent_transaction.ts @@ -1,9 +1,10 @@ /* disable max-classes rule, because extending error shouldn't count! */ /* eslint max-classes-per-file: 0 */ -import type { MethodOptions, SentTransactionOptions, Tx } from "./types"; +import type { MethodOptions } from "./types"; import { Server } from "../rpc/server" import { Api } from "../rpc/api" import { DEFAULT_TIMEOUT, withExponentialBackoff } from "./utils"; +import type { AssembledTransaction } from "./assembled_transaction"; /** * A transaction that has been sent to the Soroban network. This happens in two steps: @@ -49,11 +50,11 @@ export class SentTransaction { }; constructor( - public options: SentTransactionOptions, - public signed: Tx, + _: any, // deprecated: used to take sentTransaction, need to wait for major release for breaking change + public assembled: AssembledTransaction, ) { - this.server = new Server(this.options.rpcUrl, { - allowHttp: this.options.allowHttp ?? false, + this.server = new Server(this.assembled.options.rpcUrl, { + allowHttp: this.assembled.options.allowHttp ?? false, }); } @@ -62,27 +63,19 @@ export class SentTransaction { * AssembledTransaction. This will also send the transaction to the network. */ static init = async ( - /** - * Configuration options for initializing the SentTransaction. - * - * @typedef {Object} SentTransactionOptions - * @property {number} [timeoutInSeconds] - Optional timeout duration in seconds for the transaction. - * @property {string} rpcUrl - The RPC URL of the network to which the transaction will be sent. - * @property {boolean} [allowHttp] - Optional flag to allow HTTP connections (default is false, HTTPS is preferred). - * @property {(xdr: xdr.ScVal) => U} parseResultXdr - Function to parse the XDR result returned by the network. - */ - options: SentTransactionOptions, - /** The signed transaction to send to the network */ - signed: Tx, + /** @deprecated variable is ignored. Now handled by AssembledTransaction. */ + _: any, // eslint-disable-line @typescript-eslint/no-unused-vars + /** {@link AssembledTransaction} from which this SentTransaction was initialized */ + assembled: AssembledTransaction, ): Promise> => { - const tx = new SentTransaction(options, signed); + const tx = new SentTransaction(undefined, assembled); const sent = await tx.send(); return sent; }; private send = async (): Promise => { this.sendTransactionResponse = await this.server.sendTransaction( - this.signed, + this.assembled.signed!, ); if (this.sendTransactionResponse.status !== "PENDING") { @@ -98,7 +91,7 @@ export class SentTransaction { const { hash } = this.sendTransactionResponse; const timeoutInSeconds = - this.options.timeoutInSeconds ?? DEFAULT_TIMEOUT; + this.assembled.options.timeoutInSeconds ?? DEFAULT_TIMEOUT; this.getTransactionResponseAll = await withExponentialBackoff( () => this.server.getTransaction(hash), (resp) => resp.status === Api.GetTransactionStatus.NOT_FOUND, @@ -135,7 +128,7 @@ export class SentTransaction { if ("getTransactionResponse" in this && this.getTransactionResponse) { // getTransactionResponse has a `returnValue` field unless it failed if ("returnValue" in this.getTransactionResponse) { - return this.options.parseResultXdr( + return this.assembled.options.parseResultXdr( this.getTransactionResponse.returnValue!, ); } @@ -160,7 +153,7 @@ export class SentTransaction { // 3. finally, if neither of those are present, throw an error throw new Error( - `Sending transaction failed: ${JSON.stringify(this.signed)}`, + `Sending transaction failed: ${JSON.stringify(this.assembled.signed)}`, ); } } diff --git a/src/contract/types.ts b/src/contract/types.ts index 339f896ca..d329bd0da 100644 --- a/src/contract/types.ts +++ b/src/contract/types.ts @@ -123,10 +123,3 @@ export type AssembledTransactionOptions = MethodOptions & args?: any[]; parseResultXdr: (xdr: xdr.ScVal) => T; }; - -export type SentTransactionOptions = { - timeoutInSeconds?: number, - rpcUrl: string, - allowHttp?: boolean, - parseResultXdr: (xdr: xdr.ScVal) => T, -};