Skip to content

Commit

Permalink
add toXDR and fromXDR for multiauth flow
Browse files Browse the repository at this point in the history
  • Loading branch information
BlaineHeffron committed Jun 5, 2024
1 parent e5e49dc commit 151cf16
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 14 deletions.
51 changes: 44 additions & 7 deletions src/contract/assembled_transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
implementsToString,
} from "./utils";
import { SentTransaction } from "./sent_transaction";
import { Spec } from "./spec";

export const NULL_ACCOUNT =
"GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF";
Expand Down Expand Up @@ -364,6 +365,40 @@ export class AssembledTransaction<T> {
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<T>(
options: Omit<AssembledTransactionOptions<T>, "args" | "method" | "parseResultXdr">,
encodedXDR: string,
spec: Spec
): AssembledTransaction<T> {
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<T>) {
this.options.simulate = this.options.simulate ?? true;
this.server = new Server(this.options.rpcUrl, {
Expand Down Expand Up @@ -412,14 +447,16 @@ export class AssembledTransaction<T> {
}

simulate = async (): Promise<this> => {
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)) {
Expand Down
3 changes: 3 additions & 0 deletions src/contract/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,5 +124,8 @@ export class Client {
tx,
);
};

txFromXDR = <T>(xdrBase64: string): AssembledTransaction<T> => AssembledTransaction.fromXDR(this.options, xdrBase64, this.spec);

}

15 changes: 8 additions & 7 deletions test/e2e/src/test-swap.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down

0 comments on commit 151cf16

Please sign in to comment.