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 Jul 18, 2024
1 parent d26383d commit 45d2d3d
Show file tree
Hide file tree
Showing 11 changed files with 208 additions and 61 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
31 changes: 21 additions & 10 deletions examples/typescript-esm/multisig_v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@ import {
Account,
Aptos,
AptosConfig,
Ed25519PublicKey,

Check failure on line 24 in examples/typescript-esm/multisig_v2.ts

View workflow job for this annotation

GitHub Actions / run-tests

'Ed25519PublicKey' is defined but never used
Network,
NetworkToNetworkName,
MoveString,
generateRawTransaction,
TransactionPayloadMultiSig,
MultiSig,
AccountAddress,
InputEntryFunctionData,
InputViewFunctionData,
SimpleTransaction,
generateTransactionPayload,
Expand Down Expand Up @@ -131,6 +133,22 @@ const fundMultiSigAccount = async () => {
await aptos.fundAccount({ accountAddress: multisigAddress, amount: 100_000_000 });
};

const simulateTransactionPayloadMultiSig = async (multisigAddress: AccountAddress, entryFunctionData: InputEntryFunctionData) => {

Check failure on line 136 in examples/typescript-esm/multisig_v2.ts

View workflow job for this annotation

GitHub Actions / run-tests

'multisigAddress' is already declared in the upper scope on line 51 column 5
// Build a simple transaction using the multisig address as the sender, including the provided entry function payload.
// This transaction will have the default fee payer address set to 0x0.
const rawTxn = await aptos.transaction.build.simple({
sender: multisigAddress,
data: entryFunctionData,
withFeePayer: true,
});

await aptos.transaction.simulate.simple({
signerPublicKey: null,
transaction: rawTxn,
feePayerPublicKey: null,
});
}

const createMultiSigTransferTransaction = async () => {
console.log("Creating a multisig transaction to transfer coins...");

Expand All @@ -141,16 +159,9 @@ 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),
const simulateMultisigTx = await simulateTransactionPayloadMultiSig(AccountAddress.fromString(multisigAddress), {
function: "0x1::aptos_account::transfer",
functionArguments: [recipient.accountAddress, 1_000_000],
});

console.log("simulateMultisigTx", simulateMultisigTx);
Expand Down
2 changes: 1 addition & 1 deletion src/api/transactionSubmission/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function ValidateFeePayerDataOnSimulation(target: unknown, propertyKey: s
descriptor.value = async function (...args: any[]) {
const [methodArgs] = args;

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

Expand Down
10 changes: 5 additions & 5 deletions src/api/transactionSubmission/simulate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ export class Simulate {
*/
@ValidateFeePayerDataOnSimulation
async simple(args: {
signerPublicKey: PublicKey;
signerPublicKey: PublicKey | null;
transaction: AnyRawTransaction;
feePayerPublicKey?: PublicKey;
feePayerPublicKey?: PublicKey | null;
options?: InputSimulateTransactionOptions;
}): Promise<Array<UserTransactionResponse>> {
return simulateTransaction({ aptosConfig: this.config, ...args });
Expand All @@ -51,10 +51,10 @@ export class Simulate {
*/
@ValidateFeePayerDataOnSimulation
async multiAgent(args: {
signerPublicKey: PublicKey;
signerPublicKey: PublicKey | null;
transaction: AnyRawTransaction;
secondarySignersPublicKeys: Array<PublicKey>;
feePayerPublicKey?: PublicKey;
secondarySignersPublicKeys: Array<PublicKey | null>;
feePayerPublicKey?: PublicKey | null;
options?: InputSimulateTransactionOptions;
}): Promise<Array<UserTransactionResponse>> {
return simulateTransaction({ aptosConfig: this.config, ...args });
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
20 changes: 20 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,21 @@ export class AccountAuthenticatorMultiKey extends AccountAuthenticator {
return new AccountAuthenticatorMultiKey(public_keys, signatures);
}
}

/**
* AccountAuthenticatorNoAccountAuthenticator for no account authenticator
*/
export class AccountAuthenticatorNoAccountAuthenticator extends AccountAuthenticator {

constructor() {

Check failure on line 180 in src/transactions/authenticator/account.ts

View workflow job for this annotation

GitHub Actions / run-tests

Useless constructor
super();
}

serialize(serializer: Serializer): void {

Check failure on line 184 in src/transactions/authenticator/account.ts

View workflow job for this annotation

GitHub Actions / run-tests

Expected 'this' to be used by class method 'serialize'
serializer.serializeU32AsUleb128(AccountAuthenticatorVariant.NoAccountAuthenticator);
}

static load(deserializer: Deserializer): AccountAuthenticatorNoAccountAuthenticator {

Check failure on line 188 in src/transactions/authenticator/account.ts

View workflow job for this annotation

GitHub Actions / run-tests

'deserializer' is defined but never used
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 | null) {
if (publicKey === null) {
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
6 changes: 3 additions & 3 deletions src/transactions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,15 +278,15 @@ export type InputSimulateTransactionData = {
/**
* For a single signer transaction
*/
signerPublicKey: PublicKey;
signerPublicKey: PublicKey | null;
/**
* For a fee payer or multi-agent transaction that requires additional signers in
*/
secondarySignersPublicKeys?: Array<PublicKey>;
secondarySignersPublicKeys?: Array<PublicKey | null>;
/**
* For a fee payer transaction (aka Sponsored Transaction)
*/
feePayerPublicKey?: PublicKey;
feePayerPublicKey?: PublicKey | null;
options?: InputSimulateTransactionOptions;
};

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 45d2d3d

Please sign in to comment.