Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Runtianz/new script composer #587

Merged
merged 14 commits into from
Feb 4, 2025
Merged

Conversation

runtian-zhou
Copy link
Contributor

Description

Reopen the script composer feature with updated dependency built into aptos-labs.

Test Plan

CI

Tested that the package can work in web, nodejs and nextjs environment.

Related Links

#565

Checklist

  • Have you ran pnpm fmt?
  • Have you updated the CHANGELOG.md?

@runtian-zhou runtian-zhou requested a review from a team as a code owner November 20, 2024 18:50
@0xmaayan
Copy link
Collaborator

Please test and validate it

  1. Passes all SDK unit + examples tests
  2. Does not break a client-side render app (react)
  3. Does not break a server-side render app (nextjs)

@WGB5445
Copy link
Contributor

WGB5445 commented Nov 20, 2024

Please test and validate it

  1. Passes all SDK unit + examples tests
  2. Does not break a client-side render app (react)
  3. Does not break a server-side render app (nextjs)

I have tested a React + Vite client-side render app and a Next.js server-side render app.
Both work fine.

However, it's worth noting that in the current version, the initialization is done when the SDK loads, so the bundled JavaScript is a bit large—about 5 MB for the client-side.

@0xmaayan
Copy link
Collaborator

0xmaayan commented Nov 21, 2024

Please test and validate it

  1. Passes all SDK unit + examples tests
  2. Does not break a client-side render app (react)
  3. Does not break a server-side render app (nextjs)

I have tested a React + Vite client-side render app and a Next.js server-side render app. Both work fine.

However, it's worth noting that in the current version, the initialization is done when the SDK loads, so the bundled JavaScript is a bit large—about 5 MB for the client-side.

The bundle size is a concern. I'd like to get consensus from the sdk team before approving it. @gregnazario @GhostWalker562

@GhostWalker562
Copy link
Contributor

GhostWalker562 commented Nov 21, 2024

@0xmaayan I personally think its too much 😞 since it's already 5x the bundle size. People are already complaining about 421kb from poseidon-lite #578 but if it's really needed in the SDK I'm not going to push back that much.

I'm curious if we can test it in a react-native environment as well?

@0xmaayan
Copy link
Collaborator

@0xmaayan I personally think its too much 😞 since it's already 5x the bundle size. People are already complaining about 421kb from poseidon-lite #578 but if it's really needed in the SDK I'm not going to push back that much.

I'm curious if we can test it in a react-native environment as well?

@runtian-zhou

  1. Any reason we dont move the wasm initialization to the end user?
  2. Thoughts on releasing it under a tagged version?

@GhostWalker562 I dont think the SDK officially supports react-native, but I assume you want it tested for Petra?

@runtian-zhou
Copy link
Contributor Author

Thoughts on releasing it under a tagged version?

I think that would be amazing.

@0xmaayan
Copy link
Collaborator

Thoughts on releasing it under a tagged version?

I think that would be amazing.

Cool. Then we dont need to merge it to main, but release a tagged version from this branch

@runtian-zhou
Copy link
Contributor Author

Let's release it first and get feedbacks from the community. I'm getting multiple asks for this feature so would be great to let them try it out first. In the meantime, we can optimize on the packaging situation.

@lumos42
Copy link

lumos42 commented Nov 21, 2024

eagerly waiting to use this feature in our app

@itsmnthn
Copy link

itsmnthn commented Nov 28, 2024

@0xmaayan I personally think its too much 😞 since it's already 5x the bundle size. People are already complaining about 421kb from poseidon-lite #578 but if it's really needed in the SDK I'm not going to push back that much.

I'm curious if we can test it in a react-native environment as well?

One workaround for the size is lazy load.
Script Composer can be different package and could by lazy loaded and uses ts-sdk to compose the script wen needed. This is gud since it can be loaded only wen needed.

wdyt?

@runtian-zhou runtian-zhou force-pushed the runtianz/new_script_composer branch from 659a19c to 7018ff6 Compare January 10, 2025 18:22
@0xmaayan
Copy link
Collaborator

This feature has been available for some time under a different version https://www.npmjs.com/package/@aptos-labs/ts-sdk/v/1.33.0-sc.1 and @runtian-zhou mentioned receiving positive feedback from users, along with excitement about integrating it officially into the ts-sdk.

@WGB5445 validated that the feature works in both web and Node.js environments.

@0xmaayan confirmed there is no increase in the bundle size

