Skip to content

Commit

Permalink
Add the NoAccountAuthenticator variant
Browse files Browse the repository at this point in the history
Simulation API Update: Allows users to simulate transactions without providing public keys by updating simulateTransaction to accept PublicKey | null instead of PublicKey. If null is provided, NoAccountAuthenticator is used as an authenticator.

Multisig V2 Example Update: The multisig v2 example (multisig_v2.ts) is updated to reflect the change in the multisig transaction simulation behavior. To pre-check the multisig payload before creation, an entry function payload simulation with the multisig account as the sender and 0x0 as the fee payer is used.
  • Loading branch information
junkil-park committed Aug 6, 2024
1 parent 1ee2192 commit 6381bf8
Show file tree
Hide file tree
Showing 14 changed files with 213 additions and 70 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ examples/typescript/facoin/facoin.json

# Vim swap files
*.swp
/.fleet
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ All notable changes to the Aptos TypeScript SDK will be captured in this file. T
- Update Indexer GraphQL schema
- Add `convertAmountFromHumanReadableToOnChain` and `convertAmountFromOnChainToHumanReadable` helper methods
- Export `helpers.ts` file
- Allow optional provision of public keys in transaction simulation
- Update the multisig v2 example to demonstrate a new way to pre-check a multisig payload before it is created on-chain

# 1.26.0 (2024-07-18)

Expand Down
48 changes: 35 additions & 13 deletions examples/typescript-esm/multisig_v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
InputViewFunctionData,
SimpleTransaction,
generateTransactionPayload,
TransactionPayloadEntryFunction,
} from "@aptos-labs/ts-sdk";

// Default to devnet, but allow for overriding
Expand Down Expand Up @@ -141,19 +142,40 @@ const createMultiSigTransferTransaction = async () => {
aptosConfig: config,
});

// Simulate the transfer transaction to make sure it passes
const transactionToSimulate = await generateRawTransaction({
aptosConfig: config,
sender: owner2.accountAddress,
payload: transactionPayload,
});

const simulateMultisigTx = await aptos.transaction.simulate.simple({
signerPublicKey: owner2.publicKey,
transaction: new SimpleTransaction(transactionToSimulate),
});

console.log("simulateMultisigTx", simulateMultisigTx);
// The simulation enhancement feature is not enabled on the devnet yet.
const isSimulationEnhancementFeatureEnabled = false;
if (!isSimulationEnhancementFeatureEnabled) {
// Simulate the transfer transaction to make sure it passes
const transactionToSimulate = await generateRawTransaction({
aptosConfig: config,
sender: owner2.accountAddress,
payload: transactionPayload,
});

const simulateMultisigTx = await aptos.transaction.simulate.simple({
signerPublicKey: owner2.publicKey,
transaction: new SimpleTransaction(transactionToSimulate),
});

console.log("simulateMultisigTx", simulateMultisigTx);
}
else {
// Generate a raw transaction with the multisig address as the sender,
// the provided entry function payload, and 0x0 as the fee payer address.
const transactionToSimulate = await generateRawTransaction({
aptosConfig: config,
sender: transactionPayload.multiSig.multisig_address,
payload: new TransactionPayloadEntryFunction(transactionPayload.multiSig.transaction_payload.transaction_payload),
feePayerAddress: AccountAddress.ZERO,
});

// Simulate the transaction, skipping the public/auth key check for both the sender and the fee payer.
const simulateMultisigTx = await aptos.transaction.simulate.simple({
transaction: new SimpleTransaction(transactionToSimulate),
});

console.log("simulateMultisigTx", simulateMultisigTx);
}

