diff --git a/src/contract/assembled_transaction.ts b/src/contract/assembled_transaction.ts index 9e548f5e9..3aef2499d 100644 --- a/src/contract/assembled_transaction.ts +++ b/src/contract/assembled_transaction.ts @@ -309,7 +309,7 @@ export class AssembledTransaction { */ static Errors = { ExpiredState: class ExpiredStateError extends Error { }, - RestoreFailure: class RestoreFailureError extends Error { }, + RestorationFailure: class RestoreFailureError extends Error { }, NeedsMoreSignatures: class NeedsMoreSignaturesError extends Error { }, NoSignatureNeeded: class NoSignatureNeededError extends Error { }, NoUnsignedNonInvokerAuthEntries: class NoUnsignedNonInvokerAuthEntriesError extends Error { }, @@ -329,8 +329,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"), @@ -374,8 +374,6 @@ export class AssembledTransaction { }); } - - /** * Construct a new AssembledTransaction. This is the only way to create a new * AssembledTransaction; the main constructor is private. @@ -472,7 +470,7 @@ export class AssembledTransaction { await this.simulate(); return this; } - throw new AssembledTransaction.Errors.RestoreFailure( + throw new AssembledTransaction.Errors.RestorationFailure( `Automatic restore failed! You set 'restore: true' but the attempted restore did not work. Result:\n${JSON.stringify(result)}` ); } @@ -488,7 +486,7 @@ export class AssembledTransaction { }; get simulationData(): { - result: Api.SimulateHostFunctionResult; + result?: Api.SimulateHostFunctionResult; transactionData: xdr.SorobanTransactionData; } { if (this.simulationResult && this.simulationTransactionData) { @@ -515,7 +513,7 @@ export class AssembledTransaction { ); } - if (!simulation.result) { + /*if (!simulation.result) { throw new Error( `Expected an invocation simulation, but got no 'result' field. Simulation: ${JSON.stringify( simulation, @@ -523,7 +521,7 @@ export class AssembledTransaction { 2, )}`, ); - } + }*/ // add to object for serialization & deserialization this.simulationResult = simulation.result; @@ -537,7 +535,10 @@ export class AssembledTransaction { get result(): T { try { - return this.options.parseResultXdr(this.simulationData.result.retval); + if(!this.simulationData.result){ + throw new Error("No simulation result!"); + } + return this.options.parseResultXdr(this.simulationData.result?.retval); } catch (e) { if (!implementsToString(e)) throw e; const err = this.parseError(e.toString()); @@ -566,7 +567,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 @@ -576,11 +576,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"); @@ -611,7 +606,6 @@ export class AssembledTransaction { const sent = await SentTransaction.init( signTransaction, typeChecked, - updateTimeout ); return sent; }; @@ -797,7 +791,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() @@ -834,9 +828,7 @@ export class AssembledTransaction { minResourceFee: string; transactionData: SorobanDataBuilder; }, - /** - * The account that is executing the footprint restore operation. - */ + /** The account that is executing the footprint restore operation. */ account?: Account ): Promise { if(!this.options.signTransaction){ @@ -850,14 +842,10 @@ export class AssembledTransaction { account, restorePreamble.minResourceFee ); - const sentTransaction = await restoreTx.signAndSend({ - updateTimeout: false, - force: true, - }); + const sentTransaction = await restoreTx.signAndSend(); if (!sentTransaction.getTransactionResponse) { - // todo make better error message - throw new AssembledTransaction.Errors.RestoreFailure( - `Failure during restore. \n${JSON.stringify(sentTransaction)}` + throw new AssembledTransaction.Errors.RestorationFailure( + `The attempt at automatic restore failed. \n${JSON.stringify(sentTransaction)}` ); } return sentTransaction.getTransactionResponse; diff --git a/src/contract/sent_transaction.ts b/src/contract/sent_transaction.ts index 697d129dc..8d033e648 100644 --- a/src/contract/sent_transaction.ts +++ b/src/contract/sent_transaction.ts @@ -1,6 +1,6 @@ /* disable max-classes rule, because extending error shouldn't count! */ /* eslint max-classes-per-file: 0 */ -import { SorobanDataBuilder, TransactionBuilder } from "@stellar/stellar-base"; +import { TransactionBuilder } from "@stellar/stellar-base"; import type { ClientOptions, MethodOptions, Tx } from "./types"; import { Server } from "../rpc/server" import { Api } from "../rpc/api" @@ -76,27 +76,22 @@ 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; - if(updateTimeout) { - this.assembled.built = TransactionBuilder.cloneFrom(this.assembled.built!, { - fee: this.assembled.built!.fee, - timebounds: undefined, - sorobanData: new SorobanDataBuilder( - this.assembled.simulationData.transactionData.toXDR(), - ).build(), - }) - .setTimeout(timeoutInSeconds) - .build(); - } + 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` diff --git a/test/unit/server/soroban/assembled_transaction_test.js b/test/unit/server/soroban/assembled_transaction_test.js index 5ee57bc27..f4428341b 100644 --- a/test/unit/server/soroban/assembled_transaction_test.js +++ b/test/unit/server/soroban/assembled_transaction_test.js @@ -107,9 +107,7 @@ describe("AssembledTransaction.buildFootprintRestoreTransaction", () => { ), 52641, ) - .then((txn) => txn.signAndSend({force: true, ...wallet, - updateTimeout: false - })) + .then((txn) => txn.signAndSend({ ...wallet })) .then((result) => { expect(result.getTransactionResponse.status).to.equal(rpc.Api.GetTransactionStatus.SUCCESS); done();