current main branch

npm notice name: @aptos-labs/ts-sdk
npm notice version: 1.33.1
npm notice filename: aptos-labs-ts-sdk-1.33.1.tgz
npm notice package size: 1.1 MB
npm notice unpacked size: 6.38 MB

script compose branch

npm notice name: @aptos-labs/ts-sdk
npm notice version: 1.33.0-sc.1
npm notice filename: aptos-labs-ts-sdk-1.33.0-sc.1.tgz
npm notice package size: 1.0 MB
npm notice unpacked size: 6.4 MB

I’m okay with moving forward and merging it, thoughts @gregnazario @GhostWalker562 ?

@runtian-zhou One thing we’re missing, which could be beneficial, is adding a complete example in the examples folder, not a blocker tho

@GhostWalker562
Copy link
Contributor

@0xmaayan would like to see it tested in a react-native environment too but otherwise sounds good to me

@0xmaayan
Copy link
Collaborator

@0xmaayan would like to see it tested in a react-native environment too but otherwise sounds good to me

@runtian-zhou

@WGB5445
Copy link
Contributor

WGB5445 commented Jan 20, 2025

This is the GitHub Pages deployment page for the Next.js and React versions, where you can view the corresponding source code:

@lumos42
Copy link

lumos42 commented Jan 20, 2025

We've been using it in testnet and mainnet for some time, and there's a feature request which could really optimize the script composer - the ability to provide ABIs manually. Currently it fetches for ABIs every time which slows down the process.

@itsmnthn can provide more details on this.

@itsmnthn
Copy link

We've been using it in testnet and mainnet for some time, and there's a feature request which could really optimize the script composer - the ability to provide ABIs manually. Currently it fetches for ABIs every time which slows down the process.

@itsmnthn can provide more details on this.

Yes passing ABIs to the addBatchedCall for the given call and for standard module's ABIs as part of the script composer to avoid fetching it over the network multiple times to speed up execution time especially when connection is slow. Things add up when the script is complex and has more steps even when the network speed is gud.

I've written custom AptosScriptComposer class to use in our FE which add abi as a parameter to addBatchedCall to avoid fetching ABI. So it does not fetch for a module which being called but still fetches standard abis required for argument types etc (which is not efficient right now especially to use on frontend)

@runtian-zhou runtian-zhou force-pushed the runtianz/new_script_composer branch 2 times, most recently from fa0ecbd to 4fe12d4 Compare January 22, 2025 22:44
@runtian-zhou runtian-zhou force-pushed the runtianz/new_script_composer branch from 4fe12d4 to 7f61c14 Compare January 30, 2025 20:59
Copy link
Contributor

@GhostWalker562 GhostWalker562 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, few small comments

Also make sure to add to README.md about the wasm dependency in script-composer-pack

package.json Outdated
@@ -56,6 +56,7 @@
"@noble/hashes": "^1.4.0",
"@scure/bip32": "^1.4.0",
"@scure/bip39": "^1.3.0",
"@aptos-labs/script-composer-pack": "^0.0.4",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update to latest when possible

CHANGELOG.md Outdated Show resolved Hide resolved
aptosConfig: aptos.config,
sender: singleSignerED25519SenderAccount.accountAddress,
payload: TransactionPayloadScript.load(new Deserializer(bytes)),
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you try to use the aptos.transaction.build.scriptComposer() to build the script here?

So that it can be more consistent with the next test case

