ThalaLabs / surf

Type-Safe TypeScript Interfaces & React Hooks for Aptos.
MIT License
42 stars 8 forks source link

Add EntryPayload serialization support for nested transaction payloads #208

Open mshakeg opened 1 week ago

mshakeg commented 1 week ago

Use Case

When working with multisig transactions on Aptos, we often need to encode an EntryPayload as a parameter for another transaction. A common example is using aptos_framework::multisig_account::create_transaction, which expects its payload parameter as either a string, number[], or Uint8Array.

Currently, there's no built-in way to serialize an EntryPayload to these formats, making it difficult to compose nested transactions while maintaining type safety.

Example code demonstrating the current limitation:

// Create the inner transaction payload
const innerPayload = createEntryPayload(SOME_ABI, {
  function: 'some_function',
  functionArguments: [...],
  typeArguments: [...]
});

// Try to use it in a multisig transaction
// This fails because EntryPayload can't be used as an argument
const multisigPayload = createEntryPayload(MULTISIG_ACCOUNT_ABI, {
  function: 'create_transaction',
  functionArguments: [multisigAddress, innerPayload], // Type error!
});

Proposed Solution

Add methods to serialize EntryPayload objects into formats compatible with Aptos transactions. For example:

// Potential API:
const innerPayload = createEntryPayload(...)
const serialized = serializeEntryPayload(innerPayload);
// or
const serialized = innerPayload.serialize();

// Now works with multisig transactions
const multisigPayload = createEntryPayload(MULTISIG_ACCOUNT_ABI, {
  function: 'create_transaction',
  functionArguments: [multisigAddress, serialized],
});

Benefits

Additional Context

This functionality would be especially valuable for projects working with:

Would be happy to provide additional use cases or contribute to the implementation if helpful.

mshakeg commented 1 week ago

For anyone who needs a workaround in the meantime, you can use the Aptos SDK's transaction builder to serialize the payload:

const transaction = await aptosClient.transaction.build.simple({
  sender: multisigAddress,
  data: entryPayload,  // Your surf EntryPayload
});

const encodedPayload = transaction.bcsToBytes();

// Now you can use it in multisig transactions
const multisigPayload = createEntryPayload(MULTISIG_ACCOUNT_ABI, {
  function: 'create_transaction',
  functionArguments: [multisigAddress, encodedPayload],
  typeArguments: [],
});

This will properly serialize the payload into a Uint8Array that can be used as a function argument.

0xbe1 commented 1 week ago

@mshakeg are you interested in contributing to this feature?

mshakeg commented 5 days ago

@0xbe1 on second thought I don't think this needs to be added to surf, it's quite simple for devs to do, for example here's what I'm doing to generate the encoded tx payload for a multisig account tx:

const entryPayload: EntryPayload = createEntryPayload(ABI, payload);

const multisigAccountAddress = AccountAddress.fromString(multisigAddress);

// Generate multisig transaction payload; import generateTransactionPayload from @aptos-labs/ts-sdk
const transactionPayload = await generateTransactionPayload({
  multisigAddress: multisigAccountAddress,
  function: entryPayload.function,
  functionArguments: entryPayload.functionArguments,
  typeArguments: entryPayload.typeArguments,
  aptosConfig: aptosClient.config,
});

// this can be passed to multisig_account::create_transaction
const encodedTransactionPayload = transactionPayload.multiSig.transaction_payload?.bcsToBytes();

const proposeMultisigTxResponse = await surfClient.useABI(MULTISIG_ACCOUNT_ABI).entry.create_transaction({
  account: ownerAccount,
  functionArguments: [multisigAddress, encodedTransactionPayload],
  typeArguments: [],
});