From e6726de5087bf96ef6b5acee1e18dad8ea7fd7e9 Mon Sep 17 00:00:00 2001 From: Pavel Ivanov Date: Thu, 3 Oct 2024 17:54:12 +0300 Subject: [PATCH] feat: reduce wasm file size and improve Gas and size benchmark compare to NEAR-SDK-RS --- .github/workflows/tests.yml | 1 + .gitignore | 1 + benchmark/README.md | 700 ++--- examples/WASM-FILE-SIZE-COMPARISON.md | 37 + examples/tsconfig.json | 3 +- package.json | 2 +- packages/near-contract-standards/package.json | 1 - packages/near-sdk-js/builder/builder.c | 2378 +++++++++-------- packages/near-sdk-js/lib/cli/cli.js | 31 +- packages/near-sdk-js/lib/cli/post-install.js | 24 +- packages/near-sdk-js/lib/types/index.d.ts | 9 + packages/near-sdk-js/lib/utils.d.ts | 1 + packages/near-sdk-js/lib/utils.js | 48 +- packages/near-sdk-js/package.json | 3 +- packages/near-sdk-js/src/cli/cli.ts | 37 +- packages/near-sdk-js/src/cli/post-install.ts | 37 +- packages/near-sdk-js/src/types/index.ts | 11 + packages/near-sdk-js/src/utils.ts | 58 +- packages/near-sdk-js/tsconfig.json | 1 + pnpm-lock.yaml | 170 +- tests/tsconfig.json | 3 +- 21 files changed, 1880 insertions(+), 1676 deletions(-) create mode 100644 examples/WASM-FILE-SIZE-COMPARISON.md diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c2fac71ba..b21e7a242 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,6 +7,7 @@ on: - develop jobs: tests: + timeout-minutes: 30 strategy: matrix: platform: [ubuntu-latest, macos-latest] diff --git a/.gitignore b/.gitignore index 29d707511..1bf909fcc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.DS_Store node_modules vendor .idea diff --git a/benchmark/README.md b/benchmark/README.md index a17199dc0..39f18da60 100644 --- a/benchmark/README.md +++ b/benchmark/README.md @@ -2,455 +2,293 @@ ## Summary -NEAR-SDK-JS bundles a bytecode VM with the contract bytecode to a wasm file. Currently, the bytecode VM is the QuickJS runtime with interface to NEAR and the contract bytecode is compiled from JavaScript source code with QuickJS Compiler (QJSC). +NEAR-SDK-JS bundles a bytecode VM with the contract bytecode to a wasm file. Currently, the bytecode VM is the QuickJS runtime with an interface to NEAR, and the contract bytecode is compiled from JavaScript source code with QuickJS Compiler (QJSC). This results in: -- Size of a minimal contract is 500K, which is also the size of the bytecode VM. -- Bytecode is more compact than wasm. Complex contract in JS adds less bytes to the equivalent wasm compiled from Rust, but due to the initial 500K size, the result contract is still bigger and within same order of magnitude: several hundred KB. -- For contract that bottlenecks at calling the host functions are using similar gas in JS and Rust. -- For contract that does a lot of computation in JS, the JS bytecode uses significantly more gas. -- For a real world contract, if it doesn't including complex logic in JavaScript, it's usually sufficient, consider the complexity of the near contract standards. -- For more complex logic, We suggest to bench the most expensive contract call, including most complex path of cross contract calls, to determine whether it fits 300T Gas limit. +- Size of a minimal contract is `479K`, which is also the size of the bytecode VM. +- Bytecode is more compact than wasm. Complex contract in JS adds fewer bytes to the equivalent wasm compiled from Rust, but due to the initial `479K` size, the resulting contract is still bigger and within the same order of magnitude: several hundred KB. +- For contracts that bottleneck at calling the host functions, similar gas is used in JS and Rust. +- For contracts that do a lot of computation in JS, the JS bytecode uses significantly more gas. +- For a real-world contract, if it doesn't include complex logic in JavaScript, it's usually sufficient, considering the complexity of the NEAR contract standards. +- For more complex logic, we suggest benching the most expensive contract call, including the most complex path of cross-contract calls, to determine whether it fits the 300T gas limit. ## Detailed gas benchmark -### A minimal contract - -- RS lowlevel minimal contract - - Gas used to convert transaction to receipt: 2.43T - - Gas used to execute the receipt (actual contract call): 2.43T - - CONTRACT_LOADING_BASE : 0.00004T - - CONTRACT_LOADING_BYTES : 0.00005T - - Gas used to refund unused gas: 0.22318T - - Total gas used: 5.08T -- JS lowlevel minimal contract - - Gas used to convert transaction to receipt: 2.43T - - Gas used to execute the receipt (actual contract call): 7.07T - - CONTRACT_LOADING_BASE : 0.00004T - - CONTRACT_LOADING_BYTES : 0.11132T - - WASM_INSTRUCTION : 4.53T - - Gas used to refund unused gas: 0.22318T - - Total gas used: 9.72T - -In the very minimal contract the JS adds about `1.8T` gas. The major difference is loading the QuickJS VM and near-sdk-js uses 4.53T Gas. The 500K contract loading just adds 0.1T Gas. - -### A highlevel minimal contract (using nearbindgen) - -- highlevel-minimal.ava › RS highlevel minimal contract - - Gas used to convert transaction to receipt: 2.43T - - Gas used to execute the receipt (actual contract call): 2.63T - - BASE : 0.79G - - CONTRACT_LOADING_BASE : 0.04G - - CONTRACT_LOADING_BYTES : 35.46G - - READ_CACHED_TRIE_NODE : 4.56G - - READ_MEMORY_BASE : 7.83G - - READ_MEMORY_BYTE : 0.04G - - STORAGE_READ_BASE : 56.36G - - STORAGE_READ_KEY_BYTE : 0.15G - - STORAGE_WRITE_BASE : 64.2G - - STORAGE_WRITE_KEY_BYTE : 0.35G - - TOUCHING_TRIE_NODE : 32.2G - - WASM_INSTRUCTION : 0.46G - - WRITE_MEMORY_BASE : 2.8G - - WRITE_MEMORY_BYTE : 0.04G - - Gas used to refund unused gas: 223.18G - - Total gas used: 5.28T -- highlevel-minimal.ava › JS highlevel minimal contract - - Gas used to convert transaction to receipt: 2.43T - - Gas used to execute the receipt (actual contract call): 8.39T - - BASE : 1.59G - - CONTRACT_LOADING_BASE : 0.04G - - CONTRACT_LOADING_BYTES : 112.03G - - READ_CACHED_TRIE_NODE : 6.84G - - READ_MEMORY_BASE : 7.83G - - READ_MEMORY_BYTE : 0.05G - - READ_REGISTER_BASE : 2.52G - - READ_REGISTER_BYTE : 0G - - STORAGE_READ_BASE : 56.36G - - STORAGE_READ_KEY_BYTE : 0.15G - - STORAGE_WRITE_BASE : 64.2G - - STORAGE_WRITE_KEY_BYTE : 0.35G - - STORAGE_WRITE_VALUE_BYTE : 0.06G - - TOUCHING_TRIE_NODE : 48.31G - - WASM_INSTRUCTION : 5.66T - - WRITE_MEMORY_BASE : 5.61G - - WRITE_MEMORY_BYTE : 0.05G - - WRITE_REGISTER_BASE : 2.87G - - WRITE_REGISTER_BYTE : 0.01G - - Gas used to refund unused gas: 223.18G - - Total gas used: 11.05T - -JS `@NearBindgen` is more expensive, the major difference is in `WASM_INSTRUCTION`, because `@NearBindgen` does some class, object manipulation work, but Rust `near_bindgen` is a compile time code generation macro. Deduct the 4.5T loading VM and near-sdk-js, it's about 1T gas overhead. - -### Low level API - -- RS lowlevel API contract - - Gas used to convert transaction to receipt: 2.43T - - Gas used to execute the receipt (actual contract call): 2.53T - - BASE : 0.00026T - - CONTRACT_LOADING_BASE : 0.00004T - - CONTRACT_LOADING_BYTES : 0.00008T - - READ_MEMORY_BASE : 0.00522T - - READ_MEMORY_BYTE : 0.00008T - - STORAGE_WRITE_BASE : 0.0642T - - STORAGE_WRITE_KEY_BYTE : 0.0007T - - STORAGE_WRITE_VALUE_BYTE : 0.00031T - - TOUCHING_TRIE_NODE : 0.0322T - - WASM_INSTRUCTION : 0.00002T - - Gas used to refund unused gas: 0.22318T - - Total gas used: 5.18T -- JS lowlevel API contract - - Gas used to convert transaction to receipt: 2.43T - - Gas used to execute the receipt (actual contract call): 7.8T - - BASE : 0.00026T - - CONTRACT_LOADING_BASE : 0.00004T - - CONTRACT_LOADING_BYTES : 0.11119T - - READ_MEMORY_BASE : 0.00522T - - READ_MEMORY_BYTE : 0.00008T - - STORAGE_WRITE_BASE : 0.0642T - - STORAGE_WRITE_EVICTED_BYTE : 0.00032T - - STORAGE_WRITE_KEY_BYTE : 0.0007T - - STORAGE_WRITE_VALUE_BYTE : 0.00031T - - TOUCHING_TRIE_NODE : 0.09661T - - WASM_INSTRUCTION : 5.09T - - WRITE_REGISTER_BASE : 0.00287T - - WRITE_REGISTER_BYTE : 0.00004T - - Gas used to refund unused gas: 0.22318T - - Total gas used: 10.45T -- JS lowlevel API contract, call many - - Gas used to convert transaction to receipt: 2.43T - - Gas used to execute the receipt (actual contract call): 8.47T - - BASE : 0.00265T - - CONTRACT_LOADING_BASE : 0.00004T - - CONTRACT_LOADING_BYTES : 0.11119T - - READ_MEMORY_BASE : 0.0522T - - READ_MEMORY_BYTE : 0.00076T - - STORAGE_WRITE_BASE : 0.64197T - - STORAGE_WRITE_EVICTED_BYTE : 0.00289T - - STORAGE_WRITE_KEY_BYTE : 0.00705T - - STORAGE_WRITE_VALUE_BYTE : 0.0031T - - TOUCHING_TRIE_NODE : 0.04831T - - WASM_INSTRUCTION : 5.14T - - WRITE_REGISTER_BASE : 0.02579T - - WRITE_REGISTER_BYTE : 0.00034T - - Gas used to refund unused gas: 0.22318T - - Total gas used: 11.12T - -In this case, JS lowlevel API contract uses same gas in the storage write API part (`STORAGE_WRITE_BASE` / `STORAGE_WRITE_KEY_BYTE` / `STORAGE_WRITE_VALUE_BYTE` ). The major excessive gas is due to the overhead of initialize QuickJS VM and loading near-sdk-js. We can see this more obviously by calling storage write for 10 times ("call many tests" in above). +--- +### A Minimal Contract + +| lowlevel minimal contract | Rust | JS Before Opt | JS After Opt | JS % Diff | +| :-------------------------------------- | ------------------: | ------------------: | ------------------: | ---------------: | +| Convert transaction to receipt | 2.43T | 2.43T | 2.43T | 0% | +| Execute the receipt (actual contract call) | 2.43T | 7.07T | 4.48T | -36.6% | +| CONTRACT_LOADING_BASE | 0.00004T | 0.00004T | 0.00004T | 0% | +| CONTRACT_LOADING_BYTES | 0.00005T | 0.11132T | 0.10399T | -6.57% | +| WASM_INSTRUCTION | 0.00001T | 4.53T | 1.94T | -57.19% | +| Refund unused gas | 0.22318T | 0.22318T | 0.22318T | 0% | +| Total gas used | 5.08T | 9.72T | 7.13T | -26.63% | + +In the very minimal contract, the optimized JS implementation adds about `2.05T` more gas compared to the Rust version. The significant difference is primarily due to the WASM_INSTRUCTION overhead associated with loading and executing the QuickJS VM, which accounts for `1.94T` gas in the optimized version. + +
+ +--- + +### A Highlevel Minimal Contract (using `@nearbindgen`) + +| highlevel-minimal.ava | Rust | JS Before Opt | JS After Opt | JS % Diff | +| :-------------------------------------- | ------------------: | ------------------: | ------------------: | ---------------: | +| Convert transaction to receipt | 2.43T | 2.43T | 2.43T | 0% | +| Execute the receipt (actual contract call) | 2.63T | 8.39T | 5.26T | -37.33% | +| BASE | 0.00079T | 1.59T | 0.00159T | -99.9% | +| CONTRACT_LOADING_BASE | 0.00004T | 0.00004T | 0.00004T | 0% | +| CONTRACT_LOADING_BYTES | 0.03546T | 0.11203T | 0.1048T | -6.45% | +| READ_MEMORY_BASE | 0.00783T | 7.83T | 0.00783T | -99.9% | +| READ_MEMORY_BYTE | 0.00004T | 0.05T | 0.00005T | -99.9% | +| STORAGE_READ_BASE | 0.05636T | 56.36T | 0.05636T | -99.9% | +| STORAGE_READ_KEY_BYTE | 0.00015T | 0.15T | 0.00015T | -99.9% | +| STORAGE_WRITE_BASE | 0.0642T | 64.2T | 0.0642T | -99.9% | +| STORAGE_WRITE_KEY_BYTE | 0.00035T | 0.35T | 0.00035T | -99.9% | +| STORAGE_WRITE_VALUE_BYTE | 0.00006T | 0.06T | 0.00006T | -99.9% | +| TOUCHING_TRIE_NODE | 0.0322T | 48.31T | 0.0322T | -99.9% | +| WASM_INSTRUCTION | 0.00052T | 5.66T | 2.56T | -54.7% | +| WRITE_MEMORY_BASE | 0.0028T | 5.61T | 0.00561T | -99.9% | +| WRITE_MEMORY_BYTE | 0.00004T | 0.05T | 0.00005T | -99.9% | +| WRITE_REGISTER_BASE | 0.00287T | 2.87T | 0.00287T | -99.9% | +| WRITE_REGISTER_BYTE | 0.00001T | 0.01T | 0.00001T | -99.9% | +| Refund unused gas | 0.22318T | 0.22318T | 0.22318T | 0% | +| Total gas used | 5.28T | 11.05T | 7.91T | -28.4% | + +JS `@NearBindgen` is more expensive, the major difference is in `WASM_INSTRUCTION`, because `@NearBindgen` does some class, object manipulation work, but Rust `near_bindgen` is a compile-time code generation macro. Deduct the `4.5T` loading VM and near-sdk-js, it's about `1.04T` gas overhead. +The JavaScript implementation using `@NearBindgen` is more expensive, primarily due to the overhead in `WASM_INSTRUCTION`. This difference arises because `@NearBindgen` performs runtime class and object manipulation, whereas the Rust `near_bindgen` is a compile-time code generation macro, which is more efficient. + +
+ +--- + +### Low-Level API + +| | Rust | JS Before Opt | JS After Opt | JS % Diff | +| :-------------------------------------- | ------------------: | ------------------: | ------------------: | ---------------: | +| Convert transaction to receipt | 2.43T | 2.43T | 2.43T | 0% | +| Execute the receipt (actual contract call) | 2.53T | 7.8T | 5.19T | -33.46% | +| BASE | 0.00026T | 0.00026T | 0.00026T | 0% | +| CONTRACT_LOADING_BASE | 0.00004T | 0.00004T | 0.00004T | 0% | +| CONTRACT_LOADING_BYTES | 0.00008T | 0.11119T | 0.10377T | -6.68% | +| READ_MEMORY_BASE | 0.00522T | 0.00522T | 0.00522T | 0% | +| READ_MEMORY_BYTE | 0.00008T | 0.00008T | 0.00008T | 0% | +| STORAGE_WRITE_BASE | 0.0642T | 0.0642T | 0.0642T | 0% | +| STORAGE_WRITE_KEY_BYTE | 0.0007T | 0.0007T | 0.0007T | 0% | +| STORAGE_WRITE_VALUE_BYTE | 0.00031T | 0.00031T | 0.00031T | 0% | +| TOUCHING_TRIE_NODE | 0.0322T | 0.09661T | 0.06441T | -33.31% | +| WASM_INSTRUCTION | 0.00002T | 5.09T | 2.52T | -50.49% | +| WRITE_REGISTER_BASE | 0.00287T | 0.00287T | 0.00287T | 0% | +| WRITE_REGISTER_BYTE | 0.00004T | 0.00004T | 0.00004T | 0% | +| Refund unused gas | 0.22318T | 0.22318T | 0.22318T | 0% | +| Total gas used | 5.18T | 10.45T | 7.85T | -24.89% | + +
+ +### Low-Level API (Call Many) + +| | Rust | JS Before Opt | JS After Opt | JS % Diff | +| :-------------------------------------- | ------------------: | ------------------: | ------------------: | ---------------: | +| Convert transaction to receipt | 2.43T | 2.43T | 2.43T | 0% | +| Execute the receipt (actual contract call) | 2.53T | 8.47T | 5.85T | -30.93% | +| BASE | 0.00026T | 0.00265T | 0.00265T | 0% | +| CONTRACT_LOADING_BASE | 0.00004T | 0.00004T | 0.00004T | 0% | +| CONTRACT_LOADING_BYTES | 0.00008T | 0.11119T | 0.10377T | -6.68% | +| READ_MEMORY_BASE | 0.00522T | 0.0522T | 0.0522T | 0% | +| READ_MEMORY_BYTE | 0.00008T | 0.00076T | 0.00076T | 0% | +| STORAGE_WRITE_BASE | 0.0642T | 0.64197T | 0.64197T | 0% | +| STORAGE_WRITE_EVICTED_BYTE | 0.00032T | 0.00289T | 0.00289T | 0% | +| STORAGE_WRITE_KEY_BYTE | 0.0007T | 0.00705T | 0.00705T | 0% | +| STORAGE_WRITE_VALUE_BYTE | 0.00031T | 0.0031T | 0.0031T | 0% | +| TOUCHING_TRIE_NODE | 0.04831T | 0.0322T | 0.0322T | 0% | +| WASM_INSTRUCTION | 0.00002T | 5.14T | 2.55T | -50.48% | +| WRITE_REGISTER_BASE | 0.00287T | 0.02579T | 0.02579T | 0% | +| WRITE_REGISTER_BYTE | 0.00004T | 0.00034T | 0.00034T | 0% | +| Refund unused gas | 0.22318T | 0.22318T | 0.22318T | 0% | +| Total gas used | 5.18T | 11.12T | 8.51T | -23.47% | + +In this case, the JS low-level API contract uses the same gas in the storage write API part (`STORAGE_WRITE_BASE` / `STORAGE_WRITE_KEY_BYTE` / `STORAGE_WRITE_VALUE_BYTE`). The major excessive gas is due to the overhead of initializing QuickJS VM and loading near-sdk-js. We can see this more obviously by calling storage write 10 times ("call many tests" in above). + +
+ +--- ### Highlevel collection -- RS highlevel collection contract - - Gas used to convert transaction to receipt: 2.43T - - Gas used to execute the receipt (actual contract call): 3.32T - - BASE : 3.18G - - CONTRACT_LOADING_BASE : 0.04G - - CONTRACT_LOADING_BYTES : 70.94G - - READ_CACHED_TRIE_NODE : 95.76G - - READ_MEMORY_BASE : 26.1G - - READ_MEMORY_BYTE : 1.87G - - READ_REGISTER_BASE : 5.03G - - READ_REGISTER_BYTE : 0.03G - - STORAGE_READ_BASE : 112.71G - - STORAGE_READ_KEY_BYTE : 3.44G - - STORAGE_READ_VALUE_BYTE : 0.19G - - STORAGE_WRITE_BASE : 256.79G - - STORAGE_WRITE_EVICTED_BYTE : 1.09G - - STORAGE_WRITE_KEY_BYTE : 9.23G - - STORAGE_WRITE_VALUE_BYTE : 7.75G - - TOUCHING_TRIE_NODE : 257.63G - - WASM_INSTRUCTION : 16.36G - - WRITE_MEMORY_BASE : 8.41G - - WRITE_MEMORY_BYTE : 0.74G - - WRITE_REGISTER_BASE : 8.6G - - WRITE_REGISTER_BYTE : 1.1G - - Gas used to refund unused gas: 223.18G - - Total gas used: 5.97T -- JS highlevel collection contract - - Gas used to convert transaction to receipt: 2.43T - - Gas used to execute the receipt (actual contract call): 10.06T - - BASE : 2.91G - - CONTRACT_LOADING_BASE : 0.04G - - CONTRACT_LOADING_BYTES : 113.46G - - READ_CACHED_TRIE_NODE : 72.96G - - READ_MEMORY_BASE : 20.88G - - READ_MEMORY_BYTE : 2G - - READ_REGISTER_BASE : 5.03G - - READ_REGISTER_BYTE : 0.03G - - STORAGE_READ_BASE : 112.71G - - STORAGE_READ_KEY_BYTE : 3.31G - - STORAGE_READ_VALUE_BYTE : 0.53G - - STORAGE_WRITE_BASE : 192.59G - - STORAGE_WRITE_EVICTED_BYTE : 3.02G - - STORAGE_WRITE_KEY_BYTE : 7.96G - - STORAGE_WRITE_VALUE_BYTE : 9.49G - - TOUCHING_TRIE_NODE : 209.33G - - WASM_INSTRUCTION : 6.86T - - WRITE_MEMORY_BASE : 8.41G - - WRITE_MEMORY_BYTE : 0.9G - - WRITE_REGISTER_BASE : 8.6G - - WRITE_REGISTER_BYTE : 1.55G - - Gas used to refund unused gas: 223.18G - - Total gas used: 12.71T - -JS SDK's collection has about 1T overhead, deduct the 4.5T VM/near-sdk-js loading and 1T `@NearBindgen`. Note this benches the most complicated `UnorderedMap`, which gas usage is strictly greater than the other collections. And the gas used in actual writing the collection to storage is similar (`STORAGE_WRITE_BASE` / `STORAGE_WRITE_KEY_BYTE` / `STORAGE_WRITE_VALUE_BYTE` ). +| Highlevel collection | Rust | JS Before Opt | JS After Opt | JS % Diff | +| :-------------------------------------- | ------------------: | ------------------: | ------------------: | ---------------: | +| Convert transaction to receipt | 2.43T | 2.43T | 2.43T | 0% | +| Execute the receipt (actual contract call) | 3.32T | 10.06T | 6.86T | -31.8% | +| BASE | 0.00318T | 0.00291T | 0.00291T | 0% | +| CONTRACT_LOADING_BASE | 0.00004T | 0.00004T | 0.00004T | 0% | +| CONTRACT_LOADING_BYTES | 0.07094T | 0.11346T | 0.10634T | -6.28% | +| READ_CACHED_TRIE_NODE | 0.05472T | 0.0342T | 0.0342T | 0% | +| READ_MEMORY_BASE | 0.0261T | 0.02088T | 0.02088T | 0% | +| READ_MEMORY_BYTE | 0.00187T | 0.002T | 0.002T | 6.95% | +| READ_REGISTER_BASE | 0.00503T | 0.00503T | 0.00503T | 0% | +| READ_REGISTER_BYTE | 0.00003T | 0.00003T | 0.00003T | 0% | +| STORAGE_READ_BASE | 0.11271T | 0.11271T | 0.11271T | 0% | +| STORAGE_READ_KEY_BYTE | 0.00344T | 0.00331T | 0.00331T | -3.78% | +| STORAGE_READ_VALUE_BYTE | 0.00019T | 0.00053T | 0.00053T | 0% | +| STORAGE_WRITE_BASE | 0.25679T | 0.19259T | 0.19259T | -24.97% | +| STORAGE_WRITE_EVICTED_BYTE | 0.00109T | 0.00302T | 0.00302T | 0% | +| STORAGE_WRITE_KEY_BYTE | 0.00923T | 0.00796T | 0.00796T | -13.76% | +| STORAGE_WRITE_VALUE_BYTE | 0.00775T | 0.00949T | 0.00949T | 22.45% | +| TOUCHING_TRIE_NODE | 0.25763T | 0.20933T | 0.20933T | -18.77% | +| WASM_INSTRUCTION | 0.01848T | 3.71T | 3.71T | 0% | +| WRITE_MEMORY_BASE | 0.00841T | 0.00841T | 0.00841T | 0% | +| WRITE_MEMORY_BYTE | 0.00074T | 0.0009T | 0.0009T | 21.62% | +| WRITE_REGISTER_BASE | 0.0086T | 0.0086T | 0.0086T | 0% | +| WRITE_REGISTER_BYTE | 0.0011T | 0.00155T | 0.00155T | 40.91% | +| Refund unused gas | 0.22318T | 0.22318T | 0.22318T | 0% | +| Total gas used | 5.97T | 12.71T | 9.51T | -25.16% | + +The JS SDK's collection has about `3.54T` overhead compared to the Rust version after deducting the `4.5T` VM/near-sdk-js loading and the `1.04T` `@NearBindgen` overhead. Note that this benchmarks the most complicated `UnorderedMap`, where gas usage is strictly greater than other collections. The gas used in actual writing the collection to storage is similar (`STORAGE_WRITE_BASE`, `STORAGE_WRITE_KEY_BYTE`, `STORAGE_WRITE_VALUE_BYTE`). + +
+ +--- ### Computational expensive contract -- JS expensive contract, iterate 20000 times - - Gas used to convert transaction to receipt: 2.43T - - Gas used to execute the receipt (actual contract call): 123.26T - - BASE : 1.85G - - CONTRACT_LOADING_BASE : 0.04G - - CONTRACT_LOADING_BYTES : 112.09G - - READ_CACHED_TRIE_NODE : 4.56G - - READ_MEMORY_BASE : 10.44G - - READ_MEMORY_BYTE : 0.07G - - READ_REGISTER_BASE : 2.52G - - READ_REGISTER_BYTE : 0G - - STORAGE_READ_BASE : 56.36G - - STORAGE_READ_KEY_BYTE : 0.15G - - STORAGE_WRITE_BASE : 64.2G - - STORAGE_WRITE_KEY_BYTE : 0.35G - - STORAGE_WRITE_VALUE_BYTE : 0.06G - - TOUCHING_TRIE_NODE : 32.2G - - WASM_INSTRUCTION : 120.54T - - WRITE_MEMORY_BASE : 5.61G - - WRITE_MEMORY_BYTE : 0.07G - - WRITE_REGISTER_BASE : 2.87G - - WRITE_REGISTER_BYTE : 0.04G - - Gas used to refund unused gas: 223.18G - - Total gas used: 125.91T -- RS expensive contract. iterate 20000 times - - Gas used to convert transaction to receipt: 2.43T - - Gas used to execute the receipt (actual contract call): 3.01T - - BASE : 1.85G - - CONTRACT_LOADING_BASE : 0.04G - - CONTRACT_LOADING_BYTES : 67.77G - - READ_CACHED_TRIE_NODE : 6.84G - - READ_MEMORY_BASE : 10.44G - - READ_MEMORY_BYTE : 0.06G - - READ_REGISTER_BASE : 2.52G - - READ_REGISTER_BYTE : 0G - - STORAGE_READ_BASE : 56.36G - - STORAGE_READ_KEY_BYTE : 0.15G - - STORAGE_WRITE_BASE : 64.2G - - STORAGE_WRITE_KEY_BYTE : 0.35G - - TOUCHING_TRIE_NODE : 48.31G - - WASM_INSTRUCTION : 315.17G - - WRITE_MEMORY_BASE : 5.61G - - WRITE_MEMORY_BYTE : 0.07G - - WRITE_REGISTER_BASE : 2.87G - - WRITE_REGISTER_BYTE : 0.04G - - Gas used to refund unused gas: 223.18G - - Total gas used: 5.66T -- RS expensive contract. iterate 10000 times - - Gas used to convert transaction to receipt: 2.43T - - Gas used to execute the receipt (actual contract call): 2.9T - - BASE : 2.38G - - CONTRACT_LOADING_BASE : 0.04G - - CONTRACT_LOADING_BYTES : 67.77G - - READ_CACHED_TRIE_NODE : 13.68G - - READ_MEMORY_BASE : 10.44G - - READ_MEMORY_BYTE : 0.06G - - READ_REGISTER_BASE : 5.03G - - READ_REGISTER_BYTE : 0G - - STORAGE_READ_BASE : 56.36G - - STORAGE_READ_KEY_BYTE : 0.15G - - STORAGE_WRITE_BASE : 64.2G - - STORAGE_WRITE_KEY_BYTE : 0.35G - - TOUCHING_TRIE_NODE : 80.51G - - WASM_INSTRUCTION : 158.89G - - WRITE_MEMORY_BASE : 8.41G - - WRITE_MEMORY_BYTE : 0.07G - - WRITE_REGISTER_BASE : 8.6G - - WRITE_REGISTER_BYTE : 0.04G - - Gas used to refund unused gas: 223.18G - - Total gas used: 5.56T -- RS expensive contract. iterate 100 times - - Gas used to convert transaction to receipt: 2.43T - - Gas used to execute the receipt (actual contract call): 2.75T - - BASE : 2.38G - - CONTRACT_LOADING_BASE : 0.04G - - CONTRACT_LOADING_BYTES : 67.77G - - READ_CACHED_TRIE_NODE : 13.68G - - READ_MEMORY_BASE : 10.44G - - READ_MEMORY_BYTE : 0.05G - - READ_REGISTER_BASE : 5.03G - - READ_REGISTER_BYTE : 0G - - STORAGE_READ_BASE : 56.36G - - STORAGE_READ_KEY_BYTE : 0.15G - - STORAGE_WRITE_BASE : 64.2G - - STORAGE_WRITE_KEY_BYTE : 0.35G - - TOUCHING_TRIE_NODE : 80.51G - - WASM_INSTRUCTION : 4.02G - - WRITE_MEMORY_BASE : 8.41G - - WRITE_MEMORY_BYTE : 0.07G - - WRITE_REGISTER_BASE : 8.6G - - WRITE_REGISTER_BYTE : 0.03G - - Gas used to refund unused gas: 223.18G - - Total gas used: 5.4T -- JS expensive contract, iterate 100 times - - Gas used to convert transaction to receipt: 2.43T - - Gas used to execute the receipt (actual contract call): 9.09T - - BASE : 2.38G - - CONTRACT_LOADING_BASE : 0.04G - - CONTRACT_LOADING_BYTES : 112.09G - - READ_CACHED_TRIE_NODE : 13.68G - - READ_MEMORY_BASE : 10.44G - - READ_MEMORY_BYTE : 0.06G - - READ_REGISTER_BASE : 5.03G - - READ_REGISTER_BYTE : 0G - - STORAGE_READ_BASE : 56.36G - - STORAGE_READ_KEY_BYTE : 0.15G - - STORAGE_READ_VALUE_BYTE : 0.01G - - STORAGE_WRITE_BASE : 64.2G - - STORAGE_WRITE_EVICTED_BYTE : 0.06G - - STORAGE_WRITE_KEY_BYTE : 0.35G - - STORAGE_WRITE_VALUE_BYTE : 0.06G - - TOUCHING_TRIE_NODE : 80.51G - - WASM_INSTRUCTION : 6.3T - - WRITE_MEMORY_BASE : 8.41G - - WRITE_MEMORY_BYTE : 0.07G - - WRITE_REGISTER_BASE : 8.6G - - WRITE_REGISTER_BYTE : 0.05G - - Gas used to refund unused gas: 223.18G - - Total gas used: 11.75T -- JS expensive contract, iterate 10000 times - - Gas used to convert transaction to receipt: 2.43T - - Gas used to execute the receipt (actual contract call): 65.94T - - BASE : 2.38G - - CONTRACT_LOADING_BASE : 0.04G - - CONTRACT_LOADING_BYTES : 112.09G - - READ_CACHED_TRIE_NODE : 13.68G - - READ_MEMORY_BASE : 10.44G - - READ_MEMORY_BYTE : 0.06G - - READ_REGISTER_BASE : 5.03G - - READ_REGISTER_BYTE : 0G - - STORAGE_READ_BASE : 56.36G - - STORAGE_READ_KEY_BYTE : 0.15G - - STORAGE_READ_VALUE_BYTE : 0.01G - - STORAGE_WRITE_BASE : 64.2G - - STORAGE_WRITE_EVICTED_BYTE : 0.06G - - STORAGE_WRITE_KEY_BYTE : 0.35G - - STORAGE_WRITE_VALUE_BYTE : 0.06G - - TOUCHING_TRIE_NODE : 80.51G - - WASM_INSTRUCTION : 63.15T - - WRITE_MEMORY_BASE : 8.41G - - WRITE_MEMORY_BYTE : 0.08G - - WRITE_REGISTER_BASE : 8.6G - - WRITE_REGISTER_BYTE : 0.06G - - Gas used to refund unused gas: 223.18G - - Total gas used: 68.59T - -In this case, JS uses much more gas. Because JS Number is object and that's a lot of overhead compare to native integer arithmetic. It's even a lot of overhead compare to native float arithmetic. Also in QuickJS there's no JIT. If your contract does a lot of calculation or complex algorithm in JavaScript, it'd be better to do a similar benchmark. - -### Deploy and cross contract call - -- JS promise batch deploy contract and call - - - Gas used to convert transaction to receipt: 2.43T - - Gas used to execute the receipt (actual contract call): 25.86T - - CREATE_ACCOUNT : 0.09961T - - DEPLOY_CONTRACT : 3.71T - - FUNCTION_CALL : 2.32T - - NEW_RECEIPT : 0.10806T - - TRANSFER : 0.11512T - - BASE : 0.00159T - - CONTRACT_LOADING_BASE : 0.00004T - - CONTRACT_LOADING_BYTES : 0.22386T - - PROMISE_RETURN : 0.00056T - - READ_MEMORY_BASE : 0.01566T - - READ_MEMORY_BYTE : 1.97T - - UTF8_DECODING_BASE : 0.00311T - - UTF8_DECODING_BYTE : 0.00525T - - WASM_INSTRUCTION : 14.86T - - Gas used to execute the cross contract call: 41.9T - - BASE : 0.00344T - - CONTRACT_LOADING_BASE : 0.00004T - - CONTRACT_LOADING_BYTES : 0.11228T - - READ_MEMORY_BASE : 0.00261T - - READ_MEMORY_BYTE : 0.0005T - - READ_REGISTER_BASE : 0.01007T - - READ_REGISTER_BYTE : 0T - - WASM_INSTRUCTION : 5.47T - - WRITE_MEMORY_BASE : 0.01122T - - WRITE_MEMORY_BYTE : 0.00014T - - WRITE_REGISTER_BASE : 0.01146T - - WRITE_REGISTER_BYTE : 0.00019T - - Gas used to refund unused gas for cross contract call: 0.22318T - - Gas used to refund unused gas: 0.22318T - - Total gas used: 70.63T - -- RS promise batch deploy contract and call - - Gas used to convert transaction to receipt: 2.43T - - Gas used to execute the receipt (actual contract call): 10.89T - - CREATE_ACCOUNT : 0.09961T - - DEPLOY_CONTRACT : 3.71T - - FUNCTION_CALL : 2.32T - - NEW_RECEIPT : 0.10806T - - TRANSFER : 0.11512T - - BASE : 0.00159T - - CONTRACT_LOADING_BASE : 0.00004T - - CONTRACT_LOADING_BYTES : 0.11283T - - PROMISE_RETURN : 0.00056T - - READ_MEMORY_BASE : 0.01566T - - READ_MEMORY_BYTE : 1.97T - - UTF8_DECODING_BASE : 0.00311T - - UTF8_DECODING_BYTE : 0.00525T - - WASM_INSTRUCTION : 0.00038T - - Gas used to execute the cross contract call: 41.9T - - BASE : 0.00344T - - CONTRACT_LOADING_BASE : 0.00004T - - CONTRACT_LOADING_BYTES : 0.11228T - - READ_MEMORY_BASE : 0.00261T - - READ_MEMORY_BYTE : 0.0005T - - READ_REGISTER_BASE : 0.01007T - - READ_REGISTER_BYTE : 0T - - WASM_INSTRUCTION : 5.47T - - WRITE_MEMORY_BASE : 0.01122T - - WRITE_MEMORY_BYTE : 0.00014T - - WRITE_REGISTER_BASE : 0.01146T - - WRITE_REGISTER_BYTE : 0.00019T - - Gas used to refund unused gas for cross contract call: 0.22318T - - Gas used to refund unused gas: 0.22318T - - Total gas used: 55.67T - -In this test, we use a JS contract and RS contract to both deploy a JS contract and cross contract call this newly deployed contract. We can see the gas to do the cross contract call is the same. JS SDK has a `~10T` overhead to parse a `~500K` contract in byte. This is because JS, either represent code in Uint8Array or string has some overhead while rust compiler can directly turn it into data section in wasm. In practice, a 10T overhead for a one time contract deploy is not a big deal. - -## Tips to do your own benchmark - -If the above cases don't cover use case or you have a complex algorithm to implement in JavaScript, it's a good idea to benchmark your specific algorithm before choose near-sdk-js for your project. - -You don't have to implement the exact algorithm to estimate the gas usage. Instead, you can find out the most expensive execution path of the algorithm, and estimate it by using the upper bound. For example, store the biggest possible objects into the collection and iterate for most possible times. Then goes to write the benchmark and the total gas cannot be more than 300T to be a valid contract. Also, if it has cross contract call, make sure the total gas, that's a sum of all cross contract calls, is less than 300T. - -To add your benchmark, write a one function contract of your most expensive operation. And write a test to call this function. If it doesn't involve cross contract call or promises, creating such test is simple. You can refer to `bench/src/expensive-calc.js` and `bench/__tests__/test-expensive-calc.ava.js` on how to write such test and print the gas breakdown. If it involves create promises or cross contract calls, printing the gas breakdown is a little bit more complex, you can refer to `bench/__tests__/test-deploy-contract.ava.js` for the recipe. +`20000 iterations` +| | Rust | JS Before Opt | JS After Opt | JS % Diff | +| :-------------------------------------- | ------------------: | ------------------: | ------------------: | ---------------: | +| Convert transaction to receipt | 2.43T | 2.43T | 2.43T | 0% | +| Execute the receipt (actual contract call) | 3.01T | 123.26T | 34.93T | -71.65% | +| BASE | 0.00185T | 0.00185T | 0.00185T | 0% | +| CONTRACT_LOADING_BASE | 0.00004T | 0.00004T | 0.00004T | 0% | +| CONTRACT_LOADING_BYTES | 0.06777T | 0.11209T | 0.10483T | -6.48% | +| READ_MEMORY_BASE | 0.01044T | 0.01044T | 0.01044T | 0% | +| READ_MEMORY_BYTE | 0.00006T | 0.00007T | 0.00007T | 0% | +| READ_REGISTER_BASE | 0.00252T | 0.00252T | 0.00252T | 0% | +| STORAGE_READ_BASE | 0.05636T | 0.05636T | 0.05636T | 0% | +| STORAGE_READ_KEY_BYTE | 0.00015T | 0.00015T | 0.00015T | 0% | +| STORAGE_WRITE_BASE | 0.0642T | 0.0642T | 0.0642T | 0% | +| STORAGE_WRITE_KEY_BYTE | 0.00035T | 0.00035T | 0.00035T | 0% | +| TOUCHING_TRIE_NODE | 0.0322T | 0.04831T | 0.04831T | 0% | +| WASM_INSTRUCTION | 0.33187T | 120.54T | 32.19T | -73.3% | +| WRITE_MEMORY_BASE | 0.00561T | 0.00561T | 0.00561T | 0% | +| WRITE_MEMORY_BYTE | 0.00007T | 0.00007T | 0.00007T | 0% | +| WRITE_REGISTER_BASE | 0.00287T | 0.00287T | 0.00287T | 0% | +| WRITE_REGISTER_BYTE | 0.00004T | 0.00004T | 0.00004T | 0% | +| Refund unused gas | 0.22318T | 0.22318T | 0.22318T | 0% | +| Total gas used | 5.66T | 125.91T | 37.58T | -70.15% | + +
+ +`10000 iterations` +| | Rust | JS Before Opt | JS After Opt | JS % Diff | +| :-------------------------------------- | ------------------: | ------------------: | ------------------: | ---------------: | +| Convert transaction to receipt | 2.43T | 2.43T | 2.43T | 0% | +| Execute the receipt (actual contract call) | 2.87T | 65.94T | 20.08T | -69.54% | +| BASE | 0.00238T | 0.00238T | 0.00238T | 0% | +| CONTRACT_LOADING_BASE | 0.00004T | 0.00004T | 0.00004T | 0% | +| CONTRACT_LOADING_BYTES | 0.06777T | 0.11209T | 0.10483T | -6.48% | +| READ_CACHED_TRIE_NODE | 0.00228T | 0.00228T | 0.00228T | 0% | +| READ_MEMORY_BASE | 0.01044T | 0.01044T | 0.01044T | 0% | +| READ_MEMORY_BYTE | 0.00006T | 0.00006T | 0.00006T | 0% | +| READ_REGISTER_BASE | 0.00503T | 0.00503T | 0.00503T | 0% | +| READ_REGISTER_BYTE | 0T | 0T | 0T | 0% | +| STORAGE_READ_BASE | 0.05636T | 0.05636T | 0.05636T | 0% | +| STORAGE_READ_KEY_BYTE | 0.00015T | 0.00015T | 0.00015T | 0% | +| STORAGE_WRITE_BASE | 0.0642T | 0.0642T | 0.0642T | 0% | +| STORAGE_WRITE_KEY_BYTE | 0.00035T | 0.00035T | 0.00035T | 0% | +| TOUCHING_TRIE_NODE | 0.08051T | 0.08051T | 0.08051T | 0% | +| WASM_INSTRUCTION | 0.16738T | 63.15T | 17.37T | -72.5% | +| WRITE_MEMORY_BASE | 0.00841T | 0.00841T | 0.00841T | 0% | +| WRITE_MEMORY_BYTE | 0.00007T | 0.00007T | 0.00007T | 0% | +| WRITE_REGISTER_BASE | 0.0086T | 0.0086T | 0.0086T | 0% | +| WRITE_REGISTER_BYTE | 0.00004T | 0.00004T | 0.00004T | 0% | +| Refund unused gas | 0.22318T | 0.22318T | 0.22318T | 0% | +| Total gas used | 5.55T | 68.59T | 22.73T | -66.85% | + +
+ +`100 iterations` +| | Rust | JS Before Opt | JS After Opt | JS % Diff | +| :-------------------------------------- | ------------------: | ------------------: | ------------------: | ---------------: | +| Convert transaction to receipt | 2.43T | 2.43T | 2.43T | 0% | +| Execute the receipt (actual contract call) | 2.71T | 9.09T | 5.52T | -39.23% | +| BASE | 0.00238T | 0.00238T | 0.00238T | 0% | +| CONTRACT_LOADING_BASE | 0.00004T | 0.00004T | 0.00004T | 0% | +| CONTRACT_LOADING_BYTES | 0.06777T | 0.11209T | 0.10483T | -6.48% | +| READ_CACHED_TRIE_NODE | 0.00228T | 0.00228T | 0.00228T | 0% | +| READ_MEMORY_BASE | 0.01044T | 0.01044T | 0.01044T | 0% | +| READ_MEMORY_BYTE | 0.00005T | 0.00006T | 0.00006T | 0% | +| READ_REGISTER_BASE | 0.00503T | 0.00503T | 0.00503T | 0% | +| READ_REGISTER_BYTE | 0T | 0T | 0T | 0% | +| STORAGE_READ_BASE | 0.05636T | 0.05636T | 0.05636T | 0% | +| STORAGE_READ_KEY_BYTE | 0.00015T | 0.00015T | 0.00015T | 0% | +| STORAGE_WRITE_BASE | 0.0642T | 0.0642T | 0.0642T | 0% | +| STORAGE_WRITE_KEY_BYTE | 0.00035T | 0.00035T | 0.00035T | 0% | +| TOUCHING_TRIE_NODE | 0.08051T | 0.08051T | 0.08051T | 0% | +| WASM_INSTRUCTION | 0.00437T | 6.3T | 2.75T | -56.35% | +| WRITE_MEMORY_BASE | 0.00841T | 0.00841T | 0.00841T | 0% | +| WRITE_MEMORY_BYTE | 0.00007T | 0.00007T | 0.00007T | 0% | +| WRITE_REGISTER_BASE | 0.0086T | 0.0086T | 0.0086T | 0% | +| WRITE_REGISTER_BYTE | 0.00003T | 0.00003T | 0.00003T | 0% | +| Refund unused gas | 0.22318T | 0.22318T | 0.22318T | 0% | +| Total gas used | 5.36T | 11.75T | 8.17T | -30.43% | + +
+ +In this case, JS uses much more gas. This is because the JS `Number` is an object, which has a lot of overhead compared to native integer arithmetic. It's even a lot of overhead compared to native float arithmetic. Also, in QuickJS, there's no JIT. If your contract does a lot of calculation or complex algorithm in JavaScript, it'd be better to do a similar benchmark. + +
+ +--- + +### Promise batch deploy contract and call + +| Deploy and cross-contract call | Rust | JS Before Opt | JS After Opt | JS % Diff | +| :-------------------------------------- | ------------------: | ------------------: | ------------------: | ---------------: | +| Convert transaction to receipt | 2.43T | 2.43T | 2.43T | 0% | +| Execute the receipt (actual contract call) | 14.64T | 25.86T | 25.88T | 0.08% | +| CREATE_ACCOUNT | 3.85T | 3.85T | 3.85T | 0% | +| DEPLOY_CONTRACT_BASE | 0.18477T | 0.18477T | 0.18477T | 0% | +| DEPLOY_CONTRACT_BYTE | 3.53T | 3.53T | 3.28T | -7.08% | +| FUNCTION_CALL_BASE | 2.32T | 2.32T | 2.32T | 0% | +| FUNCTION_CALL_BYTE | 0.00005T | 0.00005T | 0.00005T | 0% | +| NEW_ACTION_RECEIPT | 0.10806T | 0.10806T | 0.10806T | 0% | +| TRANSFER | 0.11512T | 0.11512T | 0.11512T | 0% | +| CONTRACT_LOADING_BASE | 0.00004T | 0.00004T | 0.00004T | 0% | +| CONTRACT_LOADING_BYTES | 0.11283T | 0.22386T | 0.2085T | -6.87% | +| PROMISE_RETURN | 0.00056T | 0.00056T | 0.00056T | 0% | +| READ_MEMORY_BASE | 0.01566T | 0.01566T | 0.01566T | 0% | +| READ_MEMORY_BYTE | 1.97T | 1.97T | 1.83T | -7.11% | +| UTF8_DECODING_BASE | 0.00311T | 0.00311T | 0.00311T | 0% | +| UTF8_DECODING_BYTE | 0.00525T | 0.00525T | 0.00525T | 0% | +| WASM_INSTRUCTION | 0.00043T | 11.54T | 11.53T | -0.09% | +| Gas used to execute the cross-contract call | 45.58T | 41.9T | 40.62T | -3.06% | +| Refund unused gas | 0.22318T | 0.22318T | 0.22318T | 0% | +| Total gas used | 63.1T | 70.63T | 69.37T | -1.79% | + +In this test, we use a JS contract and an RS contract to both deploy a JS contract and cross-contract call this newly deployed contract. We can see the gas used for the cross-contract call is the same. The JS SDK has a `~9.4T` overhead to parse a `~961K` contract in bytes. This is because JS, either representing code in Uint8Array or string, has some overhead, while the Rust compiler can directly turn it into the data section in WASM. In practice, a `~9.4T` overhead for a one-time contract deployment is not a big deal. + +
+ +--- ## Details of size benchmark -### JS Contract +| File Name | Rust Contract (KB) | JS Before Opt (KB) | JS After Opt (KB) | JS % Diff | +| :-------------------------------------- | ------------------: | ------------------: | ------------------: | ---------------: | +| deploy-contract.wasm | 508.37 | 947.53 | 939.41 | -0.86% | +| expensive-calc.wasm | 305.34 | 495.32 | 472.33 | -4.64% | +| highlevel-collection.wasm | 319.64 | 502.68 | 479.13 | -4.68% | +| highlevel-minimal.wasm | 159.75 | 495.07 | 472.19 | -4.63% | +| lowlevel-api.wasm | 0.38 | 471.08 | 467.53 | -0.75% | +| lowlevel-minimal.wasm | 0.21 | 471.96 | 468.51 | -0.73% | -``` --rwxrwxr-x 1 bo bo 1009K Feb 9 10:49 ./build/deploy-contract.wasm --rwxrwxr-x 1 bo bo 506K Feb 8 12:11 ./build/expensive-calc.wasm --rwxrwxr-x 1 bo bo 512K Feb 7 15:57 ./build/highlevel-collection.wasm --rwxrwxr-x 1 bo bo 505K Feb 7 10:53 ./build/highlevel-minimal.wasm --rwxrwxr-x 1 bo bo 502K Feb 10 11:32 ./build/lowlevel-api.wasm --rwxrwxr-x 1 bo bo 502K Feb 10 11:47 ./build/lowlevel-minimal.wasm -``` +
-### Rust Contract - -``` --rwxrwxr-x 1 bo bo 509K Feb 10 10:02 ./res/deploy_contract.wasm --rwxrwxr-x 1 bo bo 306K Feb 8 12:18 ./res/expensive_calc.wasm --rwxrwxr-x 1 bo bo 320K Feb 8 11:26 ./res/highlevel_collection.wasm --rwxrwxr-x 1 bo bo 160K Feb 7 10:51 ./res/highlevel_minimal.wasm --rwxrwxr-x 1 bo bo 387 Feb 7 11:56 ./res/lowlevel_api.wasm --rwxrwxr-x 1 bo bo 219 Feb 7 10:33 ./res/lowlevel_minimal.wasm -``` +--- ## Appendix diff --git a/examples/WASM-FILE-SIZE-COMPARISON.md b/examples/WASM-FILE-SIZE-COMPARISON.md new file mode 100644 index 000000000..1d0ccca39 --- /dev/null +++ b/examples/WASM-FILE-SIZE-COMPARISON.md @@ -0,0 +1,37 @@ +# NEAR-SDK-JS EXAMPLES + +### WASM File Size Comparison Before and After Optimization + +| File Name | Before Opt (KB) | After Opt (KB) | % Diff | +| :-------------------------------------- | ------------------: | ------------------: | ------------------: | +| basic-updates-base.wasm | 500.53 | 477.35 | -4.63% | +| basic-updates-update.wasm | 562.14 | 498.71 | -11.27% | +| clean-state.wasm | 496.45 | 473.48 | -4.62% | +| counter-lowlevel.wasm | 472.62 | 468.67 | -0.84% | +| counter-ts.wasm | 496.66 | 473.56 | -4.66% | +| counter.wasm | 496.56 | 473.51 | -4.64% | +| cross-contract-call-loop.wasm | 504.86 | 480.77 | -4.77% | +| cross-contract-call-ts.wasm | 498.54 | 475.04 | -4.71% | +| cross-contract-call.wasm | 498.51 | 475.01 | -4.71% | +| fungible-token-helper.wasm | 495.88 | 472.92 | -4.63% | +| fungible-token-lockable.wasm | 505.26 | 481.73 | -4.66% | +| fungible-token.wasm | 505.12 | 481.39 | -4.69% | +| my-ft.wasm | 520.98 | 495.55 | -4.89% | +| my-nft.wasm | 534.88 | 507.94 | -5.04% | +| nested-collections.wasm | 504.90 | 481.18 | -4.71% | +| nft-approval-receiver.wasm | 504.91 | 480.82 | -4.76% | +| nft-receiver.wasm | 505.10 | 481.05 | -4.76% | +| non-fungible-token-receiver.wasm | 496.51 | 473.51 | -4.63% | +| non-fungible-token.wasm | 503.30 | 479.39 | -4.76% | +| parking-lot.wasm | 500.11 | 476.87 | -4.65% | +| programmatic-update-after.wasm | 496.49 | 473.41 | -4.65% | +| programmatic-update-before.wasm | 496.47 | 473.38 | -4.65% | +| state-migration-new.wasm | 501.13 | 477.72 | -4.67% | +| state-migration-original.wasm | 499.98 | 476.68 | -4.65% | +| status-deserialize-class.wasm | 522.52 | 498.15 | -4.66% | +| status-message-borsh.wasm | 506.13 | 482.19 | -4.73% | +| status-message-collections.wasm | 505.38 | 481.67 | -4.70% | +| status-message-deserialize-err.wasm | 496.05 | 473.03 | -4.64% | +| status-message-migrate-add-field.wasm | 498.11 | 475.02 | -4.64% | +| status-message-serialize-err.wasm | 496.05 | 473.03 | -4.64% | +| status-message.wasm | 496.19 | 473.16 | -4.65% | diff --git a/examples/tsconfig.json b/examples/tsconfig.json index 7bebe8855..524e76306 100644 --- a/examples/tsconfig.json +++ b/examples/tsconfig.json @@ -1,8 +1,9 @@ { "compilerOptions": { "experimentalDecorators": true, - "target": "es2020", "moduleResolution": "node", + "target": "es2020", + "skipLibCheck": true, "noEmit": true }, "exclude": ["node_modules"] diff --git a/package.json b/package.json index d31a34c19..59d314318 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "docs:generate": "typedoc" }, "devDependencies": { - "turbo": "1.10.16", + "turbo": "1.13.3", "typedoc": "0.25.4", "typescript": "4.7.4" } diff --git a/packages/near-contract-standards/package.json b/packages/near-contract-standards/package.json index 6578904e5..fb3dc9185 100644 --- a/packages/near-contract-standards/package.json +++ b/packages/near-contract-standards/package.json @@ -10,7 +10,6 @@ "author": "Near Inc ", "license": "Apache-2.0", "dependencies": { - "lodash-es": "4.17.21", "near-sdk-js": "workspace:*" }, "devDependencies": { diff --git a/packages/near-sdk-js/builder/builder.c b/packages/near-sdk-js/builder/builder.c index 47c3de721..f7df95f7a 100644 --- a/packages/near-sdk-js/builder/builder.c +++ b/packages/near-sdk-js/builder/builder.c @@ -1,1183 +1,1195 @@ -#include -#include "../node_modules/near-sdk-js/lib/cli/deps/quickjs/quickjs-libc-min.h" -#include "../node_modules/near-sdk-js/lib/cli/deps/quickjs/libbf.h" -#include "code.h" - -static JSContext *JS_NewCustomContext(JSRuntime *rt) -{ - JSContext *ctx = JS_NewContextRaw(rt); - if (!ctx) - return NULL; - JS_AddIntrinsicBaseObjects(ctx); - JS_AddIntrinsicDate(ctx); - JS_AddIntrinsicEval(ctx); - JS_AddIntrinsicStringNormalize(ctx); - JS_AddIntrinsicRegExp(ctx); - JS_AddIntrinsicJSON(ctx); - JS_AddIntrinsicProxy(ctx); - JS_AddIntrinsicMapSet(ctx); - JS_AddIntrinsicTypedArrays(ctx); - JS_AddIntrinsicPromise(ctx); - JS_AddIntrinsicBigInt(ctx); - return ctx; -} - -#define DEFINE_NEAR_METHOD(name) \ - void name () __attribute__((export_name(#name))) {\ - JSRuntime *rt;\ - JSContext *ctx;\ - JSValue mod_obj, fun_obj, result, error, error_message, error_stack;\ - const char *error_message_c, *error_stack_c;\ - char *error_c;\ - size_t msg_len, stack_len;\ - rt = JS_NewRuntime();\ - ctx = JS_NewCustomContext(rt);\ - js_add_near_host_functions(ctx);\ - mod_obj = js_load_module_binary(ctx, code, code_size);\ - fun_obj = JS_GetProperty(ctx, mod_obj, JS_NewAtom(ctx, #name));\ - result = JS_Call(ctx, fun_obj, mod_obj, 0, NULL);\ - if (JS_IsException(result)) {\ - error = JS_GetException(ctx);\ - error_message = JS_GetPropertyStr(ctx, error, "message");\ - error_stack = JS_GetPropertyStr(ctx, error, "stack");\ - error_message_c = JS_ToCStringLen(ctx, &msg_len, error_message);\ - error_stack_c = JS_ToCStringLen(ctx, &stack_len, error_stack);\ - error_c = malloc(msg_len+1+stack_len);\ - strncpy(error_c, error_message_c, msg_len);\ - error_c[msg_len] = '\n';\ - strncpy(error_c+msg_len+1, error_stack_c, stack_len);\ - panic_utf8(msg_len+1+stack_len, (uint64_t)error_c);\ - }\ - js_std_loop(ctx);\ - } - -// ############# -// # Registers # -// ############# -extern void read_register(uint64_t register_id, uint64_t ptr); -extern uint64_t register_len(uint64_t register_id); -extern void write_register(uint64_t register_id, uint64_t data_len, uint64_t data_ptr); -// ############### -// # Context API # -// ############### -extern void current_account_id(uint64_t register_id); -extern void signer_account_id(uint64_t register_id); -extern void signer_account_pk(uint64_t register_id); -extern void predecessor_account_id(uint64_t register_id); -extern void input(uint64_t register_id); -extern uint64_t block_index(); -extern uint64_t block_timestamp(); -extern uint64_t epoch_height(); -extern uint64_t storage_usage(); -// ################# -// # Economics API # -// ################# -extern void account_balance(uint64_t balance_ptr); -extern void account_locked_balance(uint64_t balance_ptr); -extern void attached_deposit(uint64_t balance_ptr); -extern uint64_t prepaid_gas(); -extern uint64_t used_gas(); -// ############ -// # Math API # -// ############ -extern void random_seed(uint64_t register_id); -extern void sha256(uint64_t value_len, uint64_t value_ptr, uint64_t register_id); -extern void keccak256(uint64_t value_len, uint64_t value_ptr, uint64_t register_id); -extern void keccak512(uint64_t value_len, uint64_t value_ptr, uint64_t register_id); -extern void ripemd160(uint64_t value_len, uint64_t value_ptr, uint64_t register_id); -extern uint64_t ecrecover(uint64_t hash_len, uint64_t hash_ptr, uint64_t sign_len, uint64_t sig_ptr, uint64_t v, uint64_t malleability_flag, uint64_t register_id); -// ##################### -// # Miscellaneous API # -// ##################### -extern void value_return(uint64_t value_len, uint64_t value_ptr); -extern void panic(void); -extern void panic_utf8(uint64_t len, uint64_t ptr); -extern void log_utf8(uint64_t len, uint64_t ptr); -extern void log_utf16(uint64_t len, uint64_t ptr); -// Name confliction with WASI. Can be re-exported with a different name on NEAR side with a protocol upgrade -// Or, this is actually not a primitive, can be implement with log and panic host functions in C side or JS side. -// extern void abort(uint32_t msg_ptr, uint32_t filename_ptr, uint32_t u32, uint32_t col); -// ################ -// # Promises API # -// ################ -extern uint64_t promise_create(uint64_t account_id_len, uint64_t account_id_ptr, uint64_t method_name_len, uint64_t method_name_ptr, uint64_t arguments_len, uint64_t arguments_ptr, uint64_t amount_ptr, uint64_t gas); -extern uint64_t promise_then(uint64_t promise_index, uint64_t account_id_len, uint64_t account_id_ptr, uint64_t method_name_len, uint64_t method_name_ptr, uint64_t arguments_len, uint64_t arguments_ptr, uint64_t amount_ptr, uint64_t gas); -extern uint64_t promise_and(uint64_t promise_idx_ptr, uint64_t promise_idx_count); -extern uint64_t promise_batch_create(uint64_t account_id_len, uint64_t account_id_ptr); -extern uint64_t promise_batch_then(uint64_t promise_index, uint64_t account_id_len, uint64_t account_id_ptr); -// ####################### -// # Promise API actions # -// ####################### -extern void promise_batch_action_create_account(uint64_t promise_index); -extern void promise_batch_action_deploy_contract(uint64_t promise_index, uint64_t code_len, uint64_t code_ptr); -extern void promise_batch_action_function_call(uint64_t promise_index, uint64_t method_name_len, uint64_t method_name_ptr, uint64_t arguments_len, uint64_t arguments_ptr, uint64_t amount_ptr, uint64_t gas); -extern void promise_batch_action_transfer(uint64_t promise_index, uint64_t amount_ptr); -extern void promise_batch_action_stake(uint64_t promise_index, uint64_t amount_ptr, uint64_t public_key_len, uint64_t public_key_ptr); -extern void promise_batch_action_add_key_with_full_access(uint64_t promise_index, uint64_t public_key_len, uint64_t public_key_ptr, uint64_t nonce); -extern void promise_batch_action_add_key_with_function_call(uint64_t promise_index, uint64_t public_key_len, uint64_t public_key_ptr, uint64_t nonce, uint64_t allowance_ptr, uint64_t receiver_id_len, uint64_t receiver_id_ptr, uint64_t method_names_len, uint64_t method_names_ptr); -extern void promise_batch_action_delete_key(uint64_t promise_index, uint64_t public_key_len, uint64_t public_key_ptr); -extern void promise_batch_action_delete_account(uint64_t promise_index, uint64_t beneficiary_id_len, uint64_t beneficiary_id_ptr); -extern void promise_batch_action_function_call_weight(uint64_t promise_index, uint64_t function_name_len, uint64_t function_name_ptr, uint64_t arguments_len, uint64_t arguments_ptr, uint64_t amount_ptr, uint64_t gas, uint64_t weight); -// ####################### -// # Promise API results # -// ####################### -extern uint64_t promise_results_count(void); -extern uint64_t promise_result(uint64_t result_idx, uint64_t register_id); -extern void promise_return(uint64_t promise_idx); -// ############### -// # Storage API # -// ############### -extern uint64_t storage_write(uint64_t key_len, uint64_t key_ptr, uint64_t value_len, uint64_t value_ptr, uint64_t register_id); -extern uint64_t storage_read(uint64_t key_len, uint64_t key_ptr, uint64_t register_id); -extern uint64_t storage_remove(uint64_t key_len, uint64_t key_ptr, uint64_t register_id); -extern uint64_t storage_has_key(uint64_t key_len, uint64_t key_ptr); -// ################# -// # Validator API # -// ################# -extern void validator_stake(uint64_t account_id_len, uint64_t account_id_ptr, uint64_t stake_ptr); -extern void validator_total_stake(uint64_t stake_ptr); -// ############# -// # Alt BN128 # -// ############# -extern void alt_bn128_g1_multiexp(uint64_t value_len, uint64_t value_ptr, uint64_t register_id); -extern void alt_bn128_g1_sum(uint64_t value_len, uint64_t value_ptr, uint64_t register_id); -extern uint64_t alt_bn128_pairing_check(uint64_t value_len, uint64_t value_ptr); - -static uint8_t* JS_Uint8Array_to_C(JSContext *ctx, JSValue array, size_t *len) { - uint8_t *ptr; - JSValue buffer; - size_t pbyte_offset, psize, pbytes_per_element = 0; - - buffer = JS_GetTypedArrayBuffer(ctx, array, &pbyte_offset, len, &pbytes_per_element); - if (JS_IsException(buffer) || pbytes_per_element != 1) { - return NULL; - } - ptr = JS_GetArrayBuffer(ctx, &psize, buffer); - if (ptr == NULL) { - return NULL; - } - return ptr + pbyte_offset; -} - -static JSValue near_read_register(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t register_id; - uint8_t *data; - uint64_t data_len; - JSValue arraybuffer, ret; - - if (JS_ToUint64Ext(ctx, ®ister_id, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); - } - data_len = register_len(register_id); - if (data_len != UINT64_MAX) { - data = malloc(data_len); - read_register(register_id, (uint64_t)data); - arraybuffer = JS_NewArrayBuffer(ctx, data, (size_t)data_len, NULL, NULL, TRUE); - return JS_CallConstructor(ctx, JS_GetPropertyStr(ctx, JS_GetGlobalObject(ctx), "Uint8Array"), 1, (JSValueConst *)&arraybuffer); - } else { - return JS_UNDEFINED; - } -} - -static JSValue near_register_len(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t register_id, len; - - if (JS_ToUint64Ext(ctx, ®ister_id, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); - } - len = register_len(register_id); - return JS_NewBigUint64(ctx, len); -} - -static JSValue near_write_register(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t register_id; - uint8_t *data_ptr; - size_t data_len; - - if (JS_ToUint64Ext(ctx, ®ister_id, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); - } - data_ptr = JS_Uint8Array_to_C(ctx, argv[1], &data_len); - if (data_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for data"); - } - - write_register(register_id, data_len, (uint64_t)data_ptr); - return JS_UNDEFINED; -} - -static JSValue near_current_account_id(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t register_id; - - if (JS_ToUint64Ext(ctx, ®ister_id, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); - } - current_account_id(register_id); - return JS_UNDEFINED; -} - -static JSValue near_signer_account_id(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - uint64_t register_id; - - if (JS_ToUint64Ext(ctx, ®ister_id, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); - } - signer_account_id(register_id); - return JS_UNDEFINED; -} - -static JSValue near_signer_account_pk(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - uint64_t register_id; - - if (JS_ToUint64Ext(ctx, ®ister_id, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); - } - signer_account_pk(register_id); - return JS_UNDEFINED; -} - -static JSValue near_predecessor_account_id(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - uint64_t register_id; - - if (JS_ToUint64Ext(ctx, ®ister_id, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); - } - predecessor_account_id(register_id); - return JS_UNDEFINED; -} - -static JSValue near_input(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t register_id; - - if (JS_ToUint64Ext(ctx, ®ister_id, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); - } - input(register_id); - return JS_UNDEFINED; -} - -static JSValue near_block_index(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t value; - - value = block_index(); - return JS_NewBigUint64(ctx, value); -} - -static JSValue near_block_timestamp(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t value; - - value = block_timestamp(); - return JS_NewBigUint64(ctx, value); -} - -static JSValue near_epoch_height(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t value; - - value = epoch_height(); - return JS_NewBigUint64(ctx, value); -} - -static JSValue near_storage_usage(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t value; - - value = storage_usage(); - return JS_NewBigUint64(ctx, value); -} - -// ptr[0] ptr[1] is little-endian u128. -static JSValue u128_to_quickjs(JSContext *ctx, uint64_t* ptr) { - JSValue value; - bf_t* bn; - bf_t b; - - value = JS_NewBigInt(ctx); - bn = JS_GetBigInt(value); - // from ptr[] to bn - // high 64 bits - bf_set_ui(bn, ptr[1]); - bf_mul_2exp(bn, 64, BF_PREC_INF, BF_RNDZ); - // low 64 bits - bf_init(bn->ctx, &b); - bf_set_ui(&b, ptr[0]); - bf_add(bn, bn, &b, BF_PREC_INF, BF_RNDZ); - bf_delete(&b); - - return value; -} - -static int quickjs_bigint_to_u128(JSContext *ctx, JSValueConst val, uint64_t* ptr) { - bf_t* a; - bf_t q, r, b, one, u128max; - a = JS_GetBigInt(val); - bf_init(a->ctx, &u128max); - bf_set_ui(&u128max, 1); - bf_mul_2exp(&u128max, 128, BF_PREC_INF, BF_RNDZ); - if (bf_cmp_le(&u128max, a)) { - return 1; - } - bf_init(a->ctx, &q); - bf_init(a->ctx, &r); - bf_init(a->ctx, &b); - bf_init(a->ctx, &one); - bf_set_ui(&b, UINT64_MAX); - bf_set_ui(&one, 1); - bf_add(&b, &b, &one, BF_PREC_INF, BF_RNDZ); - bf_divrem(&q, &r, a, &b, BF_PREC_INF, BF_RNDZ, BF_RNDZ); - - bf_get_uint64(ptr, &r); - bf_get_uint64(ptr+1, &q); - return 0; -} - -static int quickjs_int_to_u128(JSContext *ctx, JSValueConst val, uint64_t* ptr) { - if (JS_ToUint64Ext(ctx, ptr, val) < 0) { - return 1; - } - ptr[1] = 0; - return 0; -} - -static int quickjs_to_u128(JSContext *ctx, JSValueConst val, uint64_t* ptr) { - if (JS_IsBigInt(ctx, val)) - return quickjs_bigint_to_u128(ctx, val, ptr); - else { - return quickjs_int_to_u128(ctx, val, ptr); - } -} - -static JSValue near_account_balance(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t ptr[2]; - - account_balance((uint64_t)ptr); - return u128_to_quickjs(ctx, ptr); -} - -static JSValue near_account_locked_balance(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t ptr[2]; - - account_locked_balance((uint64_t)ptr); - return u128_to_quickjs(ctx, ptr); -} - -static JSValue near_attached_deposit(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t ptr[2]; - - attached_deposit((uint64_t)ptr); - return u128_to_quickjs(ctx, ptr); -} - -static JSValue near_prepaid_gas(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t value; - - value = prepaid_gas(); - return JS_NewBigUint64(ctx, value); -} - -static JSValue near_used_gas(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t value; - - value = used_gas(); - return JS_NewBigUint64(ctx, value); -} - -static JSValue near_random_seed(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t register_id; - - if (JS_ToUint64Ext(ctx, ®ister_id, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); - } - random_seed(register_id); - return JS_UNDEFINED; -} - -static JSValue near_sha256(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t register_id; - uint8_t *data_ptr; - size_t data_len; - - data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); - if (data_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for data"); - } - if (JS_ToUint64Ext(ctx, ®ister_id, argv[1]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); - } - - sha256(data_len, (uint64_t)data_ptr, register_id); - return JS_UNDEFINED; -} - -static JSValue near_keccak256(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t register_id; - uint8_t *data_ptr; - size_t data_len; - - data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); - if (data_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for data"); - } - if (JS_ToUint64Ext(ctx, ®ister_id, argv[1]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); - } - keccak256(data_len, (uint64_t)data_ptr, register_id); - return JS_UNDEFINED; -} - -static JSValue near_keccak512(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t register_id; - uint8_t *data_ptr; - size_t data_len; - - data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); - if (data_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for data"); - } - if (JS_ToUint64Ext(ctx, ®ister_id, argv[1]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); - } - - keccak512(data_len, (uint64_t)data_ptr, register_id); - return JS_UNDEFINED; -} - -static JSValue near_ripemd160(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t register_id; - uint8_t *data_ptr; - size_t data_len; - - data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); - if (data_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for data"); - } - if (JS_ToUint64Ext(ctx, ®ister_id, argv[1]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); - } - - ripemd160(data_len, (uint64_t)data_ptr, register_id); - return JS_UNDEFINED; -} - -static JSValue near_ecrecover(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t malleability_flag, v, register_id, result; - uint8_t *hash_ptr, *sig_ptr; - size_t hash_len, sign_len; - - hash_ptr = JS_Uint8Array_to_C(ctx, argv[0], &hash_len); - if (hash_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for hash"); - } - sig_ptr = JS_Uint8Array_to_C(ctx, argv[1], &sign_len); - if (sig_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for sig"); - } - if (JS_ToUint64Ext(ctx, &malleability_flag, argv[2]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for malleability_flag"); - } - if (JS_ToUint64Ext(ctx, &v, argv[3]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for v"); - } - if (JS_ToUint64Ext(ctx, ®ister_id, argv[4]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); - } - - result = ecrecover(hash_len, (uint64_t)hash_ptr, sign_len, (uint64_t)sig_ptr, malleability_flag, v, register_id); - return JS_NewBigUint64(ctx, result); -} - -static JSValue near_value_return(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint8_t *value_ptr; - size_t value_len; - - value_ptr = JS_Uint8Array_to_C(ctx, argv[0], &value_len); - if (value_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for value"); - } - value_return(value_len, (uint64_t)(value_ptr)); - return JS_UNDEFINED; -} - -static JSValue near_panic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - const char *data_ptr; - size_t data_len; - - if (argc == 1) { - data_ptr = JS_ToCStringLen(ctx, &data_len, argv[0]); - panic_utf8(data_len, (uint64_t)data_ptr); - } else { - panic(); - } - return JS_UNDEFINED; -} - -static JSValue near_panic_utf8(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint8_t *data_ptr; - size_t data_len; - - data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); - if (data_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for message"); - } - - panic_utf8(data_len, (uint64_t)data_ptr); - return JS_UNDEFINED; -} - -static JSValue near_log(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - const char *data_ptr; - size_t data_len; - - data_ptr = JS_ToCStringLen(ctx, &data_len, argv[0]); - - log_utf8(data_len, (uint64_t)data_ptr); - return JS_UNDEFINED; -} - -static JSValue near_log_utf8(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint8_t *data_ptr; - size_t data_len; - - data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); - if (data_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for message"); - } - - log_utf8(data_len, (uint64_t)data_ptr); - return JS_UNDEFINED; -} - -static JSValue near_log_utf16(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint8_t *data_ptr; - size_t data_len; - - data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); - if (data_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for message"); - } - - log_utf16(data_len, (uint64_t)data_ptr); - return JS_UNDEFINED; -} - -static JSValue near_promise_create(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - const char *account_id_ptr, *method_name_ptr; - uint8_t *arguments_ptr; - size_t account_id_len, method_name_len, arguments_len; - uint64_t amount_ptr[2]; // amount is u128 - uint64_t gas, ret; - - account_id_ptr = JS_ToCStringLen(ctx, &account_id_len, argv[0]); - method_name_ptr = JS_ToCStringLen(ctx, &method_name_len, argv[1]); - arguments_ptr = JS_Uint8Array_to_C(ctx, argv[2], &arguments_len); - if (arguments_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for arguments"); - } - if (quickjs_to_u128(ctx, argv[3], amount_ptr) != 0) { - return JS_ThrowTypeError(ctx, "Expect Uint128 for amount"); - } - if (JS_ToUint64Ext(ctx, &gas, argv[4]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for gas"); - } - - ret = promise_create(account_id_len, (uint64_t)account_id_ptr, method_name_len, (uint64_t)method_name_ptr, arguments_len, (uint64_t)arguments_ptr, (uint64_t)amount_ptr, gas); - - return JS_NewBigUint64(ctx, ret); -} - -static JSValue near_promise_then(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t promise_index; - const char *account_id_ptr, *method_name_ptr; - uint8_t *arguments_ptr; - size_t account_id_len, method_name_len, arguments_len; - uint64_t amount_ptr[2]; // amount is u128 - uint64_t gas, ret; - - if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); - } - account_id_ptr = JS_ToCStringLen(ctx, &account_id_len, argv[1]); - method_name_ptr = JS_ToCStringLen(ctx, &method_name_len, argv[2]); - arguments_ptr = JS_Uint8Array_to_C(ctx, argv[3], &arguments_len); - if (arguments_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for arguments"); - } - if (quickjs_to_u128(ctx, argv[4], amount_ptr) != 0) { - return JS_ThrowTypeError(ctx, "Expect Uint128 for amount"); - } - if (JS_ToUint64Ext(ctx, &gas, argv[5]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for gas"); - } - - ret = promise_then(promise_index, account_id_len, (uint64_t)account_id_ptr, method_name_len, (uint64_t)method_name_ptr, arguments_len, (uint64_t)arguments_ptr, (uint64_t)amount_ptr, gas); - - return JS_NewBigUint64(ctx, ret); -} - -static JSValue near_promise_and(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t promise_idx_ptr[argc], ret; - - for(int i = 0; i < argc; i++) { - if (JS_ToUint64Ext(ctx, &promise_idx_ptr[i], argv[i]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_id"); - } - } - ret = promise_and((uint64_t)promise_idx_ptr, argc); - return JS_NewBigUint64(ctx, ret); -} - -static JSValue near_promise_batch_create(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - const char *account_id_ptr; - size_t account_id_len; - uint64_t ret; - - account_id_ptr = JS_ToCStringLen(ctx, &account_id_len, argv[0]); - ret = promise_batch_create(account_id_len, (uint64_t)account_id_ptr); - return JS_NewBigUint64(ctx, ret); -} - -static JSValue near_promise_batch_then(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t promise_index; - const char *account_id_ptr; - size_t account_id_len; - uint64_t ret; - - if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); - } - account_id_ptr = JS_ToCStringLen(ctx, &account_id_len, argv[1]); - ret = promise_batch_then(promise_index, account_id_len, (uint64_t)account_id_ptr); - return JS_NewBigUint64(ctx, ret); -} - -static JSValue near_promise_batch_action_create_account(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t promise_index; - - if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); - } - promise_batch_action_create_account(promise_index); - return JS_UNDEFINED; -} - -static JSValue near_promise_batch_action_deploy_contract(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t promise_index; - uint8_t *code_ptr; - size_t code_len; - - if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); - } - code_ptr = JS_Uint8Array_to_C(ctx, argv[1], &code_len); - if (code_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for code"); - } - promise_batch_action_deploy_contract(promise_index, code_len, (uint64_t)code_ptr); - return JS_UNDEFINED; -} - -static JSValue near_promise_batch_action_function_call(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t promise_index; - const char *method_name_ptr; - uint8_t *arguments_ptr; - size_t method_name_len, arguments_len; - uint64_t amount_ptr[2]; // amount is u128 - uint64_t gas; - - if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); - } - method_name_ptr = JS_ToCStringLen(ctx, &method_name_len, argv[1]); - arguments_ptr = JS_Uint8Array_to_C(ctx, argv[2], &arguments_len); - if (arguments_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for arguments"); - } - if (quickjs_to_u128(ctx, argv[3], amount_ptr) != 0) { - return JS_ThrowTypeError(ctx, "Expect Uint128 for amount"); - } - if (JS_ToUint64Ext(ctx, &gas, argv[4]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for gas"); - } - promise_batch_action_function_call(promise_index, method_name_len, (uint64_t)method_name_ptr, arguments_len, (uint64_t)arguments_ptr, (uint64_t)amount_ptr, gas); - return JS_UNDEFINED; -} - -static JSValue near_promise_batch_action_transfer(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t promise_index; - uint64_t amount_ptr[2]; // amount is u128 - - if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); - } - if (quickjs_to_u128(ctx, argv[1], amount_ptr) != 0) { - return JS_ThrowTypeError(ctx, "Expect Uint128 for amount"); - } - promise_batch_action_transfer(promise_index, (uint64_t)amount_ptr); - return JS_UNDEFINED; -} - -static JSValue near_promise_batch_action_stake(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t promise_index; - uint64_t amount_ptr[2]; - uint8_t *public_key_ptr; - size_t public_key_len; - - if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); - } - if (quickjs_to_u128(ctx, argv[1], amount_ptr) != 0) { - return JS_ThrowTypeError(ctx, "Expect Uint128 for amount"); - } - public_key_ptr = JS_Uint8Array_to_C(ctx, argv[2], &public_key_len); - if (public_key_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for public key"); - } - - promise_batch_action_stake(promise_index, (uint64_t)amount_ptr, public_key_len, (uint64_t)public_key_ptr); - return JS_UNDEFINED; -} - -static JSValue near_promise_batch_action_add_key_with_full_access(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t promise_index; - uint8_t *public_key_ptr; - size_t public_key_len; - uint64_t nonce; - - if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); - } - public_key_ptr = JS_Uint8Array_to_C(ctx, argv[1], &public_key_len); - if (public_key_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for public key"); - } - if (JS_ToUint64Ext(ctx, &nonce, argv[2]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for nonce"); - } - promise_batch_action_add_key_with_full_access(promise_index, public_key_len, (uint64_t)public_key_ptr, nonce); - return JS_UNDEFINED; -} - -static JSValue near_promise_batch_action_add_key_with_function_call(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t promise_index; - const char *receiver_id_ptr, *method_names_ptr; - uint8_t *public_key_ptr; - size_t public_key_len, receiver_id_len, method_names_len; - uint64_t nonce, allowance_ptr[2]; - - if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); - } - public_key_ptr = JS_Uint8Array_to_C(ctx, argv[1], &public_key_len); - if (public_key_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for public key"); - } - if (JS_ToUint64Ext(ctx, &nonce, argv[2]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for nonce"); - } - if (quickjs_to_u128(ctx, argv[3], allowance_ptr) != 0) { - return JS_ThrowTypeError(ctx, "Expect Uint128 for allowance"); - } - receiver_id_ptr = JS_ToCStringLen(ctx, &receiver_id_len, argv[4]); - method_names_ptr = JS_ToCStringLen(ctx, &method_names_len, argv[5]); - - promise_batch_action_add_key_with_function_call(promise_index, public_key_len, (uint64_t)public_key_ptr, nonce, (uint64_t)allowance_ptr, receiver_id_len, (uint64_t)receiver_id_ptr, method_names_len, (uint64_t)method_names_ptr); - return JS_UNDEFINED; -} - -static JSValue near_promise_batch_action_delete_key(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t promise_index; - uint8_t *public_key_ptr; - size_t public_key_len; - - if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); - } - public_key_ptr = JS_Uint8Array_to_C(ctx, argv[1], &public_key_len); - if (public_key_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for public key"); - } - promise_batch_action_delete_key(promise_index, public_key_len, (uint64_t)public_key_ptr); - return JS_UNDEFINED; -} - -static JSValue near_promise_batch_action_function_call_weight(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t promise_index; - const char *method_name_ptr, *arguments_ptr; - size_t method_name_len, arguments_len; - uint64_t amount_ptr[2]; // amount is u128 - uint64_t gas; - uint64_t weight; - - if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); - } - method_name_ptr = JS_ToCStringLen(ctx, &method_name_len, argv[1]); - arguments_ptr = JS_ToCStringLenRaw(ctx, &arguments_len, argv[2]); - if (quickjs_to_u128(ctx, argv[3], amount_ptr) != 0) { - return JS_ThrowTypeError(ctx, "Expect Uint128 for amount"); - } - if (JS_ToUint64Ext(ctx, &gas, argv[4]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for gas"); - } - if (JS_ToUint64Ext(ctx, &weight, argv[5]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for weight"); - } - promise_batch_action_function_call_weight(promise_index, method_name_len, (uint64_t)method_name_ptr, arguments_len, (uint64_t)arguments_ptr, (uint64_t)amount_ptr, gas, weight); - return JS_UNDEFINED; -} - -static JSValue near_promise_batch_action_delete_account(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t promise_index; - const char *beneficiary_id_ptr; - size_t beneficiary_id_len; - - if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); - } - beneficiary_id_ptr = JS_ToCStringLen(ctx, &beneficiary_id_len, argv[1]); - promise_batch_action_delete_account(promise_index, beneficiary_id_len, (uint64_t)beneficiary_id_ptr); - return JS_UNDEFINED; -} - -static JSValue near_promise_results_count(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t value; - - value = promise_results_count(); - return JS_NewBigUint64(ctx, value); -} - -static JSValue near_promise_result(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t result_idx, register_id; - uint64_t ret; - - if (JS_ToUint64Ext(ctx, &result_idx, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for result_idx"); - } - if (JS_ToUint64Ext(ctx, ®ister_id, argv[1]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); - } - ret = promise_result(result_idx, register_id); - - return JS_NewBigUint64(ctx, ret); -} - -static JSValue near_promise_return(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t promise_idx; - if (JS_ToUint64Ext(ctx, &promise_idx, argv[0]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_idx"); - } - promise_return(promise_idx); - - return JS_UNDEFINED; -} - -static JSValue near_storage_write(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint8_t *key_ptr, *value_ptr; - size_t key_len, value_len; - uint64_t register_id, ret; - - key_ptr = JS_Uint8Array_to_C(ctx, argv[0], &key_len); - if (key_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for key"); - } - value_ptr = JS_Uint8Array_to_C(ctx, argv[1], &value_len); - if (value_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for value"); - } - if (JS_ToUint64Ext(ctx, ®ister_id, argv[2]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); - } - ret = storage_write(key_len, (uint64_t)key_ptr, value_len, (uint64_t)value_ptr, register_id); - return JS_NewBigUint64(ctx, ret); -} - -static JSValue near_storage_read(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint8_t *key_ptr; - size_t key_len; - uint64_t register_id; - uint64_t ret; - - key_ptr = JS_Uint8Array_to_C(ctx, argv[0], &key_len); - if (key_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for key"); - } - if (JS_ToUint64Ext(ctx, ®ister_id, argv[1]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); - } - ret = storage_read(key_len, (uint64_t)key_ptr, register_id); - return JS_NewBigUint64(ctx, ret); -} - -static JSValue near_storage_remove(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint8_t *key_ptr; - size_t key_len; - uint64_t register_id; - uint64_t ret; - - key_ptr = JS_Uint8Array_to_C(ctx, argv[0], &key_len); - if (key_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for key"); - } - if (JS_ToUint64Ext(ctx, ®ister_id, argv[1]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); - } - ret = storage_remove(key_len, (uint64_t)key_ptr, register_id); - return JS_NewBigUint64(ctx, ret); -} - -static JSValue near_storage_has_key(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint8_t *key_ptr; - size_t key_len; - uint64_t ret; - - key_ptr = JS_Uint8Array_to_C(ctx, argv[0], &key_len); - if (key_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for key"); - } - ret = storage_has_key(key_len, (uint64_t)key_ptr); - return JS_NewBigUint64(ctx, ret); -} - -static JSValue near_validator_stake(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - const char *account_id_ptr; - size_t account_id_len; - uint64_t stake_ptr[2]; - - account_id_ptr = JS_ToCStringLen(ctx, &account_id_len, argv[0]); - validator_stake(account_id_len, (uint64_t)account_id_ptr, (uint64_t)stake_ptr); - - return u128_to_quickjs(ctx, stake_ptr); -} - -static JSValue near_validator_total_stake(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t stake_ptr[2]; - - validator_total_stake((uint64_t)stake_ptr); - return u128_to_quickjs(ctx, stake_ptr); -} - -static JSValue near_utf8_string_to_uint8array(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - const char *data; - size_t len; - JSValue arraybuffer; - - data = JS_ToCStringLen(ctx, &len, argv[0]); - - arraybuffer = JS_NewArrayBuffer(ctx, (uint8_t *)data, len, NULL, NULL, TRUE); - return JS_CallConstructor(ctx, JS_GetPropertyStr(ctx, JS_GetGlobalObject(ctx), "Uint8Array"), 1, (JSValueConst *)&arraybuffer); -} - -static JSValue near_latin1_string_to_uint8array(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - const char *data; - size_t len; - JSValue arraybuffer; - - data = JS_ToCStringLenRaw(ctx, &len, argv[0]); - - arraybuffer = JS_NewArrayBuffer(ctx, (uint8_t *)data, len, NULL, NULL, TRUE); - return JS_CallConstructor(ctx, JS_GetPropertyStr(ctx, JS_GetGlobalObject(ctx), "Uint8Array"), 1, (JSValueConst *)&arraybuffer); -} - -static JSValue near_uint8array_to_latin1_string(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint8_t *data_ptr; - size_t data_len; - - data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); - if (data_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array"); - } - - return JS_NewStringLenRaw(ctx, (const char *)data_ptr, data_len); -} - -static JSValue near_uint8array_to_utf8_string(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint8_t *data_ptr; - size_t data_len; - - data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); - if (data_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array"); - } - - return JS_NewStringLen(ctx, (const char *)data_ptr, data_len); -} - -static JSValue near_alt_bn128_g1_multiexp(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t register_id; - uint8_t *data_ptr; - size_t data_len; - - data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); - if (data_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for data"); - } - if (JS_ToUint64Ext(ctx, ®ister_id, argv[1]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); - } - - alt_bn128_g1_multiexp(data_len, (uint64_t)data_ptr, register_id); - return JS_UNDEFINED; -} - -static JSValue near_alt_bn128_g1_sum(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint64_t register_id; - uint8_t *data_ptr; - size_t data_len; - - data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); - if (data_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for data"); - } - if (JS_ToUint64Ext(ctx, ®ister_id, argv[1]) < 0) { - return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); - } - - alt_bn128_g1_sum(data_len, (uint64_t)data_ptr, register_id); - return JS_UNDEFINED; -} - -static JSValue near_alt_bn128_pairing_check(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - uint8_t *data_ptr; - size_t data_len; - uint64_t ret; - - data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); - if (data_ptr == NULL) { - return JS_ThrowTypeError(ctx, "Expect Uint8Array for data"); - } - ret = alt_bn128_pairing_check(data_len, (uint64_t)data_ptr); - return JS_NewBigUint64(ctx, ret); -} - -static void js_add_near_host_functions(JSContext* ctx) { - JSValue global_obj, env; - - global_obj = JS_GetGlobalObject(ctx); - env = JS_NewObject(ctx); - - JS_SetPropertyStr(ctx, env, "read_register", JS_NewCFunction(ctx, near_read_register, "read_register", 1)); - JS_SetPropertyStr(ctx, env, "register_len", JS_NewCFunction(ctx, near_register_len, "register_len", 1)); - JS_SetPropertyStr(ctx, env, "write_register", JS_NewCFunction(ctx, near_write_register, "write_register", 2)); - JS_SetPropertyStr(ctx, env, "current_account_id", JS_NewCFunction(ctx, near_current_account_id, "current_account_id", 1)); - JS_SetPropertyStr(ctx, env, "signer_account_id", JS_NewCFunction(ctx, near_signer_account_id, "signer_account_id", 1)); - JS_SetPropertyStr(ctx, env, "signer_account_pk", JS_NewCFunction(ctx, near_signer_account_pk, "signer_account_pk", 1)); - JS_SetPropertyStr(ctx, env, "predecessor_account_id", JS_NewCFunction(ctx, near_predecessor_account_id, "predecessor_account_id", 1)); - JS_SetPropertyStr(ctx, env, "input", JS_NewCFunction(ctx, near_input, "input", 1)); - JS_SetPropertyStr(ctx, env, "block_index", JS_NewCFunction(ctx, near_block_index, "block_index", 0)); - JS_SetPropertyStr(ctx, env, "block_timestamp", JS_NewCFunction(ctx, near_block_timestamp, "block_timestamp", 0)); - JS_SetPropertyStr(ctx, env, "epoch_height", JS_NewCFunction(ctx, near_epoch_height, "epoch_height", 0)); - JS_SetPropertyStr(ctx, env, "storage_usage", JS_NewCFunction(ctx, near_storage_usage, "storage_usage", 0)); - JS_SetPropertyStr(ctx, env, "account_balance", JS_NewCFunction(ctx, near_account_balance, "account_balance", 0)); - JS_SetPropertyStr(ctx, env, "account_locked_balance", JS_NewCFunction(ctx, near_account_locked_balance, "account_locked_balance", 0)); - JS_SetPropertyStr(ctx, env, "attached_deposit", JS_NewCFunction(ctx, near_attached_deposit, "attached_deposit", 0)); - JS_SetPropertyStr(ctx, env, "prepaid_gas", JS_NewCFunction(ctx, near_prepaid_gas, "prepaid_gas", 0)); - JS_SetPropertyStr(ctx, env, "used_gas", JS_NewCFunction(ctx, near_used_gas, "used_gas", 0)); - JS_SetPropertyStr(ctx, env, "random_seed", JS_NewCFunction(ctx, near_random_seed, "random_seed", 1)); - JS_SetPropertyStr(ctx, env, "sha256", JS_NewCFunction(ctx, near_sha256, "sha256", 2)); - JS_SetPropertyStr(ctx, env, "keccak256", JS_NewCFunction(ctx, near_keccak256, "keccak256", 2)); - JS_SetPropertyStr(ctx, env, "keccak512", JS_NewCFunction(ctx, near_keccak512, "keccak512", 2)); - JS_SetPropertyStr(ctx, env, "ripemd160", JS_NewCFunction(ctx, near_ripemd160, "ripemd160", 2)); - JS_SetPropertyStr(ctx, env, "ecrecover", JS_NewCFunction(ctx, near_ecrecover, "ecrecover", 5)); - JS_SetPropertyStr(ctx, env, "value_return", JS_NewCFunction(ctx, near_value_return, "value_return", 1)); - JS_SetPropertyStr(ctx, env, "panic", JS_NewCFunction(ctx, near_panic, "panic", 1)); - JS_SetPropertyStr(ctx, env, "panic_utf8", JS_NewCFunction(ctx, near_panic_utf8, "panic_utf8", 1)); - JS_SetPropertyStr(ctx, env, "log", JS_NewCFunction(ctx, near_log, "log", 1)); - JS_SetPropertyStr(ctx, env, "log_utf8", JS_NewCFunction(ctx, near_log_utf8, "log_utf8", 1)); - JS_SetPropertyStr(ctx, env, "log_utf16", JS_NewCFunction(ctx, near_log_utf16, "log_utf16", 1)); - JS_SetPropertyStr(ctx, env, "promise_create", JS_NewCFunction(ctx, near_promise_create, "promise_create", 5)); - JS_SetPropertyStr(ctx, env, "promise_then", JS_NewCFunction(ctx, near_promise_then, "promise_then", 6)); - JS_SetPropertyStr(ctx, env, "promise_and", JS_NewCFunction(ctx, near_promise_and, "promise_and", 1)); - JS_SetPropertyStr(ctx, env, "promise_batch_create", JS_NewCFunction(ctx, near_promise_batch_create, "promise_batch_create", 1)); - JS_SetPropertyStr(ctx, env, "promise_batch_then", JS_NewCFunction(ctx, near_promise_batch_then, "promise_batch_then", 2)); - JS_SetPropertyStr(ctx, env, "promise_batch_action_create_account", JS_NewCFunction(ctx, near_promise_batch_action_create_account, "promise_batch_action_create_account", 1)); - JS_SetPropertyStr(ctx, env, "promise_batch_action_deploy_contract", JS_NewCFunction(ctx, near_promise_batch_action_deploy_contract, "promise_batch_action_deploy_contract", 2)); - JS_SetPropertyStr(ctx, env, "promise_batch_action_function_call", JS_NewCFunction(ctx, near_promise_batch_action_function_call, "promise_batch_action_function_call", 5)); - JS_SetPropertyStr(ctx, env, "promise_batch_action_transfer", JS_NewCFunction(ctx, near_promise_batch_action_transfer, "promise_batch_action_transfer", 2)); - JS_SetPropertyStr(ctx, env, "promise_batch_action_stake", JS_NewCFunction(ctx, near_promise_batch_action_stake, "promise_batch_action_stake", 3)); - JS_SetPropertyStr(ctx, env, "promise_batch_action_add_key_with_full_access", JS_NewCFunction(ctx, near_promise_batch_action_add_key_with_full_access, "promise_batch_action_add_key_with_full_access", 3)); - JS_SetPropertyStr(ctx, env, "promise_batch_action_add_key_with_function_call", JS_NewCFunction(ctx, near_promise_batch_action_add_key_with_function_call, "promise_batch_action_add_key_with_function_call", 6)); - JS_SetPropertyStr(ctx, env, "promise_batch_action_delete_key", JS_NewCFunction(ctx, near_promise_batch_action_delete_key, "promise_batch_action_delete_key", 2)); - JS_SetPropertyStr(ctx, env, "promise_batch_action_delete_account", JS_NewCFunction(ctx, near_promise_batch_action_delete_account, "promise_batch_action_delete_account", 2)); - JS_SetPropertyStr(ctx, env, "promise_batch_action_function_call_weight", JS_NewCFunction(ctx, near_promise_batch_action_function_call_weight, "promise_batch_action_function_call_weight", 6)); - JS_SetPropertyStr(ctx, env, "promise_results_count", JS_NewCFunction(ctx, near_promise_results_count, "promise_results_count", 0)); - JS_SetPropertyStr(ctx, env, "promise_result", JS_NewCFunction(ctx, near_promise_result, "promise_result", 2)); - JS_SetPropertyStr(ctx, env, "promise_return", JS_NewCFunction(ctx, near_promise_return, "promise_return", 1)); - JS_SetPropertyStr(ctx, env, "storage_write", JS_NewCFunction(ctx, near_storage_write, "storage_write", 2)); - JS_SetPropertyStr(ctx, env, "storage_read", JS_NewCFunction(ctx, near_storage_read, "storage_read", 2)); - JS_SetPropertyStr(ctx, env, "storage_remove", JS_NewCFunction(ctx, near_storage_remove, "storage_remove", 2)); - JS_SetPropertyStr(ctx, env, "storage_has_key", JS_NewCFunction(ctx, near_storage_has_key, "storage_has_key", 2)); - JS_SetPropertyStr(ctx, env, "validator_stake", JS_NewCFunction(ctx, near_validator_stake, "validator_stake", 2)); - JS_SetPropertyStr(ctx, env, "validator_total_stake", JS_NewCFunction(ctx, near_validator_total_stake, "validator_total_stake", 1)); - JS_SetPropertyStr(ctx, env, "alt_bn128_g1_multiexp", JS_NewCFunction(ctx, near_alt_bn128_g1_multiexp, "alt_bn128_g1_multiexp", 2)); - JS_SetPropertyStr(ctx, env, "alt_bn128_g1_sum", JS_NewCFunction(ctx, near_alt_bn128_g1_sum, "alt_bn128_g1_sum", 2)); - JS_SetPropertyStr(ctx, env, "alt_bn128_pairing_check", JS_NewCFunction(ctx, near_alt_bn128_pairing_check, "alt_bn128_pairing_check", 1)); - - JS_SetPropertyStr(ctx, env, "latin1_string_to_uint8array", JS_NewCFunction(ctx, near_latin1_string_to_uint8array, "latin1_string_to_uint8array", 1)); - JS_SetPropertyStr(ctx, env, "utf8_string_to_uint8array", JS_NewCFunction(ctx, near_utf8_string_to_uint8array, "utf8_string_to_uint8array", 1)); - JS_SetPropertyStr(ctx, env, "uint8array_to_latin1_string", JS_NewCFunction(ctx, near_uint8array_to_latin1_string, "uint8array_to_latin1_string", 1)); - JS_SetPropertyStr(ctx, env, "uint8array_to_utf8_string", JS_NewCFunction(ctx, near_uint8array_to_utf8_string, "uint8array_to_utf8_string", 1)); - - JS_SetPropertyStr(ctx, global_obj, "env", env); -} - -JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, - int argc, JSValueConst *argv); - -void _start() {} - -#include "methods.h" +#include +#include "../node_modules/near-sdk-js/lib/cli/deps/quickjs/quickjs-libc-min.h" +#include "../node_modules/near-sdk-js/lib/cli/deps/quickjs/libbf.h" +#include "code.h" + +static JSContext *JS_NewCustomContext(JSRuntime *rt) +{ + JSContext *ctx = JS_NewContextRaw(rt); + if (!ctx) + return NULL; + JS_AddIntrinsicBaseObjects(ctx); + JS_AddIntrinsicDate(ctx); + JS_AddIntrinsicEval(ctx); + JS_AddIntrinsicStringNormalize(ctx); + JS_AddIntrinsicRegExp(ctx); + JS_AddIntrinsicJSON(ctx); + JS_AddIntrinsicProxy(ctx); + JS_AddIntrinsicMapSet(ctx); + JS_AddIntrinsicTypedArrays(ctx); + JS_AddIntrinsicPromise(ctx); + JS_AddIntrinsicBigInt(ctx); + return ctx; +} + +#define DEFINE_NEAR_METHOD(name) \ + void name () __attribute__((export_name(#name))) {\ + JSRuntime *rt;\ + JSContext *ctx;\ + JSValue mod_obj, fun_obj, result, error, error_message, error_stack;\ + const char *error_message_c, *error_stack_c;\ + char *error_c;\ + size_t msg_len, stack_len;\ + rt = JS_NewRuntime();\ + ctx = JS_NewCustomContext(rt);\ + js_add_near_host_functions(ctx);\ + mod_obj = js_load_module_binary(ctx, code, code_size);\ + fun_obj = JS_GetProperty(ctx, mod_obj, JS_NewAtom(ctx, #name));\ + result = JS_Call(ctx, fun_obj, mod_obj, 0, NULL);\ + if (JS_IsException(result)) {\ + error = JS_GetException(ctx);\ + error_message_c = JS_ToCString(ctx, JS_GetPropertyStr(ctx, error, "message"));\ + error_stack_c = JS_ToCString(ctx, JS_GetPropertyStr(ctx, error, "stack"));\ + if (error_message_c && error_stack_c) {\ + size_t total_len = strlen(error_message_c) + 1 + strlen(error_stack_c);\ + error_c = malloc(total_len);\ + if (error_c) {\ + snprintf(error_c, total_len + 1, "%s\n%s", error_message_c, error_stack_c);\ + panic_utf8(total_len, (uint64_t)error_c);\ + free(error_c);\ + }\ + }\ + JS_FreeCString(ctx, error_message_c);\ + JS_FreeCString(ctx, error_stack_c);\ + }\ + js_std_loop(ctx);\ + } + +// ############# +// # Registers # +// ############# +extern void read_register(uint64_t register_id, uint64_t ptr); +extern uint64_t register_len(uint64_t register_id); +extern void write_register(uint64_t register_id, uint64_t data_len, uint64_t data_ptr); +// ############### +// # Context API # +// ############### +extern void current_account_id(uint64_t register_id); +extern void signer_account_id(uint64_t register_id); +extern void signer_account_pk(uint64_t register_id); +extern void predecessor_account_id(uint64_t register_id); +extern void input(uint64_t register_id); +extern uint64_t block_index(); +extern uint64_t block_timestamp(); +extern uint64_t epoch_height(); +extern uint64_t storage_usage(); +// ################# +// # Economics API # +// ################# +extern void account_balance(uint64_t balance_ptr); +extern void account_locked_balance(uint64_t balance_ptr); +extern void attached_deposit(uint64_t balance_ptr); +extern uint64_t prepaid_gas(); +extern uint64_t used_gas(); +// ############ +// # Math API # +// ############ +extern void random_seed(uint64_t register_id); +extern void sha256(uint64_t value_len, uint64_t value_ptr, uint64_t register_id); +extern void keccak256(uint64_t value_len, uint64_t value_ptr, uint64_t register_id); +extern void keccak512(uint64_t value_len, uint64_t value_ptr, uint64_t register_id); +extern void ripemd160(uint64_t value_len, uint64_t value_ptr, uint64_t register_id); +extern uint64_t ecrecover(uint64_t hash_len, uint64_t hash_ptr, uint64_t sign_len, uint64_t sig_ptr, uint64_t v, uint64_t malleability_flag, uint64_t register_id); +// ##################### +// # Miscellaneous API # +// ##################### +extern void value_return(uint64_t value_len, uint64_t value_ptr); +extern void panic(void); +extern void panic_utf8(uint64_t len, uint64_t ptr); +extern void log_utf8(uint64_t len, uint64_t ptr); +extern void log_utf16(uint64_t len, uint64_t ptr); +// Name confliction with WASI. Can be re-exported with a different name on NEAR side with a protocol upgrade +// Or, this is actually not a primitive, can be implement with log and panic host functions in C side or JS side. +// extern void abort(uint32_t msg_ptr, uint32_t filename_ptr, uint32_t u32, uint32_t col); +// ################ +// # Promises API # +// ################ +extern uint64_t promise_create(uint64_t account_id_len, uint64_t account_id_ptr, uint64_t method_name_len, uint64_t method_name_ptr, uint64_t arguments_len, uint64_t arguments_ptr, uint64_t amount_ptr, uint64_t gas); +extern uint64_t promise_then(uint64_t promise_index, uint64_t account_id_len, uint64_t account_id_ptr, uint64_t method_name_len, uint64_t method_name_ptr, uint64_t arguments_len, uint64_t arguments_ptr, uint64_t amount_ptr, uint64_t gas); +extern uint64_t promise_and(uint64_t promise_idx_ptr, uint64_t promise_idx_count); +extern uint64_t promise_batch_create(uint64_t account_id_len, uint64_t account_id_ptr); +extern uint64_t promise_batch_then(uint64_t promise_index, uint64_t account_id_len, uint64_t account_id_ptr); +// ####################### +// # Promise API actions # +// ####################### +extern void promise_batch_action_create_account(uint64_t promise_index); +extern void promise_batch_action_deploy_contract(uint64_t promise_index, uint64_t code_len, uint64_t code_ptr); +extern void promise_batch_action_function_call(uint64_t promise_index, uint64_t method_name_len, uint64_t method_name_ptr, uint64_t arguments_len, uint64_t arguments_ptr, uint64_t amount_ptr, uint64_t gas); +extern void promise_batch_action_transfer(uint64_t promise_index, uint64_t amount_ptr); +extern void promise_batch_action_stake(uint64_t promise_index, uint64_t amount_ptr, uint64_t public_key_len, uint64_t public_key_ptr); +extern void promise_batch_action_add_key_with_full_access(uint64_t promise_index, uint64_t public_key_len, uint64_t public_key_ptr, uint64_t nonce); +extern void promise_batch_action_add_key_with_function_call(uint64_t promise_index, uint64_t public_key_len, uint64_t public_key_ptr, uint64_t nonce, uint64_t allowance_ptr, uint64_t receiver_id_len, uint64_t receiver_id_ptr, uint64_t method_names_len, uint64_t method_names_ptr); +extern void promise_batch_action_delete_key(uint64_t promise_index, uint64_t public_key_len, uint64_t public_key_ptr); +extern void promise_batch_action_delete_account(uint64_t promise_index, uint64_t beneficiary_id_len, uint64_t beneficiary_id_ptr); +extern void promise_batch_action_function_call_weight(uint64_t promise_index, uint64_t function_name_len, uint64_t function_name_ptr, uint64_t arguments_len, uint64_t arguments_ptr, uint64_t amount_ptr, uint64_t gas, uint64_t weight); +// ####################### +// # Promise API results # +// ####################### +extern uint64_t promise_results_count(void); +extern uint64_t promise_result(uint64_t result_idx, uint64_t register_id); +extern void promise_return(uint64_t promise_idx); +// ############### +// # Storage API # +// ############### +extern uint64_t storage_write(uint64_t key_len, uint64_t key_ptr, uint64_t value_len, uint64_t value_ptr, uint64_t register_id); +extern uint64_t storage_read(uint64_t key_len, uint64_t key_ptr, uint64_t register_id); +extern uint64_t storage_remove(uint64_t key_len, uint64_t key_ptr, uint64_t register_id); +extern uint64_t storage_has_key(uint64_t key_len, uint64_t key_ptr); +// ################# +// # Validator API # +// ################# +extern void validator_stake(uint64_t account_id_len, uint64_t account_id_ptr, uint64_t stake_ptr); +extern void validator_total_stake(uint64_t stake_ptr); +// ############# +// # Alt BN128 # +// ############# +extern void alt_bn128_g1_multiexp(uint64_t value_len, uint64_t value_ptr, uint64_t register_id); +extern void alt_bn128_g1_sum(uint64_t value_len, uint64_t value_ptr, uint64_t register_id); +extern uint64_t alt_bn128_pairing_check(uint64_t value_len, uint64_t value_ptr); + +static uint8_t* JS_Uint8Array_to_C(JSContext *ctx, JSValue array, size_t *len) { + uint8_t *ptr; + JSValue buffer; + size_t pbyte_offset, psize, pbytes_per_element = 0; + + buffer = JS_GetTypedArrayBuffer(ctx, array, &pbyte_offset, len, &pbytes_per_element); + if (JS_IsException(buffer) || pbytes_per_element != 1) { + return NULL; + } + ptr = JS_GetArrayBuffer(ctx, &psize, buffer); + if (ptr == NULL) { + return NULL; + } + return ptr + pbyte_offset; +} + +static JSValue near_read_register(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t register_id; + uint8_t *data; + uint64_t data_len; + JSValue arraybuffer, ret; + + if (JS_ToUint64Ext(ctx, ®ister_id, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); + } + data_len = register_len(register_id); + if (data_len != UINT64_MAX) { + data = malloc(data_len); + read_register(register_id, (uint64_t)data); + arraybuffer = JS_NewArrayBuffer(ctx, data, (size_t)data_len, NULL, NULL, TRUE); + return JS_CallConstructor(ctx, JS_GetPropertyStr(ctx, JS_GetGlobalObject(ctx), "Uint8Array"), 1, (JSValueConst *)&arraybuffer); + } else { + return JS_UNDEFINED; + } +} + +static JSValue near_register_len(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t register_id, len; + + if (JS_ToUint64Ext(ctx, ®ister_id, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); + } + len = register_len(register_id); + return JS_NewBigUint64(ctx, len); +} + +static JSValue near_write_register(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t register_id; + uint8_t *data_ptr; + size_t data_len; + + if (JS_ToUint64Ext(ctx, ®ister_id, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); + } + data_ptr = JS_Uint8Array_to_C(ctx, argv[1], &data_len); + if (data_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for data"); + } + + write_register(register_id, data_len, (uint64_t)data_ptr); + return JS_UNDEFINED; +} + +static JSValue near_current_account_id(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t register_id; + + if (JS_ToUint64Ext(ctx, ®ister_id, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); + } + current_account_id(register_id); + return JS_UNDEFINED; +} + +static JSValue near_signer_account_id(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + uint64_t register_id; + + if (JS_ToUint64Ext(ctx, ®ister_id, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); + } + signer_account_id(register_id); + return JS_UNDEFINED; +} + +static JSValue near_signer_account_pk(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + uint64_t register_id; + + if (JS_ToUint64Ext(ctx, ®ister_id, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); + } + signer_account_pk(register_id); + return JS_UNDEFINED; +} + +static JSValue near_predecessor_account_id(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + uint64_t register_id; + + if (JS_ToUint64Ext(ctx, ®ister_id, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); + } + predecessor_account_id(register_id); + return JS_UNDEFINED; +} + +static JSValue near_input(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t register_id; + + if (JS_ToUint64Ext(ctx, ®ister_id, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); + } + input(register_id); + return JS_UNDEFINED; +} + +static JSValue near_block_index(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t value; + + value = block_index(); + return JS_NewBigUint64(ctx, value); +} + +static JSValue near_block_timestamp(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t value; + + value = block_timestamp(); + return JS_NewBigUint64(ctx, value); +} + +static JSValue near_epoch_height(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t value; + + value = epoch_height(); + return JS_NewBigUint64(ctx, value); +} + +static JSValue near_storage_usage(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t value; + + value = storage_usage(); + return JS_NewBigUint64(ctx, value); +} + +// ptr[0] ptr[1] is little-endian u128. +static JSValue u128_to_quickjs(JSContext *ctx, uint64_t* ptr) { + JSValue value; + bf_t* bn; + bf_t b; + + value = JS_NewBigInt(ctx); + bn = JS_GetBigInt(value); + // from ptr[] to bn + // high 64 bits + bf_set_ui(bn, ptr[1]); + bf_mul_2exp(bn, 64, BF_PREC_INF, BF_RNDZ); + // low 64 bits + bf_init(bn->ctx, &b); + bf_set_ui(&b, ptr[0]); + bf_add(bn, bn, &b, BF_PREC_INF, BF_RNDZ); + bf_delete(&b); + + return value; +} + +static int quickjs_bigint_to_u128(JSContext *ctx, JSValueConst val, uint64_t* ptr) { + bf_t* a; + bf_t q, r, b, one, u128max; + a = JS_GetBigInt(val); + bf_init(a->ctx, &u128max); + bf_set_ui(&u128max, 1); + bf_mul_2exp(&u128max, 128, BF_PREC_INF, BF_RNDZ); + if (bf_cmp_le(&u128max, a)) { + return 1; + } + bf_init(a->ctx, &q); + bf_init(a->ctx, &r); + bf_init(a->ctx, &b); + bf_init(a->ctx, &one); + bf_set_ui(&b, UINT64_MAX); + bf_set_ui(&one, 1); + bf_add(&b, &b, &one, BF_PREC_INF, BF_RNDZ); + bf_divrem(&q, &r, a, &b, BF_PREC_INF, BF_RNDZ, BF_RNDZ); + + bf_get_uint64(ptr, &r); + bf_get_uint64(ptr+1, &q); + return 0; +} + +static int quickjs_to_u128(JSContext *ctx, JSValueConst val, uint64_t* ptr) { + if (JS_IsBigInt(ctx, val)) { + return quickjs_bigint_to_u128(ctx, val, ptr); + } else { + if (JS_ToUint64Ext(ctx, ptr, val) < 0) { + return 1; + } + ptr[1] = 0; + return 0; + } +} + +static JSValue near_account_balance(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t ptr[2]; + + account_balance((uint64_t)ptr); + return u128_to_quickjs(ctx, ptr); +} + +static JSValue near_account_locked_balance(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t ptr[2]; + + account_locked_balance((uint64_t)ptr); + return u128_to_quickjs(ctx, ptr); +} + +static JSValue near_attached_deposit(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t ptr[2]; + + attached_deposit((uint64_t)ptr); + return u128_to_quickjs(ctx, ptr); +} + +static JSValue near_prepaid_gas(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t value; + + value = prepaid_gas(); + return JS_NewBigUint64(ctx, value); +} + +static JSValue near_used_gas(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t value; + + value = used_gas(); + return JS_NewBigUint64(ctx, value); +} + +static JSValue near_random_seed(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t register_id; + + if (JS_ToUint64Ext(ctx, ®ister_id, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); + } + random_seed(register_id); + return JS_UNDEFINED; +} + +static JSValue near_sha256(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t register_id; + uint8_t *data_ptr; + size_t data_len; + + data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); + if (data_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for data"); + } + if (JS_ToUint64Ext(ctx, ®ister_id, argv[1]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); + } + + sha256(data_len, (uint64_t)data_ptr, register_id); + return JS_UNDEFINED; +} + +static JSValue near_keccak256(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t register_id; + uint8_t *data_ptr; + size_t data_len; + + data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); + if (data_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for data"); + } + if (JS_ToUint64Ext(ctx, ®ister_id, argv[1]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); + } + keccak256(data_len, (uint64_t)data_ptr, register_id); + return JS_UNDEFINED; +} + +static JSValue near_keccak512(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t register_id; + uint8_t *data_ptr; + size_t data_len; + + data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); + if (data_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for data"); + } + if (JS_ToUint64Ext(ctx, ®ister_id, argv[1]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); + } + + keccak512(data_len, (uint64_t)data_ptr, register_id); + return JS_UNDEFINED; +} + +static JSValue near_ripemd160(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t register_id; + uint8_t *data_ptr; + size_t data_len; + + data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); + if (data_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for data"); + } + if (JS_ToUint64Ext(ctx, ®ister_id, argv[1]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); + } + + ripemd160(data_len, (uint64_t)data_ptr, register_id); + return JS_UNDEFINED; +} + +static JSValue near_ecrecover(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t malleability_flag, v, register_id, result; + uint8_t *hash_ptr, *sig_ptr; + size_t hash_len, sign_len; + + hash_ptr = JS_Uint8Array_to_C(ctx, argv[0], &hash_len); + if (hash_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for hash"); + } + sig_ptr = JS_Uint8Array_to_C(ctx, argv[1], &sign_len); + if (sig_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for sig"); + } + if (JS_ToUint64Ext(ctx, &malleability_flag, argv[2]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for malleability_flag"); + } + if (JS_ToUint64Ext(ctx, &v, argv[3]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for v"); + } + if (JS_ToUint64Ext(ctx, ®ister_id, argv[4]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); + } + + result = ecrecover(hash_len, (uint64_t)hash_ptr, sign_len, (uint64_t)sig_ptr, malleability_flag, v, register_id); + return JS_NewBigUint64(ctx, result); +} + +static JSValue near_value_return(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint8_t *value_ptr; + size_t value_len; + + value_ptr = JS_Uint8Array_to_C(ctx, argv[0], &value_len); + if (value_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for value"); + } + value_return(value_len, (uint64_t)(value_ptr)); + return JS_UNDEFINED; +} + +static JSValue near_panic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + const char *data_ptr; + size_t data_len; + + if (argc == 1) { + data_ptr = JS_ToCStringLen(ctx, &data_len, argv[0]); + panic_utf8(data_len, (uint64_t)data_ptr); + } else { + panic(); + } + return JS_UNDEFINED; +} + +static JSValue near_panic_utf8(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint8_t *data_ptr; + size_t data_len; + + data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); + if (data_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for message"); + } + + panic_utf8(data_len, (uint64_t)data_ptr); + return JS_UNDEFINED; +} + +static JSValue near_log(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + const char *data_ptr; + size_t data_len; + + data_ptr = JS_ToCStringLen(ctx, &data_len, argv[0]); + + log_utf8(data_len, (uint64_t)data_ptr); + return JS_UNDEFINED; +} + +static JSValue near_log_utf8(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint8_t *data_ptr; + size_t data_len; + + data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); + if (data_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for message"); + } + + log_utf8(data_len, (uint64_t)data_ptr); + return JS_UNDEFINED; +} + +static JSValue near_log_utf16(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint8_t *data_ptr; + size_t data_len; + + data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); + if (data_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for message"); + } + + log_utf16(data_len, (uint64_t)data_ptr); + return JS_UNDEFINED; +} + +static JSValue near_promise_create(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + const char *account_id_ptr, *method_name_ptr; + uint8_t *arguments_ptr; + size_t account_id_len, method_name_len, arguments_len; + uint64_t amount_ptr[2]; // amount is u128 + uint64_t gas, ret; + + account_id_ptr = JS_ToCStringLen(ctx, &account_id_len, argv[0]); + method_name_ptr = JS_ToCStringLen(ctx, &method_name_len, argv[1]); + arguments_ptr = JS_Uint8Array_to_C(ctx, argv[2], &arguments_len); + if (arguments_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for arguments"); + } + if (quickjs_to_u128(ctx, argv[3], amount_ptr) != 0) { + return JS_ThrowTypeError(ctx, "Expect Uint128 for amount"); + } + if (JS_ToUint64Ext(ctx, &gas, argv[4]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for gas"); + } + + ret = promise_create(account_id_len, (uint64_t)account_id_ptr, method_name_len, (uint64_t)method_name_ptr, arguments_len, (uint64_t)arguments_ptr, (uint64_t)amount_ptr, gas); + + return JS_NewBigUint64(ctx, ret); +} + +static JSValue near_promise_then(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + uint64_t promise_index, gas, ret, amount_ptr[2]; // amount is u128 + size_t account_id_len, method_name_len, arguments_len; + const char *account_id_ptr; + const char *method_name_ptr; + uint8_t *arguments_ptr; + + if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); + } + + account_id_ptr = JS_ToCStringLen(ctx, &account_id_len, argv[1]); + if (!account_id_ptr) { + return JS_ThrowTypeError(ctx, "Expect string for account_id"); + } + + method_name_ptr = JS_ToCStringLen(ctx, &method_name_len, argv[2]); + if (!method_name_ptr) { + return JS_ThrowTypeError(ctx, "Expect string for method_name"); + } + + arguments_ptr = JS_Uint8Array_to_C(ctx, argv[3], &arguments_len); + if (!arguments_ptr) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for arguments"); + } + + if (quickjs_to_u128(ctx, argv[4], amount_ptr) != 0) { + return JS_ThrowTypeError(ctx, "Expect Uint128 for amount"); + } + + if (JS_ToUint64Ext(ctx, &gas, argv[5]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for gas"); + } + + ret = promise_then(promise_index, account_id_len, (uint64_t)account_id_ptr, method_name_len, + (uint64_t)method_name_ptr, arguments_len, (uint64_t)arguments_ptr, + (uint64_t)amount_ptr, gas); + + return JS_NewBigUint64(ctx, ret); +} + + +static JSValue near_promise_and(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t promise_idx_ptr[argc], ret; + + for(int i = 0; i < argc; i++) { + if (JS_ToUint64Ext(ctx, &promise_idx_ptr[i], argv[i]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_id"); + } + } + ret = promise_and((uint64_t)promise_idx_ptr, argc); + return JS_NewBigUint64(ctx, ret); +} + +static JSValue near_promise_batch_create(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + const char *account_id_ptr; + size_t account_id_len; + uint64_t ret; + + account_id_ptr = JS_ToCStringLen(ctx, &account_id_len, argv[0]); + ret = promise_batch_create(account_id_len, (uint64_t)account_id_ptr); + return JS_NewBigUint64(ctx, ret); +} + +static JSValue near_promise_batch_then(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t promise_index; + const char *account_id_ptr; + size_t account_id_len; + uint64_t ret; + + if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); + } + account_id_ptr = JS_ToCStringLen(ctx, &account_id_len, argv[1]); + ret = promise_batch_then(promise_index, account_id_len, (uint64_t)account_id_ptr); + return JS_NewBigUint64(ctx, ret); +} + +static JSValue near_promise_batch_action_create_account(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t promise_index; + + if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); + } + promise_batch_action_create_account(promise_index); + return JS_UNDEFINED; +} + +static JSValue near_promise_batch_action_deploy_contract(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t promise_index; + uint8_t *code_ptr; + size_t code_len; + + if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); + } + code_ptr = JS_Uint8Array_to_C(ctx, argv[1], &code_len); + if (code_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for code"); + } + promise_batch_action_deploy_contract(promise_index, code_len, (uint64_t)code_ptr); + return JS_UNDEFINED; +} + +static JSValue near_promise_batch_action_function_call(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t promise_index; + const char *method_name_ptr; + uint8_t *arguments_ptr; + size_t method_name_len, arguments_len; + uint64_t amount_ptr[2]; // amount is u128 + uint64_t gas; + + if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); + } + method_name_ptr = JS_ToCStringLen(ctx, &method_name_len, argv[1]); + arguments_ptr = JS_Uint8Array_to_C(ctx, argv[2], &arguments_len); + if (arguments_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for arguments"); + } + if (quickjs_to_u128(ctx, argv[3], amount_ptr) != 0) { + return JS_ThrowTypeError(ctx, "Expect Uint128 for amount"); + } + if (JS_ToUint64Ext(ctx, &gas, argv[4]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for gas"); + } + promise_batch_action_function_call(promise_index, method_name_len, (uint64_t)method_name_ptr, arguments_len, (uint64_t)arguments_ptr, (uint64_t)amount_ptr, gas); + return JS_UNDEFINED; +} + +static JSValue near_promise_batch_action_transfer(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t promise_index; + uint64_t amount_ptr[2]; // amount is u128 + + if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); + } + if (quickjs_to_u128(ctx, argv[1], amount_ptr) != 0) { + return JS_ThrowTypeError(ctx, "Expect Uint128 for amount"); + } + promise_batch_action_transfer(promise_index, (uint64_t)amount_ptr); + return JS_UNDEFINED; +} + +static JSValue near_promise_batch_action_stake(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t promise_index; + uint64_t amount_ptr[2]; + uint8_t *public_key_ptr; + size_t public_key_len; + + if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); + } + if (quickjs_to_u128(ctx, argv[1], amount_ptr) != 0) { + return JS_ThrowTypeError(ctx, "Expect Uint128 for amount"); + } + public_key_ptr = JS_Uint8Array_to_C(ctx, argv[2], &public_key_len); + if (public_key_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for public key"); + } + + promise_batch_action_stake(promise_index, (uint64_t)amount_ptr, public_key_len, (uint64_t)public_key_ptr); + return JS_UNDEFINED; +} + +static JSValue near_promise_batch_action_add_key_with_full_access(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t promise_index; + uint8_t *public_key_ptr; + size_t public_key_len; + uint64_t nonce; + + if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); + } + public_key_ptr = JS_Uint8Array_to_C(ctx, argv[1], &public_key_len); + if (public_key_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for public key"); + } + if (JS_ToUint64Ext(ctx, &nonce, argv[2]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for nonce"); + } + promise_batch_action_add_key_with_full_access(promise_index, public_key_len, (uint64_t)public_key_ptr, nonce); + return JS_UNDEFINED; +} + +static JSValue near_promise_batch_action_add_key_with_function_call(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t promise_index; + const char *receiver_id_ptr, *method_names_ptr; + uint8_t *public_key_ptr; + size_t public_key_len, receiver_id_len, method_names_len; + uint64_t nonce, allowance_ptr[2]; + + if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); + } + public_key_ptr = JS_Uint8Array_to_C(ctx, argv[1], &public_key_len); + if (public_key_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for public key"); + } + if (JS_ToUint64Ext(ctx, &nonce, argv[2]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for nonce"); + } + if (quickjs_to_u128(ctx, argv[3], allowance_ptr) != 0) { + return JS_ThrowTypeError(ctx, "Expect Uint128 for allowance"); + } + receiver_id_ptr = JS_ToCStringLen(ctx, &receiver_id_len, argv[4]); + method_names_ptr = JS_ToCStringLen(ctx, &method_names_len, argv[5]); + + promise_batch_action_add_key_with_function_call(promise_index, public_key_len, (uint64_t)public_key_ptr, nonce, (uint64_t)allowance_ptr, receiver_id_len, (uint64_t)receiver_id_ptr, method_names_len, (uint64_t)method_names_ptr); + return JS_UNDEFINED; +} + +static JSValue near_promise_batch_action_delete_key(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t promise_index; + uint8_t *public_key_ptr; + size_t public_key_len; + + if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); + } + public_key_ptr = JS_Uint8Array_to_C(ctx, argv[1], &public_key_len); + if (public_key_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for public key"); + } + promise_batch_action_delete_key(promise_index, public_key_len, (uint64_t)public_key_ptr); + return JS_UNDEFINED; +} + +static JSValue near_promise_batch_action_function_call_weight(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t promise_index; + const char *method_name_ptr, *arguments_ptr; + size_t method_name_len, arguments_len; + uint64_t amount_ptr[2]; // amount is u128 + uint64_t gas; + uint64_t weight; + + if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); + } + method_name_ptr = JS_ToCStringLen(ctx, &method_name_len, argv[1]); + arguments_ptr = JS_ToCStringLenRaw(ctx, &arguments_len, argv[2]); + if (quickjs_to_u128(ctx, argv[3], amount_ptr) != 0) { + return JS_ThrowTypeError(ctx, "Expect Uint128 for amount"); + } + if (JS_ToUint64Ext(ctx, &gas, argv[4]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for gas"); + } + if (JS_ToUint64Ext(ctx, &weight, argv[5]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for weight"); + } + promise_batch_action_function_call_weight(promise_index, method_name_len, (uint64_t)method_name_ptr, arguments_len, (uint64_t)arguments_ptr, (uint64_t)amount_ptr, gas, weight); + return JS_UNDEFINED; +} + +static JSValue near_promise_batch_action_delete_account(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t promise_index; + const char *beneficiary_id_ptr; + size_t beneficiary_id_len; + + if (JS_ToUint64Ext(ctx, &promise_index, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_index"); + } + beneficiary_id_ptr = JS_ToCStringLen(ctx, &beneficiary_id_len, argv[1]); + promise_batch_action_delete_account(promise_index, beneficiary_id_len, (uint64_t)beneficiary_id_ptr); + return JS_UNDEFINED; +} + +static JSValue near_promise_results_count(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t value; + + value = promise_results_count(); + return JS_NewBigUint64(ctx, value); +} + +static JSValue near_promise_result(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t result_idx, register_id; + uint64_t ret; + + if (JS_ToUint64Ext(ctx, &result_idx, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for result_idx"); + } + if (JS_ToUint64Ext(ctx, ®ister_id, argv[1]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); + } + ret = promise_result(result_idx, register_id); + + return JS_NewBigUint64(ctx, ret); +} + +static JSValue near_promise_return(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t promise_idx; + if (JS_ToUint64Ext(ctx, &promise_idx, argv[0]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for promise_idx"); + } + promise_return(promise_idx); + + return JS_UNDEFINED; +} + +static JSValue near_storage_write(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint8_t *key_ptr, *value_ptr; + size_t key_len, value_len; + uint64_t register_id, ret; + + key_ptr = JS_Uint8Array_to_C(ctx, argv[0], &key_len); + if (key_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for key"); + } + value_ptr = JS_Uint8Array_to_C(ctx, argv[1], &value_len); + if (value_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for value"); + } + if (JS_ToUint64Ext(ctx, ®ister_id, argv[2]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); + } + ret = storage_write(key_len, (uint64_t)key_ptr, value_len, (uint64_t)value_ptr, register_id); + return JS_NewBigUint64(ctx, ret); +} + +static JSValue near_storage_read(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint8_t *key_ptr; + size_t key_len; + uint64_t register_id; + uint64_t ret; + + key_ptr = JS_Uint8Array_to_C(ctx, argv[0], &key_len); + if (key_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for key"); + } + if (JS_ToUint64Ext(ctx, ®ister_id, argv[1]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); + } + ret = storage_read(key_len, (uint64_t)key_ptr, register_id); + return JS_NewBigUint64(ctx, ret); +} + +static JSValue near_storage_remove(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint8_t *key_ptr; + size_t key_len; + uint64_t register_id; + uint64_t ret; + + key_ptr = JS_Uint8Array_to_C(ctx, argv[0], &key_len); + if (key_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for key"); + } + if (JS_ToUint64Ext(ctx, ®ister_id, argv[1]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); + } + ret = storage_remove(key_len, (uint64_t)key_ptr, register_id); + return JS_NewBigUint64(ctx, ret); +} + +static JSValue near_storage_has_key(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint8_t *key_ptr; + size_t key_len; + uint64_t ret; + + key_ptr = JS_Uint8Array_to_C(ctx, argv[0], &key_len); + if (key_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for key"); + } + ret = storage_has_key(key_len, (uint64_t)key_ptr); + return JS_NewBigUint64(ctx, ret); +} + +static JSValue near_validator_stake(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + const char *account_id_ptr; + size_t account_id_len; + uint64_t stake_ptr[2]; + + account_id_ptr = JS_ToCStringLen(ctx, &account_id_len, argv[0]); + validator_stake(account_id_len, (uint64_t)account_id_ptr, (uint64_t)stake_ptr); + + return u128_to_quickjs(ctx, stake_ptr); +} + +static JSValue near_validator_total_stake(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t stake_ptr[2]; + + validator_total_stake((uint64_t)stake_ptr); + return u128_to_quickjs(ctx, stake_ptr); +} + +static JSValue near_utf8_string_to_uint8array(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + const char *data; + size_t len; + JSValue arraybuffer; + + data = JS_ToCStringLen(ctx, &len, argv[0]); + + arraybuffer = JS_NewArrayBuffer(ctx, (uint8_t *)data, len, NULL, NULL, TRUE); + return JS_CallConstructor(ctx, JS_GetPropertyStr(ctx, JS_GetGlobalObject(ctx), "Uint8Array"), 1, (JSValueConst *)&arraybuffer); +} + +static JSValue near_latin1_string_to_uint8array(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + const char *data; + size_t len; + JSValue arraybuffer; + + data = JS_ToCStringLenRaw(ctx, &len, argv[0]); + + arraybuffer = JS_NewArrayBuffer(ctx, (uint8_t *)data, len, NULL, NULL, TRUE); + return JS_CallConstructor(ctx, JS_GetPropertyStr(ctx, JS_GetGlobalObject(ctx), "Uint8Array"), 1, (JSValueConst *)&arraybuffer); +} + +static JSValue near_uint8array_to_latin1_string(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint8_t *data_ptr; + size_t data_len; + + data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); + if (data_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array"); + } + + return JS_NewStringLenRaw(ctx, (const char *)data_ptr, data_len); +} + +static JSValue near_uint8array_to_utf8_string(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint8_t *data_ptr; + size_t data_len; + + data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); + if (data_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array"); + } + + return JS_NewStringLen(ctx, (const char *)data_ptr, data_len); +} + +static JSValue near_alt_bn128_g1_multiexp(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t register_id; + uint8_t *data_ptr; + size_t data_len; + + data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); + if (data_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for data"); + } + if (JS_ToUint64Ext(ctx, ®ister_id, argv[1]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); + } + + alt_bn128_g1_multiexp(data_len, (uint64_t)data_ptr, register_id); + return JS_UNDEFINED; +} + +static JSValue near_alt_bn128_g1_sum(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint64_t register_id; + uint8_t *data_ptr; + size_t data_len; + + data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); + if (data_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for data"); + } + if (JS_ToUint64Ext(ctx, ®ister_id, argv[1]) < 0) { + return JS_ThrowTypeError(ctx, "Expect Uint64 for register_id"); + } + + alt_bn128_g1_sum(data_len, (uint64_t)data_ptr, register_id); + return JS_UNDEFINED; +} + +static JSValue near_alt_bn128_pairing_check(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + uint8_t *data_ptr; + size_t data_len; + uint64_t ret; + + data_ptr = JS_Uint8Array_to_C(ctx, argv[0], &data_len); + if (data_ptr == NULL) { + return JS_ThrowTypeError(ctx, "Expect Uint8Array for data"); + } + ret = alt_bn128_pairing_check(data_len, (uint64_t)data_ptr); + return JS_NewBigUint64(ctx, ret); +} + +static void js_add_near_host_functions(JSContext* ctx) { + JSValue global_obj, env; + + global_obj = JS_GetGlobalObject(ctx); + env = JS_NewObject(ctx); + + JS_SetPropertyStr(ctx, env, "read_register", JS_NewCFunction(ctx, near_read_register, "read_register", 1)); + JS_SetPropertyStr(ctx, env, "register_len", JS_NewCFunction(ctx, near_register_len, "register_len", 1)); + JS_SetPropertyStr(ctx, env, "write_register", JS_NewCFunction(ctx, near_write_register, "write_register", 2)); + JS_SetPropertyStr(ctx, env, "current_account_id", JS_NewCFunction(ctx, near_current_account_id, "current_account_id", 1)); + JS_SetPropertyStr(ctx, env, "signer_account_id", JS_NewCFunction(ctx, near_signer_account_id, "signer_account_id", 1)); + JS_SetPropertyStr(ctx, env, "signer_account_pk", JS_NewCFunction(ctx, near_signer_account_pk, "signer_account_pk", 1)); + JS_SetPropertyStr(ctx, env, "predecessor_account_id", JS_NewCFunction(ctx, near_predecessor_account_id, "predecessor_account_id", 1)); + JS_SetPropertyStr(ctx, env, "input", JS_NewCFunction(ctx, near_input, "input", 1)); + JS_SetPropertyStr(ctx, env, "block_index", JS_NewCFunction(ctx, near_block_index, "block_index", 0)); + JS_SetPropertyStr(ctx, env, "block_timestamp", JS_NewCFunction(ctx, near_block_timestamp, "block_timestamp", 0)); + JS_SetPropertyStr(ctx, env, "epoch_height", JS_NewCFunction(ctx, near_epoch_height, "epoch_height", 0)); + JS_SetPropertyStr(ctx, env, "storage_usage", JS_NewCFunction(ctx, near_storage_usage, "storage_usage", 0)); + JS_SetPropertyStr(ctx, env, "account_balance", JS_NewCFunction(ctx, near_account_balance, "account_balance", 0)); + JS_SetPropertyStr(ctx, env, "account_locked_balance", JS_NewCFunction(ctx, near_account_locked_balance, "account_locked_balance", 0)); + JS_SetPropertyStr(ctx, env, "attached_deposit", JS_NewCFunction(ctx, near_attached_deposit, "attached_deposit", 0)); + JS_SetPropertyStr(ctx, env, "prepaid_gas", JS_NewCFunction(ctx, near_prepaid_gas, "prepaid_gas", 0)); + JS_SetPropertyStr(ctx, env, "used_gas", JS_NewCFunction(ctx, near_used_gas, "used_gas", 0)); + JS_SetPropertyStr(ctx, env, "random_seed", JS_NewCFunction(ctx, near_random_seed, "random_seed", 1)); + JS_SetPropertyStr(ctx, env, "sha256", JS_NewCFunction(ctx, near_sha256, "sha256", 2)); + JS_SetPropertyStr(ctx, env, "keccak256", JS_NewCFunction(ctx, near_keccak256, "keccak256", 2)); + JS_SetPropertyStr(ctx, env, "keccak512", JS_NewCFunction(ctx, near_keccak512, "keccak512", 2)); + JS_SetPropertyStr(ctx, env, "ripemd160", JS_NewCFunction(ctx, near_ripemd160, "ripemd160", 2)); + JS_SetPropertyStr(ctx, env, "ecrecover", JS_NewCFunction(ctx, near_ecrecover, "ecrecover", 5)); + JS_SetPropertyStr(ctx, env, "value_return", JS_NewCFunction(ctx, near_value_return, "value_return", 1)); + JS_SetPropertyStr(ctx, env, "panic", JS_NewCFunction(ctx, near_panic, "panic", 1)); + JS_SetPropertyStr(ctx, env, "panic_utf8", JS_NewCFunction(ctx, near_panic_utf8, "panic_utf8", 1)); + JS_SetPropertyStr(ctx, env, "log", JS_NewCFunction(ctx, near_log, "log", 1)); + JS_SetPropertyStr(ctx, env, "log_utf8", JS_NewCFunction(ctx, near_log_utf8, "log_utf8", 1)); + JS_SetPropertyStr(ctx, env, "log_utf16", JS_NewCFunction(ctx, near_log_utf16, "log_utf16", 1)); + JS_SetPropertyStr(ctx, env, "promise_create", JS_NewCFunction(ctx, near_promise_create, "promise_create", 5)); + JS_SetPropertyStr(ctx, env, "promise_then", JS_NewCFunction(ctx, near_promise_then, "promise_then", 6)); + JS_SetPropertyStr(ctx, env, "promise_and", JS_NewCFunction(ctx, near_promise_and, "promise_and", 1)); + JS_SetPropertyStr(ctx, env, "promise_batch_create", JS_NewCFunction(ctx, near_promise_batch_create, "promise_batch_create", 1)); + JS_SetPropertyStr(ctx, env, "promise_batch_then", JS_NewCFunction(ctx, near_promise_batch_then, "promise_batch_then", 2)); + JS_SetPropertyStr(ctx, env, "promise_batch_action_create_account", JS_NewCFunction(ctx, near_promise_batch_action_create_account, "promise_batch_action_create_account", 1)); + JS_SetPropertyStr(ctx, env, "promise_batch_action_deploy_contract", JS_NewCFunction(ctx, near_promise_batch_action_deploy_contract, "promise_batch_action_deploy_contract", 2)); + JS_SetPropertyStr(ctx, env, "promise_batch_action_function_call", JS_NewCFunction(ctx, near_promise_batch_action_function_call, "promise_batch_action_function_call", 5)); + JS_SetPropertyStr(ctx, env, "promise_batch_action_transfer", JS_NewCFunction(ctx, near_promise_batch_action_transfer, "promise_batch_action_transfer", 2)); + JS_SetPropertyStr(ctx, env, "promise_batch_action_stake", JS_NewCFunction(ctx, near_promise_batch_action_stake, "promise_batch_action_stake", 3)); + JS_SetPropertyStr(ctx, env, "promise_batch_action_add_key_with_full_access", JS_NewCFunction(ctx, near_promise_batch_action_add_key_with_full_access, "promise_batch_action_add_key_with_full_access", 3)); + JS_SetPropertyStr(ctx, env, "promise_batch_action_add_key_with_function_call", JS_NewCFunction(ctx, near_promise_batch_action_add_key_with_function_call, "promise_batch_action_add_key_with_function_call", 6)); + JS_SetPropertyStr(ctx, env, "promise_batch_action_delete_key", JS_NewCFunction(ctx, near_promise_batch_action_delete_key, "promise_batch_action_delete_key", 2)); + JS_SetPropertyStr(ctx, env, "promise_batch_action_delete_account", JS_NewCFunction(ctx, near_promise_batch_action_delete_account, "promise_batch_action_delete_account", 2)); + JS_SetPropertyStr(ctx, env, "promise_batch_action_function_call_weight", JS_NewCFunction(ctx, near_promise_batch_action_function_call_weight, "promise_batch_action_function_call_weight", 6)); + JS_SetPropertyStr(ctx, env, "promise_results_count", JS_NewCFunction(ctx, near_promise_results_count, "promise_results_count", 0)); + JS_SetPropertyStr(ctx, env, "promise_result", JS_NewCFunction(ctx, near_promise_result, "promise_result", 2)); + JS_SetPropertyStr(ctx, env, "promise_return", JS_NewCFunction(ctx, near_promise_return, "promise_return", 1)); + JS_SetPropertyStr(ctx, env, "storage_write", JS_NewCFunction(ctx, near_storage_write, "storage_write", 2)); + JS_SetPropertyStr(ctx, env, "storage_read", JS_NewCFunction(ctx, near_storage_read, "storage_read", 2)); + JS_SetPropertyStr(ctx, env, "storage_remove", JS_NewCFunction(ctx, near_storage_remove, "storage_remove", 2)); + JS_SetPropertyStr(ctx, env, "storage_has_key", JS_NewCFunction(ctx, near_storage_has_key, "storage_has_key", 2)); + JS_SetPropertyStr(ctx, env, "validator_stake", JS_NewCFunction(ctx, near_validator_stake, "validator_stake", 2)); + JS_SetPropertyStr(ctx, env, "validator_total_stake", JS_NewCFunction(ctx, near_validator_total_stake, "validator_total_stake", 1)); + JS_SetPropertyStr(ctx, env, "alt_bn128_g1_multiexp", JS_NewCFunction(ctx, near_alt_bn128_g1_multiexp, "alt_bn128_g1_multiexp", 2)); + JS_SetPropertyStr(ctx, env, "alt_bn128_g1_sum", JS_NewCFunction(ctx, near_alt_bn128_g1_sum, "alt_bn128_g1_sum", 2)); + JS_SetPropertyStr(ctx, env, "alt_bn128_pairing_check", JS_NewCFunction(ctx, near_alt_bn128_pairing_check, "alt_bn128_pairing_check", 1)); + + JS_SetPropertyStr(ctx, env, "latin1_string_to_uint8array", JS_NewCFunction(ctx, near_latin1_string_to_uint8array, "latin1_string_to_uint8array", 1)); + JS_SetPropertyStr(ctx, env, "utf8_string_to_uint8array", JS_NewCFunction(ctx, near_utf8_string_to_uint8array, "utf8_string_to_uint8array", 1)); + JS_SetPropertyStr(ctx, env, "uint8array_to_latin1_string", JS_NewCFunction(ctx, near_uint8array_to_latin1_string, "uint8array_to_latin1_string", 1)); + JS_SetPropertyStr(ctx, env, "uint8array_to_utf8_string", JS_NewCFunction(ctx, near_uint8array_to_utf8_string, "uint8array_to_utf8_string", 1)); + + JS_SetPropertyStr(ctx, global_obj, "env", env); +} + +JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, + int argc, JSValueConst *argv); + +void _start() {} + +#include "methods.h" diff --git a/packages/near-sdk-js/lib/cli/cli.js b/packages/near-sdk-js/lib/cli/cli.js index 477d2ab18..fb205d7db 100755 --- a/packages/near-sdk-js/lib/cli/cli.js +++ b/packages/near-sdk-js/lib/cli/cli.js @@ -1,4 +1,5 @@ #!/usr/bin/env node +import { terser } from "rollup-plugin-terser"; import fs from "fs"; import path, { basename, dirname } from "path"; import { nodeResolve } from "@rollup/plugin-node-resolve"; @@ -88,7 +89,7 @@ function ensureTargetDirExists(target) { return; } signal.await(`Creating ${targetDir} directory...`); - fs.mkdirSync(targetDir, {}); + fs.mkdirSync(targetDir); } export async function validateCom(source, { verbose = false }) { const signale = new Signale({ scope: "validate", interactive: !verbose }); @@ -147,6 +148,7 @@ export async function transpileJsAndBuildWasmCom(target, { verbose = false }) { await createWasmContract(getQjscTarget(target), getContractTarget(target), verbose); signale.await("Executing wasi-stub..."); await wasiStubContract(getContractTarget(target), verbose); + await optimizeWasmContract(target, verbose); signale.success(`Generated ${getContractTarget(target)} contract successfully!`); } export async function buildCom(source, target, packageJson, tsConfig, { verbose = false, generateABI = false }) { @@ -174,7 +176,6 @@ async function createJsFileWithRullup(sourceFileWithPath, rollupTarget, verbose extensions: [".js", ".ts"], }), sourcemaps(), - // commonjs(), babel({ babelHelpers: "bundled", extensions: [".ts", ".js", ".jsx", ".es6", ".es", ".mjs"], @@ -188,6 +189,28 @@ async function createJsFileWithRullup(sourceFileWithPath, rollupTarget, verbose ["@babel/plugin-proposal-decorators", { version: "legacy" }], ], }), + terser({ + mangle: false, + compress: { + passes: 5, + hoist_vars: true, + reduce_funcs: true, + reduce_vars: true, + collapse_vars: true, + dead_code: true, + conditionals: true, + evaluate: true, + unused: true, + if_return: true, + join_vars: true, + sequences: true, + side_effects: true, + inline: true, + drop_console: true, + drop_debugger: true, + pure_funcs: ['console.log'], + }, + }), ], }); await bundle.write({ @@ -231,3 +254,7 @@ async function wasiStubContract(contractTarget, verbose = false) { const WASI_STUB = `${NEAR_SDK_JS}/lib/cli/deps/binaryen/wasi-stub/run.sh`; await executeCommand(`${WASI_STUB} ${contractTarget}`, verbose); } +async function optimizeWasmContract(contractTarget, verbose = false) { + const WASM_OPT = `${NEAR_SDK_JS}/lib/cli/deps/webassembly/bin/wasm-opt`; + await executeCommand(`${WASM_OPT} -Oz -o ${contractTarget} ${contractTarget}`, verbose); +} diff --git a/packages/near-sdk-js/lib/cli/post-install.js b/packages/near-sdk-js/lib/cli/post-install.js index 1094f9418..ac39034e7 100644 --- a/packages/near-sdk-js/lib/cli/post-install.js +++ b/packages/near-sdk-js/lib/cli/post-install.js @@ -27,18 +27,38 @@ signale.await("Installing wasi-stub..."); const BINARYEN_VERSION = `0.1.16`; const BINARYEN_VERSION_TAG = `v${BINARYEN_VERSION}`; const BINARYEN_SYSTEM_NAME = PLATFORM === "linux" - ? "Linux" + ? "linux" : PLATFORM === "darwin" ? "macOS" : PLATFORM === "win32" ? "windows" : "other"; -const BINARYEN_ARCH_NAME = (ARCH == 'aarch64') ? 'ARM64' : ARCH.toUpperCase(); +const BINARYEN_ARCH_NAME = (ARCH == 'aarch64') ? 'ARM64' : ARCH.toLowerCase(); const BINARYEN_TAR_NAME = `binaryen-${BINARYEN_SYSTEM_NAME}-${BINARYEN_ARCH_NAME}.tar.gz`; await download(`https://github.com/ailisp/binaryen/releases/download/${BINARYEN_VERSION_TAG}/${BINARYEN_TAR_NAME}`); fs.mkdirSync("binaryen"); await executeCommand(`tar xvf ${BINARYEN_TAR_NAME} --directory binaryen`); fs.rmSync(BINARYEN_TAR_NAME); +signale.await("Installing WebAssembly Binaryen..."); +const WEB_ASSEMBLY_BINARYEN_VERSION = `version_118`; +const WEB_ASSEMBLY_BINARYEN_VERSION_TAG = WEB_ASSEMBLY_BINARYEN_VERSION; +const WEB_ASSEMBLY_BINARYEN_SYSTEM_NAME = PLATFORM === "linux" + ? "linux" + : PLATFORM === "darwin" + ? "macos" + : PLATFORM === "win32" + ? "windows" + : "other"; +const WEB_ASSEMBLY_BINARYEN_ARCH_NAME = ARCH === "x64" ? "x86_64" : ARCH === "arm64" ? "arm64" : "unsupported"; +if (WEB_ASSEMBLY_BINARYEN_ARCH_NAME === "unsupported") { + console.error(`Architecture ${ARCH} is not supported for downloading binaries.`); + process.exit(1); +} +const WEB_ASSEMBLY_BINARYEN_TAR_NAME = `binaryen-${WEB_ASSEMBLY_BINARYEN_VERSION_TAG}-${WEB_ASSEMBLY_BINARYEN_ARCH_NAME}-${WEB_ASSEMBLY_BINARYEN_SYSTEM_NAME}.tar.gz`; +await download(`https://github.com/WebAssembly/binaryen/releases/download/${WEB_ASSEMBLY_BINARYEN_VERSION_TAG}/${WEB_ASSEMBLY_BINARYEN_TAR_NAME}`); +fs.mkdirSync("webassembly"); +await executeCommand(`tar --strip-components=1 -xvf ${WEB_ASSEMBLY_BINARYEN_TAR_NAME} --directory webassembly`); +fs.rmSync(WEB_ASSEMBLY_BINARYEN_TAR_NAME); signale.await("Installing QuickJS..."); const QUICK_JS_VERSION = `0.1.3`; const QUICK_JS_VERSION_TAG = `v${QUICK_JS_VERSION}`; diff --git a/packages/near-sdk-js/lib/types/index.d.ts b/packages/near-sdk-js/lib/types/index.d.ts index 73c741d3f..b50d4f944 100644 --- a/packages/near-sdk-js/lib/types/index.d.ts +++ b/packages/near-sdk-js/lib/types/index.d.ts @@ -1,5 +1,14 @@ +import * as ts from "typescript"; export * from "./account_id"; export * from "./gas"; export * from "./primitives"; export * from "./public_key"; export * from "./vm_types"; +declare module "typescript" { + interface ClassDeclaration { + decorators?: ts.NodeArray; + } + interface MethodDeclaration { + decorators?: ts.NodeArray; + } +} diff --git a/packages/near-sdk-js/lib/utils.d.ts b/packages/near-sdk-js/lib/utils.d.ts index 616adccd0..17e2ae2ba 100644 --- a/packages/near-sdk-js/lib/utils.d.ts +++ b/packages/near-sdk-js/lib/utils.d.ts @@ -92,3 +92,4 @@ export declare function decode(a: Uint8Array): string; export interface IntoStorageKey { into_storage_key(): string; } +export declare function deepCopy(obj: T): T; diff --git a/packages/near-sdk-js/lib/utils.js b/packages/near-sdk-js/lib/utils.js index c858e818c..e36cf3930 100644 --- a/packages/near-sdk-js/lib/utils.js +++ b/packages/near-sdk-js/lib/utils.js @@ -1,4 +1,3 @@ -import { cloneDeep } from "lodash-es"; const TYPE_KEY = "typeInfo"; var TypeBrand; (function (TypeBrand) { @@ -200,7 +199,7 @@ export function decodeObj2class(class_instance, obj) { class_instance[key] = obj[key]; } } - const instance_tmp = cloneDeep(class_instance); + const instance_tmp = deepCopy(class_instance); for (key in obj) { if (typeof class_instance[key] == "object" && !(class_instance[key] instanceof Date)) { @@ -279,3 +278,48 @@ export function encode(s) { export function decode(a) { return env.uint8array_to_utf8_string(a); } +export function deepCopy(obj) { + // Handle primitives and null + if (obj === null || typeof obj !== "object") { + return obj; + } + // Handle Date objects + if (obj instanceof Date) { + return new Date(obj.getTime()); + } + // Handle RegExp objects + if (obj instanceof RegExp) { + return new RegExp(obj.source, obj.flags); + } + // Handle Map objects + if (obj instanceof Map) { + const mapCopy = new Map(); + obj.forEach((value, key) => { + mapCopy.set(deepCopy(key), deepCopy(value)); + }); + return mapCopy; + } + // Handle Set objects + if (obj instanceof Set) { + const setCopy = new Set(); + obj.forEach((value) => { + setCopy.add(deepCopy(value)); + }); + return setCopy; + } + // Handle Arrays + if (Array.isArray(obj)) { + return obj.map((item) => deepCopy(item)); + } + // Handle Objects + const copy = Object.create(Object.getPrototypeOf(obj)); + Object.getOwnPropertyNames(obj).forEach((key) => { + copy[key] = deepCopy(obj[key]); + }); + // Handle symbol properties + const symbols = Object.getOwnPropertySymbols(obj); + symbols.forEach((sym) => { + copy[sym] = deepCopy(obj[sym]); + }); + return copy; +} diff --git a/packages/near-sdk-js/package.json b/packages/near-sdk-js/package.json index 61cdfab6b..9b7fd7444 100644 --- a/packages/near-sdk-js/package.json +++ b/packages/near-sdk-js/package.json @@ -48,6 +48,7 @@ "near-typescript-json-schema": "0.55.0", "rollup": "2.79.1", "rollup-plugin-sourcemaps": "0.6.3", + "rollup-plugin-terser": "7.0.2", "signale": "1.4.0", "ts-morph": "16.0.0", "typescript": "4.7.4" @@ -67,7 +68,7 @@ "@types/babel__core": "7.20.5", "@types/babel__traverse": "7.20.4", "@types/eslint": "9.6.0", - "@types/node": "17.0.45", + "@types/node": "17.0.38", "@types/rollup": "0.54.0", "@types/signale": "1.4.7", "@typescript-eslint/eslint-plugin": "5.62.0", diff --git a/packages/near-sdk-js/src/cli/cli.ts b/packages/near-sdk-js/src/cli/cli.ts index e2b7a298f..1e4829e57 100644 --- a/packages/near-sdk-js/src/cli/cli.ts +++ b/packages/near-sdk-js/src/cli/cli.ts @@ -1,5 +1,7 @@ #!/usr/bin/env node +import { terser } from "rollup-plugin-terser"; + import fs from "fs"; import path, { basename, dirname } from "path"; @@ -135,7 +137,7 @@ function ensureTargetDirExists(target: string): void { } signal.await(`Creating ${targetDir} directory...`); - fs.mkdirSync(targetDir, {}); + fs.mkdirSync(targetDir); } export async function validateCom( @@ -242,6 +244,8 @@ export async function transpileJsAndBuildWasmCom( signale.await("Executing wasi-stub..."); await wasiStubContract(getContractTarget(target), verbose); + await optimizeWasmContract(target, verbose); + signale.success( `Generated ${getContractTarget(target)} contract successfully!` ); @@ -298,7 +302,6 @@ async function createJsFileWithRullup( extensions: [".js", ".ts"], }), sourcemaps(), - // commonjs(), babel({ babelHelpers: "bundled", extensions: [".ts", ".js", ".jsx", ".es6", ".es", ".mjs"], @@ -312,6 +315,28 @@ async function createJsFileWithRullup( ["@babel/plugin-proposal-decorators", { version: "legacy" }], ], }), + terser({ + mangle: false, + compress: { + passes: 5, + hoist_vars: true, + reduce_funcs: true, + reduce_vars: true, + collapse_vars: true, + dead_code: true, + conditionals: true, + evaluate: true, + unused: true, + if_return: true, + join_vars: true, + sequences: true, + side_effects: true, + inline: true, + drop_console: true, + drop_debugger: true, + pure_funcs: ['console.log'], + }, + }), ], }); @@ -389,3 +414,11 @@ async function wasiStubContract(contractTarget: string, verbose = false) { const WASI_STUB = `${NEAR_SDK_JS}/lib/cli/deps/binaryen/wasi-stub/run.sh`; await executeCommand(`${WASI_STUB} ${contractTarget}`, verbose); } + +async function optimizeWasmContract(contractTarget: string, verbose = false) { + const WASM_OPT = `${NEAR_SDK_JS}/lib/cli/deps/webassembly/bin/wasm-opt`; + await executeCommand( + `${WASM_OPT} -Oz -o ${contractTarget} ${contractTarget}`, + verbose + ); +} diff --git a/packages/near-sdk-js/src/cli/post-install.ts b/packages/near-sdk-js/src/cli/post-install.ts index 3ea007ed0..e4c2a2724 100644 --- a/packages/near-sdk-js/src/cli/post-install.ts +++ b/packages/near-sdk-js/src/cli/post-install.ts @@ -38,14 +38,14 @@ const BINARYEN_VERSION_TAG = `v${BINARYEN_VERSION}`; const BINARYEN_SYSTEM_NAME = PLATFORM === "linux" - ? "Linux" + ? "linux" : PLATFORM === "darwin" ? "macOS" : PLATFORM === "win32" ? "windows" : "other"; -const BINARYEN_ARCH_NAME = (ARCH == 'aarch64') ? 'ARM64' : ARCH.toUpperCase(); +const BINARYEN_ARCH_NAME = (ARCH == 'aarch64') ? 'ARM64' : ARCH.toLowerCase(); const BINARYEN_TAR_NAME = `binaryen-${BINARYEN_SYSTEM_NAME}-${BINARYEN_ARCH_NAME}.tar.gz`; @@ -58,6 +58,39 @@ fs.mkdirSync("binaryen"); await executeCommand(`tar xvf ${BINARYEN_TAR_NAME} --directory binaryen`); fs.rmSync(BINARYEN_TAR_NAME); +signale.await("Installing WebAssembly Binaryen..."); + +const WEB_ASSEMBLY_BINARYEN_VERSION = `version_118`; +const WEB_ASSEMBLY_BINARYEN_VERSION_TAG = WEB_ASSEMBLY_BINARYEN_VERSION; + +const WEB_ASSEMBLY_BINARYEN_SYSTEM_NAME = + PLATFORM === "linux" + ? "linux" + : PLATFORM === "darwin" + ? "macos" + : PLATFORM === "win32" + ? "windows" + : "other"; + +const WEB_ASSEMBLY_BINARYEN_ARCH_NAME = ARCH === "x64" ? "x86_64" : ARCH === "arm64" ? "arm64" : "unsupported"; +if (WEB_ASSEMBLY_BINARYEN_ARCH_NAME === "unsupported") { + console.error(`Architecture ${ARCH} is not supported for downloading binaries.`); + process.exit(1); +} + +const WEB_ASSEMBLY_BINARYEN_TAR_NAME = `binaryen-${WEB_ASSEMBLY_BINARYEN_VERSION_TAG}-${WEB_ASSEMBLY_BINARYEN_ARCH_NAME}-${WEB_ASSEMBLY_BINARYEN_SYSTEM_NAME}.tar.gz`; + + +await download( + `https://github.com/WebAssembly/binaryen/releases/download/${WEB_ASSEMBLY_BINARYEN_VERSION_TAG}/${WEB_ASSEMBLY_BINARYEN_TAR_NAME}` +); + +fs.mkdirSync("webassembly"); + +await executeCommand(`tar --strip-components=1 -xvf ${WEB_ASSEMBLY_BINARYEN_TAR_NAME} --directory webassembly`); +fs.rmSync(WEB_ASSEMBLY_BINARYEN_TAR_NAME); + + signale.await("Installing QuickJS..."); const QUICK_JS_VERSION = `0.1.3`; diff --git a/packages/near-sdk-js/src/types/index.ts b/packages/near-sdk-js/src/types/index.ts index 73c741d3f..9dfdcca33 100644 --- a/packages/near-sdk-js/src/types/index.ts +++ b/packages/near-sdk-js/src/types/index.ts @@ -1,5 +1,16 @@ +import * as ts from "typescript"; + export * from "./account_id"; export * from "./gas"; export * from "./primitives"; export * from "./public_key"; export * from "./vm_types"; + +declare module "typescript" { + interface ClassDeclaration { + decorators?: ts.NodeArray; + } + interface MethodDeclaration { + decorators?: ts.NodeArray; + } +} diff --git a/packages/near-sdk-js/src/utils.ts b/packages/near-sdk-js/src/utils.ts index 3c4ac140c..0b11680f9 100644 --- a/packages/near-sdk-js/src/utils.ts +++ b/packages/near-sdk-js/src/utils.ts @@ -1,5 +1,4 @@ import { GetOptions } from "./types/collections"; -import { cloneDeep } from "lodash-es"; export interface Env { uint8array_to_latin1_string(a: Uint8Array): string; @@ -266,7 +265,8 @@ export function decodeObj2class(class_instance, obj) { class_instance[key] = obj[key]; } } - const instance_tmp = cloneDeep(class_instance); + const instance_tmp = deepCopy(class_instance); + for (key in obj) { if ( typeof class_instance[key] == "object" && @@ -360,3 +360,57 @@ export function decode(a: Uint8Array): string { export interface IntoStorageKey { into_storage_key(): string; } + +export function deepCopy(obj: T): T { + // Handle primitives and null + if (obj === null || typeof obj !== "object") { + return obj; + } + + // Handle Date objects + if (obj instanceof Date) { + return new Date(obj.getTime()) as unknown as T; + } + + // Handle RegExp objects + if (obj instanceof RegExp) { + return new RegExp(obj.source, obj.flags) as unknown as T; + } + + // Handle Map objects + if (obj instanceof Map) { + const mapCopy = new Map(); + obj.forEach((value, key) => { + mapCopy.set(deepCopy(key), deepCopy(value)); + }); + return mapCopy as unknown as T; + } + + // Handle Set objects + if (obj instanceof Set) { + const setCopy = new Set(); + obj.forEach((value) => { + setCopy.add(deepCopy(value)); + }); + return setCopy as unknown as T; + } + + // Handle Arrays + if (Array.isArray(obj)) { + return obj.map((item) => deepCopy(item)) as unknown as T; + } + + // Handle Objects + const copy = Object.create(Object.getPrototypeOf(obj)); + Object.getOwnPropertyNames(obj).forEach((key) => { + copy[key] = deepCopy(obj[key]); + }); + + // Handle symbol properties + const symbols = Object.getOwnPropertySymbols(obj); + symbols.forEach((sym) => { + copy[sym] = deepCopy(obj[sym]); + }); + + return copy as T; +} diff --git a/packages/near-sdk-js/tsconfig.json b/packages/near-sdk-js/tsconfig.json index e9532036b..f05f96fac 100644 --- a/packages/near-sdk-js/tsconfig.json +++ b/packages/near-sdk-js/tsconfig.json @@ -17,6 +17,7 @@ "noImplicitReturns": true, "noUnusedLocals": true, "experimentalDecorators": true, + "emitDecoratorMetadata": true, "resolveJsonModule": true, "allowJs": true, "skipLibCheck": true diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8cd0f7f41..616916e7e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: devDependencies: turbo: - specifier: 1.10.16 - version: 1.10.16 + specifier: 1.13.3 + version: 1.13.3 typedoc: specifier: 0.25.4 version: 0.25.4(typescript@4.7.4) @@ -70,9 +70,6 @@ importers: packages/near-contract-standards: dependencies: - lodash-es: - specifier: 4.17.21 - version: 4.17.21 near-sdk-js: specifier: workspace:* version: link:../near-sdk-js @@ -130,7 +127,10 @@ importers: version: 2.79.1 rollup-plugin-sourcemaps: specifier: 0.6.3 - version: 0.6.3(@types/node@17.0.45)(rollup@2.79.1) + version: 0.6.3(@types/node@17.0.38)(rollup@2.79.1) + rollup-plugin-terser: + specifier: 7.0.2 + version: 7.0.2(rollup@2.79.1) signale: specifier: 1.4.0 version: 1.4.0 @@ -154,8 +154,8 @@ importers: specifier: 9.6.0 version: 9.6.0 '@types/node': - specifier: 17.0.45 - version: 17.0.45 + specifier: 17.0.38 + version: 17.0.38 '@types/rollup': specifier: 0.54.0 version: 0.54.0 @@ -412,6 +412,9 @@ packages: resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} + '@jridgewell/source-map@0.3.6': + resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} + '@jridgewell/sourcemap-codec@1.5.0': resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} @@ -585,8 +588,8 @@ packages: '@types/node@16.18.105': resolution: {integrity: sha512-w2d0Z9yMk07uH3+Cx0N8lqFyi3yjXZxlbYappPj+AsOlT02OyxyiuNoNHdGt6EuiSm8Wtgp2YV7vWg+GMFrvFA==} - '@types/node@17.0.45': - resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} + '@types/node@17.0.38': + resolution: {integrity: sha512-5jY9RhV7c0Z4Jy09G+NIDTsCZ5G0L5n+Z+p+Y7t5VJHM30bgwzSjVtlcBxqAj+6L/swIlvtOSzr8rBk/aNyV2g==} '@types/resolve@1.17.1': resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} @@ -832,6 +835,9 @@ packages: bs58@4.0.1: resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + builtin-modules@3.3.0: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} @@ -936,6 +942,9 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + commander@9.5.0: resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} engines: {node: ^12.20.0 || >=14} @@ -1532,6 +1541,10 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + jest-worker@26.6.2: + resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} + engines: {node: '>= 10.13.0'} + js-sha256@0.9.0: resolution: {integrity: sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==} @@ -1664,6 +1677,9 @@ packages: resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} engines: {node: '>= 0.10.0'} + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -2051,6 +2067,12 @@ packages: '@types/node': optional: true + rollup-plugin-terser@7.0.2: + resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==} + deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser + peerDependencies: + rollup: ^2.0.0 + rollup@2.79.1: resolution: {integrity: sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==} engines: {node: '>=10.0.0'} @@ -2091,6 +2113,9 @@ packages: resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} engines: {node: '>=10'} + serialize-javascript@4.0.0: + resolution: {integrity: sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -2151,6 +2176,13 @@ packages: resolution: {integrity: sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==} deprecated: See https://github.com/lydell/source-map-resolve#deprecated + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + sourcemap-codec@1.4.8: resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} deprecated: Please use @jridgewell/sourcemap-codec instead @@ -2241,6 +2273,11 @@ packages: resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} engines: {node: '>=8'} + terser@5.34.1: + resolution: {integrity: sha512-FsJZ7iZLd/BXkz+4xrRTGJ26o/6VTjQytUk8b8OxkwcD2I+79VPJlz7qss1+zE7h8GNIScFqXcDyJ/KqBYZFVA==} + engines: {node: '>=10'} + hasBin: true + text-encoding-utf-8@1.0.2: resolution: {integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==} @@ -2292,38 +2329,38 @@ packages: peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' - turbo-darwin-64@1.10.16: - resolution: {integrity: sha512-+Jk91FNcp9e9NCLYlvDDlp2HwEDp14F9N42IoW3dmHI5ZkGSXzalbhVcrx3DOox3QfiNUHxzWg4d7CnVNCuuMg==} + turbo-darwin-64@1.13.3: + resolution: {integrity: sha512-glup8Qx1qEFB5jerAnXbS8WrL92OKyMmg5Hnd4PleLljAeYmx+cmmnsmLT7tpaVZIN58EAAwu8wHC6kIIqhbWA==} cpu: [x64] os: [darwin] - turbo-darwin-arm64@1.10.16: - resolution: {integrity: sha512-jqGpFZipIivkRp/i+jnL8npX0VssE6IAVNKtu573LXtssZdV/S+fRGYA16tI46xJGxSAivrZ/IcgZrV6Jk80bw==} + turbo-darwin-arm64@1.13.3: + resolution: {integrity: sha512-/np2xD+f/+9qY8BVtuOQXRq5f9LehCFxamiQnwdqWm5iZmdjygC5T3uVSYuagVFsZKMvX3ycySwh8dylGTl6lg==} cpu: [arm64] os: [darwin] - turbo-linux-64@1.10.16: - resolution: {integrity: sha512-PpqEZHwLoizQ6sTUvmImcRmACyRk9EWLXGlqceogPZsJ1jTRK3sfcF9fC2W56zkSIzuLEP07k5kl+ZxJd8JMcg==} + turbo-linux-64@1.13.3: + resolution: {integrity: sha512-G+HGrau54iAnbXLfl+N/PynqpDwi/uDzb6iM9hXEDG+yJnSJxaHMShhOkXYJPk9offm9prH33Khx2scXrYVW1g==} cpu: [x64] os: [linux] - turbo-linux-arm64@1.10.16: - resolution: {integrity: sha512-TMjFYz8to1QE0fKVXCIvG/4giyfnmqcQIwjdNfJvKjBxn22PpbjeuFuQ5kNXshUTRaTJihFbuuCcb5OYFNx4uw==} + turbo-linux-arm64@1.13.3: + resolution: {integrity: sha512-qWwEl5VR02NqRyl68/3pwp3c/olZuSp+vwlwrunuoNTm6JXGLG5pTeme4zoHNnk0qn4cCX7DFrOboArlYxv0wQ==} cpu: [arm64] os: [linux] - turbo-windows-64@1.10.16: - resolution: {integrity: sha512-+jsf68krs0N66FfC4/zZvioUap/Tq3sPFumnMV+EBo8jFdqs4yehd6+MxIwYTjSQLIcpH8KoNMB0gQYhJRLZzw==} + turbo-windows-64@1.13.3: + resolution: {integrity: sha512-Nudr4bRChfJzBPzEmpVV85VwUYRCGKecwkBFpbp2a4NtrJ3+UP1VZES653ckqCu2FRyRuS0n03v9euMbAvzH+Q==} cpu: [x64] os: [win32] - turbo-windows-arm64@1.10.16: - resolution: {integrity: sha512-sKm3hcMM1bl0B3PLG4ifidicOGfoJmOEacM5JtgBkYM48ncMHjkHfFY7HrJHZHUnXM4l05RQTpLFoOl/uIo2HQ==} + turbo-windows-arm64@1.13.3: + resolution: {integrity: sha512-ouJCgsVLd3icjRLmRvHQDDZnmGzT64GBupM1Y+TjtYn2LVaEBoV6hicFy8x5DUpnqdLy+YpCzRMkWlwhmkX7sQ==} cpu: [arm64] os: [win32] - turbo@1.10.16: - resolution: {integrity: sha512-2CEaK4FIuSZiP83iFa9GqMTQhroW2QryckVqUydmg4tx78baftTOS0O+oDAhvo9r9Nit4xUEtC1RAHoqs6ZEtg==} + turbo@1.13.3: + resolution: {integrity: sha512-n17HJv4F4CpsYTvKzUJhLbyewbXjq1oLCi90i5tW1TiWDz16ML1eDG7wi5dHaKxzh5efIM56SITnuVbMq5dk4g==} hasBin: true type-check@0.4.0: @@ -2746,6 +2783,11 @@ snapshots: '@jridgewell/set-array@1.2.1': {} + '@jridgewell/source-map@0.3.6': + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/sourcemap-codec@1.5.0': {} '@jridgewell/trace-mapping@0.3.25': @@ -2971,7 +3013,7 @@ snapshots: dependencies: '@types/http-cache-semantics': 4.0.4 '@types/keyv': 3.1.4 - '@types/node': 17.0.45 + '@types/node': 17.0.38 '@types/responselike': 1.0.3 '@types/eslint@9.6.0': @@ -2989,7 +3031,7 @@ snapshots: '@types/keyv@3.1.4': dependencies: - '@types/node': 17.0.45 + '@types/node': 17.0.38 '@types/lodash-es@4.17.12': dependencies: @@ -2999,15 +3041,15 @@ snapshots: '@types/node@16.18.105': {} - '@types/node@17.0.45': {} + '@types/node@17.0.38': {} '@types/resolve@1.17.1': dependencies: - '@types/node': 17.0.45 + '@types/node': 17.0.38 '@types/responselike@1.0.3': dependencies: - '@types/node': 17.0.45 + '@types/node': 17.0.38 '@types/rollup@0.54.0': dependencies: @@ -3017,7 +3059,7 @@ snapshots: '@types/signale@1.4.7': dependencies: - '@types/node': 17.0.45 + '@types/node': 17.0.38 '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.54.0)(typescript@4.7.4))(eslint@8.54.0)(typescript@4.7.4)': dependencies: @@ -3306,6 +3348,8 @@ snapshots: dependencies: base-x: 3.0.10 + buffer-from@1.1.2: {} + builtin-modules@3.3.0: {} cacheable-lookup@5.0.4: {} @@ -3412,6 +3456,8 @@ snapshots: color-name@1.1.4: {} + commander@2.20.3: {} + commander@9.5.0: {} common-path-prefix@3.0.0: {} @@ -4066,6 +4112,12 @@ snapshots: isexe@2.0.0: {} + jest-worker@26.6.2: + dependencies: + '@types/node': 17.0.38 + merge-stream: 2.0.0 + supports-color: 7.2.0 + js-sha256@0.9.0: {} js-string-escape@1.0.1: {} @@ -4179,6 +4231,8 @@ snapshots: memorystream@0.3.1: {} + merge-stream@2.0.0: {} + merge2@1.4.1: {} micromatch@4.0.7: @@ -4544,13 +4598,21 @@ snapshots: dependencies: glob: 7.2.3 - rollup-plugin-sourcemaps@0.6.3(@types/node@17.0.45)(rollup@2.79.1): + rollup-plugin-sourcemaps@0.6.3(@types/node@17.0.38)(rollup@2.79.1): dependencies: '@rollup/pluginutils': 3.1.0(rollup@2.79.1) rollup: 2.79.1 source-map-resolve: 0.6.0 optionalDependencies: - '@types/node': 17.0.45 + '@types/node': 17.0.38 + + rollup-plugin-terser@7.0.2(rollup@2.79.1): + dependencies: + '@babel/code-frame': 7.24.7 + jest-worker: 26.6.2 + rollup: 2.79.1 + serialize-javascript: 4.0.0 + terser: 5.34.1 rollup@2.79.1: optionalDependencies: @@ -4587,6 +4649,10 @@ snapshots: dependencies: type-fest: 0.13.1 + serialize-javascript@4.0.0: + dependencies: + randombytes: 2.1.0 + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -4655,6 +4721,13 @@ snapshots: atob: 2.1.2 decode-uri-component: 0.2.2 + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + sourcemap-codec@1.4.8: {} spdx-correct@3.2.0: @@ -4757,6 +4830,13 @@ snapshots: temp-dir@2.0.0: {} + terser@5.34.1: + dependencies: + '@jridgewell/source-map': 0.3.6 + acorn: 8.12.1 + commander: 2.20.3 + source-map-support: 0.5.21 + text-encoding-utf-8@1.0.2: {} text-table@0.2.0: {} @@ -4803,32 +4883,32 @@ snapshots: tslib: 1.14.1 typescript: 4.7.4 - turbo-darwin-64@1.10.16: + turbo-darwin-64@1.13.3: optional: true - turbo-darwin-arm64@1.10.16: + turbo-darwin-arm64@1.13.3: optional: true - turbo-linux-64@1.10.16: + turbo-linux-64@1.13.3: optional: true - turbo-linux-arm64@1.10.16: + turbo-linux-arm64@1.13.3: optional: true - turbo-windows-64@1.10.16: + turbo-windows-64@1.13.3: optional: true - turbo-windows-arm64@1.10.16: + turbo-windows-arm64@1.13.3: optional: true - turbo@1.10.16: + turbo@1.13.3: optionalDependencies: - turbo-darwin-64: 1.10.16 - turbo-darwin-arm64: 1.10.16 - turbo-linux-64: 1.10.16 - turbo-linux-arm64: 1.10.16 - turbo-windows-64: 1.10.16 - turbo-windows-arm64: 1.10.16 + turbo-darwin-64: 1.13.3 + turbo-darwin-arm64: 1.13.3 + turbo-linux-64: 1.13.3 + turbo-linux-arm64: 1.13.3 + turbo-windows-64: 1.13.3 + turbo-windows-arm64: 1.13.3 type-check@0.4.0: dependencies: diff --git a/tests/tsconfig.json b/tests/tsconfig.json index 1b0512668..524e76306 100644 --- a/tests/tsconfig.json +++ b/tests/tsconfig.json @@ -1,8 +1,9 @@ { "compilerOptions": { - "moduleResolution": "node", "experimentalDecorators": true, + "moduleResolution": "node", "target": "es2020", + "skipLibCheck": true, "noEmit": true }, "exclude": ["node_modules"]