diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index e66c4f27fbe8..2206aea78ec2 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -45,10 +45,7 @@ use frame_support::{ ord_parameter_types, parameter_types, traits::{ fungible, fungibles, - tokens::{ - imbalance::ResolveAssetTo, nonfungibles_v2::Inspect, Fortitude::Polite, - Preservation::Expendable, - }, + tokens::{imbalance::ResolveAssetTo, nonfungibles_v2::Inspect}, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, InstanceFilter, Nothing, TransformOrigin, }, @@ -68,7 +65,7 @@ use parachains_common::{ NORMAL_DISPATCH_RATIO, }; use sp_api::impl_runtime_apis; -use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H160}; +use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H160, U256}; use sp_runtime::{ generic, impl_opaque_keys, traits::{AccountIdConversion, BlakeTwo256, Block as BlockT, Saturating, Verify}, @@ -127,7 +124,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: alloc::borrow::Cow::Borrowed("westmint"), impl_name: alloc::borrow::Cow::Borrowed("westmint"), authoring_version: 1, - spec_version: 1_016_005, + spec_version: 1_016_006, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 16, @@ -2080,10 +2077,8 @@ impl_runtime_apis! { impl pallet_revive::ReviveApi for Runtime { - fn balance(address: H160) -> Balance { - use frame_support::traits::fungible::Inspect; - let account = ::AddressMapper::to_account_id(&address); - Balances::reducible_balance(&account, Expendable, Polite) + fn balance(address: H160) -> U256 { + Revive::evm_balance(&address) } fn nonce(address: H160) -> Nonce { @@ -2093,7 +2088,7 @@ impl_runtime_apis! { fn eth_transact( from: H160, dest: Option, - value: Balance, + value: U256, input: Vec, gas_limit: Option, storage_deposit_limit: Option, diff --git a/prdoc/pr_6466.prdoc b/prdoc/pr_6466.prdoc new file mode 100644 index 000000000000..0faa6afc8005 --- /dev/null +++ b/prdoc/pr_6466.prdoc @@ -0,0 +1,12 @@ +title: '[pallet-revive] add piggy-bank sol example' +doc: +- audience: Runtime Dev + description: |- + This PR update the pallet to use the EVM 18 decimal balance in contracts call and host functions instead of the native balance. + + It also updates the js example to add the piggy-bank solidity contract that expose the problem +crates: +- name: pallet-revive-eth-rpc + bump: minor +- name: pallet-revive + bump: minor diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 5a2ff3ceb7f6..914b51fb5621 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -54,7 +54,7 @@ use frame_support::{ }, tokens::{ imbalance::ResolveAssetTo, nonfungibles_v2::Inspect, pay::PayAssetFromAccount, - Fortitude::Polite, GetSalary, PayFromAccount, Preservation::Preserve, + GetSalary, PayFromAccount, }, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, ConstU32, ConstU64, Contains, Currency, EitherOfDiverse, EnsureOriginWithArg, EqualPrivilegeOnly, Imbalance, InsideBoth, @@ -86,6 +86,7 @@ use pallet_nis::WithMaximumOf; use pallet_nomination_pools::PoolId; use pallet_revive::{evm::runtime::EthExtra, AddressMapper}; use pallet_session::historical as pallet_session_historical; +use sp_core::U256; // Can't use `FungibleAdapter` here until Treasury pallet migrates to fungibles // use pallet_broker::TaskId; @@ -3205,10 +3206,8 @@ impl_runtime_apis! { impl pallet_revive::ReviveApi for Runtime { - fn balance(address: H160) -> Balance { - use frame_support::traits::fungible::Inspect; - let account = ::AddressMapper::to_account_id(&address); - Balances::reducible_balance(&account, Preserve, Polite) + fn balance(address: H160) -> U256 { + Revive::evm_balance(&address) } fn nonce(address: H160) -> Nonce { @@ -3219,7 +3218,7 @@ impl_runtime_apis! { fn eth_transact( from: H160, dest: Option, - value: Balance, + value: U256, input: Vec, gas_limit: Option, storage_deposit_limit: Option, diff --git a/substrate/frame/revive/rpc/examples/js/abi/event.json b/substrate/frame/revive/rpc/examples/js/abi/event.json new file mode 100644 index 000000000000..d36089fbc84e --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/abi/event.json @@ -0,0 +1,34 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "message", + "type": "string" + } + ], + "name": "ExampleEvent", + "type": "event" + }, + { + "inputs": [], + "name": "triggerEvent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/substrate/frame/revive/rpc/examples/js/abi/piggyBank.json b/substrate/frame/revive/rpc/examples/js/abi/piggyBank.json new file mode 100644 index 000000000000..2c2cfd5f7533 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/abi/piggyBank.json @@ -0,0 +1,65 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "deposit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "getDeposit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "withdrawAmount", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [ + { + "internalType": "uint256", + "name": "remainingBal", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/substrate/frame/revive/rpc/examples/js/abi/revert.json b/substrate/frame/revive/rpc/examples/js/abi/revert.json new file mode 100644 index 000000000000..be2945fcc0a5 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/abi/revert.json @@ -0,0 +1,14 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "doRevert", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/substrate/frame/revive/rpc/examples/js/bun.lockb b/substrate/frame/revive/rpc/examples/js/bun.lockb index 8bf47d7eb8b8..700dca51da2a 100755 Binary files a/substrate/frame/revive/rpc/examples/js/bun.lockb and b/substrate/frame/revive/rpc/examples/js/bun.lockb differ diff --git a/substrate/frame/revive/rpc/examples/js/contracts/PiggyBank.sol b/substrate/frame/revive/rpc/examples/js/contracts/PiggyBank.sol new file mode 100644 index 000000000000..1906c4658889 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/contracts/PiggyBank.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract PiggyBank { + + uint private balance; + address public owner; + + constructor() { + owner = msg.sender; + balance = 0; + } + + function deposit() public payable returns (uint) { + balance += msg.value; + return balance; + } + + function getDeposit() public view returns (uint) { + return balance; + } + + function withdraw(uint withdrawAmount) public returns (uint remainingBal) { + require(msg.sender == owner); + balance -= withdrawAmount; + (bool success, ) = payable(msg.sender).call{value: withdrawAmount}(""); + require(success, "Transfer failed"); + + return balance; + } +} + diff --git a/substrate/frame/revive/rpc/examples/js/evm-contracts.json b/substrate/frame/revive/rpc/examples/js/evm-contracts.json deleted file mode 100644 index 4d98f5dd8149..000000000000 --- a/substrate/frame/revive/rpc/examples/js/evm-contracts.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "event": { - "abi": [ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "string", - "name": "message", - "type": "string" - } - ], - "name": "ExampleEvent", - "type": "event" - }, - { - "inputs": [], - "name": "triggerEvent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "6080604052348015600e575f5ffd5b506101b68061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063ede48fb71461002d575b5f5ffd5b610035610037565b005b5f61303990505f6040518060400160405280600b81526020017f48656c6c6f20776f726c6400000000000000000000000000000000000000000081525090503373ffffffffffffffffffffffffffffffffffffffff167f1585375487296ff2f0370daeec4214074a032b31af827c12622fa9a58c16c7d083836040516100be929190610152565b60405180910390a25050565b5f819050919050565b6100dc816100ca565b82525050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f610124826100e2565b61012e81856100ec565b935061013e8185602086016100fc565b6101478161010a565b840191505092915050565b5f6040820190506101655f8301856100d3565b8181036020830152610177818461011a565b9050939250505056fea2646970667358221220a159f2cdba512e018377f5822cfd8ef04769755d98c3e494275605d96d7d13e864736f6c634300081c0033" - }, - "revert": { - "abi": [ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "doRevert", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "6080604052348015600e575f5ffd5b506101138061001c5f395ff3fe6080604052348015600e575f5ffd5b50600436106026575f3560e01c8063afc874d214602a575b5f5ffd5b60306032565b005b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040160629060c1565b60405180910390fd5b5f82825260208201905092915050565b7f726576657274206d6573736167650000000000000000000000000000000000005f82015250565b5f60ad600e83606b565b915060b682607b565b602082019050919050565b5f6020820190508181035f83015260d68160a3565b905091905056fea264697066735822122084f7096e030faf779d12b20184187708d335e4bcd4208a52c0651700fe8dde6a64736f6c634300081c0033" - } -} \ No newline at end of file diff --git a/substrate/frame/revive/rpc/examples/js/index.html b/substrate/frame/revive/rpc/examples/js/index.html index 052daf2787f6..97efebe180ea 100644 --- a/substrate/frame/revive/rpc/examples/js/index.html +++ b/substrate/frame/revive/rpc/examples/js/index.html @@ -1,29 +1,38 @@ - - - - - MetaMask Playground - - - - - + button { + display: block; + margin-bottom: 10px; + } + + + + + - + - - + + - - - + + + diff --git a/substrate/frame/revive/rpc/examples/js/package-lock.json b/substrate/frame/revive/rpc/examples/js/package-lock.json index f1453eae64cc..5c7db0abc936 100644 --- a/substrate/frame/revive/rpc/examples/js/package-lock.json +++ b/substrate/frame/revive/rpc/examples/js/package-lock.json @@ -1,443 +1,443 @@ { - "name": "demo", - "version": "0.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "demo", - "version": "0.0.0", - "dependencies": { - "ethers": "^6.13.1", - "solc": "^0.8.28" - }, - "devDependencies": { - "typescript": "^5.5.3", - "vite": "^5.4.8" - } - }, - "node_modules/@adraffy/ens-normalize": { - "version": "1.10.1", - "license": "MIT" - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@noble/curves": { - "version": "1.2.0", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.3.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "1.3.2", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.24.0", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.24.0", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@types/estree": { - "version": "1.0.6", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "18.15.13", - "license": "MIT" - }, - "node_modules/aes-js": { - "version": "4.0.0-beta.5", - "license": "MIT" - }, - "node_modules/command-exists": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", - "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", - "license": "MIT" - }, - "node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/esbuild": { - "version": "0.21.5", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "node_modules/ethers": { - "version": "6.13.3", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/ethers-io/" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "1.10.1", - "@noble/curves": "1.2.0", - "@noble/hashes": "1.3.2", - "@types/node": "18.15.13", - "aes-js": "4.0.0-beta.5", - "tslib": "2.4.0", - "ws": "8.17.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/js-sha3": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", - "license": "MIT" - }, - "node_modules/memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/nanoid": { - "version": "3.3.7", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/picocolors": { - "version": "1.1.0", - "dev": true, - "license": "ISC" - }, - "node_modules/postcss": { - "version": "8.4.47", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.1.0", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/rollup": { - "version": "4.24.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.6" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.24.0", - "@rollup/rollup-android-arm64": "4.24.0", - "@rollup/rollup-darwin-arm64": "4.24.0", - "@rollup/rollup-darwin-x64": "4.24.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.24.0", - "@rollup/rollup-linux-arm-musleabihf": "4.24.0", - "@rollup/rollup-linux-arm64-gnu": "4.24.0", - "@rollup/rollup-linux-arm64-musl": "4.24.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.24.0", - "@rollup/rollup-linux-riscv64-gnu": "4.24.0", - "@rollup/rollup-linux-s390x-gnu": "4.24.0", - "@rollup/rollup-linux-x64-gnu": "4.24.0", - "@rollup/rollup-linux-x64-musl": "4.24.0", - "@rollup/rollup-win32-arm64-msvc": "4.24.0", - "@rollup/rollup-win32-ia32-msvc": "4.24.0", - "@rollup/rollup-win32-x64-msvc": "4.24.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/solc": { - "version": "0.8.28", - "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.28.tgz", - "integrity": "sha512-AFCiJ+b4RosyyNhnfdVH4ZR1+TxiL91iluPjw0EJslIu4LXGM9NYqi2z5y8TqochC4tcH9QsHfwWhOIC9jPDKA==", - "license": "MIT", - "dependencies": { - "command-exists": "^1.2.8", - "commander": "^8.1.0", - "follow-redirects": "^1.12.1", - "js-sha3": "0.8.0", - "memorystream": "^0.3.1", - "semver": "^5.5.0", - "tmp": "0.0.33" - }, - "bin": { - "solcjs": "solc.js" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "license": "MIT", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/tslib": { - "version": "2.4.0", - "license": "0BSD" - }, - "node_modules/typescript": { - "version": "5.6.3", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/vite": { - "version": "5.4.8", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/ws": { - "version": "8.17.1", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - } - } + "name": "demo", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "demo", + "version": "0.0.0", + "dependencies": { + "ethers": "^6.13.1", + "solc": "^0.8.28" + }, + "devDependencies": { + "typescript": "^5.5.3", + "vite": "^5.4.8" + } + }, + "node_modules/@adraffy/ens-normalize": { + "version": "1.10.1", + "license": "MIT" + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@noble/curves": { + "version": "1.2.0", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.3.2", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.24.0", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.24.0", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "18.15.13", + "license": "MIT" + }, + "node_modules/aes-js": { + "version": "4.0.0-beta.5", + "license": "MIT" + }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "license": "MIT" + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/ethers": { + "version": "6.13.3", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/ethers-io/" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "1.10.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "18.15.13", + "aes-js": "4.0.0-beta.5", + "tslib": "2.4.0", + "ws": "8.17.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "license": "MIT" + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.0", + "dev": true, + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.4.47", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "4.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.24.0", + "@rollup/rollup-android-arm64": "4.24.0", + "@rollup/rollup-darwin-arm64": "4.24.0", + "@rollup/rollup-darwin-x64": "4.24.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.24.0", + "@rollup/rollup-linux-arm-musleabihf": "4.24.0", + "@rollup/rollup-linux-arm64-gnu": "4.24.0", + "@rollup/rollup-linux-arm64-musl": "4.24.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.24.0", + "@rollup/rollup-linux-riscv64-gnu": "4.24.0", + "@rollup/rollup-linux-s390x-gnu": "4.24.0", + "@rollup/rollup-linux-x64-gnu": "4.24.0", + "@rollup/rollup-linux-x64-musl": "4.24.0", + "@rollup/rollup-win32-arm64-msvc": "4.24.0", + "@rollup/rollup-win32-ia32-msvc": "4.24.0", + "@rollup/rollup-win32-x64-msvc": "4.24.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/solc": { + "version": "0.8.28", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.28.tgz", + "integrity": "sha512-AFCiJ+b4RosyyNhnfdVH4ZR1+TxiL91iluPjw0EJslIu4LXGM9NYqi2z5y8TqochC4tcH9QsHfwWhOIC9jPDKA==", + "license": "MIT", + "dependencies": { + "command-exists": "^1.2.8", + "commander": "^8.1.0", + "follow-redirects": "^1.12.1", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "bin": { + "solcjs": "solc.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "5.6.3", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "5.4.8", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/ws": { + "version": "8.17.1", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } } diff --git a/substrate/frame/revive/rpc/examples/js/package.json b/substrate/frame/revive/rpc/examples/js/package.json index ec05cb74f7d1..3ae1f0fbd799 100644 --- a/substrate/frame/revive/rpc/examples/js/package.json +++ b/substrate/frame/revive/rpc/examples/js/package.json @@ -6,11 +6,14 @@ "scripts": { "dev": "vite", "build": "tsc && vite build", - "preview": "vite preview" + "preview": "vite preview", + "generate-types": "typechain --target=ethers-v6 'abi/*.json'" }, "dependencies": { - "ethers": "^6.13.1", - "solc": "^0.8.28" + "@typechain/ethers-v6": "^0.5.1", + "ethers": "^6.13.4", + "solc": "^0.8.28", + "typechain": "^8.3.2" }, "devDependencies": { "typescript": "^5.5.3", diff --git a/substrate/frame/revive/rpc/examples/js/pvm-contracts.json b/substrate/frame/revive/rpc/examples/js/pvm-contracts.json deleted file mode 100644 index be58e88a9a63..000000000000 --- a/substrate/frame/revive/rpc/examples/js/pvm-contracts.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "event": { - "abi": [ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "string", - "name": "message", - "type": "string" - } - ], - "name": "ExampleEvent", - "type": "event" - }, - { - "inputs": [], - "name": "triggerEvent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "50564d00014214000000000000010700c13004c00040045f0600000000060000001300000018000000230000003500000063616c6c65726465706f7369745f6576656e74696e7075747365616c5f72657475726e7365745f696d6d757461626c655f6461746176616c75655f7472616e73666572726564051102912c0463616c6c9133066465706c6f790693b42602913cc8000c0111013001cb010a0327034303570374030c05270530054b055605d505e905f7050b062f06a7075d09e109460a9c0b400c730cdf0c710e800ef70ed20f2610bb10e710131133113b1152790e7a1004070f0a41040a0000012f8a3908890802871f1277e03b370000010a040713000a08000002297814160700000252780407100002088707130004071000020887071300130018875e08970a14a80b099c0128cc29bc1d29873107094a5279110b8b028801029c01109b52c91eacf405350709335279110b8b028801029c01109b52c91eacf4051e07091c027aff0288ff1108980b0bbb029cff089a09109b52c90f0cf113000211e003101c0315180316140215201211e0127601040704080610023dff16070800020d010004040710000352184e0211011726032c040326032804032603240403260320040326031c0403260318040326031404031607100403070607061004090610064b020211c003103c0315380316340215401211e05216040740040820061008d5fe070716020408080002260364000200000080260360000226035c000226035800022603540002260350000226034c000203681826034800020217e01277e003671c52710d171c0d17180d17140d17100d170c0d17080d17040d074e051101681c0182100183018914018a1c018b0c018c040187180188080cba0a0cc9090ca9090c87070c23080c87070c97070f077e0104074004082006100a3afe07077b01016718017450017040017b58017c48017a5401724c0173440e2808128800ff000e29180c9808122900ff000999080922180c92090c980803681c0e3808128800ff000e39180c9808123900ff000999080933180c93090c89030ea808128800ff000ea9180c980812a900ff0009990809aa180ca9090c89020ec808128800ff000ec9180c980812c900ff0009990809cc180cc9090c890c0eb808128800ff000eb9180c980812b900ff0009990809bb180cb9090c98080e0908129900ff000e0b180cb909120b00ff0009bb080900180cb00b0cb9090e4b0812bb00ff000e4a180cba0a124b00ff0009bb080944180cb40b0cba0a0ca9090cc8080c98080c3209016a1c0ca9090c98080f086e01681801885c0e8908129900ff000e8a180ca909128700ff000977080988180c87070c970703671c040806100cfbfc07073c0a080c000207080b04073004034e041101671c040806100edefc07071f01681801671c087808040704094e031104070408061010c2fc0f070400040808000204070104090400124e03110211a003105c0315580316540215601211e004074004082006101491fc0f07040004061004030a0710040303171c0a041404030a031804030a092c04030a082804030a002004030a0c2404032797278a54970a27cb270754cb070c980b54ba070316180a0b1c04032742011a1c1baa041faa0154420a27b2273654b2060cb30b54b60a0cc9090c80080c980854870a0409080002260364000200000080260360000226035c000226035800022603540002260350000226034c00022603480002070a0b010a071000030f47ede48fb7020103191c0d113c0d11380d11340d11300d112c0d11280d11240d11200217204e0511011230011820011934011a3c011b2c011c240116380117280cba0a0cc9090ca9090c67070c28080c87070c97070f07b10001171801721c017318017414017a100178017c0c017604017708028bfc248b0808860b02bbff1c6b09246b0b53980b0278ff08b8092479002489081b7601146c060868081cc80624c8085360081c97070c6707537b0802a7ff0878082478071ba8011484080878092489085377080c4a071b77011473090898082498082473071472070887072d074604070408061016f9fa07076bfe040808000204070104094e0304001805ca00061018c7000407040806101ad5fa070747fe040808000204070104094e0304001c05c80006101cc50004074004082006101eaffa070721fe011b1c01b24c01b34401ba5401b94801bc4001b65001b8580c6c0c0c98080cc8080c3a090c29090c98080e8908129900ff000e8a180ca909098a18128800ff000988080ca8080c98080f08d4fd01b85c0e8908129900ff000e8a180ca909128700ff000977080988180c87070c9707031718040852b606102030fa0707a2fd011818086808040704090400224e03110211fc0310040704080610240efa0f070400040808000204070104090400264e0311021140ff0310bc000315b8000316b4000215c0001211e05216040740040820061028d6f90707e70a04040800020a036400020a084800020a0a6000020a025000020a0c4c00020e8b0812b900ff000e8b180cb909128b00ff0009bb080988180cb8080c98080368780ec808128800ff000ec9180c980812c900ff0009990809cc180cc9090c89000ea808128800ff000ea9180c980812a900ff0009990809aa180ca9090c890a0e3808128800ff000e39180c9808123900ff000999080933180c93090c890902a801036a6c1baaff0369741b99c0548a090e2808128800ff000e2a180ca808122a00ff0009aa080a0b5400020922180ca20a0c8a020eb808128800ff000eba180ca80812ba00ff0009aa080a0c58000209bb180cba0a0c8a030ec808128800ff000eca180ca80812ca00ff0009aa0803647c0a0b5c000209cc180cca0a0c8a0c0eb808128800ff000eba180ca80812b700ff0009770809bb180cb7070c870a0362680167780c72070360700363640c03080c8707036c60036a5c0cca08036854568903675856790709190904074004082006102a5ef807076f0901677402784003685024780701686c08780903694824890b53770b01675c08b70024700701686008780224820c53770c53bb0c016764087c0c247c0b01676808b70424740853bb0801677008870a247a080163780883030e3708127700ff000e38180c7808123700ff000977080933180c73070c870703674c0ea708127700ff000ea9180c970712a900ff0009990809aa180ca9090c97070367440e4708127700ff000e49180c9707124900ff000999080944180c94090c79040ec708127700ff000ec9180c970712c900ff0009990809cc180cc9090c79030e2708127700ff000e29180c9707122900ff000999080922180c92090c79020e0908129900ff000e0a180ca909120a00ff0009aa080900180ca00a0ca9090167480e7a0812aa00ff000e78180ca808127a00ff0009aa08097c180cca0a0ca8080167500e7a0812aa00ff000e7c180cca0a127b00ff0009bb08097c180ccb0b0cba0a016b7c03ba5c03b85803b95403b25003b34c03b44801674403b74401676c0168680c87070168600169780c98080c870701685c0169700c98080169640c98080c870701684c03b8400f07c80704082001677406102ca8f60707b9070162741b27e01f770101696c279854980701685c2788016a6027a953a8090168545387090167642777016a6827a853a708016c7027c7016b7827ba53b70a0cbc0753780a01675853790a01677c0827080d181c0000000b0d18180d18140d18100d180c0d18080d18040368440d080f0a470702272004082003676006102e24f60707350701687c0167600878080d181c0d18180d18140d18100d180c0d1808726c640d18046f20776f0368340d0848656c6c026780004e0167900003671401678c000367180167880003671c0167840003672001678000036724040740040820061030bff50707d00601677c017250017340017458017048017c54017b4c0179440eb808128800ff000eba180ca80812ba00ff0009aa0809bb180cba0a0ca8080368700e9808128800ff000e9a180ca808129a00ff0009aa080999180ca9090c98080368680ec808128800ff000ec9180c980812c900ff0009990809cc180cc9090c890b0e0808128800ff000e09180c9808120900ff000999080900180c90090c89000e4808128800ff000e49180c9808124900ff000999080944180c94090c890c0e3808128800ff000e39180c9808123900ff000999080933180c93090c890a0e2808128800ff000e29180c9808122900ff000999080922180c92090c9808036a5c0368540ca808036058036c6c0c0c090c9808036b640169680cb909016a700ca9090c98080f08ae0501687c01885c0e8908129900ff000e8a180ca909128700ff000977080988180c87070c970704082003677806103269f407077a05016a7c016778087a0a527b0d1a1c000030390d1a180d1a140d1a100d1a0c0d1a080d1a0401686c27891bb7e01f7c0103694854890c01676427780160542704530804016770277801635827325338020169682798016b5c27b753b8070cb9085382070168700c98080cb3090c98080169640c090903694c03644054940c03685003673c54870c036a100d0a0168780f0ce804028720040820036738061034c5f30707d60401677c0168380887070d171c000000400d17180d17140d17100d170c0d17080d17040d0704082001677406103692f30707a3040169781b97c01f770101686c016a48548a0701684c016a40548a07016850016a3c548a070f077b0401674401781c03684801781803687401781403684001781003683c01780c03683801780803683001780403682c017703674402974004082003672806103826f3070737040167781b77a001686c568701684c5687016850568701687c016928089808016c2c038c04016a44038a016b30038b0801643803840c01623c03821001604003801401697403891801694803891c0707e6030ea808128800ff000ea9180c980812a900ff0009990809aa180ca9090c98080368500ec808128800ff000ec9180c980812c900ff0009990809ca180ca9090c890c0eb808128800ff000eb9180c980812b900ff0009990809ba180ca9090c89030e4808128800ff000e49180c9808124900ff00099908094a180ca9090c89040e2808128800ff000e29180c9808122900ff00099908092a180ca9090c89020e0808128800ff000e09180c9808120900ff00099908090a180ca9090c8900016a740ea808128800ff000ea9180c980812a900ff0009990809aa180ca9090c980803684403633c0c38080362300169500c92090c9808036c4003602c0cc0090364380c49090c98080f08dc02016a480ea808128800ff000ea9180c980812a700ff0009770809a9180c97070c780801677802776003674c03687406103a94f10707a50201676001687406103c85f10707960201677801684c247807528b01686c08780903690c24890853770801676408870903692824790701695408790a036a48249a0953770953880901677008790903696024790701685808780903696424890853770801676808780803686c24780703676801677c08b70701683401697406103e58f101684c016974089808016a4401670c08a7070368702498080887021ca20924a20a53980a01682c016928088909016730016c48087c0c24890b08cb0b08a904249409089b031c730c24730b24840753c70b1c84070cc707537a0b01683801676008870724870a01683c016c64088c0c08ac0c1c8c09248c08539a08087b0b247b07087c0024c00953770901675c016a5008a707016a6808a707016a40016c6c08ac0c24ac0a08a70708c80824c80a08a7070889092489080887070cb4080c98080c73070c02090c98080c87070f07530104082001677006104033f00707440101687c0167700878080d181c0d18180d18140d18100d180c0d18080d180401697402971f249709016a4408a909129901127be01bbaa01faa0154990a0d080167780f0aff0002b86003687c061042dfef0707f0000217c01277e052710d171c8c16c7d00d1718622fa9a50d1714af827c120d17104a032b310d170cec4214070d1708f0370dae0d170487296ff20d071585375401681403783c01681803783801681c03783401682003783001682403782c0d17280d17240d1720040802016910016a7c4e01025140ff0110bc000115b8000116b4000211c000130004082004070610444aef07075b01687c0d181c0d18180d18140d18100d180c0d18080d18040d084e487b710407040408200610461eef07072f01687c0d1820000000410d181c0d18180d18140d18100d180c0d18080d18040408240407061048f2ee0f07040004080800020407010409244e03040704004a0581ef040706104a7cef04070106104c74ef00a58424092a241452482549495a52292da994644a2a2549920a21422d8410420821119224290911028410420809494a92243529499224491249882449928424244912929024094948928424244942129224210949929084244992244912929024292424348524a956c890d2244992902124841042a854928492a492244908104208218408014992244993244992244924494a9224499224499224499224499224a9102195840a115249484224499224499290242489242421495221924a53850c298d8888948408218410129290244948429224242149129290244992242421214942121292242421094912929024499224494a91844892244992244992244992242421499290842449421292242109499290842449484292242109499284242449922449922449922449242192a4a49424a5a4942449024992a448122249922408248891482412494224499224242149929084244942129224210949929084244948429224242149922449922491242421499210490a2449929224a5a494949224499224494a2409912490244949882449922489244992244952928448524a4992942449922491908424494212922421094992908424494842922424214992908424499224499244129290244912220991a424499224499224499224499284244992244992244992244992244992244992244992244992248924449224499224499294484224050281402010089224499224498a8888524892244990842490244952c8905452480800" - }, - "revert": { - "abi": [ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "doRevert", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "50564d0001ba09000000000000010700c13004c0004004440400000000050000001000000022000000696e7075747365616c5f72657475726e7365745f696d6d757461626c655f6461746176616c75655f7472616e7366657272656405110288020463616c6c8809066465706c6f79068947170288126700aa00af00ce006901a802c502e102f5021303ab04c604cf04eb043d06d50632078f07c907dc07ea070908110852790e7a1004070f0a41040a0000012f8a3908890802871f1277e03b370000010a040713000a0800000229781416070000025278040710000208870713000407100002088707130013000211e003101c0315180316140215201211e0127601040704080610029d16070400020d010004040710000352184e11011726032c040326032804032603240403260320040326031c0403260318040326031404031607100403070607061004090610064b020211c003103c0315380316340215401211e0521604074004082006100837ff07071602040804000226036000020000008026035c000226035800022603540002260350000226034c0002260348000203681826034400020217e01277e003671c52710d171c0d17180d17140d17100d170c0d17080d17040d074e031101681c0182100183018914018a1c018b0c018c040187180188080cba0a0cc9090ca9090c87070c23080c87070c97070f077e0104074004082006100a9cfe07077b01016718017450017040017b58017c48017a5401724c0173440e2808128800ff000e29180c9808122900ff000999080922180c92090c980803681c0e3808128800ff000e39180c9808123900ff000999080933180c93090c89030ea808128800ff000ea9180c980812a900ff0009990809aa180ca9090c89020ec808128800ff000ec9180c980812c900ff0009990809cc180cc9090c890c0eb808128800ff000eb9180c980812b900ff0009990809bb180cb9090c98080e0908129900ff000e0b180cb909120b00ff0009bb080900180cb00b0cb9090e4b0812bb00ff000e4a180cba0a124b00ff0009bb080944180cb40b0cba0a0ca9090cc8080c98080c3209016a1c0ca9090c98080f086e01681801885c0e8908129900ff000e8a180ca909128700ff000977080988180c87070c970703671c040806100c5dfd07073c0a0808000207080b04073004034e021101671c040806100e40fd07071f01681801671c087808040704094e01110407040806101024fd0f070400040804000204070104090400124e011102118003107c031578031674021580001211e0040740040820061014f2fc0f07040004061004030a0710040303173c0a041404030a031804030a092c04030a082804030a002004030a0c2404032797278a54970a27cb270754cb070c980b54ba070316380a0b1c04032742011a3c1baa041faa0154420a27b2273654b2060cb30b54b60a0cc9090c80080c980854870a040904000226036000020000008026035c000226035800022603540002260350000226034c000226034800022603440002070a0b010a071000030f47afc874d2020103193c0d115c0d11580d11540d11500d114c0d11480d11440d11400217404e0311011250011840011954011a5c011b4c011c440116580117480cba0a0cc9090ca9090c67070c28080c87070c97070f07b10001173801721c017318017414017a100178017c0c017604017708028bfc248b0808860b02bbff1c6b09246b0b53980b0278ff08b8092479002489081b7601146c060868081cc80624c8085360081c97070c6707537b0802a7ff0878082478071ba8011484080878092489085377080c4a071b77011473090898082498082473071472070887072d0741040704080610165afb07076bfe040804000204070104094e01040018051e030610181b030407040806101a36fb070747fe040804000204070104094e011104074004082006101c1afb07072bfe01103c010250010340010458010b48010c54010a4c0108440ea608126600ff000ea9180c690912a600ff0009660809aa180c6a0a0ca9090319380e8908129900ff000e8a180ca909128a00ff0009aa080988180ca8080c98080318340ec808128800ff000ec9180c980812c900ff0009990809cc180cc9090c890c0eb808128800ff000eb9180c980812b900ff0009990809bb180cb9090c890a0e4808128800ff000e49180c9808124900ff000999080944180c94090c89040e3808128800ff000e39180c9808123900ff000999080933180c93090c89030e2808128800ff000e29180c9808122900ff000999080922180c92060c860b0c3b080ca4090c98080119340cc9090116380c69090c98080f0818fd52b6031320031a24031c2803142c01085c0e8908129900ff000e8a180ca909128700ff000977080988180c87070c970704082003173006101ec8f90707d9fc011230011a3c082a0a0d0a08c379a00113382737011424274b53470b011c3427c701182027895387090c8c07537b09011b2827b727605367000cb6060cc3070d1a1c0d1a180d1a140d1a100d1a0c0d1a080c8408011b2c27bc0c78081b27fc1f770154bc070316385460075489070d1a040f0764fc031c20031824031028031934031a1c011730027704040820527606102030f9070741fc01173c0867070d171c000000200d17180d17140d17100d170c0d17080d17040118301b88dc1f880101192c011a20549a08011928011a3854a908011934011a2454a9080d070f08f8fb0117300276240408205267061022d3f80707e4fb01173c0867070d171c0000000e0d17180d17140d17100d170c0d17080d17040118301b88bc1f880101192c011a20549a08011928011a3854a908011934011a2454a9080d070f089bfb011730027644040820526706102476f8070787fb01173c0867070d171c0d17180d17140d17100d170c67650d1708657373610d17047274206d0d07726576650408640117300610263cf807074dfb04070104096401181c0400284e01110211fc03100407040806102a1bf80f070400040804000204070104094e01040704002c054bf8040706102c46f804070106102e3ef800a58424092a241452482549928a10a10b21841042488424494a4284002184104242929224494d4a9224499244122249922421094992842424494212922421094992908424494842922424214992244992842424490a09094d2149aa1532a434492249c81012420821542a494249524992240408218410428480244992a449922449922492242549922449922449922449922449925488904a428508a9498824499284242449129290244948429224242149129290240949489284242449922449942449484292242192042925a524a924499224254992449224492192409224499224495224294412489224499224498a24854892240402411222499a2a64489514120200" - } -} \ No newline at end of file diff --git a/substrate/frame/revive/rpc/examples/js/pvm/event.polkavm b/substrate/frame/revive/rpc/examples/js/pvm/event.polkavm new file mode 100644 index 000000000000..859c1cdf5d3e Binary files /dev/null and b/substrate/frame/revive/rpc/examples/js/pvm/event.polkavm differ diff --git a/substrate/frame/revive/rpc/examples/js/pvm/piggyBank.polkavm b/substrate/frame/revive/rpc/examples/js/pvm/piggyBank.polkavm new file mode 100644 index 000000000000..1a45c15d53f6 Binary files /dev/null and b/substrate/frame/revive/rpc/examples/js/pvm/piggyBank.polkavm differ diff --git a/substrate/frame/revive/rpc/examples/js/pvm/revert.polkavm b/substrate/frame/revive/rpc/examples/js/pvm/revert.polkavm new file mode 100644 index 000000000000..7505c402f21b Binary files /dev/null and b/substrate/frame/revive/rpc/examples/js/pvm/revert.polkavm differ diff --git a/substrate/frame/revive/rpc/examples/js/src/build-contracts.ts b/substrate/frame/revive/rpc/examples/js/src/build-contracts.ts index 3e9d036d1b7d..c6b7700d1ccf 100644 --- a/substrate/frame/revive/rpc/examples/js/src/build-contracts.ts +++ b/substrate/frame/revive/rpc/examples/js/src/build-contracts.ts @@ -25,11 +25,10 @@ function evmCompile(sources: CompileInput) { console.log('Compiling contracts...') -let pvmContracts: Map = new Map() -let evmContracts: Map = new Map() const input = [ { file: 'Event.sol', contract: 'EventExample', keypath: 'event' }, { file: 'Revert.sol', contract: 'RevertExample', keypath: 'revert' }, + { file: 'PiggyBank.sol', contract: 'PiggyBank', keypath: 'piggyBank' }, ] for (const { keypath, contract, file } of input) { @@ -41,16 +40,17 @@ for (const { keypath, contract, file } of input) { console.log(`Compile with solc ${file}`) const out = JSON.parse(evmCompile(input)) const entry = out.contracts[file][contract] - evmContracts.set(keypath, { abi: entry.abi, bytecode: entry.evm.bytecode.object }) + writeFileSync(join('evm', `${keypath}.bin`), Buffer.from(entry.evm.bytecode.object, 'hex')) + writeFileSync(join('abi', `${keypath}.json`), JSON.stringify(entry.abi, null, 2)) } { console.log(`Compile with revive ${file}`) const out = await compile(input) const entry = out.contracts[file][contract] - pvmContracts.set(keypath, { abi: entry.abi, bytecode: entry.evm.bytecode.object }) + writeFileSync( + join('pvm', `${keypath}.polkavm`), + Buffer.from(entry.evm.bytecode.object, 'hex') + ) } } - -writeFileSync('pvm-contracts.json', JSON.stringify(Object.fromEntries(pvmContracts), null, 2)) -writeFileSync('evm-contracts.json', JSON.stringify(Object.fromEntries(evmContracts), null, 2)) diff --git a/substrate/frame/revive/rpc/examples/js/src/event.ts b/substrate/frame/revive/rpc/examples/js/src/event.ts index 95e630a43461..94cc2560272e 100644 --- a/substrate/frame/revive/rpc/examples/js/src/event.ts +++ b/substrate/frame/revive/rpc/examples/js/src/event.ts @@ -3,8 +3,8 @@ import { call, getContract, deploy } from './lib.ts' try { const { abi, bytecode } = getContract('event') - const address = await deploy(bytecode, abi) - const receipt = await call('triggerEvent', address, abi) + const contract = await deploy(bytecode, abi) + const receipt = await call('triggerEvent', await contract.getAddress(), abi) if (receipt) { for (const log of receipt.logs) { console.log('Event log:', JSON.stringify(log, null, 2)) diff --git a/substrate/frame/revive/rpc/examples/js/src/lib.ts b/substrate/frame/revive/rpc/examples/js/src/lib.ts index 7f6fc19aea75..975d8faf15b3 100644 --- a/substrate/frame/revive/rpc/examples/js/src/lib.ts +++ b/substrate/frame/revive/rpc/examples/js/src/lib.ts @@ -10,6 +10,7 @@ import { readFileSync } from 'node:fs' import type { compile } from '@parity/revive' import { spawn } from 'node:child_process' import { parseArgs } from 'node:util' +import { BaseContract } from 'ethers' type CompileOutput = Awaited> type Abi = CompileOutput['contracts'][string][string]['abi'] @@ -41,7 +42,7 @@ if (geth) { '--http.api', 'web3,eth,debug,personal,net', '--http.port', - '8545', + '8546', '--dev', '--verbosity', '0', @@ -54,11 +55,15 @@ if (geth) { await new Promise((resolve) => setTimeout(resolve, 500)) } -const provider = new JsonRpcProvider( - westend ? 'https://westend-asset-hub-eth-rpc.polkadot.io' : 'http://localhost:8545' +export const provider = new JsonRpcProvider( + westend + ? 'https://westend-asset-hub-eth-rpc.polkadot.io' + : geth + ? 'http://localhost:8546' + : 'http://localhost:8545' ) -const signer = privateKey ? new Wallet(privateKey, provider) : await provider.getSigner() +export const signer = privateKey ? new Wallet(privateKey, provider) : await provider.getSigner() console.log(`Signer address: ${await signer.getAddress()}, Nonce: ${await signer.getNonce()}`) /** @@ -66,18 +71,16 @@ console.log(`Signer address: ${await signer.getAddress()}, Nonce: ${await signer * @param name - the contract name */ export function getContract(name: string): { abi: Abi; bytecode: string } { - const file = geth - ? readFileSync('evm-contracts.json', 'utf8') - : readFileSync('pvm-contracts.json', 'utf8') - const contracts = JSON.parse(file) as Record - return contracts[name] + const bytecode = geth ? readFileSync(`evm/${name}.bin`) : readFileSync(`pvm/${name}.polkavm`) + const abi = JSON.parse(readFileSync(`abi/${name}.json`, 'utf8')) as Abi + return { abi, bytecode: Buffer.from(bytecode).toString('hex') } } /** * Deploy a contract * @returns the contract address **/ -export async function deploy(bytecode: string, abi: Abi, args: any[] = []): Promise { +export async function deploy(bytecode: string, abi: Abi, args: any[] = []): Promise { console.log('Deploying contract with', args) const contractFactory = new ContractFactory(abi, bytecode, signer) @@ -85,7 +88,8 @@ export async function deploy(bytecode: string, abi: Abi, args: any[] = []): Prom await contract.waitForDeployment() const address = await contract.getAddress() console.log(`Contract deployed: ${address}`) - return address + + return contract } /** diff --git a/substrate/frame/revive/rpc/examples/js/src/piggy-bank.ts b/substrate/frame/revive/rpc/examples/js/src/piggy-bank.ts new file mode 100644 index 000000000000..7a8edbde3662 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/src/piggy-bank.ts @@ -0,0 +1,24 @@ +import { provider, call, getContract, deploy } from './lib.ts' +import { parseEther } from 'ethers' +import { PiggyBank } from '../types/ethers-contracts/PiggyBank' + +try { + const { abi, bytecode } = getContract('piggyBank') + const contract = (await deploy(bytecode, abi)) as PiggyBank + const address = await contract.getAddress() + + let receipt = await call('deposit', address, abi, [], { + value: parseEther('10.0'), + }) + console.log('Deposit receipt:', receipt?.status) + console.log(`Contract balance: ${await provider.getBalance(address)}`) + + console.log('deposit: ', await contract.getDeposit()) + + receipt = await call('withdraw', address, abi, [parseEther('5.0')]) + console.log('Withdraw receipt:', receipt?.status) + console.log(`Contract balance: ${await provider.getBalance(address)}`) + console.log('deposit: ', await contract.getDeposit()) +} catch (err) { + console.error(err) +} diff --git a/substrate/frame/revive/rpc/examples/js/src/revert.ts b/substrate/frame/revive/rpc/examples/js/src/revert.ts index 5fb3ccde6fae..ea1bf4eceeb9 100644 --- a/substrate/frame/revive/rpc/examples/js/src/revert.ts +++ b/substrate/frame/revive/rpc/examples/js/src/revert.ts @@ -3,8 +3,8 @@ import { call, getContract, deploy } from './lib.ts' try { const { abi, bytecode } = getContract('revert') - const address = await deploy(bytecode, abi) - await call('doRevert', address, abi) + const contract = await deploy(bytecode, abi) + await call('doRevert', await contract.getAddress(), abi) } catch (err) { console.error(err) } diff --git a/substrate/frame/revive/rpc/examples/js/src/transfer.ts b/substrate/frame/revive/rpc/examples/js/src/transfer.ts new file mode 100644 index 000000000000..ae2dd50f2af8 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/src/transfer.ts @@ -0,0 +1,17 @@ +import { parseEther } from 'ethers' +import { provider, signer } from './lib.ts' + +const recipient = '0x75E480dB528101a381Ce68544611C169Ad7EB342' +try { + console.log(`Signer balance: ${await provider.getBalance(signer.address)}`) + console.log(`Recipient balance: ${await provider.getBalance(recipient)}`) + await signer.sendTransaction({ + to: recipient, + value: parseEther('1.0'), + }) + console.log(`Sent: ${parseEther('1.0')}`) + console.log(`Signer balance: ${await provider.getBalance(signer.address)}`) + console.log(`Recipient balance: ${await provider.getBalance(recipient)}`) +} catch (err) { + console.error(err) +} diff --git a/substrate/frame/revive/rpc/examples/js/tsconfig.json b/substrate/frame/revive/rpc/examples/js/tsconfig.json index 0511b9f0e041..55cb8379e886 100644 --- a/substrate/frame/revive/rpc/examples/js/tsconfig.json +++ b/substrate/frame/revive/rpc/examples/js/tsconfig.json @@ -1,23 +1,23 @@ { - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "skipLibCheck": true, + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "isolatedModules": true, - "moduleDetection": "force", - "noEmit": true, + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] } diff --git a/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/Event.ts b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/Event.ts new file mode 100644 index 000000000000..d65f953969f0 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/Event.ts @@ -0,0 +1,117 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { + BaseContract, + BigNumberish, + BytesLike, + FunctionFragment, + Result, + Interface, + EventFragment, + AddressLike, + ContractRunner, + ContractMethod, + Listener, +} from 'ethers' +import type { + TypedContractEvent, + TypedDeferredTopicFilter, + TypedEventLog, + TypedLogDescription, + TypedListener, + TypedContractMethod, +} from './common' + +export interface EventInterface extends Interface { + getFunction(nameOrSignature: 'triggerEvent'): FunctionFragment + + getEvent(nameOrSignatureOrTopic: 'ExampleEvent'): EventFragment + + encodeFunctionData(functionFragment: 'triggerEvent', values?: undefined): string + + decodeFunctionResult(functionFragment: 'triggerEvent', data: BytesLike): Result +} + +export namespace ExampleEventEvent { + export type InputTuple = [sender: AddressLike, value: BigNumberish, message: string] + export type OutputTuple = [sender: string, value: bigint, message: string] + export interface OutputObject { + sender: string + value: bigint + message: string + } + export type Event = TypedContractEvent + export type Filter = TypedDeferredTopicFilter + export type Log = TypedEventLog + export type LogDescription = TypedLogDescription +} + +export interface Event extends BaseContract { + connect(runner?: ContractRunner | null): Event + waitForDeployment(): Promise + + interface: EventInterface + + queryFilter( + event: TCEvent, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>> + queryFilter( + filter: TypedDeferredTopicFilter, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>> + + on( + event: TCEvent, + listener: TypedListener + ): Promise + on( + filter: TypedDeferredTopicFilter, + listener: TypedListener + ): Promise + + once( + event: TCEvent, + listener: TypedListener + ): Promise + once( + filter: TypedDeferredTopicFilter, + listener: TypedListener + ): Promise + + listeners( + event: TCEvent + ): Promise>> + listeners(eventName?: string): Promise> + removeAllListeners(event?: TCEvent): Promise + + triggerEvent: TypedContractMethod<[], [void], 'nonpayable'> + + getFunction(key: string | FunctionFragment): T + + getFunction(nameOrSignature: 'triggerEvent'): TypedContractMethod<[], [void], 'nonpayable'> + + getEvent( + key: 'ExampleEvent' + ): TypedContractEvent< + ExampleEventEvent.InputTuple, + ExampleEventEvent.OutputTuple, + ExampleEventEvent.OutputObject + > + + filters: { + 'ExampleEvent(address,uint256,string)': TypedContractEvent< + ExampleEventEvent.InputTuple, + ExampleEventEvent.OutputTuple, + ExampleEventEvent.OutputObject + > + ExampleEvent: TypedContractEvent< + ExampleEventEvent.InputTuple, + ExampleEventEvent.OutputTuple, + ExampleEventEvent.OutputObject + > + } +} diff --git a/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/PiggyBank.ts b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/PiggyBank.ts new file mode 100644 index 000000000000..ca137fcc8b30 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/PiggyBank.ts @@ -0,0 +1,96 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { + BaseContract, + BigNumberish, + BytesLike, + FunctionFragment, + Result, + Interface, + ContractRunner, + ContractMethod, + Listener, +} from 'ethers' +import type { + TypedContractEvent, + TypedDeferredTopicFilter, + TypedEventLog, + TypedListener, + TypedContractMethod, +} from './common' + +export interface PiggyBankInterface extends Interface { + getFunction(nameOrSignature: 'deposit' | 'getDeposit' | 'owner' | 'withdraw'): FunctionFragment + + encodeFunctionData(functionFragment: 'deposit', values?: undefined): string + encodeFunctionData(functionFragment: 'getDeposit', values?: undefined): string + encodeFunctionData(functionFragment: 'owner', values?: undefined): string + encodeFunctionData(functionFragment: 'withdraw', values: [BigNumberish]): string + + decodeFunctionResult(functionFragment: 'deposit', data: BytesLike): Result + decodeFunctionResult(functionFragment: 'getDeposit', data: BytesLike): Result + decodeFunctionResult(functionFragment: 'owner', data: BytesLike): Result + decodeFunctionResult(functionFragment: 'withdraw', data: BytesLike): Result +} + +export interface PiggyBank extends BaseContract { + connect(runner?: ContractRunner | null): PiggyBank + waitForDeployment(): Promise + + interface: PiggyBankInterface + + queryFilter( + event: TCEvent, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>> + queryFilter( + filter: TypedDeferredTopicFilter, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>> + + on( + event: TCEvent, + listener: TypedListener + ): Promise + on( + filter: TypedDeferredTopicFilter, + listener: TypedListener + ): Promise + + once( + event: TCEvent, + listener: TypedListener + ): Promise + once( + filter: TypedDeferredTopicFilter, + listener: TypedListener + ): Promise + + listeners( + event: TCEvent + ): Promise>> + listeners(eventName?: string): Promise> + removeAllListeners(event?: TCEvent): Promise + + deposit: TypedContractMethod<[], [bigint], 'payable'> + + getDeposit: TypedContractMethod<[], [bigint], 'view'> + + owner: TypedContractMethod<[], [string], 'view'> + + withdraw: TypedContractMethod<[withdrawAmount: BigNumberish], [bigint], 'nonpayable'> + + getFunction(key: string | FunctionFragment): T + + getFunction(nameOrSignature: 'deposit'): TypedContractMethod<[], [bigint], 'payable'> + getFunction(nameOrSignature: 'getDeposit'): TypedContractMethod<[], [bigint], 'view'> + getFunction(nameOrSignature: 'owner'): TypedContractMethod<[], [string], 'view'> + getFunction( + nameOrSignature: 'withdraw' + ): TypedContractMethod<[withdrawAmount: BigNumberish], [bigint], 'nonpayable'> + + filters: {} +} diff --git a/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/Revert.ts b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/Revert.ts new file mode 100644 index 000000000000..ad6e23b38a65 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/Revert.ts @@ -0,0 +1,78 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { + BaseContract, + BytesLike, + FunctionFragment, + Result, + Interface, + ContractRunner, + ContractMethod, + Listener, +} from 'ethers' +import type { + TypedContractEvent, + TypedDeferredTopicFilter, + TypedEventLog, + TypedListener, + TypedContractMethod, +} from './common' + +export interface RevertInterface extends Interface { + getFunction(nameOrSignature: 'doRevert'): FunctionFragment + + encodeFunctionData(functionFragment: 'doRevert', values?: undefined): string + + decodeFunctionResult(functionFragment: 'doRevert', data: BytesLike): Result +} + +export interface Revert extends BaseContract { + connect(runner?: ContractRunner | null): Revert + waitForDeployment(): Promise + + interface: RevertInterface + + queryFilter( + event: TCEvent, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>> + queryFilter( + filter: TypedDeferredTopicFilter, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>> + + on( + event: TCEvent, + listener: TypedListener + ): Promise + on( + filter: TypedDeferredTopicFilter, + listener: TypedListener + ): Promise + + once( + event: TCEvent, + listener: TypedListener + ): Promise + once( + filter: TypedDeferredTopicFilter, + listener: TypedListener + ): Promise + + listeners( + event: TCEvent + ): Promise>> + listeners(eventName?: string): Promise> + removeAllListeners(event?: TCEvent): Promise + + doRevert: TypedContractMethod<[], [void], 'nonpayable'> + + getFunction(key: string | FunctionFragment): T + + getFunction(nameOrSignature: 'doRevert'): TypedContractMethod<[], [void], 'nonpayable'> + + filters: {} +} diff --git a/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/common.ts b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/common.ts new file mode 100644 index 000000000000..247b9468ece2 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/common.ts @@ -0,0 +1,100 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { + FunctionFragment, + Typed, + EventFragment, + ContractTransaction, + ContractTransactionResponse, + DeferredTopicFilter, + EventLog, + TransactionRequest, + LogDescription, +} from 'ethers' + +export interface TypedDeferredTopicFilter<_TCEvent extends TypedContractEvent> + extends DeferredTopicFilter {} + +export interface TypedContractEvent< + InputTuple extends Array = any, + OutputTuple extends Array = any, + OutputObject = any, +> { + ( + ...args: Partial + ): TypedDeferredTopicFilter> + name: string + fragment: EventFragment + getFragment(...args: Partial): EventFragment +} + +type __TypechainAOutputTuple = T extends TypedContractEvent ? W : never +type __TypechainOutputObject = + T extends TypedContractEvent ? V : never + +export interface TypedEventLog extends Omit { + args: __TypechainAOutputTuple & __TypechainOutputObject +} + +export interface TypedLogDescription + extends Omit { + args: __TypechainAOutputTuple & __TypechainOutputObject +} + +export type TypedListener = ( + ...listenerArg: [...__TypechainAOutputTuple, TypedEventLog, ...undefined[]] +) => void + +export type MinEthersFactory = { + deploy(...a: ARGS[]): Promise +} + +export type GetContractTypeFromFactory = F extends MinEthersFactory ? C : never +export type GetARGsTypeFromFactory = + F extends MinEthersFactory ? Parameters : never + +export type StateMutability = 'nonpayable' | 'payable' | 'view' + +export type BaseOverrides = Omit +export type NonPayableOverrides = Omit +export type PayableOverrides = Omit +export type ViewOverrides = Omit +export type Overrides = S extends 'nonpayable' + ? NonPayableOverrides + : S extends 'payable' + ? PayableOverrides + : ViewOverrides + +export type PostfixOverrides, S extends StateMutability> = + | A + | [...A, Overrides] +export type ContractMethodArgs, S extends StateMutability> = PostfixOverrides< + { [I in keyof A]-?: A[I] | Typed }, + S +> + +export type DefaultReturnType = R extends Array ? R[0] : R + +// export interface ContractMethod = Array, R = any, D extends R | ContractTransactionResponse = R | ContractTransactionResponse> { +export interface TypedContractMethod< + A extends Array = Array, + R = any, + S extends StateMutability = 'payable', +> { + ( + ...args: ContractMethodArgs + ): S extends 'view' ? Promise> : Promise + + name: string + + fragment: FunctionFragment + + getFragment(...args: ContractMethodArgs): FunctionFragment + + populateTransaction(...args: ContractMethodArgs): Promise + staticCall(...args: ContractMethodArgs): Promise> + send(...args: ContractMethodArgs): Promise + estimateGas(...args: ContractMethodArgs): Promise + staticCallResult(...args: ContractMethodArgs): Promise +} diff --git a/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/Event__factory.ts b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/Event__factory.ts new file mode 100644 index 000000000000..2e16b18a7ed8 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/Event__factory.ts @@ -0,0 +1,51 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ + +import { Contract, Interface, type ContractRunner } from 'ethers' +import type { Event, EventInterface } from '../Event' + +const _abi = [ + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + { + indexed: false, + internalType: 'string', + name: 'message', + type: 'string', + }, + ], + name: 'ExampleEvent', + type: 'event', + }, + { + inputs: [], + name: 'triggerEvent', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, +] as const + +export class Event__factory { + static readonly abi = _abi + static createInterface(): EventInterface { + return new Interface(_abi) as EventInterface + } + static connect(address: string, runner?: ContractRunner | null): Event { + return new Contract(address, _abi, runner) as unknown as Event + } +} diff --git a/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/PiggyBank__factory.ts b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/PiggyBank__factory.ts new file mode 100644 index 000000000000..0efea80ed2dc --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/PiggyBank__factory.ts @@ -0,0 +1,82 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ + +import { Contract, Interface, type ContractRunner } from 'ethers' +import type { PiggyBank, PiggyBankInterface } from '../PiggyBank' + +const _abi = [ + { + inputs: [], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { + inputs: [], + name: 'deposit', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [], + name: 'getDeposit', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'owner', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'withdrawAmount', + type: 'uint256', + }, + ], + name: 'withdraw', + outputs: [ + { + internalType: 'uint256', + name: 'remainingBal', + type: 'uint256', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, +] as const + +export class PiggyBank__factory { + static readonly abi = _abi + static createInterface(): PiggyBankInterface { + return new Interface(_abi) as PiggyBankInterface + } + static connect(address: string, runner?: ContractRunner | null): PiggyBank { + return new Contract(address, _abi, runner) as unknown as PiggyBank + } +} diff --git a/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/Revert__factory.ts b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/Revert__factory.ts new file mode 100644 index 000000000000..ece1c6b5426e --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/Revert__factory.ts @@ -0,0 +1,31 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ + +import { Contract, Interface, type ContractRunner } from 'ethers' +import type { Revert, RevertInterface } from '../Revert' + +const _abi = [ + { + inputs: [], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { + inputs: [], + name: 'doRevert', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, +] as const + +export class Revert__factory { + static readonly abi = _abi + static createInterface(): RevertInterface { + return new Interface(_abi) as RevertInterface + } + static connect(address: string, runner?: ContractRunner | null): Revert { + return new Contract(address, _abi, runner) as unknown as Revert + } +} diff --git a/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/index.ts b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/index.ts new file mode 100644 index 000000000000..67370dba411c --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/index.ts @@ -0,0 +1,6 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +export { Event__factory } from './Event__factory' +export { PiggyBank__factory } from './PiggyBank__factory' +export { Revert__factory } from './Revert__factory' diff --git a/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/index.ts b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/index.ts new file mode 100644 index 000000000000..3e324e80dcb1 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/index.ts @@ -0,0 +1,10 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +export type { Event } from './Event' +export type { PiggyBank } from './PiggyBank' +export type { Revert } from './Revert' +export * as factories from './factories' +export { Event__factory } from './factories/Event__factory' +export { PiggyBank__factory } from './factories/PiggyBank__factory' +export { Revert__factory } from './factories/Revert__factory' diff --git a/substrate/frame/revive/rpc/examples/package.json b/substrate/frame/revive/rpc/examples/package.json deleted file mode 100644 index 37d819aaa481..000000000000 --- a/substrate/frame/revive/rpc/examples/package.json +++ /dev/null @@ -1 +0,0 @@ -{ "dependencies": { "@parity/revive": "^0.0.5" } } \ No newline at end of file diff --git a/substrate/frame/revive/rpc/revive_chain.metadata b/substrate/frame/revive/rpc/revive_chain.metadata index e5bfa0820b10..3560b3b90407 100644 Binary files a/substrate/frame/revive/rpc/revive_chain.metadata and b/substrate/frame/revive/rpc/revive_chain.metadata differ diff --git a/substrate/frame/revive/rpc/src/client.rs b/substrate/frame/revive/rpc/src/client.rs index bc4f59b5e26e..4606a40269be 100644 --- a/substrate/frame/revive/rpc/src/client.rs +++ b/substrate/frame/revive/rpc/src/client.rs @@ -236,7 +236,6 @@ struct ClientInner { cache: Shared>, chain_id: u64, max_block_weight: Weight, - native_to_evm_ratio: U256, } impl ClientInner { @@ -252,20 +251,10 @@ impl ClientInner { let rpc = LegacyRpcMethods::::new(RpcClient::new(rpc_client.clone())); - let (native_to_evm_ratio, chain_id, max_block_weight) = - tokio::try_join!(native_to_evm_ratio(&api), chain_id(&api), max_block_weight(&api))?; + let (chain_id, max_block_weight) = + tokio::try_join!(chain_id(&api), max_block_weight(&api))?; - Ok(Self { api, rpc_client, rpc, cache, chain_id, max_block_weight, native_to_evm_ratio }) - } - - /// Convert a native balance to an EVM balance. - fn native_to_evm_decimals(&self, value: U256) -> U256 { - value.saturating_mul(self.native_to_evm_ratio) - } - - /// Convert an evm balance to a native balance. - fn evm_to_native_decimals(&self, value: U256) -> U256 { - value / self.native_to_evm_ratio + Ok(Self { api, rpc_client, rpc, cache, chain_id, max_block_weight }) } /// Get the receipt infos from the extrinsics in a block. @@ -368,13 +357,6 @@ async fn max_block_weight(api: &OnlineClient) -> Result) -> Result { - let query = subxt_client::constants().revive().native_to_eth_ratio(); - let ratio = api.constants().at(&query)?; - Ok(U256::from(ratio)) -} - /// Extract the block timestamp. async fn extract_block_timestamp(block: &SubstrateBlock) -> Option { let extrinsics = block.extrinsics().await.ok()?; @@ -607,8 +589,9 @@ impl Client { let runtime_api = self.runtime_api(at).await?; let payload = subxt_client::apis().revive_api().balance(address); - let balance = runtime_api.call(payload).await?.into(); - Ok(self.inner.native_to_evm_decimals(balance)) + let balance = runtime_api.call(payload).await?; + + Ok(*balance) } /// Get the contract storage for the given contract address and key. @@ -659,13 +642,8 @@ impl Client { ) -> Result>, ClientError> { let runtime_api = self.runtime_api(&block).await?; - let value = self - .inner - .evm_to_native_decimals(tx.value.unwrap_or_default()) - .try_into() - .map_err(|_| ClientError::ConversionFailed)?; - // TODO: remove once subxt is updated + let value = subxt::utils::Static(tx.value.unwrap_or_default()); let from = tx.from.map(|v| v.0.into()); let to = tx.to.map(|v| v.0.into()); diff --git a/substrate/frame/revive/rpc/src/example.rs b/substrate/frame/revive/rpc/src/example.rs index d2f9b509f4d2..20f00465b146 100644 --- a/substrate/frame/revive/rpc/src/example.rs +++ b/substrate/frame/revive/rpc/src/example.rs @@ -105,6 +105,30 @@ impl TransactionBuilder { self } + /// Call eth_call to get the result of a view function + pub async fn eth_call( + self, + client: &(impl EthRpcClient + Send + Sync), + ) -> anyhow::Result> { + let TransactionBuilder { signer, value, input, to, .. } = self; + + let from = signer.address(); + let result = client + .call( + GenericTransaction { + from: Some(from), + input: Some(input.clone()), + value: Some(value), + to, + ..Default::default() + }, + None, + ) + .await + .with_context(|| "eth_call failed")?; + Ok(result.0) + } + /// Send the transaction. pub async fn send(self, client: &(impl EthRpcClient + Send + Sync)) -> anyhow::Result { let TransactionBuilder { signer, value, input, to, mutate } = self; @@ -156,6 +180,7 @@ impl TransactionBuilder { Ok(hash) } + /// Send the transaction and wait for the receipt. pub async fn send_and_wait_for_receipt( self, client: &(impl EthRpcClient + Send + Sync), diff --git a/substrate/frame/revive/rpc/src/subxt_client.rs b/substrate/frame/revive/rpc/src/subxt_client.rs index 11a0d51ed03e..a232b231bc7c 100644 --- a/substrate/frame/revive/rpc/src/subxt_client.rs +++ b/substrate/frame/revive/rpc/src/subxt_client.rs @@ -21,6 +21,11 @@ use subxt::config::{signed_extensions, Config, PolkadotConfig}; #[subxt::subxt( runtime_metadata_path = "revive_chain.metadata", + // TODO remove once subxt use the same U256 type + substitute_type( + path = "primitive_types::U256", + with = "::subxt::utils::Static<::sp_core::U256>" + ), substitute_type( path = "pallet_revive::primitives::EthContractResult", with = "::subxt::utils::Static<::pallet_revive::EthContractResult>" diff --git a/substrate/frame/revive/rpc/src/tests.rs b/substrate/frame/revive/rpc/src/tests.rs index 3d2cbe42be8e..eb23bd7583a0 100644 --- a/substrate/frame/revive/rpc/src/tests.rs +++ b/substrate/frame/revive/rpc/src/tests.rs @@ -22,6 +22,7 @@ use crate::{ EthRpcClient, }; use clap::Parser; +use ethabi::Token; use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; use pallet_revive::{ create1, @@ -48,15 +49,12 @@ async fn ws_client_with_retry(url: &str) -> WsClient { } fn get_contract(name: &str) -> anyhow::Result<(Vec, ethabi::Contract)> { - const PVM_CONTRACTS: &str = include_str!("../examples/js/pvm-contracts.json"); - let pvm_contract: serde_json::Value = serde_json::from_str(PVM_CONTRACTS)?; - let pvm_contract = pvm_contract[name].as_object().unwrap(); - let bytecode = pvm_contract["bytecode"].as_str().unwrap(); - let bytecode = hex::decode(bytecode)?; + let pvm_dir: std::path::PathBuf = "./examples/js/pvm".into(); + let abi_dir: std::path::PathBuf = "./examples/js/abi".into(); + let bytecode = std::fs::read(pvm_dir.join(format!("{}.polkavm", name)))?; - let abi = pvm_contract["abi"].clone(); - let abi = serde_json::to_string(&abi)?; - let contract = ethabi::Contract::load(abi.as_bytes())?; + let abi = std::fs::read(abi_dir.join(format!("{}.json", name)))?; + let contract = ethabi::Contract::load(abi.as_slice())?; Ok((bytecode, contract)) } @@ -280,3 +278,44 @@ async fn invalid_transaction() -> anyhow::Result<()> { Ok(()) } + +#[tokio::test] +async fn native_evm_ratio_works() -> anyhow::Result<()> { + let _lock = SHARED_RESOURCES.write(); + let client = SharedResources::client().await; + let (bytecode, contract) = get_contract("piggyBank")?; + let contract_address = TransactionBuilder::default() + .input(bytecode) + .send_and_wait_for_receipt(&client) + .await? + .contract_address + .unwrap(); + + let value = 10_000_000_000_000_000_000u128; // 10 eth + TransactionBuilder::default() + .to(contract_address) + .input(contract.function("deposit")?.encode_input(&[])?.to_vec()) + .value(value.into()) + .send_and_wait_for_receipt(&client) + .await?; + + let contract_value = client.get_balance(contract_address, BlockTag::Latest.into()).await?; + assert_eq!(contract_value, value.into()); + + let withdraw_value = 1_000_000_000_000_000_000u128; // 1 eth + TransactionBuilder::default() + .to(contract_address) + .input( + contract + .function("withdraw")? + .encode_input(&[Token::Uint(withdraw_value.into())])? + .to_vec(), + ) + .send_and_wait_for_receipt(&client) + .await?; + + let contract_value = client.get_balance(contract_address, BlockTag::Latest.into()).await?; + assert_eq!(contract_value, (value - withdraw_value).into()); + + Ok(()) +} diff --git a/substrate/frame/revive/src/benchmarking/mod.rs b/substrate/frame/revive/src/benchmarking/mod.rs index 593c16cbb2d8..40ad3a3aed17 100644 --- a/substrate/frame/revive/src/benchmarking/mod.rs +++ b/substrate/frame/revive/src/benchmarking/mod.rs @@ -1516,7 +1516,7 @@ mod benchmarks { let callee_bytes = callee.encode(); let callee_len = callee_bytes.len() as u32; - let value: BalanceOf = t.into(); + let value: BalanceOf = (1_000_000 * t).into(); let value_bytes = Into::::into(value).encode(); let deposit: BalanceOf = (u32::MAX - 100).into(); @@ -1591,7 +1591,7 @@ mod benchmarks { let hash_bytes = hash.encode(); let hash_len = hash_bytes.len() as u32; - let value: BalanceOf = 1u32.into(); + let value: BalanceOf = 1_000_000u32.into(); let value_bytes = Into::::into(value).encode(); let value_len = value_bytes.len() as u32; @@ -1645,7 +1645,10 @@ mod benchmarks { assert_ok!(result); assert!(ContractInfoOf::::get(&addr).is_some()); - assert_eq!(T::Currency::balance(&account_id), Pallet::::min_balance() + value); + assert_eq!( + T::Currency::balance(&account_id), + Pallet::::min_balance() + Pallet::::convert_evm_to_native(value.into()).unwrap() + ); Ok(()) } diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index c27edac93500..21294fdf6baa 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -313,9 +313,10 @@ pub trait EthExtra { return Err(InvalidTransaction::Call); } - let value = (value / U256::from(::NativeToEthRatio::get())) - .try_into() - .map_err(|_| InvalidTransaction::Call)?; + let value = crate::Pallet::::convert_evm_to_native(value).map_err(|err| { + log::debug!(target: LOG_TARGET, "Failed to convert value to native: {err:?}"); + InvalidTransaction::Call + })?; let call = if let Some(dest) = to { crate::Call::call:: { diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 4f90b41b0de5..fdb45f045bbc 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -569,8 +569,8 @@ struct Frame { account_id: T::AccountId, /// The cached in-storage data of the contract. contract_info: CachedContract, - /// The amount of balance transferred by the caller as part of the call. - value_transferred: BalanceOf, + /// The EVM balance transferred by the caller as part of the call. + value_transferred: U256, /// Determines whether this is a call or instantiate frame. entry_point: ExportedFunction, /// The gas meter capped to the supplied gas limit. @@ -757,7 +757,7 @@ where dest: H160, gas_meter: &'a mut GasMeter, storage_meter: &'a mut storage::meter::Meter, - value: BalanceOf, + value: U256, input_data: Vec, debug_message: Option<&'a mut DebugBuffer>, ) -> ExecResult { @@ -791,7 +791,7 @@ where executable: E, gas_meter: &'a mut GasMeter, storage_meter: &'a mut storage::meter::Meter, - value: BalanceOf, + value: U256, input_data: Vec, salt: Option<&[u8; 32]>, debug_message: Option<&'a mut DebugBuffer>, @@ -834,7 +834,7 @@ where origin, gas_meter, storage_meter, - value, + value.into(), debug_message, ) .unwrap() @@ -843,14 +843,14 @@ where /// Create a new call stack. /// - /// Returns `None` when calling a non existant contract. This is not an error case + /// Returns `None` when calling a non existent contract. This is not an error case /// since this will result in a value transfer. fn new( args: FrameArgs, origin: Origin, gas_meter: &'a mut GasMeter, storage_meter: &'a mut storage::meter::Meter, - value: BalanceOf, + value: U256, debug_message: Option<&'a mut DebugBuffer>, ) -> Result, ExecError> { origin.ensure_mapped()?; @@ -890,7 +890,7 @@ where /// not initialized, yet. fn new_frame( frame_args: FrameArgs, - value_transferred: BalanceOf, + value_transferred: U256, gas_meter: &mut GasMeter, gas_limit: Weight, storage_meter: &mut storage::meter::GenericMeter, @@ -975,7 +975,7 @@ where fn push_frame( &mut self, frame_args: FrameArgs, - value_transferred: BalanceOf, + value_transferred: U256, gas_limit: Weight, deposit_limit: BalanceOf, read_only: bool, @@ -1282,8 +1282,9 @@ where origin: &Origin, from: &T::AccountId, to: &T::AccountId, - value: BalanceOf, + value: U256, ) -> ExecResult { + let value = crate::Pallet::::convert_evm_to_native(value)?; if value.is_zero() { return Ok(Default::default()); } @@ -1311,7 +1312,7 @@ where origin: &Origin, from: &Origin, to: &T::AccountId, - value: BalanceOf, + value: U256, ) -> ExecResult { // If the from address is root there is no account to transfer from, and therefore we can't // take any `value` other than 0. @@ -1358,7 +1359,11 @@ where /// Returns the *free* balance of the supplied AccountId. fn account_balance(&self, who: &T::AccountId) -> U256 { - T::Currency::reducible_balance(who, Preservation::Preserve, Fortitude::Polite).into() + crate::Pallet::::convert_native_to_evm(T::Currency::reducible_balance( + who, + Preservation::Preserve, + Fortitude::Polite, + )) } /// Certain APIs, e.g. `{set,get}_immutable_data` behave differently depending @@ -2066,7 +2071,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - value, + value.into(), vec![], None, ), @@ -2086,7 +2091,7 @@ mod tests { set_balance(&BOB, 0); let origin = Origin::from_account_id(ALICE); - MockStack::transfer(&origin, &ALICE, &BOB, 55).unwrap(); + MockStack::transfer(&origin, &ALICE, &BOB, 55u64.into()).unwrap(); let min_balance = ::Currency::minimum_balance(); assert_eq!(get_balance(&ALICE), 45 - min_balance); @@ -2107,7 +2112,12 @@ mod tests { set_balance(&ALICE, ed * 2); set_balance(&BOB, ed + value); - assert_ok!(MockStack::transfer(&Origin::from_account_id(ALICE), &BOB, &CHARLIE, value)); + assert_ok!(MockStack::transfer( + &Origin::from_account_id(ALICE), + &BOB, + &CHARLIE, + value.into() + )); assert_eq!(get_balance(&ALICE), ed); assert_eq!(get_balance(&BOB), ed); assert_eq!(get_balance(&CHARLIE), ed + value); @@ -2116,7 +2126,7 @@ mod tests { set_balance(&ALICE, ed); set_balance(&BOB, ed + value); assert_err!( - MockStack::transfer(&Origin::from_account_id(ALICE), &BOB, &DJANGO, value), + MockStack::transfer(&Origin::from_account_id(ALICE), &BOB, &DJANGO, value.into()), >::TransferFailed ); @@ -2124,7 +2134,7 @@ mod tests { set_balance(&ALICE, ed * 2); set_balance(&BOB, value); assert_err!( - MockStack::transfer(&Origin::from_account_id(ALICE), &BOB, &EVE, value), + MockStack::transfer(&Origin::from_account_id(ALICE), &BOB, &EVE, value.into()), >::TransferFailed ); // The ED transfer would work. But it should only be executed with the actual transfer @@ -2153,7 +2163,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - value, + value.into(), vec![], None, ) @@ -2191,7 +2201,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - value, + value.into(), vec![], None, ) @@ -2223,7 +2233,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 55, + 55u64.into(), vec![], None, ) @@ -2246,7 +2256,7 @@ mod tests { ExtBuilder::default().build().execute_with(|| { set_balance(&from, 0); - let result = MockStack::transfer(&origin, &from, &dest, 100); + let result = MockStack::transfer(&origin, &from, &dest, 100u64.into()); assert_eq!(result, Err(Error::::TransferFailed.into())); assert_eq!(get_balance(&from), 0); @@ -2272,7 +2282,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ); @@ -2301,7 +2311,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ); @@ -2330,7 +2340,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![1, 2, 3, 4], None, ); @@ -2365,7 +2375,7 @@ mod tests { executable, &mut gas_meter, &mut storage_meter, - min_balance, + min_balance.into(), vec![1, 2, 3, 4], Some(&[0; 32]), None, @@ -2420,7 +2430,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - value, + value.into(), vec![], None, ); @@ -2484,7 +2494,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ); @@ -2549,7 +2559,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ); @@ -2581,7 +2591,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ); @@ -2618,7 +2628,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], None, ); @@ -2644,7 +2654,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], None, ); @@ -2688,7 +2698,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], None, ); @@ -2714,7 +2724,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], None, ); @@ -2740,7 +2750,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 1, + 1u64.into(), vec![0], None, ); @@ -2784,7 +2794,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], None, ); @@ -2829,7 +2839,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ); @@ -2854,7 +2864,7 @@ mod tests { executable, &mut gas_meter, &mut storage_meter, - 0, // <- zero value + U256::zero(), // <- zero value vec![], Some(&[0; 32]), None, @@ -2889,8 +2899,7 @@ mod tests { executable, &mut gas_meter, &mut storage_meter, - - min_balance, + min_balance.into(), vec![], Some(&[0 ;32]), None, @@ -2945,7 +2954,7 @@ mod tests { &mut gas_meter, &mut storage_meter, - min_balance, + min_balance.into(), vec![], Some(&[0; 32]), None, @@ -3010,7 +3019,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - min_balance * 10, + (min_balance * 10).into(), vec![], None, ), @@ -3090,7 +3099,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ), @@ -3132,7 +3141,7 @@ mod tests { executable, &mut gas_meter, &mut storage_meter, - 100, + 100u64.into(), vec![], Some(&[0; 32]), None, @@ -3197,7 +3206,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], None, ); @@ -3258,7 +3267,7 @@ mod tests { executable, &mut gas_meter, &mut storage_meter, - 10, + 10u64.into(), vec![], Some(&[0; 32]), None, @@ -3305,7 +3314,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], None, ) @@ -3336,7 +3345,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], Some(&mut debug_buffer), ) @@ -3369,7 +3378,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], Some(&mut debug_buffer), ); @@ -3402,7 +3411,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], Some(&mut debug_buf_after), ) @@ -3435,7 +3444,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), CHARLIE_ADDR.as_bytes().to_vec(), None, )); @@ -3447,7 +3456,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), BOB_ADDR.as_bytes().to_vec(), None, ) @@ -3497,7 +3506,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], None, ) @@ -3531,7 +3540,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], None, ) @@ -3615,7 +3624,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], None, ) @@ -3740,7 +3749,7 @@ mod tests { fail_executable, &mut gas_meter, &mut storage_meter, - min_balance * 100, + (min_balance * 100).into(), vec![], Some(&[0; 32]), None, @@ -3753,7 +3762,7 @@ mod tests { success_executable, &mut gas_meter, &mut storage_meter, - min_balance * 100, + (min_balance * 100).into(), vec![], Some(&[0; 32]), None, @@ -3765,7 +3774,7 @@ mod tests { succ_fail_executable, &mut gas_meter, &mut storage_meter, - min_balance * 200, + (min_balance * 200).into(), vec![], Some(&[0; 32]), None, @@ -3777,7 +3786,7 @@ mod tests { succ_succ_executable, &mut gas_meter, &mut storage_meter, - min_balance * 200, + (min_balance * 200).into(), vec![], Some(&[0; 32]), None, @@ -3846,7 +3855,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], None, )); @@ -3957,7 +3966,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], None, )); @@ -3996,7 +4005,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], None, )); @@ -4035,7 +4044,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], None, )); @@ -4088,7 +4097,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], None, )); @@ -4144,7 +4153,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], None, )); @@ -4219,7 +4228,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, )); @@ -4289,7 +4298,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], None, ); @@ -4327,7 +4336,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, )); @@ -4389,7 +4398,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], None, ); @@ -4422,7 +4431,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ); @@ -4505,7 +4514,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ) @@ -4573,7 +4582,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], None, ); @@ -4639,7 +4648,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ); @@ -4690,7 +4699,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ) @@ -4761,7 +4770,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ) @@ -4807,7 +4816,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ) @@ -4851,7 +4860,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ) @@ -4906,7 +4915,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], None, ), diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 5ca0042d929b..caecf07c4071 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -59,6 +59,7 @@ use frame_support::{ pallet_prelude::DispatchClass, traits::{ fungible::{Inspect, Mutate, MutateHold}, + tokens::{Fortitude::Polite, Preservation::Preserve}, ConstU32, ConstU64, Contains, EnsureOrigin, Get, IsType, OriginTrait, Time, }, weights::{Weight, WeightMeter}, @@ -73,7 +74,7 @@ use pallet_transaction_payment::OnChargeTransaction; use scale_info::TypeInfo; use sp_core::{H160, H256, U256}; use sp_runtime::{ - traits::{BadOrigin, Convert, Dispatchable, Saturating}, + traits::{BadOrigin, Convert, Dispatchable, Saturating, Zero}, DispatchError, }; @@ -379,7 +380,7 @@ pub mod pallet { type RuntimeMemory = ConstU32<{ 128 * 1024 * 1024 }>; type PVFMemory = ConstU32<{ 512 * 1024 * 1024 }>; type ChainId = ConstU64<0>; - type NativeToEthRatio = ConstU32<1_000_000>; + type NativeToEthRatio = ConstU32<1>; } } @@ -561,6 +562,8 @@ pub mod pallet { ExecutionFailed, /// Failed to convert a U256 to a Balance. BalanceConversionFailed, + /// Failed to convert an EVM balance to a native balance. + DecimalPrecisionLoss, /// Immutable data can only be set during deploys and only be read during calls. /// Additionally, it is only valid to set the data once and it must not be empty. InvalidImmutableAccess, @@ -1115,7 +1118,7 @@ where dest, &mut gas_meter, &mut storage_meter, - value, + Self::convert_native_to_evm(value), data, debug_message.as_mut(), )?; @@ -1180,7 +1183,7 @@ where executable, &mut gas_meter, &mut storage_meter, - value, + Self::convert_native_to_evm(value), data, salt.as_ref(), debug_message.as_mut(), @@ -1214,7 +1217,7 @@ where /// /// - `origin`: The origin of the call. /// - `dest`: The destination address of the call. - /// - `value`: The value to transfer. + /// - `value`: The EVM value to transfer. /// - `input`: The input data. /// - `gas_limit`: The gas limit enforced during contract execution. /// - `storage_deposit_limit`: The maximum balance that can be charged to the caller for storage @@ -1226,7 +1229,7 @@ where pub fn bare_eth_transact( origin: T::AccountId, dest: Option, - value: BalanceOf, + value: U256, input: Vec, gas_limit: Weight, storage_deposit_limit: BalanceOf, @@ -1250,6 +1253,18 @@ where // Get the nonce to encode in the tx. let nonce: T::Nonce = >::account_nonce(&origin); + // Convert the value to the native balance type. + let native_value = match Self::convert_evm_to_native(value) { + Ok(v) => v, + Err(err) => + return EthContractResult { + gas_required: Default::default(), + storage_deposit: Default::default(), + fee: Default::default(), + result: Err(err.into()), + }, + }; + // Dry run the call let (mut result, dispatch_info) = match dest { // A contract call. @@ -1258,13 +1273,14 @@ where let result = crate::Pallet::::bare_call( T::RuntimeOrigin::signed(origin), dest, - value, + native_value, gas_limit, storage_deposit_limit, input.clone(), debug, collect_events, ); + let result = EthContractResult { gas_required: result.gas_required, storage_deposit: result.storage_deposit.charge_or_zero(), @@ -1274,7 +1290,7 @@ where // Get the dispatch info of the call. let dispatch_call: ::RuntimeCall = crate::Call::::call { dest, - value, + value: native_value, gas_limit: result.gas_required, storage_deposit_limit: result.storage_deposit, data: input.clone(), @@ -1300,7 +1316,7 @@ where // Dry run the call. let result = crate::Pallet::::bare_instantiate( T::RuntimeOrigin::signed(origin), - value, + native_value, gas_limit, storage_deposit_limit, Code::Upload(code.to_vec()), @@ -1320,7 +1336,7 @@ where // Get the dispatch info of the call. let dispatch_call: ::RuntimeCall = crate::Call::::instantiate_with_code { - value, + value: native_value, gas_limit: result.gas_required, storage_deposit_limit: result.storage_deposit, code: code.to_vec(), @@ -1333,7 +1349,7 @@ where }; let mut tx = TransactionLegacyUnsigned { - value: value.into().saturating_mul(T::NativeToEthRatio::get().into()), + value, input: input.into(), nonce: nonce.into(), chain_id: Some(T::ChainId::get().into()), @@ -1372,6 +1388,12 @@ where result } + /// Get the balance with EVM decimals of the given `address`. + pub fn evm_balance(address: &H160) -> U256 { + let account = T::AddressMapper::to_account_id(&address); + Self::convert_native_to_evm(T::Currency::reducible_balance(&account, Preserve, Polite)) + } + /// A generalized version of [`Self::upload_code`]. /// /// It is identical to [`Self::upload_code`] and only differs in the information it returns. @@ -1424,6 +1446,25 @@ where .and_then(|r| r) }) } + + /// Convert a native balance to EVM balance. + fn convert_native_to_evm(value: BalanceOf) -> U256 { + value.into().saturating_mul(T::NativeToEthRatio::get().into()) + } + + /// Convert an EVM balance to a native balance. + fn convert_evm_to_native(value: U256) -> Result, Error> { + if value.is_zero() { + return Ok(Zero::zero()) + } + let ratio = T::NativeToEthRatio::get().into(); + let res = value.checked_div(ratio).expect("divisor is non-zero; qed"); + if res.saturating_mul(ratio) == value { + res.try_into().map_err(|_| Error::::BalanceConversionFailed) + } else { + Err(Error::::DecimalPrecisionLoss) + } + } } impl Pallet { @@ -1451,8 +1492,8 @@ sp_api::decl_runtime_apis! { BlockNumber: Codec, EventRecord: Codec, { - /// Returns the free balance of the given `[H160]` address. - fn balance(address: H160) -> Balance; + /// Returns the free balance of the given `[H160]` address, using EVM decimals. + fn balance(address: H160) -> U256; /// Returns the nonce of the given `[H160]` address. fn nonce(address: H160) -> Nonce; @@ -1489,7 +1530,7 @@ sp_api::decl_runtime_apis! { fn eth_transact( origin: H160, dest: Option, - value: Balance, + value: U256, input: Vec, gas_limit: Option, storage_deposit_limit: Option,