Comment on lines 56 to 59
for (const typeTag of input.typeArguments) {
// eslint-disable-next-line no-await-in-loop
await this.builder.load_type_tag(nodeUrl, typeTag.toString());
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change to await Promise.all(input.typeArguments.map((typeTag) => this.builder.load_type_tag(nodeUrl, typeTag.toString()))); to await the promises in parellel

await builder.init();
await builder.addBatchedCalls({
function: `${contractPublisherAccount.accountAddress}::transfer::transfer`,
functionArguments: [CallArgument.new_signer(0), 1, receiverAccounts[0].accountAddress],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there's a way to update the dependency to not use snake case, that would be great.

Even better, we can have a SignerArgument instance instead using static functions from CallArgument.

@@ -0,0 +1,85 @@
// Copyright © Aptos Foundation
Copy link
Contributor

@GhostWalker562 GhostWalker562 Jan 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename directory from script-composer to scriptComposer

@runtian-zhou runtian-zhou force-pushed the runtianz/new_script_composer branch from 9674c3f to df5cef1 Compare January 31, 2025 00:32
CHANGELOG.md Outdated
@@ -3,6 +3,7 @@
All notable changes to the Aptos TypeScript SDK will be captured in this file. This changelog is written by hand for now. It adheres to the format set out by [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

# Unreleased
- [`Breaking`] Add new new `scriptComposer` api in transactionSubmission api to allow SDK callers to invoke multiple Move functions inside a same transaction and compose the calls dynamically.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be "Add new"

// Copyright © Aptos Foundation
// SPDX-License-Identifier: Apache-2.0

export class callArgument {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happened to CallArgument here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sry should have removed this file...

@runtian-zhou runtian-zhou force-pushed the runtianz/new_script_composer branch from 725ea9a to 61d0ac5 Compare January 31, 2025 01:08
@runtian-zhou runtian-zhou force-pushed the runtianz/new_script_composer branch from 630ef2a to 25d2de4 Compare February 4, 2025 00:14
CHANGELOG.md Outdated Show resolved Hide resolved
builder: (builder: AptosScriptComposer) => Promise<AptosScriptComposer>;
options?: InputGenerateTransactionOptions;
withFeePayer?: boolean;
}): Promise<SimpleTransaction> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any reason we are not following the other transactions build flow format?

return generateTransaction({ aptosConfig: this.config, ...args });

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because the generateTransaction cannot take the serialized blob of move script as input (input contains both bytecode and type arguments/inputs).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, we would have generateBatchTransaction

payload: TransactionPayloadScript.load(new Deserializer(bytes)),
...args,
});
return new SimpleTransaction(rawTxn, args.withFeePayer === true ? AccountAddress.ZERO : undefined);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/transactions/scriptComposer/index.ts Outdated Show resolved Hide resolved
// before using the composer.
async init() {
if (!AptosScriptComposer.transactionComposer) {
const module = await import("@aptos-labs/script-composer-pack");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was this tested in node/web (react+next)/react native envs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

initSync({ module: ScriptComposerWasm.wasm });
AptosScriptComposer.transactionComposer = TransactionComposer;
}
this.builder = AptosScriptComposer.transactionComposer.single_signer();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets keep the same format

Suggested change
this.builder = AptosScriptComposer.transactionComposer.single_signer();
this.builder = AptosScriptComposer.transactionComposer.singleSigner();


private builder?: any;

private static transactionComposer?: any;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why any?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to allow for a lazy initialization of the composer so we don't need to pull the types in rightaway.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then ideally the sdk would hold an internal type for that

src/transactions/scriptComposer/index.ts Show resolved Hide resolved
//
// The function would also return a list of `CallArgument` that can be passed on to future calls.
async addBatchedCalls(input: InputBatchedFunctionData): Promise<CallArgument[]> {
const { moduleAddress, moduleName, functionName } = getFunctionParts(input.function);
Copy link
Collaborator

@0xmaayan 0xmaayan Feb 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because we have some extra bookkeeping logics to maintain in the composer? Was wondering if you have some suggestions for how to refactor the codes here.

}

build(): Uint8Array {
return this.builder.generate_batched_calls(true);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return this.builder.generate_batched_calls(true);
return this.builder.generateBatchedCalls(true);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit unfortunate the camel cases are in the packed wasm so we can't just change the calls here. Tho these apis aren't called by users directly so it should be safe?

@0xmaayan
Copy link
Collaborator

0xmaayan commented Feb 4, 2025

Overall LGTM, most important thing is that the change is marked as Breaking on CHANGELOG - not sure why, but if it is breaking we need to go with a major bump release cc @GhostWalker562

@runtian-zhou
Copy link
Contributor Author

Oh this shouldn't be a breaking cause we didn't remove existing apis, just a new feature. Lemme remove that.

Copy link
Collaborator

@0xmaayan 0xmaayan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 ship it!

@runtian-zhou runtian-zhou force-pushed the runtianz/new_script_composer branch from b92ed09 to e81b8d7 Compare February 4, 2025 17:59
@runtian-zhou runtian-zhou force-pushed the runtianz/new_script_composer branch from e81b8d7 to d091088 Compare February 4, 2025 18:01
@runtian-zhou runtian-zhou merged commit d5f7124 into main Feb 4, 2025
8 checks passed
@runtian-zhou runtian-zhou deleted the runtianz/new_script_composer branch February 4, 2025 18:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants