Skip to content

Commit

Permalink
Updates for auth-next (#47)
Browse files Browse the repository at this point in the history
* Updates for auth-next

* Update stellar-base to 8.2.2-soroban.10

* Naming feedback

* Add a couple unit tests for assembleTransaction
  • Loading branch information
Paul Bellamy authored Feb 14, 2023
1 parent 9d5316d commit b7d9441
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 61 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@
"axios": "0.25.0",
"es6-promise": "^4.2.4",
"lodash": "4.17.21",
"stellar-base": "8.0.1-soroban.6",
"stellar-base": "8.2.2-soroban.10",
"urijs": "^1.19.1"
}
}
39 changes: 0 additions & 39 deletions src/footprint.ts

This file was deleted.

1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export {
SERVER_TIME_MAP,
getCurrentServerTime,
} from "./axios";
export * from "./transaction";

// expose classes and functions from stellar-base
export * from "stellar-base";
Expand Down
25 changes: 15 additions & 10 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import {
import URI from "urijs";

import AxiosClient from "./axios";
import { addFootprint } from "./footprint";
import { Friendbot } from "./friendbot";
import * as jsonrpc from "./jsonrpc";
import { SorobanRpc } from "./soroban_rpc";
import { assembleTransaction } from "./transaction";

export const SUBMIT_TRANSACTION_TIMEOUT = 60 * 1000;

Expand Down Expand Up @@ -298,7 +298,7 @@ export class Server {

/**
* Submit a trial contract invocation to get back return values, expected
* ledger footprint, and expected costs.
* ledger footprint, expected authorizations, and expected costs.
*
* @example
* const contractId = '0000000000000000000000000000000000000000000000000000000000000001';
Expand Down Expand Up @@ -331,7 +331,6 @@ export class Server {
*
* server.simulateTransaction(transaction).then(sim => {
* console.log("cost:", sim.cost);
* console.log("footprint:", sim.footprint);
* console.log("results:", sim.results);
* console.log("error:", sim.error);
* console.log("latestLedger:", sim.latestLedger);
Expand All @@ -342,7 +341,7 @@ export class Server {
* {@link InvokeHostFunctionOp}. Any provided footprint will be ignored.
* @returns {Promise<SorobanRpc.SimulateTransactionResponse>} Returns a
* promise to the {@link SorobanRpc.SimulateTransactionResponse} object
* with the cost, result, footprint, and error of the transaction.
* with the cost, result, footprint, auth, and error of the transaction.
*/
public async simulateTransaction(
transaction: Transaction | FeeBumpTransaction,
Expand All @@ -355,8 +354,8 @@ export class Server {
}

/**
* Submit a trial contract invocation, then add the expected
* ledger footprint into the transaction so it is ready for signing & sending.
* Submit a trial contract invocation, then add the expected ledger footprint
* and auth into the transaction so it is ready for signing & sending.
*
* @example
* const contractId = '0000000000000000000000000000000000000000000000000000000000000001';
Expand Down Expand Up @@ -408,13 +407,19 @@ export class Server {
transaction: Transaction | FeeBumpTransaction,
networkPassphrase?: string,
): Promise<Transaction | FeeBumpTransaction> {
const [{ passphrase }, { footprint }] = await Promise.all([
const [{ passphrase }, { error, results }] = await Promise.all([
networkPassphrase
? Promise.resolve({ passphrase: networkPassphrase })
: this.getNetwork(),
this.simulateTransaction(transaction),
]);
return addFootprint(transaction, passphrase, footprint);
if (error) {
throw error;
}
if (!results) {
throw new Error("transaction simulation failed");
}
return assembleTransaction(transaction, passphrase, results);
}

/**
Expand All @@ -439,8 +444,8 @@ export class Server {
* networkPassphrase: SorobanClient.Networks.STANDALONE
* })
* // Add a contract.increment soroban contract invocation operation
* // Note: For real transactions you will need to include the footprint in
* // the operation, as returned from simulateTransaction.
* // Note: For real transactions you will need to include the footprint
* // and auth in the operation, as returned from simulateTransaction.
* .addOperation(contract.call("increment"))
* // Make this transaction valid for the next 30 seconds only
* .setTimeout(30)
Expand Down
13 changes: 6 additions & 7 deletions src/soroban_rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ export namespace SorobanRpc {
memBytes: string;
}

export interface Result {
xdr: string;
}

export type TransactionStatus = "pending" | "success" | "error";

export interface GetHealthResponse {
Expand Down Expand Up @@ -53,7 +49,7 @@ export namespace SorobanRpc {
envelopeXdr?: string;
resultXdr?: string;
resultMetaXdr?: string;
results?: Result[];
results?: Array<{ xdr: string }>;
error?: jsonrpc.Error;
}

Expand Down Expand Up @@ -91,8 +87,11 @@ export namespace SorobanRpc {
export interface SimulateTransactionResponse {
id: string;
cost: Cost;
footprint: string;
results?: Result[];
results?: Array<{
xdr: string;
footprint: string;
auth: string[];
}>;
error?: jsonrpc.Error;
latestLedger: number;
}
Expand Down
78 changes: 78 additions & 0 deletions src/transaction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import {
Account,
FeeBumpTransaction,
Operation,
Transaction,
TransactionBuilder,
xdr,
} from "stellar-base";

// TODO: Transaction is immutable, so we need to re-build it here. :(
export function assembleTransaction(
raw: Transaction | FeeBumpTransaction,
networkPassphrase: string,
simulated: Array<null | {
footprint: Buffer | string | xdr.LedgerFootprint;
auth: Array<Buffer | string | xdr.ContractAuth>;
}>,
): Transaction {
if ("innerTransaction" in raw) {
// TODO: Handle feebump transactions
return assembleTransaction(
raw.innerTransaction,
networkPassphrase,
simulated,
);
}

if (simulated.length !== raw.operations.length) {
throw new Error(
"number of simulated operations not equal to number of transaction operations",
);
}

// TODO: Figure out a cleaner way to clone this transaction.
const source = new Account(raw.source, `${parseInt(raw.sequence, 10) - 1}`);
const txn = new TransactionBuilder(source, {
fee: raw.fee,
memo: raw.memo,
networkPassphrase,
timebounds: raw.timeBounds,
ledgerbounds: raw.ledgerBounds,
minAccountSequence: raw.minAccountSequence,
minAccountSequenceAge: raw.minAccountSequenceAge,
minAccountSequenceLedgerGap: raw.minAccountSequenceLedgerGap,
extraSigners: raw.extraSigners,
});
for (let i = 0; i < raw.operations.length; i++) {
const rawOp = raw.operations[i];
if ("function" in rawOp) {
const sim = simulated[i];
if (!sim) {
throw new Error("missing simulated operation");
}
let footprint = sim.footprint;
if (!(footprint instanceof xdr.LedgerFootprint)) {
footprint = xdr.LedgerFootprint.fromXDR(footprint.toString(), "base64");
}
const auth = sim.auth.map((a) =>
a instanceof xdr.ContractAuth
? a
: xdr.ContractAuth.fromXDR(a.toString(), "base64"),
);
// TODO: Figure out a cleaner way to clone these operations
txn.addOperation(
Operation.invokeHostFunction({
function: rawOp.function,
parameters: rawOp.parameters,
footprint,
auth,
}),
);
} else {
// TODO: Handle this.
throw new Error("Unsupported operation type");
}
}
return txn.build();
}
82 changes: 82 additions & 0 deletions test/unit/transaction_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
const xdr = SorobanClient.xdr;

describe("assembleTransaction", () => {
describe("FeeBumpTransaction", () => {
// TODO: Add support for fee bump transactions
});

describe("Transaction", () => {
const networkPassphrase = SorobanClient.Networks.TESTNET;
const source = new SorobanClient.Account(
"GBZXN7PIRZGNMHGA7MUUUF4GWPY5AYPV6LY4UV2GL6VJGIQRXFDNMADI",
"1",
);
const emptyFootprint = new xdr.LedgerFootprint({
readOnly: [],
readWrite: [],
});
function emptyTransaction() {
return new SorobanClient.TransactionBuilder(source, {
fee: 100,
networkPassphrase,
v1: true,
})
.addOperation(
SorobanClient.Operation.invokeHostFunction({
function: xdr.HostFunction.hostFunctionTypeInvokeContract([]),
parameters: [],
footprint: emptyFootprint,
auth: [],
}),
)
.setTimeout(SorobanClient.TimeoutInfinite)
.build();
}

it("adds the footprint to the transaction", () => {
const txn = emptyTransaction();

const result = SorobanClient.assembleTransaction(txn, networkPassphrase, [
{
auth: [],
footprint: new xdr.LedgerFootprint({
readOnly: [
xdr.LedgerKey.contractCode(
new xdr.LedgerKeyContractCode({
hash: Buffer.alloc(32),
}),
),
],
readWrite: [],
}),
},
]);

expect(result.operations[0].footprint.readOnly.length).to.equal(1);
});

it("adds the auth to the transaction", () => {
const txn = emptyTransaction();

const result = SorobanClient.assembleTransaction(txn, networkPassphrase, [
{
auth: [
new xdr.ContractAuth({
addressWithNonce: null,
rootInvocation: new xdr.AuthorizedInvocation({
contractId: Buffer.alloc(32),
functionName: "foo",
args: [],
subInvocations: [],
}),
signatureArgs: [],
}),
],
footprint: emptyFootprint,
},
]);

expect(result.operations[0].auth.length).to.equal(1);
});
});
});
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7989,10 +7989,10 @@ statuses@~1.5.0:
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==

stellar-base@8.0.1-soroban.6:
version "8.0.1-soroban.6"
resolved "https://registry.yarnpkg.com/stellar-base/-/stellar-base-8.0.1-soroban.6.tgz#cf5c07224c2fda7df12f659cc2ae5890dbe1590d"
integrity sha512-LQhre31jzZBNXTaiUfkLlEcC2g2TQOrKJEsY1rbsUv9urlvUsTTIGRmvaw2TH8406FOJZolBtizN/VnZqLqnvg==
stellar-base@8.2.2-soroban.10:
version "8.2.2-soroban.10"
resolved "https://registry.yarnpkg.com/stellar-base/-/stellar-base-8.2.2-soroban.10.tgz#2eb5910375a1eadfb20e2fab3539e9c4c11c0adf"
integrity sha512-n+5Rn94u6hsKC0nxVLQrTqiTJJNgqMmZPmFiDrLFzgaVsEUkGJTZYBlDD5MCrA/65oxW4pFzP72Fh8bvBDD2jA==
dependencies:
base32.js "^0.1.0"
bignumber.js "^4.0.0"
Expand Down

0 comments on commit b7d9441

Please sign in to comment.