diff --git a/src/contract/assembled_transaction.ts b/src/contract/assembled_transaction.ts index 1f46824b9..38b9938ef 100644 --- a/src/contract/assembled_transaction.ts +++ b/src/contract/assembled_transaction.ts @@ -28,6 +28,7 @@ import { implementsToString, } from "./utils"; import { SentTransaction } from "./sent_transaction"; +import { Spec } from "./spec"; export const NULL_ACCOUNT = "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF"; @@ -364,6 +365,40 @@ export class AssembledTransaction { return txn; } + /** + * Serialize the AssembledTransaction to a base64-encoded XDR string. + */ + toXDR(): string { + if(!this.built) throw new Error( + "Transaction has not yet been simulated; " + + "call `AssembledTransaction.simulate` first.", + ); + return this.built?.toEnvelope().toXDR('base64'); + } + + /** + * Deserialize the AssembledTransaction from a base64-encoded XDR string. + */ + static fromXDR( + options: Omit, "args" | "method" | "parseResultXdr">, + encodedXDR: string, + spec: Spec + ): AssembledTransaction { + const envelope = xdr.TransactionEnvelope.fromXDR(encodedXDR, "base64"); + const built = TransactionBuilder.fromXDR(envelope, options.networkPassphrase) as Tx; + const method = ((built.operations[0] as Operation.InvokeHostFunction).func.value() as xdr.InvokeContractArgs).functionName().toString('utf-8'); + console.log(`method name is ${method}`); + const txn = new AssembledTransaction( + { ...options, + method, + parseResultXdr: (result: xdr.ScVal) => + spec.funcResToNative(method, result), + } + ); + txn.built = built; + return txn; + } + private constructor(public options: AssembledTransactionOptions) { this.options.simulate = this.options.simulate ?? true; this.server = new Server(this.options.rpcUrl, { @@ -412,14 +447,16 @@ export class AssembledTransaction { } simulate = async (): Promise => { - if (!this.raw) { - throw new Error( - "Transaction has not yet been assembled; " + - "call `AssembledTransaction.build` first.", - ); - } + if(!this.built){ + if (!this.raw) { + throw new Error( + "Transaction has not yet been assembled; " + + "call `AssembledTransaction.build` first.", + ); + } - this.built = this.raw.build(); + this.built = this.raw.build(); + } this.simulation = await this.server.simulateTransaction(this.built); if (Api.isSimulationSuccess(this.simulation)) { diff --git a/src/contract/client.ts b/src/contract/client.ts index e0c298b4a..f576762a6 100644 --- a/src/contract/client.ts +++ b/src/contract/client.ts @@ -124,5 +124,8 @@ export class Client { tx, ); }; + + txFromXDR = (xdrBase64: string): AssembledTransaction => AssembledTransaction.fromXDR(this.options, xdrBase64, this.spec); + } diff --git a/test/e2e/src/test-swap.js b/test/e2e/src/test-swap.js index 129c181be..3fd141c68 100644 --- a/test/e2e/src/test-swap.js +++ b/test/e2e/src/test-swap.js @@ -100,32 +100,33 @@ describe("Swap Contract Tests", function () { expect(needsNonInvokerSigningBy.indexOf(this.context.bob.publicKey())).to.equal(1, "needsNonInvokerSigningBy does not have bob's public key!"); // root serializes & sends to alice - const jsonFromRoot = tx.toJSON(); + const xdrFromRoot = tx.toXDR(); const { client: clientAlice } = await clientFor("swap", { keypair: this.context.alice, contractId: this.context.swapId, }); - const txAlice = clientAlice.txFromJSON(jsonFromRoot); + const txAlice = clientAlice.txFromXDR(xdrFromRoot); await txAlice.signAuthEntries(); // alice serializes & sends to bob - const jsonFromAlice = txAlice.toJSON(); + const xdrFromAlice = txAlice.toXDR(); const { client: clientBob } = await clientFor("swap", { keypair: this.context.bob, contractId: this.context.swapId, }); - const txBob = clientBob.txFromJSON(jsonFromAlice); + const txBob = clientBob.txFromXDR(xdrFromAlice); await txBob.signAuthEntries(); // bob serializes & sends back to root - const jsonFromBob = txBob.toJSON(); + const xdrFromBob = txBob.toXDR(); const { client: clientRoot } = await clientFor("swap", { keypair: this.context.root, contractId: this.context.swapId, }); - const txRoot = clientRoot.txFromJSON(jsonFromBob); + const txRoot = clientRoot.txFromXDR(xdrFromBob); - const result = await txRoot.signAndSend(); + await txRoot.simulate(); + const result = await txRoot.signAndSend({force: true}); expect(result).to.have.property('sendTransactionResponse'); expect(result.sendTransactionResponse).to.have.property('status', 'PENDING');