// Build create_transaction transaction
const createMultisigTx = await aptos.transaction.build.simple({
Expand Down
1 change: 1 addition & 0 deletions examples/typescript/local_node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ async function stopLocalNode() {
// Query localnet endpoint
await fetch("http://localhost:8080");
} catch (err: any) {
// eslint-disable-next-line no-console
console.log("localnet stopped");
}
}
Expand Down
6 changes: 0 additions & 6 deletions src/api/transactionSubmission/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,6 @@ export function ValidateFeePayerDataOnSimulation(target: unknown, propertyKey: s
const originalMethod = descriptor.value;
/* eslint-disable-next-line func-names, no-param-reassign */
descriptor.value = async function (...args: any[]) {
const [methodArgs] = args;

if (methodArgs.transaction.feePayerAddress && !methodArgs.feePayerPublicKey) {
throw new Error("You are simulating a Fee Payer transaction but missing the feePayerPublicKey");
}

return originalMethod.apply(this, args);
};

Expand Down
12 changes: 6 additions & 6 deletions src/api/transactionSubmission/simulate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class Simulate {
/**
* Simulate a simple transaction
*
* @param args.signerPublicKey The signer public key
* @param args.signerPublicKey optional. The signer public key
* @param args.transaction An instance of a raw transaction
* @param args.options optional. Optional transaction configurations
* @param args.feePayerPublicKey optional. The fee payer public key if it is a fee payer transaction
Expand All @@ -30,7 +30,7 @@ export class Simulate {
*/
@ValidateFeePayerDataOnSimulation
async simple(args: {
signerPublicKey: PublicKey;
signerPublicKey?: PublicKey;
transaction: AnyRawTransaction;
feePayerPublicKey?: PublicKey;
options?: InputSimulateTransactionOptions;
Expand All @@ -41,19 +41,19 @@ export class Simulate {
/**
* Simulate a multi agent transaction
*
* @param args.signerPublicKey The signer public key
* @param args.signerPublicKey optional. The signer public key
* @param args.transaction An instance of a raw transaction
* @param args.secondarySignersPublicKeys An array of the secondary signers public keys
* @param args.secondarySignersPublicKeys An array of the secondary signers public keys. Each key is optional, allowing the public key check to be skipped.

Check failure on line 46 in src/api/transactionSubmission/simulate.ts

View workflow job for this annotation

GitHub Actions / run-tests

This line has a length of 157. Maximum allowed is 140
* @param args.options optional. Optional transaction configurations
* @param args.feePayerPublicKey optional. The fee payer public key if it is a fee payer transaction
*
* @returns Array<UserTransactionResponse>
*/
@ValidateFeePayerDataOnSimulation
async multiAgent(args: {
signerPublicKey: PublicKey;
signerPublicKey?: PublicKey;
transaction: AnyRawTransaction;
secondarySignersPublicKeys: Array<PublicKey>;
secondarySignersPublicKeys: Array<PublicKey | undefined>;
feePayerPublicKey?: PublicKey;
options?: InputSimulateTransactionOptions;
}): Promise<Array<UserTransactionResponse>> {
Expand Down
5 changes: 3 additions & 2 deletions src/cli/localNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ export class LocalNode {
* Starts the local testnet by running the aptos node run-local-testnet command
*/
start() {
const cliCommand = "npx";
const cliArgs = ["aptos", "node", "run-localnet", "--force-restart", "--assume-yes", "--with-indexer-api"];
// TODO: Revert this change before merging.
const cliCommand = "aptos";
const cliArgs = ["node", "run-local-testnet", "--force-restart", "--assume-yes", "--with-indexer-api"];

const currentPlatform = platform();
let childProcess;
Expand Down
2 changes: 1 addition & 1 deletion src/internal/transactionSubmission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ export function signTransaction(args: { signer: Account; transaction: AnyRawTran
/**
* Simulates a transaction before singing it.
*
* @param args.signerPublicKey The signer public key
* @param args.signerPublicKey optional. The signer public key
* @param args.transaction The raw transaction to simulate
* @param args.secondarySignersPublicKeys optional. For when the transaction is a multi signers transaction
* @param args.feePayerPublicKey optional. For when the transaction is a fee payer (aka sponsored) transaction
Expand Down
19 changes: 19 additions & 0 deletions src/transactions/authenticator/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export abstract class AccountAuthenticator extends Serializable {
return AccountAuthenticatorSingleKey.load(deserializer);
case AccountAuthenticatorVariant.MultiKey:
return AccountAuthenticatorMultiKey.load(deserializer);
case AccountAuthenticatorVariant.NoAccountAuthenticator:
return AccountAuthenticatorNoAccountAuthenticator.load(deserializer);
default:
throw new Error(`Unknown variant index for AccountAuthenticator: ${index}`);
}
Expand Down Expand Up @@ -169,3 +171,20 @@ export class AccountAuthenticatorMultiKey extends AccountAuthenticator {
return new AccountAuthenticatorMultiKey(public_keys, signatures);
}
}

/**
* AccountAuthenticatorNoAccountAuthenticator for no account authenticator
* It represents the absence of a public key for transaction simulation.
* It allows skipping the public/auth key check during the simulation.
*/
export class AccountAuthenticatorNoAccountAuthenticator extends AccountAuthenticator {
// eslint-disable-next-line class-methods-use-this
serialize(serializer: Serializer): void {
serializer.serializeU32AsUleb128(AccountAuthenticatorVariant.NoAccountAuthenticator);
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
static load(deserializer: Deserializer): AccountAuthenticatorNoAccountAuthenticator {
return new AccountAuthenticatorNoAccountAuthenticator();
}
}
9 changes: 8 additions & 1 deletion src/transactions/transactionBuilder/transactionBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { normalizeBundle } from "../../utils/normalizeBundle";
import {
AccountAuthenticator,
AccountAuthenticatorEd25519,
AccountAuthenticatorNoAccountAuthenticator,
AccountAuthenticatorSingleKey,
} from "../authenticator/account";
import {
Expand Down Expand Up @@ -438,13 +439,19 @@ export function generateSignedTransactionForSimulation(args: InputSimulateTransa
);
} else if (accountAuthenticator instanceof AccountAuthenticatorSingleKey) {
transactionAuthenticator = new TransactionAuthenticatorSingleSender(accountAuthenticator);
} else if (accountAuthenticator instanceof AccountAuthenticatorNoAccountAuthenticator) {
transactionAuthenticator = new TransactionAuthenticatorSingleSender(accountAuthenticator);
} else {
throw new Error("Invalid public key");
}
return new SignedTransaction(transaction.rawTransaction, transactionAuthenticator).bcsToBytes();
}

export function getAuthenticatorForSimulation(publicKey: PublicKey) {
export function getAuthenticatorForSimulation(publicKey?: PublicKey) {
if (!publicKey) {
return new AccountAuthenticatorNoAccountAuthenticator();
}

// No need to for the signature to be matching in scheme. All that matters for simulations is that it's not valid
const invalidSignature = new Ed25519Signature(new Uint8Array(64));

Expand Down
5 changes: 3 additions & 2 deletions src/transactions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,12 +277,13 @@ export type InputSimulateTransactionData = {
transaction: AnyRawTransaction;
/**
* For a single signer transaction
* This is optional and can be undefined to skip the public/auth key check during the transaction simulation.
*/
signerPublicKey: PublicKey;
signerPublicKey?: PublicKey;
/**
* For a fee payer or multi-agent transaction that requires additional signers in
*/
secondarySignersPublicKeys?: Array<PublicKey>;
secondarySignersPublicKeys?: Array<PublicKey | undefined>;
/**
* For a fee payer transaction (aka Sponsored Transaction)
*/
Expand Down
1 change: 1 addition & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export enum AccountAuthenticatorVariant {
MultiEd25519 = 1,
SingleKey = 2,
MultiKey = 3,
NoAccountAuthenticator = 4,
}

export enum AnyPublicKeyVariant {
Expand Down
Loading

0 comments on commit 6381bf8

Please sign in to comment.