mirror of
https://github.com/datahaven-xyz/datahaven
synced 2026-05-24 01:38:32 +00:00
feat(test): expand Moonwall test coverage with balance and precompile tests (#414)
## Summary - Import and adapt balance tests from Moonbeam's test suite for DataHaven runtime compatibility - Add comprehensive precompile tests covering ERC20, modexp, proxy, identity, and cryptographic precompiles - Add helper utilities for precompile testing including address constants and contract call wrappers ## Changes ### Balance Tests - `test-balance-existential.ts` - Existential deposit behavior - `test-balance-extrinsics.ts` - Balance extrinsics (transfer, force_transfer) - `test-balance-genesis.ts` - Genesis balance verification - `test-balance-transfer.ts` - Various transfer scenarios ### Precompile Tests - **ERC20**: Native token interface tests including overflow handling - **Modexp**: Comprehensive modular exponentiation tests with extensive test vectors - **Proxy**: Proxy account management and proxy call tests - **Identity**: Full identity precompile test coverage (14 test files) - **Cryptographic**: blake2, bn128add, bn128mul, bn128pairing, ecrecover, ripemd160, sha3fips - **Preimage**: Preimage noting and unnoting tests ### Helper Utilities - `precompile-addresses.ts` - Precompile address constants - `precompile-contract-calls.ts` - Typed contract call helpers (Preimage class) - `modexp.ts` - Modexp test utilities ### Runtime Fixes - Fix Ethan's address in genesis presets to match Moonwall util constants --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com> Co-authored-by: Ahmad Kaouk <ahmadkaouk.93@gmail.com>
This commit is contained in:
parent
ce24450b70
commit
506471db24
41 changed files with 4291 additions and 9 deletions
|
|
@ -8,6 +8,7 @@
|
|||
"**/*.yml",
|
||||
"**/*.md",
|
||||
"!node_modules/*",
|
||||
"!**/moonwall/**/*",
|
||||
"!target/*",
|
||||
"!**/tmp/*",
|
||||
"!**/*.spec.json",
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@ pub fn dorothy() -> AccountId {
|
|||
}
|
||||
|
||||
pub fn ethan() -> AccountId {
|
||||
AccountId::from(hex!("Ff64d3F6efE2317EE2807d2235B1ac2AA69d9E87"))
|
||||
AccountId::from(hex!("Ff64d3F6efE2317EE2807d223a0Bdc4c0c49dfDB"))
|
||||
}
|
||||
|
||||
pub fn frank() -> AccountId {
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ pub fn dorothy() -> AccountId {
|
|||
}
|
||||
|
||||
pub fn ethan() -> AccountId {
|
||||
AccountId::from(hex!("Ff64d3F6efE2317EE2807d2235B1ac2AA69d9E87"))
|
||||
AccountId::from(hex!("Ff64d3F6efE2317EE2807d223a0Bdc4c0c49dfDB"))
|
||||
}
|
||||
|
||||
pub fn frank() -> AccountId {
|
||||
|
|
|
|||
|
|
@ -265,7 +265,7 @@ pub fn dorothy() -> AccountId {
|
|||
}
|
||||
|
||||
pub fn ethan() -> AccountId {
|
||||
AccountId::from(hex!("Ff64d3F6efE2317EE2807d2235B1ac2AA69d9E87"))
|
||||
AccountId::from(hex!("Ff64d3F6efE2317EE2807d223a0Bdc4c0c49dfDB"))
|
||||
}
|
||||
|
||||
pub fn frank() -> AccountId {
|
||||
|
|
|
|||
51
test/moonwall/contracts/src/ECContracts.sol
Normal file
51
test/moonwall/contracts/src/ECContracts.sol
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity >=0.8.3;
|
||||
|
||||
contract RecoveryChecker {
|
||||
constructor() {}
|
||||
|
||||
function checkRecovery(
|
||||
bytes32 msgHash,
|
||||
uint256 v,
|
||||
bytes32 r,
|
||||
bytes32 s
|
||||
) public view returns (address) {
|
||||
(, bytes memory data) = address(0x01).staticcall(
|
||||
abi.encode(msgHash, v, r, s)
|
||||
);
|
||||
return abi.decode(data, (address));
|
||||
}
|
||||
}
|
||||
|
||||
contract PairingChecker {
|
||||
bool public status = false;
|
||||
|
||||
function callBn256Pairing(bytes memory input)
|
||||
public
|
||||
returns (bytes32 result)
|
||||
{
|
||||
uint256 len = input.length;
|
||||
assembly {
|
||||
let memPtr := mload(0x40)
|
||||
let success := call(
|
||||
gas(),
|
||||
0x08,
|
||||
0,
|
||||
add(input, 0x20),
|
||||
len,
|
||||
memPtr,
|
||||
0x20
|
||||
)
|
||||
switch success
|
||||
case 0 {
|
||||
revert(0, 0)
|
||||
}
|
||||
default {
|
||||
result := mload(memPtr)
|
||||
}
|
||||
}
|
||||
status =
|
||||
result ==
|
||||
0x0000000000000000000000000000000000000000000000000000000000000001;
|
||||
}
|
||||
}
|
||||
226
test/moonwall/contracts/src/HasherChecker.sol
Normal file
226
test/moonwall/contracts/src/HasherChecker.sol
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
pragma solidity >=0.8.3;
|
||||
|
||||
contract HasherChecker {
|
||||
uint256 public lastResult;
|
||||
|
||||
function ripemd160Check() public pure {
|
||||
require(
|
||||
ripemd160(bytes("Hello World!")) ==
|
||||
hex"8476ee4631b9b30ac2754b0ee0c47e161d3f724c"
|
||||
);
|
||||
}
|
||||
|
||||
function bn128AdditionCheck() public {
|
||||
bool success;
|
||||
uint256[4] memory input = [
|
||||
0x2243525c5efd4b9c3d3c45ac0ca3fe4dd85e830a4ce6b65fa1eeaee202839703,
|
||||
0x301d1d33be6da8e509df21cc35964723180eed7532537db9ae5e7d48f195c915,
|
||||
0x18b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9,
|
||||
0x063c909c4720840cb5134cb9f59fa749755796819658d32efc0d288198f37266
|
||||
];
|
||||
uint256[2] memory result;
|
||||
|
||||
assembly {
|
||||
// 0x06 id of the bn256Add precompile
|
||||
// 0 number of ether to transfer
|
||||
// 128 size of call parameters, i.e. 128 bytes total
|
||||
// 64 size of return value, i.e. 64 bytes / 512 bit for a BN256 curve point
|
||||
success := call(not(0), 0x06, 0, input, 128, result, 64)
|
||||
}
|
||||
require(success, "elliptic curve addition failed");
|
||||
require(
|
||||
result[0] ==
|
||||
0x2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb7,
|
||||
"failed"
|
||||
);
|
||||
require(
|
||||
result[1] ==
|
||||
0x21611ce0a6af85915e2f1d70300909ce2e49dfad4a4619c8390cae66cefdb204,
|
||||
"failed"
|
||||
);
|
||||
}
|
||||
|
||||
function bn128MultiplyCheck() public {
|
||||
bool success;
|
||||
uint256[3] memory input = [
|
||||
0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe3,
|
||||
0x1a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6,
|
||||
0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000
|
||||
];
|
||||
uint256[2] memory result;
|
||||
|
||||
assembly {
|
||||
// 0x07 id of the bn256Mul precompile
|
||||
// 0 number of ether to transfer
|
||||
// 96 size of call parameters, i.e. 128 bytes total
|
||||
// 64 size of return value, i.e. 64 bytes / 512 bit for a BN256 curve point
|
||||
success := call(not(0), 0x07, 0, input, 96, result, 64)
|
||||
}
|
||||
require(success, "elliptic curve addition failed");
|
||||
require(
|
||||
result[0] ==
|
||||
0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe3,
|
||||
"failed"
|
||||
);
|
||||
require(
|
||||
result[1] ==
|
||||
0x163511ddc1c3f25d396745388200081287b3fd1472d8339d5fecb2eae0830451,
|
||||
"failed"
|
||||
);
|
||||
}
|
||||
|
||||
function bn128PairingCheck() public {
|
||||
uint256[12] memory input = [
|
||||
0x2eca0c7238bf16e83e7a1e6c5d49540685ff51380f309842a98561558019fc02,
|
||||
0x03d3260361bb8451de5ff5ecd17f010ff22f5c31cdf184e9020b06fa5997db84,
|
||||
0x1213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee,
|
||||
0x2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f,
|
||||
0x21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237,
|
||||
0x096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f,
|
||||
0x06967a1237ebfeca9aaae0d6d0bab8e28c198c5a339ef8a2407e31cdac516db9,
|
||||
0x22160fa257a5fd5b280642ff47b65eca77e626cb685c84fa6d3b6882a283ddd1,
|
||||
0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2,
|
||||
0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed,
|
||||
0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b,
|
||||
0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa
|
||||
];
|
||||
uint256[1] memory result;
|
||||
bool success;
|
||||
assembly {
|
||||
// 0x08 id of the bn256CheckPairing precompile
|
||||
// 0 number of ether to transfer
|
||||
// 0 since we have an array of fixed length, our input starts in 0
|
||||
// 384 size of call parameters, i.e. 12*256 bits == 384 bytes
|
||||
// 32 size of result (one 32 byte boolean!)
|
||||
success := call(sub(gas(), 2000), 0x08, 0, input, 384, result, 32)
|
||||
}
|
||||
require(success, "elliptic curve pairing failed");
|
||||
require(result[0] == 1, "failed");
|
||||
}
|
||||
|
||||
function modExpWrapper(
|
||||
uint256 _b,
|
||||
uint256 _e,
|
||||
uint256 _m
|
||||
) public returns (uint256 result) {
|
||||
assembly {
|
||||
// Free memory pointer
|
||||
let pointer := mload(0x40)
|
||||
// Define length of base, exponent and modulus. 0x20 == 32 bytes
|
||||
mstore(pointer, 0x20)
|
||||
mstore(add(pointer, 0x20), 0x20)
|
||||
mstore(add(pointer, 0x40), 0x20)
|
||||
// Define variables base, exponent and modulus
|
||||
mstore(add(pointer, 0x60), _b)
|
||||
mstore(add(pointer, 0x80), _e)
|
||||
|
||||
mstore(add(pointer, 0xa0), _m)
|
||||
// Store the result
|
||||
let value := mload(0xc0)
|
||||
// Call the precompiled contract 0x05 = bigModExp
|
||||
if iszero(call(not(0), 0x05, 0, pointer, 0xc0, value, 0x20)) {
|
||||
revert(0, 0)
|
||||
}
|
||||
result := mload(value)
|
||||
}
|
||||
}
|
||||
|
||||
function modExpVerify(
|
||||
uint256 _base,
|
||||
uint256 _exponent,
|
||||
uint256 _modulus
|
||||
) public {
|
||||
lastResult = modExpWrapper(_base, _exponent, _modulus);
|
||||
}
|
||||
|
||||
function getResult() public view returns (uint256) {
|
||||
return lastResult;
|
||||
}
|
||||
|
||||
function modExpChecker() public {
|
||||
require(modExpWrapper(3, 5, 7) == 5);
|
||||
require(modExpWrapper(5, 7, 11) == 3);
|
||||
}
|
||||
|
||||
function blake2Wrapper(
|
||||
uint32 rounds,
|
||||
bytes32[2] memory h,
|
||||
bytes32[4] memory m,
|
||||
bytes8[2] memory t,
|
||||
bool f
|
||||
) public view returns (bytes32[2] memory) {
|
||||
bytes32[2] memory output;
|
||||
|
||||
bytes memory args = abi.encodePacked(
|
||||
rounds,
|
||||
h[0],
|
||||
h[1],
|
||||
m[0],
|
||||
m[1],
|
||||
m[2],
|
||||
m[3],
|
||||
t[0],
|
||||
t[1],
|
||||
f
|
||||
);
|
||||
|
||||
assembly {
|
||||
if iszero(
|
||||
staticcall(not(0), 0x09, add(args, 32), 0xd5, output, 0x40)
|
||||
) {
|
||||
revert(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
function blake2Check() public {
|
||||
uint32 rounds = 12;
|
||||
|
||||
bytes32[2] memory h;
|
||||
h[
|
||||
0
|
||||
] = hex"48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5";
|
||||
h[
|
||||
1
|
||||
] = hex"d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b";
|
||||
|
||||
bytes32[4] memory m;
|
||||
m[
|
||||
0
|
||||
] = hex"6162630000000000000000000000000000000000000000000000000000000000";
|
||||
m[
|
||||
1
|
||||
] = hex"0000000000000000000000000000000000000000000000000000000000000000";
|
||||
m[
|
||||
2
|
||||
] = hex"0000000000000000000000000000000000000000000000000000000000000000";
|
||||
m[
|
||||
3
|
||||
] = hex"0000000000000000000000000000000000000000000000000000000000000000";
|
||||
|
||||
bytes8[2] memory t;
|
||||
t[0] = hex"03000000";
|
||||
t[1] = hex"00000000";
|
||||
|
||||
bool f = true;
|
||||
|
||||
// Expected output:
|
||||
// ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1
|
||||
// 7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923
|
||||
|
||||
bytes32[2] memory result = blake2Wrapper(rounds, h, m, t, f);
|
||||
require(
|
||||
result[0] ==
|
||||
0xba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1,
|
||||
"failed"
|
||||
);
|
||||
require(
|
||||
result[1] ==
|
||||
0x7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923,
|
||||
"failed"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,11 +4,14 @@
|
|||
*/
|
||||
|
||||
import type { GenericContext } from "@moonwall/cli";
|
||||
import {
|
||||
ALITH_GENESIS_FREE_BALANCE,
|
||||
ALITH_GENESIS_LOCK_BALANCE,
|
||||
ALITH_GENESIS_RESERVE_BALANCE
|
||||
} from "@moonwall/util";
|
||||
|
||||
// DataHaven genesis balance constants
|
||||
// From operator/runtime/stagenet/src/genesis_config_presets.rs:
|
||||
// Each endowed account receives: 1u128 << 80
|
||||
// No locks or reserves are set at genesis
|
||||
export const ALITH_GENESIS_FREE_BALANCE = 1n << 80n; // 1208925819614629174706176n
|
||||
export const ALITH_GENESIS_LOCK_BALANCE = 0n;
|
||||
export const ALITH_GENESIS_RESERVE_BALANCE = 0n;
|
||||
|
||||
export const ALITH_GENESIS_TRANSFERABLE_COUNT =
|
||||
ALITH_GENESIS_FREE_BALANCE + ALITH_GENESIS_RESERVE_BALANCE - ALITH_GENESIS_LOCK_BALANCE;
|
||||
|
|
@ -35,6 +38,27 @@ class RuntimeConstant<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// Currency units for DataHaven stagenet
|
||||
// These match the runtime configuration in operator/runtime/stagenet/src/lib.rs
|
||||
export const HAVE = 1_000_000_000_000_000_000n; // 10^18
|
||||
export const MICROHAVE = 1_000_000_000_000n; // 10^12
|
||||
export const SUPPLY_FACTOR = 1n;
|
||||
export const STORAGE_BYTE_FEE = 100n * MICROHAVE * SUPPLY_FACTOR; // 100_000_000_000_000n
|
||||
|
||||
/**
|
||||
* Calculate deposit cost matching the runtime's deposit() function
|
||||
* deposit(items, bytes) = items * HAVE * SUPPLY_FACTOR + bytes * STORAGE_BYTE_FEE
|
||||
*/
|
||||
export function deposit(items: number, bytes: number): bigint {
|
||||
return BigInt(items) * HAVE * SUPPLY_FACTOR + BigInt(bytes) * STORAGE_BYTE_FEE;
|
||||
}
|
||||
|
||||
// Identity pallet deposit constants (stagenet)
|
||||
// Calculated from: operator/runtime/stagenet/src/configs/mod.rs
|
||||
export const IDENTITY_BASIC_DEPOSIT = deposit(1, 258); // 1_025_800_000_000_000_000n
|
||||
export const IDENTITY_BYTE_DEPOSIT = deposit(0, 1); // 100_000_000_000_000n
|
||||
export const IDENTITY_SUB_ACCOUNT_DEPOSIT = deposit(1, 53); // 1_005_300_000_000_000_000n
|
||||
|
||||
const DATAHAVEN_CONSTANTS = {
|
||||
BLOCK_WEIGHT_LIMIT: new RuntimeConstant({
|
||||
0: 2_000_000_000_000n
|
||||
|
|
@ -57,7 +81,8 @@ const DATAHAVEN_CONSTANTS = {
|
|||
CALL_PERMIT: "0x000000000000000000000000000000000000080a" as const,
|
||||
PROXY: "0x000000000000000000000000000000000000080b" as const,
|
||||
ERC20_BALANCES: "0x0000000000000000000000000000000000000802" as const,
|
||||
PRECOMPILE_REGISTRY: "0x0000000000000000000000000000000000000815" as const
|
||||
PRECOMPILE_REGISTRY: "0x0000000000000000000000000000000000000815" as const,
|
||||
IDENTITY: "0x0000000000000000000000000000000000000818" as const
|
||||
}
|
||||
} as const;
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
export * from "./block";
|
||||
export * from "./constants";
|
||||
export { PRECOMPILE_IDENTITY_ADDRESS, PRECOMPILE_PROXY_ADDRESS } from "./precompile-addresses";
|
||||
export * from "./contracts";
|
||||
// Export unique functions from eth-transactions that aren't in evm.ts
|
||||
export { extractRevertReason } from "./eth-transactions";
|
||||
|
|
@ -16,3 +17,5 @@ export * from "./expect";
|
|||
export * from "./fees";
|
||||
export * from "./parameters";
|
||||
export * from "./transactions";
|
||||
export * from "./modexp";
|
||||
export * from "./precompile-contract-calls";
|
||||
|
|
|
|||
97
test/moonwall/helpers/modexp.ts
Normal file
97
test/moonwall/helpers/modexp.ts
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/**
|
||||
* Test vectors for modular exponentiation precompile tests
|
||||
* Adapted from Moonbeam test helpers
|
||||
*/
|
||||
|
||||
export const testVectors = {
|
||||
"nagydani-1-square": {
|
||||
base: "e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5",
|
||||
exponent: "02",
|
||||
modulus:
|
||||
"fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b",
|
||||
},
|
||||
"nagydani-1-qube": {
|
||||
base: "e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5",
|
||||
exponent: "03",
|
||||
modulus:
|
||||
"fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b",
|
||||
},
|
||||
"nagydani-1-pow0x10001": {
|
||||
base: "e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5",
|
||||
exponent: "010001",
|
||||
modulus:
|
||||
"fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b",
|
||||
},
|
||||
"nagydani-2-square": {
|
||||
base: "cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51",
|
||||
exponent: "02",
|
||||
modulus:
|
||||
"e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087",
|
||||
},
|
||||
"nagydani-2-qube": {
|
||||
base: "cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51",
|
||||
exponent: "03",
|
||||
modulus:
|
||||
"e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087",
|
||||
},
|
||||
"nagydani-2-pow0x10001": {
|
||||
base: "cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51",
|
||||
exponent: "010001",
|
||||
modulus:
|
||||
"e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087",
|
||||
},
|
||||
"nagydani-3-square": {
|
||||
base: "c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb",
|
||||
exponent: "02",
|
||||
modulus:
|
||||
"d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d",
|
||||
},
|
||||
"nagydani-3-qube": {
|
||||
base: "c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb",
|
||||
exponent: "03",
|
||||
modulus:
|
||||
"d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d",
|
||||
},
|
||||
"nagydani-3-pow0x10001": {
|
||||
base: "c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb",
|
||||
exponent: "010001",
|
||||
modulus:
|
||||
"d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d",
|
||||
},
|
||||
"nagydani-4-square": {
|
||||
base: "db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81",
|
||||
exponent: "02",
|
||||
modulus:
|
||||
"df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f",
|
||||
},
|
||||
"nagydani-4-qube": {
|
||||
base: "db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81",
|
||||
exponent: "03",
|
||||
modulus:
|
||||
"df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f",
|
||||
},
|
||||
"nagydani-4-pow0x10001": {
|
||||
base: "db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81",
|
||||
exponent: "010001",
|
||||
modulus:
|
||||
"df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f",
|
||||
},
|
||||
"nagydani-5-square": {
|
||||
base: "c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf",
|
||||
exponent: "02",
|
||||
modulus:
|
||||
"e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad",
|
||||
},
|
||||
"nagydani-5-qube": {
|
||||
base: "c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf",
|
||||
exponent: "03",
|
||||
modulus:
|
||||
"e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad",
|
||||
},
|
||||
"nagydani-5-pow0x10001": {
|
||||
base: "c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf",
|
||||
exponent: "010001",
|
||||
modulus:
|
||||
"e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad",
|
||||
},
|
||||
} as const;
|
||||
17
test/moonwall/helpers/precompile-addresses.ts
Normal file
17
test/moonwall/helpers/precompile-addresses.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* Precompile addresses for DataHaven
|
||||
* These addresses match Moonbeam's precompile address scheme
|
||||
*/
|
||||
|
||||
export const PRECOMPILE_NATIVE_ERC20_ADDRESS = "0x0000000000000000000000000000000000000802" as const;
|
||||
export const PRECOMPILE_ERC20_BALANCES_ADDRESS = PRECOMPILE_NATIVE_ERC20_ADDRESS; // Alias
|
||||
export const PRECOMPILE_BATCH_ADDRESS = "0x0000000000000000000000000000000000000808" as const;
|
||||
export const PRECOMPILE_CALL_PERMIT_ADDRESS = "0x000000000000000000000000000000000000080a" as const;
|
||||
export const PRECOMPILE_PROXY_ADDRESS = "0x000000000000000000000000000000000000080b" as const;
|
||||
export const PRECOMPILE_TREASURY_COUNCIL_ADDRESS = "0x0000000000000000000000000000000000000810" as const;
|
||||
export const PRECOMPILE_REFERENDA_ADDRESS = "0x0000000000000000000000000000000000000811" as const;
|
||||
export const PRECOMPILE_CONVICTION_VOTING_ADDRESS = "0x0000000000000000000000000000000000000812" as const;
|
||||
export const PRECOMPILE_PREIMAGE_ADDRESS = "0x0000000000000000000000000000000000000813" as const;
|
||||
export const PRECOMPILE_TECHNICAL_COMMITTEE_ADDRESS = "0x0000000000000000000000000000000000000814" as const;
|
||||
export const PRECOMPILE_REGISTRY_ADDRESS = "0x0000000000000000000000000000000000000815" as const;
|
||||
export const PRECOMPILE_IDENTITY_ADDRESS = "0x0000000000000000000000000000000000000818" as const;
|
||||
136
test/moonwall/helpers/precompile-contract-calls.ts
Normal file
136
test/moonwall/helpers/precompile-contract-calls.ts
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
/**
|
||||
* Precompile contract call helpers
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import type { BlockCreation, DevModeContext, PrecompileCallOptions } from "@moonwall/cli";
|
||||
import type { KeyringPair } from "@moonwall/util";
|
||||
|
||||
class PrecompileContract {
|
||||
precompileName: string;
|
||||
context: DevModeContext;
|
||||
privateKey?: `0x${string}`;
|
||||
gas?: bigint | "estimate";
|
||||
rawTxOnly?: boolean;
|
||||
signer?: KeyringPair;
|
||||
expectEvents?: [any];
|
||||
|
||||
constructor(precompileName: string, context: DevModeContext) {
|
||||
this.precompileName = precompileName;
|
||||
this.context = context;
|
||||
this.reset();
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.privateKey = undefined;
|
||||
this.gas = undefined;
|
||||
this.rawTxOnly = true;
|
||||
this.signer = undefined;
|
||||
this.expectEvents = undefined;
|
||||
return this;
|
||||
}
|
||||
|
||||
withPrivateKey(privateKey: `0x${string}`) {
|
||||
this.privateKey = privateKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
withGas(gas: bigint | "estimate") {
|
||||
this.gas = gas;
|
||||
return this;
|
||||
}
|
||||
|
||||
withRawTxOnly(rawTxOnly: boolean) {
|
||||
if (rawTxOnly === false) {
|
||||
this.rawTxOnly = undefined;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
withSigner(signer: KeyringPair) {
|
||||
this.signer = signer;
|
||||
return this;
|
||||
}
|
||||
|
||||
withExpectEvents(expectEvents: [any]) {
|
||||
this.expectEvents = expectEvents;
|
||||
return this;
|
||||
}
|
||||
|
||||
callExtrinsic(functionName: string, args: any[]): PrecompileCall {
|
||||
return this.callRpc(functionName, args, true);
|
||||
}
|
||||
|
||||
callQuery(functionName: string, args: any[]): PrecompileCall {
|
||||
return this.callRpc(functionName, args, false);
|
||||
}
|
||||
|
||||
private callRpc(functionName: string, args: any[], isExtrinsic: boolean): PrecompileCall {
|
||||
const params = {
|
||||
precompileName: this.precompileName,
|
||||
functionName,
|
||||
args,
|
||||
privateKey: this.privateKey,
|
||||
rawTxOnly: this.rawTxOnly,
|
||||
gas: this.gas,
|
||||
};
|
||||
const blockCreationOptions = {
|
||||
signer: this.signer,
|
||||
expectEvents: this.expectEvents,
|
||||
};
|
||||
if (!isExtrinsic) {
|
||||
return new ReadPrecompileCall(params, this.context, blockCreationOptions);
|
||||
}
|
||||
return new WritePrecompileCall(params, this.context, blockCreationOptions);
|
||||
}
|
||||
}
|
||||
|
||||
export class PrecompileCall {
|
||||
params: PrecompileCallOptions;
|
||||
context: DevModeContext;
|
||||
blockCreationOptions: BlockCreation;
|
||||
|
||||
constructor(
|
||||
params: PrecompileCallOptions,
|
||||
context: DevModeContext,
|
||||
blockCreationOptions: BlockCreation
|
||||
) {
|
||||
this.params = params;
|
||||
this.context = context;
|
||||
this.blockCreationOptions = blockCreationOptions;
|
||||
}
|
||||
|
||||
async tx(): Promise<unknown> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
async block() {
|
||||
return await this.context.createBlock((await this.tx()) as any, this.blockCreationOptions);
|
||||
}
|
||||
}
|
||||
|
||||
class ReadPrecompileCall extends PrecompileCall {
|
||||
async tx(): Promise<unknown> {
|
||||
return await this.context.readPrecompile!(this.params);
|
||||
}
|
||||
}
|
||||
|
||||
class WritePrecompileCall extends PrecompileCall {
|
||||
async tx(): Promise<unknown> {
|
||||
return await this.context.writePrecompile!(this.params);
|
||||
}
|
||||
}
|
||||
|
||||
export class Preimage extends PrecompileContract {
|
||||
constructor(context: DevModeContext) {
|
||||
super("Preimage", context);
|
||||
}
|
||||
|
||||
notePreimage(data: string): PrecompileCall {
|
||||
return this.callExtrinsic("notePreimage", [data]);
|
||||
}
|
||||
|
||||
unnotePreimage(data: string): PrecompileCall {
|
||||
return this.callExtrinsic("unnotePreimage", [data]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/**
|
||||
* Existential deposit tests
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { expect, describeSuite, beforeEach, TransactionTypes } from "@moonwall/cli";
|
||||
import { ALITH_ADDRESS, baltathar, GLMR } from "@moonwall/util";
|
||||
import { createRawTransfer } from "@moonwall/util";
|
||||
import { Wallet } from "ethers";
|
||||
import { ConstantStore } from "../../../../helpers";
|
||||
|
||||
describeSuite({
|
||||
id: "D030203",
|
||||
title: "Existential Deposit",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, log, it }) => {
|
||||
let privateKey: `0x${string}`;
|
||||
let randomWeb3Account: any;
|
||||
let GENESIS_BASE_FEE: bigint;
|
||||
|
||||
beforeEach(async function () {
|
||||
const { specVersion } = await context.polkadotJs().consts.system.version;
|
||||
GENESIS_BASE_FEE = ConstantStore(context).GENESIS_BASE_FEE.get(specVersion.toNumber());
|
||||
|
||||
randomWeb3Account = context.web3().eth.accounts.create();
|
||||
privateKey = randomWeb3Account.privateKey;
|
||||
const { result } = await context.createBlock(
|
||||
context.polkadotJs().tx.balances.transferAllowDeath(randomWeb3Account.address, 10n * GLMR)
|
||||
);
|
||||
expect(result!.successful, result!.error?.name).to.be.true;
|
||||
});
|
||||
|
||||
for (const txnType of TransactionTypes) {
|
||||
it({
|
||||
id: `T0${TransactionTypes.indexOf(txnType) + 1}`,
|
||||
title: `full ${txnType} transfer should not reap on 0 account balance`,
|
||||
test: async function () {
|
||||
const raw = await createRawTransfer(
|
||||
context,
|
||||
ALITH_ADDRESS,
|
||||
10n * GLMR - 21000n * GENESIS_BASE_FEE,
|
||||
{
|
||||
privateKey,
|
||||
type: txnType,
|
||||
gasPrice: GENESIS_BASE_FEE,
|
||||
gas: 21000n,
|
||||
maxFeePerGas: GENESIS_BASE_FEE,
|
||||
}
|
||||
);
|
||||
const { result } = await context.createBlock(raw);
|
||||
|
||||
expect(
|
||||
await context.viem().getTransactionCount({ address: randomWeb3Account.address })
|
||||
).toBe(1);
|
||||
expect(result!.successful, result!.error?.name).toBe(true);
|
||||
expect(await context.viem().getBalance({ address: randomWeb3Account.address })).toBe(0n);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
it({
|
||||
id: "T04",
|
||||
title: "should not reap on tiny balance",
|
||||
test: async function () {
|
||||
const signer = new Wallet(privateKey, context.ethers().provider);
|
||||
await signer.sendTransaction({
|
||||
to: baltathar.address,
|
||||
value: 10n * GLMR - 21000n * GENESIS_BASE_FEE - 1n,
|
||||
gasPrice: GENESIS_BASE_FEE,
|
||||
gasLimit: 21000n,
|
||||
});
|
||||
|
||||
await context.createBlock();
|
||||
|
||||
expect(await context.viem().getBalance({ address: randomWeb3Account.address })).toBe(1n);
|
||||
expect(
|
||||
await context.viem().getTransactionCount({ address: randomWeb3Account.address })
|
||||
).toBe(1);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T05",
|
||||
title: "runtime constant should be set to zero",
|
||||
test: async function () {
|
||||
const existentialDeposit = context
|
||||
.polkadotJs()
|
||||
.consts.balances.existentialDeposit.toBigInt();
|
||||
expect(existentialDeposit).toBe(0n);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
* Balance extrinsics tests
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { TransactionTypes, beforeAll, beforeEach, describeSuite, expect } from "@moonwall/cli";
|
||||
import {
|
||||
ALITH_ADDRESS,
|
||||
BALTATHAR_ADDRESS,
|
||||
GLMR,
|
||||
createRawTransfer,
|
||||
mapExtrinsics,
|
||||
} from "@moonwall/util";
|
||||
import type { PrivateKeyAccount } from "viem";
|
||||
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
|
||||
|
||||
describeSuite({
|
||||
id: "D030204",
|
||||
title: "Balance - Extrinsic Events",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, log, it }) => {
|
||||
let randomAccount: PrivateKeyAccount;
|
||||
|
||||
beforeAll(async function () {
|
||||
// To create the treasury account
|
||||
await context.createBlock(createRawTransfer(context, BALTATHAR_ADDRESS, 1337));
|
||||
});
|
||||
|
||||
beforeEach(async function () {
|
||||
const privateKey = generatePrivateKey();
|
||||
randomAccount = privateKeyToAccount(privateKey);
|
||||
});
|
||||
|
||||
for (const txnType of TransactionTypes) {
|
||||
it({
|
||||
id: `T0${TransactionTypes.indexOf(txnType) + 1}`,
|
||||
title: `should emit events for ${txnType} ethereum/transfers`,
|
||||
test: async function () {
|
||||
await context.createBlock(
|
||||
createRawTransfer(context, randomAccount.address, 1n * GLMR, {
|
||||
type: txnType,
|
||||
gas: 500000n,
|
||||
})
|
||||
);
|
||||
|
||||
const signedBlock = await context.polkadotJs().rpc.chain.getBlock();
|
||||
const allRecords = await context.polkadotJs().query.system.events();
|
||||
const txsWithEvents = mapExtrinsics(signedBlock.block.extrinsics, allRecords);
|
||||
|
||||
const ethTx = txsWithEvents.find(
|
||||
({ extrinsic: { method } }) => method.section === "ethereum"
|
||||
)!;
|
||||
|
||||
// Check key events are present
|
||||
const hasNewAccount = ethTx.events.some((e) =>
|
||||
context.polkadotJs().events.system.NewAccount.is(e)
|
||||
);
|
||||
const hasEndowed = ethTx.events.some((e) =>
|
||||
context.polkadotJs().events.balances.Endowed.is(e)
|
||||
);
|
||||
const hasTransfer = ethTx.events.some((e) =>
|
||||
context.polkadotJs().events.balances.Transfer.is(e)
|
||||
);
|
||||
const hasExecuted = ethTx.events.some((e) =>
|
||||
context.polkadotJs().events.ethereum.Executed.is(e)
|
||||
);
|
||||
const hasSuccess = ethTx.events.some((e) =>
|
||||
context.polkadotJs().events.system.ExtrinsicSuccess.is(e)
|
||||
);
|
||||
|
||||
expect(hasNewAccount, "NewAccount event should be present").to.be.true;
|
||||
expect(hasEndowed, "Endowed event should be present").to.be.true;
|
||||
expect(hasTransfer, "Transfer event should be present").to.be.true;
|
||||
expect(hasExecuted, "Executed event should be present").to.be.true;
|
||||
expect(hasSuccess, "ExtrinsicSuccess event should be present").to.be.true;
|
||||
|
||||
// Verify transfer event data
|
||||
const transferEvent = ethTx.events.find((e) =>
|
||||
context.polkadotJs().events.balances.Transfer.is(e)
|
||||
)!;
|
||||
expect(transferEvent.data[0].toString()).to.eq(ALITH_ADDRESS);
|
||||
expect(transferEvent.data[1].toString()).to.eq(randomAccount.address);
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
import "@moonbeam-network/api-augment";
|
||||
import { expect, describeSuite } from "@moonwall/cli";
|
||||
import { ALITH_ADDRESS } from "@moonwall/util";
|
||||
import {
|
||||
ALITH_GENESIS_FREE_BALANCE,
|
||||
ALITH_GENESIS_RESERVE_BALANCE,
|
||||
ALITH_GENESIS_TRANSFERABLE_BALANCE,
|
||||
} from "../../../../helpers";
|
||||
|
||||
describeSuite({
|
||||
id: "D030201",
|
||||
title: "Balance genesis",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, it }) => {
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should be accessible through web3",
|
||||
test: async function () {
|
||||
expect(await context.viem().getBalance({ address: ALITH_ADDRESS })).toBe(
|
||||
ALITH_GENESIS_TRANSFERABLE_BALANCE
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T02",
|
||||
title: "should be accessible through polkadotJs",
|
||||
test: async function () {
|
||||
const genesisHash = await context.polkadotJs().rpc.chain.getBlockHash(0);
|
||||
const account = await (await context.polkadotJs().at(genesisHash)).query.system.account(
|
||||
ALITH_ADDRESS
|
||||
);
|
||||
expect(account.data.free.toBigInt()).toBe(ALITH_GENESIS_FREE_BALANCE);
|
||||
expect(account.data.reserved.toBigInt()).toBe(ALITH_GENESIS_RESERVE_BALANCE);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,242 @@
|
|||
import "@moonbeam-network/api-augment";
|
||||
import { beforeEach, describeSuite, expect } from "@moonwall/cli";
|
||||
import {
|
||||
ALITH_ADDRESS,
|
||||
CHARLETH_ADDRESS,
|
||||
BALTATHAR_ADDRESS,
|
||||
BALTATHAR_PRIVATE_KEY,
|
||||
CHARLETH_PRIVATE_KEY,
|
||||
FAITH_PRIVATE_KEY,
|
||||
GLMR,
|
||||
checkBalance,
|
||||
createViemTransaction,
|
||||
createRawTransfer,
|
||||
generateKeyringPair,
|
||||
sendRawTransaction,
|
||||
} from "@moonwall/util";
|
||||
import {
|
||||
ALITH_GENESIS_TRANSFERABLE_BALANCE,
|
||||
ConstantStore,
|
||||
verifyLatestBlockFees,
|
||||
} from "../../../../helpers";
|
||||
|
||||
import { parseGwei } from "viem";
|
||||
|
||||
describeSuite({
|
||||
id: "D030202",
|
||||
title: "Balance Transfers",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, log, it }) => {
|
||||
let randomAddress: `0x${string}`;
|
||||
let GENESIS_BASE_FEE;
|
||||
|
||||
beforeEach(async function () {
|
||||
const randomAccount = generateKeyringPair();
|
||||
randomAddress = randomAccount.address as `0x${string}`;
|
||||
const { specVersion } = await context.polkadotJs().consts.system.version;
|
||||
GENESIS_BASE_FEE = ConstantStore(context).GENESIS_BASE_FEE.get(specVersion.toNumber());
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should cost 21000 gas for a transfer",
|
||||
test: async function () {
|
||||
const estimatedGas = await context.viem().estimateGas({
|
||||
account: ALITH_ADDRESS,
|
||||
value: 0n * GLMR,
|
||||
to: randomAddress,
|
||||
});
|
||||
expect(estimatedGas, "Estimated bal transfer incorrect").toBe(21000n);
|
||||
|
||||
await context.createBlock(createRawTransfer(context, randomAddress, 0n));
|
||||
expect(await context.viem().getBalance({ address: ALITH_ADDRESS })).toBe(
|
||||
ALITH_GENESIS_TRANSFERABLE_BALANCE - 21000n * GENESIS_BASE_FEE
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T02",
|
||||
title: "unsent txns should be in pending",
|
||||
test: async function () {
|
||||
await context.createBlock();
|
||||
const rawTx = (await createRawTransfer(context, randomAddress, 512n, {
|
||||
privateKey: CHARLETH_PRIVATE_KEY,
|
||||
gasPrice: GENESIS_BASE_FEE,
|
||||
gas: 21000n,
|
||||
txnType: "legacy",
|
||||
})) as `0x${string}`;
|
||||
await sendRawTransaction(context, rawTx);
|
||||
|
||||
expect(
|
||||
await context.viem().getBalance({ address: randomAddress, blockTag: "pending" })
|
||||
).toBe(512n);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T03",
|
||||
title: "should decrease from account",
|
||||
test: async function () {
|
||||
const balanceBefore = await context.viem().getBalance({ address: CHARLETH_ADDRESS });
|
||||
const fees = 21000n * GENESIS_BASE_FEE;
|
||||
await context.createBlock(
|
||||
await createRawTransfer(context, randomAddress, 512n, {
|
||||
gas: 21000n,
|
||||
gasPrice: GENESIS_BASE_FEE,
|
||||
txnType: "legacy",
|
||||
privateKey: CHARLETH_PRIVATE_KEY,
|
||||
})
|
||||
);
|
||||
const balanceAfter = await context.viem().getBalance({ address: CHARLETH_ADDRESS });
|
||||
expect(balanceBefore - balanceAfter - fees).toBe(512n);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T04",
|
||||
title: "should increase to account",
|
||||
test: async function () {
|
||||
const balanceBefore = await checkBalance(context, randomAddress);
|
||||
|
||||
await context.createBlock(
|
||||
await createRawTransfer(context, randomAddress, 512n, {
|
||||
gas: 21000n,
|
||||
gasPrice: GENESIS_BASE_FEE,
|
||||
type: "legacy",
|
||||
})
|
||||
);
|
||||
const balanceAfter = await checkBalance(context, randomAddress);
|
||||
expect(balanceBefore).toBe(0n);
|
||||
expect(balanceAfter).toBe(512n);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T05",
|
||||
title: "should reflect balance identically on polkadot/web3",
|
||||
test: async function () {
|
||||
await context.createBlock(
|
||||
await createRawTransfer(context, randomAddress, 512n, {
|
||||
gas: 21000n,
|
||||
gasPrice: GENESIS_BASE_FEE,
|
||||
type: "legacy",
|
||||
})
|
||||
);
|
||||
|
||||
const blockNumber = (
|
||||
await context.polkadotJs().rpc.chain.getBlock()
|
||||
).block.header.number.toBigInt();
|
||||
|
||||
const block1Hash = await context.polkadotJs().rpc.chain.getBlockHash(blockNumber);
|
||||
const balance = await (await context.polkadotJs().at(block1Hash)).query.system.account(
|
||||
ALITH_ADDRESS
|
||||
);
|
||||
|
||||
expect(await context.viem().getBalance({ blockNumber, address: ALITH_ADDRESS })).to.equal(
|
||||
balance.data.free.toBigInt() +
|
||||
balance.data.reserved.toBigInt() -
|
||||
balance.data.frozen.toBigInt()
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T06",
|
||||
title: "should check latest block fees",
|
||||
test: async function () {
|
||||
await context.createBlock(
|
||||
await createRawTransfer(context, randomAddress, 512n, {
|
||||
gas: 21000n,
|
||||
gasPrice: GENESIS_BASE_FEE,
|
||||
type: "legacy",
|
||||
})
|
||||
);
|
||||
|
||||
await verifyLatestBlockFees(context, BigInt(512));
|
||||
},
|
||||
});
|
||||
|
||||
// NOTE: Uses FAITH_PRIVATE_KEY (aka Frank in DataHaven) instead of GERALD_PRIVATE_KEY
|
||||
// because Gerald is not endowed at genesis in DataHaven (unlike Moonbeam).
|
||||
it({
|
||||
id: "T07",
|
||||
title: "multiple transfer should be successful",
|
||||
test: async function () {
|
||||
const { result } = await context.createBlock([
|
||||
await createRawTransfer(context, randomAddress, 10n * GLMR, {
|
||||
privateKey: FAITH_PRIVATE_KEY,
|
||||
nonce: 0,
|
||||
}),
|
||||
await createRawTransfer(context, randomAddress, 10n * GLMR, {
|
||||
privateKey: FAITH_PRIVATE_KEY,
|
||||
nonce: 1,
|
||||
}),
|
||||
await createRawTransfer(context, randomAddress, 10n * GLMR, {
|
||||
privateKey: FAITH_PRIVATE_KEY,
|
||||
nonce: 2,
|
||||
}),
|
||||
await createRawTransfer(context, randomAddress, 10n * GLMR, {
|
||||
privateKey: FAITH_PRIVATE_KEY,
|
||||
nonce: 3,
|
||||
}),
|
||||
await createRawTransfer(context, randomAddress, 10n * GLMR, {
|
||||
privateKey: FAITH_PRIVATE_KEY,
|
||||
nonce: 4,
|
||||
}),
|
||||
]);
|
||||
|
||||
expect((result as any).filter((r: any) => r.successful)).to.be.length(5);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T08",
|
||||
title: "should handle max_fee_per_gas",
|
||||
test: async function () {
|
||||
const balanceBefore = await checkBalance(context, CHARLETH_ADDRESS);
|
||||
await context.createBlock(
|
||||
await createRawTransfer(context, randomAddress, 1n * GLMR, {
|
||||
gas: 21000n,
|
||||
maxFeePerGas: GENESIS_BASE_FEE,
|
||||
maxPriorityFeePerGas: parseGwei("0.2"),
|
||||
gasPrice: GENESIS_BASE_FEE,
|
||||
type: "eip1559",
|
||||
privateKey: CHARLETH_PRIVATE_KEY,
|
||||
})
|
||||
);
|
||||
const balanceAfter = await checkBalance(context, CHARLETH_ADDRESS);
|
||||
const fee = 21000n * GENESIS_BASE_FEE;
|
||||
|
||||
expect(balanceAfter + fee + 1n * GLMR).toBe(balanceBefore);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T09",
|
||||
title: "should use partial max_priority_fee_per_gas",
|
||||
test: async function () {
|
||||
// With this configuration only half of the priority fee will be used,
|
||||
// as the max_fee_per_gas is 2GWEI and the base fee is 1GWEI.
|
||||
const accountData = (await context.polkadotJs().query.system.account(BALTATHAR_ADDRESS))
|
||||
.data;
|
||||
const freeBal = accountData.free.toBigInt() - accountData.reserved.toBigInt();
|
||||
const maxFeePerGas = 10_000_000_000n * 2n;
|
||||
await context.createBlock(
|
||||
await createViemTransaction(context, {
|
||||
privateKey: BALTATHAR_PRIVATE_KEY,
|
||||
gas: 21000n,
|
||||
to: randomAddress,
|
||||
data: "0x",
|
||||
maxFeePerGas,
|
||||
maxPriorityFeePerGas: maxFeePerGas,
|
||||
type: "eip1559",
|
||||
})
|
||||
);
|
||||
const balanceAfter = await checkBalance(context, BALTATHAR_ADDRESS);
|
||||
const fee = 21_000n * maxFeePerGas;
|
||||
expect(freeBal - balanceAfter - fee).toBe(0n);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* Blake2 precompile tests
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { deployCreateCompiledContract, describeSuite } from "@moonwall/cli";
|
||||
import { expectEVMResult } from "../../../../helpers";
|
||||
|
||||
import { createViemTransaction } from "@moonwall/util";
|
||||
import { encodeFunctionData } from "viem";
|
||||
|
||||
describeSuite({
|
||||
id: "D030101",
|
||||
title: "Precompiles - blake2",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, log, it }) => {
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should be accessible from a smart contract",
|
||||
test: async function () {
|
||||
const { abi } = await deployCreateCompiledContract(context, "HasherChecker");
|
||||
|
||||
// Execute the contract blake2 call
|
||||
const { result } = await context.createBlock(
|
||||
createViemTransaction(context, {
|
||||
data: encodeFunctionData({
|
||||
abi,
|
||||
functionName: "blake2Check",
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
expectEVMResult(result!.events, "Succeed");
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* BN128 addition precompile tests
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { deployCreateCompiledContract, describeSuite } from "@moonwall/cli";
|
||||
import { createViemTransaction } from "@moonwall/util";
|
||||
import { encodeFunctionData } from "viem";
|
||||
import { expectEVMResult } from "../../../../helpers";
|
||||
|
||||
describeSuite({
|
||||
id: "D030102",
|
||||
title: "Precompiles - bn128add",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, it, log }) => {
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should be accessible from a smart contract",
|
||||
test: async function () {
|
||||
const { abi, contractAddress } = await deployCreateCompiledContract(
|
||||
context,
|
||||
"HasherChecker"
|
||||
);
|
||||
|
||||
const { result } = await context.createBlock(
|
||||
createViemTransaction(context, {
|
||||
to: contractAddress,
|
||||
data: encodeFunctionData({
|
||||
abi,
|
||||
functionName: "bn128AdditionCheck",
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
expectEVMResult(result!.events, "Succeed");
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* BN128 multiplication precompile tests
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { deployCreateCompiledContract, describeSuite } from "@moonwall/cli";
|
||||
import { createViemTransaction } from "@moonwall/util";
|
||||
import { encodeFunctionData } from "viem";
|
||||
import { expectEVMResult } from "../../../../helpers";
|
||||
|
||||
describeSuite({
|
||||
id: "D030103",
|
||||
title: "Precompiles - bn128mul",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, it, log }) => {
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should be accessible from a smart contract",
|
||||
test: async function () {
|
||||
const { abi, contractAddress } = await deployCreateCompiledContract(
|
||||
context,
|
||||
"HasherChecker"
|
||||
);
|
||||
|
||||
const { result } = await context.createBlock(
|
||||
createViemTransaction(context, {
|
||||
to: contractAddress,
|
||||
data: encodeFunctionData({
|
||||
abi,
|
||||
functionName: "bn128MultiplyCheck",
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
expectEVMResult(result!.events, "Succeed");
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* BN128 pairing precompile tests
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { deployCreateCompiledContract, describeSuite } from "@moonwall/cli";
|
||||
import { createViemTransaction } from "@moonwall/util";
|
||||
import { encodeFunctionData } from "viem";
|
||||
import { expectEVMResult } from "../../../../helpers";
|
||||
|
||||
describeSuite({
|
||||
id: "D030104",
|
||||
title: "Precompiles - bn128pairing",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, it, log }) => {
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should be accessible from a smart contract",
|
||||
test: async function () {
|
||||
const { abi, contractAddress } = await deployCreateCompiledContract(
|
||||
context,
|
||||
"HasherChecker"
|
||||
);
|
||||
|
||||
const { result } = await context.createBlock(
|
||||
createViemTransaction(context, {
|
||||
to: contractAddress,
|
||||
data: encodeFunctionData({
|
||||
abi,
|
||||
functionName: "bn128PairingCheck",
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
expectEVMResult(result!.events, "Succeed");
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
* Ecrecover precompile tests
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { beforeAll, describeSuite, expect } from "@moonwall/cli";
|
||||
import { ALITH_ADDRESS, ALITH_PRIVATE_KEY } from "@moonwall/util";
|
||||
|
||||
describeSuite({
|
||||
id: "D030107",
|
||||
title: "Precompiles - ecrecover",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, log, it }) => {
|
||||
let contractAddress: `0x${string}`;
|
||||
|
||||
beforeAll(async function () {
|
||||
const { contractAddress: deployedAddr } = await context.deployContract!("RecoveryChecker");
|
||||
contractAddress = deployedAddr;
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "returns a matching address",
|
||||
test: async function () {
|
||||
const msg = context.web3().utils.sha3("Hello World!");
|
||||
const sig = context.web3().eth.accounts.sign(msg!, ALITH_PRIVATE_KEY);
|
||||
|
||||
const address = await context.readContract!({
|
||||
contractAddress,
|
||||
contractName: "RecoveryChecker",
|
||||
functionName: "checkRecovery",
|
||||
args: [sig.messageHash, sig.v, sig.r, sig.s],
|
||||
});
|
||||
|
||||
expect(address, "Recovered address doesn't match signer!").to.equals(ALITH_ADDRESS);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T02",
|
||||
title: "returns different address on modified message",
|
||||
test: async function () {
|
||||
const msg = context.web3().utils.sha3("Hello World!");
|
||||
const sig = context.web3().eth.accounts.sign(msg!, ALITH_PRIVATE_KEY);
|
||||
|
||||
const address = await context.readContract!({
|
||||
contractAddress,
|
||||
contractName: "RecoveryChecker",
|
||||
functionName: "checkRecovery",
|
||||
args: [sig.messageHash.replace("1", "f"), sig.v, sig.r, sig.s],
|
||||
});
|
||||
|
||||
expect(address, "Recovered address doesn't match signer!").to.equals(
|
||||
"0x58188b9AE77F7C865b04B12F5D29bF4fbDcbd937"
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T03",
|
||||
title: "returns empty on invalid V",
|
||||
test: async function () {
|
||||
const msg = context.web3().utils.sha3("Hello World!");
|
||||
const sig = context.web3().eth.accounts.sign(msg!, ALITH_PRIVATE_KEY);
|
||||
const v = "0x565656ff5656ffffffffffff3d3d02000000000040003dffff565656560f0000";
|
||||
|
||||
await expect(
|
||||
async () =>
|
||||
await context.readContract!({
|
||||
contractAddress,
|
||||
contractName: "RecoveryChecker",
|
||||
functionName: "checkRecovery",
|
||||
args: [sig.messageHash, v, sig.r, sig.s],
|
||||
web3Library: "ethers",
|
||||
gas: 1_000_000n,
|
||||
})
|
||||
).rejects.toThrowError("revert");
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
import "@moonbeam-network/api-augment";
|
||||
import { describeSuite, expect } from "@moonwall/cli";
|
||||
import { generateKeyringPair } from "@moonwall/util";
|
||||
|
||||
describeSuite({
|
||||
id: "D030402",
|
||||
title: "Precompile ERC20 - Transfering through precompile",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, it, log }) => {
|
||||
const randomAccount = generateKeyringPair();
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should not allow overflowing the value",
|
||||
test: async function () {
|
||||
await expect(
|
||||
async () =>
|
||||
await context.writePrecompile!({
|
||||
precompileName: "Batch",
|
||||
functionName: "batchAll",
|
||||
args: [
|
||||
[randomAccount.address],
|
||||
[`${(2n ** 128n + 5_000_000_000_000_000_000n).toString()}`],
|
||||
[],
|
||||
[],
|
||||
],
|
||||
})
|
||||
).rejects.toThrowError("evm error: OutOfFund");
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,291 @@
|
|||
import "@moonbeam-network/api-augment";
|
||||
import { beforeEach, describeSuite, expect } from "@moonwall/cli";
|
||||
import {
|
||||
ALITH_ADDRESS,
|
||||
BALTATHAR_ADDRESS,
|
||||
BALTATHAR_PRIVATE_KEY,
|
||||
CHARLETH_ADDRESS,
|
||||
PRECOMPILE_NATIVE_ERC20_ADDRESS,
|
||||
baltathar,
|
||||
} from "@moonwall/util";
|
||||
import { type PrivateKeyAccount, keccak256, pad, parseEther, toBytes, toHex } from "viem";
|
||||
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
|
||||
import { ALITH_GENESIS_TRANSFERABLE_BALANCE } from "../../../../helpers";
|
||||
|
||||
// const SELECTORS = {
|
||||
// balanceOf: "70a08231",
|
||||
// totalSupply: "18160ddd",
|
||||
// approve: "095ea7b3",
|
||||
// allowance: "dd62ed3e",
|
||||
// transfer: "a9059cbb",
|
||||
// transferFrom: "23b872dd",
|
||||
// deposit: "d0e30db0",
|
||||
// logApprove: "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925",
|
||||
// logTransfer: "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
|
||||
// };
|
||||
|
||||
// Error(string)
|
||||
const ABI_REVERT_SELECTOR = "0x08c379a0";
|
||||
|
||||
describeSuite({
|
||||
id: "D030401",
|
||||
title: "Precompiles - ERC20 Native",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, it, log }) => {
|
||||
let randomAccount: PrivateKeyAccount;
|
||||
|
||||
beforeEach(async () => {
|
||||
randomAccount = privateKeyToAccount(generatePrivateKey());
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "allows to call getBalance",
|
||||
test: async function () {
|
||||
const balance = await context.readPrecompile!({
|
||||
precompileName: "NativeErc20",
|
||||
functionName: "balanceOf",
|
||||
args: [ALITH_ADDRESS],
|
||||
});
|
||||
|
||||
const signedTx = context
|
||||
.polkadotJs()
|
||||
.tx.balances.transferAllowDeath(CHARLETH_ADDRESS, 1000)
|
||||
.signAsync(baltathar);
|
||||
await context.createBlock(signedTx);
|
||||
|
||||
const tx = context.polkadotJs().tx.balances.transferAllowDeath(CHARLETH_ADDRESS, 1000);
|
||||
await context.createBlock(tx, {
|
||||
signer: { privateKey: BALTATHAR_PRIVATE_KEY, type: "ethereum" },
|
||||
});
|
||||
|
||||
expect(balance).equals(ALITH_GENESIS_TRANSFERABLE_BALANCE);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T02",
|
||||
title: "allows to call totalSupply",
|
||||
test: async function () {
|
||||
const totalSupply = await context.readPrecompile!({
|
||||
precompileName: "NativeErc20",
|
||||
functionName: "totalSupply",
|
||||
});
|
||||
|
||||
const totalIssuance = (
|
||||
await context.polkadotJs().query.balances.totalIssuance()
|
||||
).toBigInt();
|
||||
expect(totalSupply).toBe(totalIssuance);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T03",
|
||||
title: "allows to approve transfers, and allowance matches",
|
||||
test: async function () {
|
||||
const allowanceBefore = (await context.readPrecompile!({
|
||||
precompileName: "NativeErc20",
|
||||
functionName: "allowance",
|
||||
args: [ALITH_ADDRESS, BALTATHAR_ADDRESS],
|
||||
})) as bigint;
|
||||
const amount = parseEther("10");
|
||||
|
||||
const rawTx = await context.writePrecompile!({
|
||||
precompileName: "NativeErc20",
|
||||
functionName: "approve",
|
||||
args: [BALTATHAR_ADDRESS, amount],
|
||||
rawTxOnly: true,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTx);
|
||||
|
||||
const allowanceAfter = (await context.readPrecompile!({
|
||||
precompileName: "NativeErc20",
|
||||
functionName: "allowance",
|
||||
args: [ALITH_ADDRESS, BALTATHAR_ADDRESS],
|
||||
})) as bigint;
|
||||
|
||||
expect(allowanceAfter - allowanceBefore).equals(BigInt(amount));
|
||||
|
||||
const { status, logs } = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result?.hash as `0x${string}` });
|
||||
|
||||
expect(status).to.equal("success");
|
||||
expect(logs.length).to.eq(1);
|
||||
expect(logs[0].topics[0]).toBe(keccak256(toBytes("Approval(address,address,uint256)")));
|
||||
expect(logs[0].topics[1]?.toLowerCase()).toBe(
|
||||
pad(ALITH_ADDRESS.toLowerCase() as `0x${string}`)
|
||||
);
|
||||
expect(logs[0].topics[2]?.toLowerCase()).toBe(
|
||||
pad(BALTATHAR_ADDRESS.toLowerCase() as `0x${string}`)
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T04",
|
||||
title: "allows to call transfer",
|
||||
test: async function () {
|
||||
expect(
|
||||
await context.readPrecompile!({
|
||||
precompileName: "NativeErc20",
|
||||
functionName: "balanceOf",
|
||||
args: [randomAccount.address],
|
||||
})
|
||||
).equals(0n);
|
||||
|
||||
const balanceBefore = await context.viem().getBalance({ address: BALTATHAR_ADDRESS });
|
||||
|
||||
const rawTx = await context.writePrecompile!({
|
||||
precompileName: "NativeErc20",
|
||||
functionName: "transfer",
|
||||
args: [randomAccount.address, parseEther("3")],
|
||||
privateKey: BALTATHAR_PRIVATE_KEY,
|
||||
rawTxOnly: true,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTx);
|
||||
const { status, gasUsed } = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result?.hash as `0x${string}` });
|
||||
expect(status).to.equal("success");
|
||||
|
||||
const balanceAfter = await context.viem().getBalance({ address: BALTATHAR_ADDRESS });
|
||||
const block = await context.viem().getBlock();
|
||||
const fees = gasUsed * block.baseFeePerGas!;
|
||||
expect(balanceAfter).toBeLessThanOrEqual(balanceBefore - parseEther("3") - fees);
|
||||
expect(await context.viem().getBalance({ address: randomAccount.address })).to.equal(
|
||||
parseEther("3")
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T05",
|
||||
title: "allows to approve transfer and use transferFrom",
|
||||
test: async function () {
|
||||
const allowedAmount = parseEther("10");
|
||||
const transferAmount = parseEther("5");
|
||||
|
||||
await context.writePrecompile!({
|
||||
precompileName: "NativeErc20",
|
||||
functionName: "approve",
|
||||
args: [BALTATHAR_ADDRESS, allowedAmount],
|
||||
});
|
||||
await context.createBlock();
|
||||
|
||||
const fromBalBefore = (
|
||||
await context.polkadotJs().query.system.account(ALITH_ADDRESS)
|
||||
).data.free.toBigInt();
|
||||
const toBalBefore = await context.viem().getBalance({ address: CHARLETH_ADDRESS });
|
||||
|
||||
const rawTx = await context.writePrecompile!({
|
||||
precompileName: "NativeErc20",
|
||||
functionName: "transferFrom",
|
||||
args: [ALITH_ADDRESS, CHARLETH_ADDRESS, transferAmount],
|
||||
privateKey: BALTATHAR_PRIVATE_KEY,
|
||||
rawTxOnly: true,
|
||||
});
|
||||
|
||||
const { result } = await context.createBlock(rawTx);
|
||||
const { logs, status } = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result?.hash as `0x${string}` });
|
||||
|
||||
const fromBalAfter = (
|
||||
await context.polkadotJs().query.system.account(ALITH_ADDRESS)
|
||||
).data.free.toBigInt();
|
||||
|
||||
const toBalAfter = await context.viem().getBalance({ address: CHARLETH_ADDRESS });
|
||||
expect(logs.length).to.eq(1);
|
||||
expect(logs[0].address).to.eq(PRECOMPILE_NATIVE_ERC20_ADDRESS);
|
||||
expect(logs[0].data).to.eq(pad(toHex(transferAmount)));
|
||||
expect(logs[0].topics.length).to.eq(3);
|
||||
expect(logs[0].topics[0]).toBe(keccak256(toBytes("Transfer(address,address,uint256)")));
|
||||
expect(logs[0].topics[1]?.toLowerCase()).toBe(
|
||||
pad(ALITH_ADDRESS.toLowerCase() as `0x${string}`)
|
||||
);
|
||||
expect(logs[0].topics[2]?.toLowerCase()).toBe(
|
||||
pad(CHARLETH_ADDRESS.toLowerCase() as `0x${string}`)
|
||||
);
|
||||
expect(status).to.equal("success");
|
||||
expect(toBalAfter).toBe(toBalBefore + transferAmount);
|
||||
expect(fromBalAfter).toBe(fromBalBefore - transferAmount);
|
||||
const newAllowedAmount = allowedAmount - transferAmount;
|
||||
expect(
|
||||
await context.readPrecompile!({
|
||||
precompileName: "NativeErc20",
|
||||
functionName: "allowance",
|
||||
args: [ALITH_ADDRESS, BALTATHAR_ADDRESS],
|
||||
})
|
||||
).toBe(newAllowedAmount);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T06",
|
||||
title: "refuses to transferFrom more than allowed",
|
||||
test: async function () {
|
||||
const allowedAmount = parseEther("10");
|
||||
const transferAmount = parseEther("15");
|
||||
|
||||
await context.writePrecompile!({
|
||||
precompileName: "NativeErc20",
|
||||
functionName: "approve",
|
||||
args: [BALTATHAR_ADDRESS, allowedAmount],
|
||||
});
|
||||
await context.createBlock();
|
||||
|
||||
const fromBalBefore = (
|
||||
await context.polkadotJs().query.system.account(ALITH_ADDRESS)
|
||||
).data.free.toBigInt();
|
||||
const toBalBefore = await context.viem().getBalance({ address: CHARLETH_ADDRESS });
|
||||
|
||||
const rawTxn = await context.writePrecompile!({
|
||||
precompileName: "NativeErc20",
|
||||
functionName: "transferFrom",
|
||||
args: [ALITH_ADDRESS, CHARLETH_ADDRESS, transferAmount],
|
||||
privateKey: BALTATHAR_PRIVATE_KEY,
|
||||
rawTxOnly: true,
|
||||
gas: 200_000n,
|
||||
web3Library: "ethers",
|
||||
});
|
||||
|
||||
const { result } = await context.createBlock(rawTxn);
|
||||
expect(result?.successful).toBe(false);
|
||||
|
||||
const fromBalAfter = (
|
||||
await context.polkadotJs().query.system.account(ALITH_ADDRESS)
|
||||
).data.free.toBigInt();
|
||||
|
||||
const toBalAfter = await context.viem().getBalance({ address: CHARLETH_ADDRESS });
|
||||
expect(toBalAfter).toBe(toBalBefore);
|
||||
expect(fromBalAfter).toBe(fromBalBefore);
|
||||
expect(
|
||||
await context.readPrecompile!({
|
||||
precompileName: "NativeErc20",
|
||||
functionName: "allowance",
|
||||
args: [ALITH_ADDRESS, BALTATHAR_ADDRESS],
|
||||
})
|
||||
).toBe(allowedAmount);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// describeDevMoonbeamAllEthTxTypes("Precompiles - ERC20 Native", (context) => {
|
||||
// it("revert message is abi-encoded as a String(error) call", async function () {
|
||||
// const request = await web3EthCall(context.web3, {
|
||||
// to: PRECOMPILE_NATIVE_ERC20_ADDRESS,
|
||||
// data: `0x${SELECTORS.deposit}`,
|
||||
// });
|
||||
// expect(request as any).to.haveOwnProperty("error");
|
||||
// // Data
|
||||
// let data = (request as any).error.data;
|
||||
// expect(data.length).to.be.eq(266);
|
||||
// expect(data.slice(0, 10)).to.be.eq(ABI_REVERT_SELECTOR);
|
||||
// // Message
|
||||
// expect((request as any).error.message).to.be.eq(
|
||||
// "VM Exception while processing transaction: revert deposited amount must be non-zero"
|
||||
// );
|
||||
// });
|
||||
// });
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
/**
|
||||
* Identity precompile tests - retrieve registrars and identity
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { beforeAll, describeSuite, expect } from "@moonwall/cli";
|
||||
import { alith, baltathar } from "@moonwall/util";
|
||||
import { toHex } from "viem";
|
||||
import { PRECOMPILE_IDENTITY_ADDRESS } from "../../../../helpers";
|
||||
|
||||
describeSuite({
|
||||
id: "D030301",
|
||||
title: "Precompiles - Identity precompile",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ it, log, context }) => {
|
||||
beforeAll(async function () {
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.sudo.sudo(context.polkadotJs().tx.identity.addRegistrar(alith.address))
|
||||
);
|
||||
|
||||
await context.createBlock(context.polkadotJs().tx.identity.setFee(0, 100));
|
||||
await context.createBlock(
|
||||
// With 0b111 we are indicating the pallet to use "Display", "Legal" and "Web" fields.
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.identity.setFields(0, 0b111 as any)
|
||||
);
|
||||
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.identity.setIdentity({
|
||||
additional: [[{ raw: "discord" }, { raw: "my-discord" }]],
|
||||
display: { raw: "display" },
|
||||
legal: { raw: "legal" },
|
||||
web: { raw: "web" },
|
||||
riot: { raw: "riot" },
|
||||
email: { raw: "email" },
|
||||
pgpFingerprint: new Array(20).fill(1),
|
||||
image: { raw: "image" },
|
||||
twitter: { raw: "twitter" },
|
||||
})
|
||||
.signAsync(baltathar)
|
||||
);
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should retrieve registrars",
|
||||
test: async function () {
|
||||
const registrars = (await context.readContract!({
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
contractName: "Identity",
|
||||
functionName: "registrars",
|
||||
args: [],
|
||||
})) as any;
|
||||
|
||||
expect(registrars.length).to.equal(1);
|
||||
expect(registrars[0].isValid).to.be.true;
|
||||
expect(registrars[0].index).to.equal(0);
|
||||
expect(registrars[0].account).to.equal(alith.address);
|
||||
expect(registrars[0].fee).to.equal(100n);
|
||||
expect(registrars[0].fields.display).to.be.true;
|
||||
expect(registrars[0].fields.web).to.be.true;
|
||||
expect(registrars[0].fields.legal).to.be.true;
|
||||
expect(registrars[0].fields.riot).to.be.false;
|
||||
expect(registrars[0].fields.email).to.be.false;
|
||||
expect(registrars[0].fields.pgpFingerprint).to.be.false;
|
||||
expect(registrars[0].fields.image).to.be.false;
|
||||
expect(registrars[0].fields.twitter).to.be.false;
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T02",
|
||||
title: "should retrieve identity",
|
||||
test: async function () {
|
||||
const identity = (await context.readContract!({
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
contractName: "Identity",
|
||||
functionName: "identity",
|
||||
args: [baltathar.address],
|
||||
})) as any;
|
||||
|
||||
expect(identity.isValid).to.be.true;
|
||||
expect(identity.judgements).to.be.empty;
|
||||
expect(identity.deposit).to.equal(1034200000000000000n);
|
||||
expect(identity.info.additional.length).to.equal(1);
|
||||
expect(identity.info.additional[0].key.hasData).to.be.true;
|
||||
expect(identity.info.additional[0].key.value).to.equal(toHex("discord"));
|
||||
expect(identity.info.additional[0].value.hasData).to.be.true;
|
||||
expect(identity.info.additional[0].value.value).to.equal(toHex("my-discord"));
|
||||
expect(identity.info.display.hasData).to.be.true;
|
||||
expect(identity.info.display.value).to.equal(toHex("display"));
|
||||
expect(identity.info.legal.hasData).to.be.true;
|
||||
expect(identity.info.legal.value).to.equal(toHex("legal"));
|
||||
expect(identity.info.web.hasData).to.be.true;
|
||||
expect(identity.info.web.value).to.equal(toHex("web"));
|
||||
expect(identity.info.riot.hasData).to.be.true;
|
||||
expect(identity.info.riot.value).to.equal(toHex("riot"));
|
||||
expect(identity.info.email.hasData).to.be.true;
|
||||
expect(identity.info.email.value).to.equal(toHex("email"));
|
||||
expect(identity.info.hasPgpFingerprint).to.be.true;
|
||||
expect(identity.info.pgpFingerprint).to.equal(
|
||||
toHex(Uint8Array.from(new Array(20).fill(1)))
|
||||
);
|
||||
expect(identity.info.image.hasData).to.be.true;
|
||||
expect(identity.info.image.value).to.equal(toHex("image"));
|
||||
expect(identity.info.twitter.hasData).to.be.true;
|
||||
expect(identity.info.twitter.value).to.equal(toHex("twitter"));
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* Identity precompile tests - set account id
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { beforeAll, describeSuite, expect } from "@moonwall/cli";
|
||||
import { alith, charleth } from "@moonwall/util";
|
||||
import { expectEVMResult, PRECOMPILE_IDENTITY_ADDRESS } from "../../../../helpers";
|
||||
|
||||
describeSuite({
|
||||
id: "D030310",
|
||||
title: "Precompiles - Identity precompile - set account id",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ it, log, context }) => {
|
||||
beforeAll(async function () {
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.sudo.sudo(context.polkadotJs().tx.identity.addRegistrar(alith.address))
|
||||
);
|
||||
|
||||
const block = await context.createBlock(
|
||||
await context.writeContract!({
|
||||
contractName: "Identity",
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
functionName: "setAccountId",
|
||||
rawTxOnly: true,
|
||||
args: [0, charleth.address],
|
||||
})
|
||||
);
|
||||
|
||||
expectEVMResult(block.result!.events, "Succeed");
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should retrieve the registrar",
|
||||
test: async function () {
|
||||
const registrars = (await context.readContract!({
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
contractName: "Identity",
|
||||
functionName: "registrars",
|
||||
})) as any;
|
||||
|
||||
expect(registrars.length).to.equal(1);
|
||||
expect(registrars[0].isValid).to.be.true;
|
||||
expect(registrars[0].index).to.equal(0);
|
||||
expect(registrars[0].account).to.equal(charleth.address);
|
||||
expect(registrars[0].fee).to.equal(0n);
|
||||
expect(registrars[0].fields.display).to.be.false;
|
||||
expect(registrars[0].fields.web).to.be.false;
|
||||
expect(registrars[0].fields.legal).to.be.false;
|
||||
expect(registrars[0].fields.riot).to.be.false;
|
||||
expect(registrars[0].fields.email).to.be.false;
|
||||
expect(registrars[0].fields.pgpFingerprint).to.be.false;
|
||||
expect(registrars[0].fields.image).to.be.false;
|
||||
expect(registrars[0].fields.twitter).to.be.false;
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/**
|
||||
* Identity precompile tests - add sub
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { beforeAll, describeSuite, expect, fetchCompiledContract } from "@moonwall/cli";
|
||||
import { BALTATHAR_PRIVATE_KEY, baltathar, charleth } from "@moonwall/util";
|
||||
import { decodeEventLog, toHex } from "viem";
|
||||
import {
|
||||
PRECOMPILE_IDENTITY_ADDRESS,
|
||||
expectEVMResult,
|
||||
expectSubstrateEvent,
|
||||
} from "../../../../helpers";
|
||||
|
||||
describeSuite({
|
||||
id: "D030311",
|
||||
title: "Precompiles - Identity precompile - add sub",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ it, log, context }) => {
|
||||
beforeAll(async function () {
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.identity.setIdentity({
|
||||
display: { raw: "display" },
|
||||
})
|
||||
.signAsync(baltathar)
|
||||
);
|
||||
|
||||
const block = await context.createBlock(
|
||||
await context.writeContract!({
|
||||
contractName: "Identity",
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
functionName: "addSub",
|
||||
privateKey: BALTATHAR_PRIVATE_KEY,
|
||||
rawTxOnly: true,
|
||||
args: [
|
||||
charleth.address,
|
||||
{
|
||||
hasData: true,
|
||||
value: toHex("test"),
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
expectEVMResult(block.result!.events, "Succeed");
|
||||
const { data } = expectSubstrateEvent(block, "evm", "Log");
|
||||
const evmLog = decodeEventLog({
|
||||
abi: fetchCompiledContract("Identity").abi,
|
||||
topics: data[0].topics.map((t) => t.toHex()) as any,
|
||||
data: data[0].data.toHex(),
|
||||
}) as any;
|
||||
|
||||
expect(evmLog.eventName).to.equal("SubIdentityAdded");
|
||||
expect(evmLog.args.sub).to.equal(charleth.address);
|
||||
expect(evmLog.args.main).to.equal(baltathar.address);
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should retrieve subs",
|
||||
test: async function () {
|
||||
const subs = (await context.readContract!({
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
contractName: "Identity",
|
||||
functionName: "subsOf",
|
||||
args: [baltathar.address],
|
||||
})) as any;
|
||||
|
||||
expect(subs.deposit).to.equal(1005300000000000000n);
|
||||
expect(subs.accounts).to.have.length(1);
|
||||
expect(subs.accounts[0]).to.be.equal(charleth.address);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T02",
|
||||
title: "should retrieve super",
|
||||
test: async function () {
|
||||
const superOf = (await context.readContract!({
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
contractName: "Identity",
|
||||
functionName: "superOf",
|
||||
args: [charleth.address],
|
||||
})) as any;
|
||||
|
||||
expect(superOf.isValid).to.be.true;
|
||||
expect(superOf.account).to.be.equal(baltathar.address);
|
||||
expect(superOf.data.hasData).to.be.true;
|
||||
expect(superOf.data.value).to.be.equal(toHex("test"));
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
* Identity precompile tests - rename sub
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { beforeAll, describeSuite, expect } from "@moonwall/cli";
|
||||
import { BALTATHAR_PRIVATE_KEY, baltathar, charleth } from "@moonwall/util";
|
||||
import { toHex } from "viem";
|
||||
import { PRECOMPILE_IDENTITY_ADDRESS, expectEVMResult } from "../../../../helpers";
|
||||
|
||||
describeSuite({
|
||||
id: "D030312",
|
||||
title: "Precompiles - Identity precompile - rename sub",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ it, log, context }) => {
|
||||
beforeAll(async function () {
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.identity.setIdentity({
|
||||
display: { raw: "display" },
|
||||
})
|
||||
.signAsync(baltathar)
|
||||
);
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.identity.addSub(charleth.address, { Raw: "test" })
|
||||
.signAsync(baltathar)
|
||||
);
|
||||
|
||||
const block = await context.createBlock(
|
||||
await context.writeContract!({
|
||||
contractName: "Identity",
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
functionName: "renameSub",
|
||||
privateKey: BALTATHAR_PRIVATE_KEY,
|
||||
rawTxOnly: true,
|
||||
args: [
|
||||
charleth.address,
|
||||
{
|
||||
hasData: true,
|
||||
value: toHex("foobar"),
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
expectEVMResult(block.result!.events, "Succeed");
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should retrieve subs",
|
||||
test: async function () {
|
||||
const subs = (await context.readContract!({
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
contractName: "Identity",
|
||||
functionName: "subsOf",
|
||||
args: [baltathar.address],
|
||||
})) as any;
|
||||
|
||||
expect(subs.deposit).to.equal(1005300000000000000n);
|
||||
expect(subs.accounts).to.have.length(1);
|
||||
expect(subs.accounts[0]).to.be.equal(charleth.address);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T02",
|
||||
title: "should retrieve super",
|
||||
test: async function () {
|
||||
const superOf = (await context.readContract!({
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
contractName: "Identity",
|
||||
functionName: "superOf",
|
||||
args: [charleth.address],
|
||||
})) as any;
|
||||
|
||||
expect(superOf.isValid).to.be.true;
|
||||
expect(superOf.account).to.be.equal(baltathar.address);
|
||||
expect(superOf.data.hasData).to.be.true;
|
||||
expect(superOf.data.value).to.be.equal(toHex("foobar"));
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/**
|
||||
* Identity precompile tests - remove sub
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { beforeAll, describeSuite, expect, fetchCompiledContract } from "@moonwall/cli";
|
||||
import { BALTATHAR_PRIVATE_KEY, baltathar, charleth } from "@moonwall/util";
|
||||
import { decodeEventLog } from "viem";
|
||||
import {
|
||||
PRECOMPILE_IDENTITY_ADDRESS,
|
||||
expectEVMResult,
|
||||
expectSubstrateEvent,
|
||||
} from "../../../../helpers";
|
||||
|
||||
describeSuite({
|
||||
id: "D030313",
|
||||
title: "Precompiles - Identity precompile - remove sub",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ it, log, context }) => {
|
||||
beforeAll(async function () {
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.identity.setIdentity({
|
||||
display: { raw: "display" },
|
||||
})
|
||||
.signAsync(baltathar)
|
||||
);
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.identity.addSub(charleth.address, { Raw: "test" })
|
||||
.signAsync(baltathar)
|
||||
);
|
||||
|
||||
const block = await context.createBlock(
|
||||
await context.writeContract!({
|
||||
contractName: "Identity",
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
functionName: "removeSub",
|
||||
privateKey: BALTATHAR_PRIVATE_KEY,
|
||||
rawTxOnly: true,
|
||||
args: [charleth.address],
|
||||
})
|
||||
);
|
||||
|
||||
expectEVMResult(block.result!.events, "Succeed");
|
||||
const { data } = expectSubstrateEvent(block, "evm", "Log");
|
||||
const evmLog = decodeEventLog({
|
||||
abi: fetchCompiledContract("Identity").abi,
|
||||
topics: data[0].topics.map((t) => t.toHex()) as any,
|
||||
data: data[0].data.toHex(),
|
||||
}) as any;
|
||||
|
||||
expect(evmLog.eventName).to.equal("SubIdentityRemoved");
|
||||
expect(evmLog.args.sub).to.equal(charleth.address);
|
||||
expect(evmLog.args.main).to.equal(baltathar.address);
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should have no subs",
|
||||
test: async function () {
|
||||
const subs = (await context.readContract!({
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
contractName: "Identity",
|
||||
functionName: "subsOf",
|
||||
args: [baltathar.address],
|
||||
})) as any;
|
||||
|
||||
expect(subs.deposit).to.be.equal(0n);
|
||||
expect(subs.accounts).to.be.empty;
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* Identity precompile tests - quit sub
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { beforeAll, describeSuite, expect, fetchCompiledContract } from "@moonwall/cli";
|
||||
import { CHARLETH_PRIVATE_KEY, baltathar, charleth } from "@moonwall/util";
|
||||
import { decodeEventLog } from "viem";
|
||||
import {
|
||||
PRECOMPILE_IDENTITY_ADDRESS,
|
||||
expectEVMResult,
|
||||
expectSubstrateEvent,
|
||||
} from "../../../../helpers";
|
||||
|
||||
describeSuite({
|
||||
id: "D030314",
|
||||
title: "Precompiles - Identity precompile - quit sub",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ it, log, context }) => {
|
||||
beforeAll(async function () {
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.identity.setIdentity({
|
||||
display: { raw: "display" },
|
||||
})
|
||||
.signAsync(baltathar)
|
||||
);
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.identity.addSub(charleth.address, { Raw: "test" })
|
||||
.signAsync(baltathar)
|
||||
);
|
||||
|
||||
const block = await context.createBlock(
|
||||
await context.writeContract!({
|
||||
contractName: "Identity",
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
functionName: "quitSub",
|
||||
privateKey: CHARLETH_PRIVATE_KEY,
|
||||
rawTxOnly: true,
|
||||
})
|
||||
);
|
||||
|
||||
expectEVMResult(block.result!.events, "Succeed");
|
||||
const { data } = expectSubstrateEvent(block, "evm", "Log");
|
||||
const evmLog = decodeEventLog({
|
||||
abi: fetchCompiledContract("Identity").abi,
|
||||
topics: data[0].topics.map((t) => t.toHex()) as any,
|
||||
data: data[0].data.toHex(),
|
||||
}) as any;
|
||||
|
||||
expect(evmLog.eventName).to.equal("SubIdentityRevoked");
|
||||
expect(evmLog.args.sub).to.equal(charleth.address);
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should have no super",
|
||||
test: async function () {
|
||||
const superOf = (await context.readContract!({
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
contractName: "Identity",
|
||||
functionName: "superOf",
|
||||
args: [charleth.address],
|
||||
})) as any;
|
||||
|
||||
expect(superOf.isValid).to.be.false;
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
/**
|
||||
* Identity precompile tests - set identity
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { beforeAll, describeSuite, expect, fetchCompiledContract } from "@moonwall/cli";
|
||||
import { BALTATHAR_PRIVATE_KEY, baltathar } from "@moonwall/util";
|
||||
import { decodeEventLog, toHex } from "viem";
|
||||
import {
|
||||
PRECOMPILE_IDENTITY_ADDRESS,
|
||||
expectEVMResult,
|
||||
expectSubstrateEvent,
|
||||
} from "../../../../helpers";
|
||||
|
||||
describeSuite({
|
||||
id: "D030302",
|
||||
title: "Precompiles - Identity precompile - set identity",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ it, log, context }) => {
|
||||
beforeAll(async function () {
|
||||
const block = await context.createBlock(
|
||||
await context.writeContract!({
|
||||
contractName: "Identity",
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
functionName: "setIdentity",
|
||||
privateKey: BALTATHAR_PRIVATE_KEY,
|
||||
rawTxOnly: true,
|
||||
args: [
|
||||
{
|
||||
additional: [
|
||||
{
|
||||
key: { hasData: true, value: toHex("discord") },
|
||||
value: { hasData: true, value: toHex("my-discord") },
|
||||
},
|
||||
],
|
||||
display: { hasData: true, value: toHex("display") },
|
||||
legal: { hasData: true, value: toHex("legal") },
|
||||
web: { hasData: true, value: toHex("web") },
|
||||
riot: { hasData: true, value: toHex("riot") },
|
||||
email: { hasData: true, value: toHex("email") },
|
||||
hasPgpFingerprint: true,
|
||||
pgpFingerprint: toHex(Uint8Array.from(new Array(20).fill(1))),
|
||||
image: { hasData: true, value: toHex("image") },
|
||||
twitter: { hasData: true, value: toHex("twitter") },
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
expectEVMResult(block.result!.events, "Succeed");
|
||||
const { data } = expectSubstrateEvent(block, "evm", "Log");
|
||||
const evmLog = decodeEventLog({
|
||||
abi: fetchCompiledContract("Identity").abi,
|
||||
topics: data[0].topics.map((t) => t.toHex()) as any,
|
||||
data: data[0].data.toHex(),
|
||||
}) as any;
|
||||
|
||||
expect(evmLog.eventName).to.equal("IdentitySet");
|
||||
expect(evmLog.args.who).to.equal(baltathar.address);
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should retrieve newly set identity",
|
||||
test: async function () {
|
||||
const identity = (await context.readContract!({
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
contractName: "Identity",
|
||||
functionName: "identity",
|
||||
args: [baltathar.address],
|
||||
})) as any;
|
||||
|
||||
expect(identity.isValid).to.be.true;
|
||||
expect(identity.judgements).to.be.empty;
|
||||
expect(identity.deposit).to.equal(1034200000000000000n);
|
||||
expect(identity.info.additional.length).to.equal(1);
|
||||
expect(identity.info.additional[0].key.hasData).to.be.true;
|
||||
expect(identity.info.additional[0].key.value).to.equal(toHex("discord"));
|
||||
expect(identity.info.additional[0].value.hasData).to.be.true;
|
||||
expect(identity.info.additional[0].value.value).to.equal(toHex("my-discord"));
|
||||
expect(identity.info.display.hasData).to.be.true;
|
||||
expect(identity.info.display.value).to.equal(toHex("display"));
|
||||
expect(identity.info.legal.hasData).to.be.true;
|
||||
expect(identity.info.legal.value).to.equal(toHex("legal"));
|
||||
expect(identity.info.web.hasData).to.be.true;
|
||||
expect(identity.info.web.value).to.equal(toHex("web"));
|
||||
expect(identity.info.riot.hasData).to.be.true;
|
||||
expect(identity.info.riot.value).to.equal(toHex("riot"));
|
||||
expect(identity.info.email.hasData).to.be.true;
|
||||
expect(identity.info.email.value).to.equal(toHex("email"));
|
||||
expect(identity.info.hasPgpFingerprint).to.be.true;
|
||||
expect(identity.info.pgpFingerprint).to.equal(
|
||||
toHex(Uint8Array.from(new Array(20).fill(1)))
|
||||
);
|
||||
expect(identity.info.image.hasData).to.be.true;
|
||||
expect(identity.info.image.value).to.equal(toHex("image"));
|
||||
expect(identity.info.twitter.hasData).to.be.true;
|
||||
expect(identity.info.twitter.value).to.equal(toHex("twitter"));
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* Identity precompile tests - clear identity
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { beforeAll, describeSuite, expect, fetchCompiledContract } from "@moonwall/cli";
|
||||
import { BALTATHAR_PRIVATE_KEY, baltathar } from "@moonwall/util";
|
||||
import { decodeEventLog } from "viem";
|
||||
import {
|
||||
PRECOMPILE_IDENTITY_ADDRESS,
|
||||
expectEVMResult,
|
||||
expectSubstrateEvent,
|
||||
} from "../../../../helpers";
|
||||
|
||||
describeSuite({
|
||||
id: "D030303",
|
||||
title: "Precompiles - Identity precompile - clear identity",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ it, log, context }) => {
|
||||
beforeAll(async function () {
|
||||
await context.createBlock([
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.identity.setIdentity({
|
||||
display: { raw: "display" },
|
||||
})
|
||||
.signAsync(baltathar),
|
||||
]);
|
||||
|
||||
const block = await context.createBlock(
|
||||
await context.writeContract!({
|
||||
contractName: "Identity",
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
functionName: "clearIdentity",
|
||||
privateKey: BALTATHAR_PRIVATE_KEY,
|
||||
rawTxOnly: true,
|
||||
})
|
||||
);
|
||||
|
||||
expectEVMResult(block.result!.events, "Succeed");
|
||||
const { data } = expectSubstrateEvent(block, "evm", "Log");
|
||||
const evmLog = decodeEventLog({
|
||||
abi: fetchCompiledContract("Identity").abi,
|
||||
topics: data[0].topics.map((t) => t.toHex()) as any,
|
||||
data: data[0].data.toHex(),
|
||||
}) as any;
|
||||
|
||||
expect(evmLog.eventName).to.equal("IdentityCleared");
|
||||
expect(evmLog.args.who).to.equal(baltathar.address);
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should have no identity",
|
||||
test: async function () {
|
||||
const identity = (await context.readContract!({
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
contractName: "Identity",
|
||||
functionName: "identity",
|
||||
args: [baltathar.address],
|
||||
})) as any;
|
||||
|
||||
expect(identity.isValid).to.be.false;
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
* Identity precompile tests - request judgement
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { beforeAll, describeSuite, expect, fetchCompiledContract } from "@moonwall/cli";
|
||||
import { BALTATHAR_PRIVATE_KEY, alith, baltathar } from "@moonwall/util";
|
||||
import { decodeEventLog, toHex } from "viem";
|
||||
import {
|
||||
PRECOMPILE_IDENTITY_ADDRESS,
|
||||
expectEVMResult,
|
||||
expectSubstrateEvent,
|
||||
} from "../../../../helpers";
|
||||
|
||||
describeSuite({
|
||||
id: "D030304",
|
||||
title: "Precompiles - Identity precompile - request judgement",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ it, log, context }) => {
|
||||
beforeAll(async function () {
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.sudo.sudo(context.polkadotJs().tx.identity.addRegistrar(alith.address))
|
||||
);
|
||||
await context.createBlock([
|
||||
context.polkadotJs().tx.identity.setFee(0, 100n),
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.identity.setIdentity({
|
||||
display: { raw: "display" },
|
||||
})
|
||||
.signAsync(baltathar),
|
||||
]);
|
||||
|
||||
const block = await context.createBlock(
|
||||
await context.writeContract!({
|
||||
contractName: "Identity",
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
functionName: "requestJudgement",
|
||||
privateKey: BALTATHAR_PRIVATE_KEY,
|
||||
rawTxOnly: true,
|
||||
args: [0, 100],
|
||||
})
|
||||
);
|
||||
|
||||
expectEVMResult(block.result!.events, "Succeed");
|
||||
const { data } = expectSubstrateEvent(block, "evm", "Log");
|
||||
const evmLog = decodeEventLog({
|
||||
abi: fetchCompiledContract("Identity").abi,
|
||||
topics: data[0].topics.map((t) => t.toHex()) as any,
|
||||
data: data[0].data.toHex(),
|
||||
}) as any;
|
||||
|
||||
expect(evmLog.eventName).to.equal("JudgementRequested");
|
||||
expect(evmLog.args.who).to.equal(baltathar.address);
|
||||
expect(evmLog.args.registrarIndex).to.equal(0);
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should retrieve requested judgement as part of identity",
|
||||
test: async function () {
|
||||
const identity = (await context.readContract!({
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
contractName: "Identity",
|
||||
functionName: "identity",
|
||||
args: [baltathar.address],
|
||||
})) as any;
|
||||
|
||||
expect(identity.isValid).to.be.true;
|
||||
expect(identity.judgements).to.have.length(1);
|
||||
expect(identity.judgements[0].registrarIndex).to.equal(0);
|
||||
expect(identity.judgements[0].judgement.isFeePaid).to.be.true;
|
||||
expect(identity.judgements[0].judgement.feePaidDeposit).to.equal(100n);
|
||||
expect(identity.deposit).to.equal(1027400000000000000n);
|
||||
expect(identity.info.display.hasData).to.be.true;
|
||||
expect(identity.info.display.value).to.equal(toHex("display"));
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
* Identity precompile tests - cancel requested judgement
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { beforeAll, describeSuite, expect, fetchCompiledContract } from "@moonwall/cli";
|
||||
import { BALTATHAR_PRIVATE_KEY, alith, baltathar } from "@moonwall/util";
|
||||
import { decodeEventLog, toHex } from "viem";
|
||||
import {
|
||||
PRECOMPILE_IDENTITY_ADDRESS,
|
||||
expectEVMResult,
|
||||
expectSubstrateEvent,
|
||||
} from "../../../../helpers";
|
||||
|
||||
describeSuite({
|
||||
id: "D030305",
|
||||
title: "Precompiles - Identity precompile - cancel requested judgement",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ it, log, context }) => {
|
||||
beforeAll(async function () {
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.sudo.sudo(context.polkadotJs().tx.identity.addRegistrar(alith.address))
|
||||
);
|
||||
await context.createBlock([
|
||||
context.polkadotJs().tx.identity.setFee(0, 100n),
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.identity.setIdentity({
|
||||
display: { raw: "display" },
|
||||
})
|
||||
.signAsync(baltathar),
|
||||
]);
|
||||
await context.createBlock(
|
||||
context.polkadotJs().tx.identity.requestJudgement(0, 1000n).signAsync(baltathar)
|
||||
);
|
||||
|
||||
const block = await context.createBlock(
|
||||
await context.writeContract!({
|
||||
contractName: "Identity",
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
functionName: "cancelRequest",
|
||||
privateKey: BALTATHAR_PRIVATE_KEY,
|
||||
rawTxOnly: true,
|
||||
args: [0],
|
||||
})
|
||||
);
|
||||
|
||||
expectEVMResult(block.result!.events, "Succeed");
|
||||
const { data } = expectSubstrateEvent(block, "evm", "Log");
|
||||
const evmLog = decodeEventLog({
|
||||
abi: fetchCompiledContract("Identity").abi,
|
||||
topics: data[0].topics.map((t) => t.toHex()) as any,
|
||||
data: data[0].data.toHex(),
|
||||
}) as any;
|
||||
|
||||
expect(evmLog.eventName).to.equal("JudgementUnrequested");
|
||||
expect(evmLog.args.who).to.equal(baltathar.address);
|
||||
expect(evmLog.args.registrarIndex).to.equal(0);
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should have no requested judgement as part of identity",
|
||||
test: async function () {
|
||||
const identity = (await context.readContract!({
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
contractName: "Identity",
|
||||
functionName: "identity",
|
||||
args: [baltathar.address],
|
||||
})) as any;
|
||||
|
||||
expect(identity.isValid).to.be.true;
|
||||
expect(identity.judgements).to.be.empty;
|
||||
expect(identity.deposit).to.equal(1027400000000000000n);
|
||||
expect(identity.info.display.hasData).to.be.true;
|
||||
expect(identity.info.display.value).to.equal(toHex("display"));
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/**
|
||||
* Identity precompile tests - provide judgement
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { beforeAll, describeSuite, expect, fetchCompiledContract } from "@moonwall/cli";
|
||||
import { alith, baltathar } from "@moonwall/util";
|
||||
import { decodeEventLog, toHex } from "viem";
|
||||
import {
|
||||
PRECOMPILE_IDENTITY_ADDRESS,
|
||||
expectEVMResult,
|
||||
expectSubstrateEvent,
|
||||
} from "../../../../helpers";
|
||||
|
||||
describeSuite({
|
||||
id: "D030306",
|
||||
title: "Precompiles - Identity precompile - provide judgement",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ it, log, context }) => {
|
||||
beforeAll(async function () {
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.sudo.sudo(context.polkadotJs().tx.identity.addRegistrar(alith.address))
|
||||
);
|
||||
const identityData = {
|
||||
display: { raw: "display" },
|
||||
};
|
||||
await context.createBlock([
|
||||
context.polkadotJs().tx.identity.setFee(0, 100n),
|
||||
context.polkadotJs().tx.identity.setIdentity(identityData).signAsync(baltathar),
|
||||
]);
|
||||
await context.createBlock(
|
||||
context.polkadotJs().tx.identity.requestJudgement(0, 1000n).signAsync(baltathar)
|
||||
);
|
||||
|
||||
const identityHash = context
|
||||
.polkadotJs()
|
||||
.registry.createType("PalletIdentityLegacyIdentityInfo", identityData)
|
||||
.hash.toHex();
|
||||
const block = await context.createBlock(
|
||||
await context.writeContract!({
|
||||
contractName: "Identity",
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
functionName: "provideJudgement",
|
||||
rawTxOnly: true,
|
||||
args: [
|
||||
0,
|
||||
baltathar.address,
|
||||
{
|
||||
isUnknown: false,
|
||||
isFeePaid: false,
|
||||
feePaidDeposit: 0,
|
||||
isReasonable: false,
|
||||
isKnownGood: true,
|
||||
isOutOfDate: false,
|
||||
isLowQuality: false,
|
||||
isErroneous: false,
|
||||
},
|
||||
identityHash,
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
expectEVMResult(block.result!.events, "Succeed");
|
||||
const { data } = expectSubstrateEvent(block, "evm", "Log");
|
||||
const evmLog = decodeEventLog({
|
||||
abi: fetchCompiledContract("Identity").abi,
|
||||
topics: data[0].topics.map((t) => t.toHex()) as any,
|
||||
data: data[0].data.toHex(),
|
||||
}) as any;
|
||||
|
||||
expect(evmLog.eventName).to.equal("JudgementGiven");
|
||||
expect(evmLog.args.target).to.equal(baltathar.address);
|
||||
expect(evmLog.args.registrarIndex).to.equal(0);
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should have provided judgement as part of identity",
|
||||
test: async function () {
|
||||
const identity = (await context.readContract!({
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
contractName: "Identity",
|
||||
functionName: "identity",
|
||||
args: [baltathar.address],
|
||||
})) as any;
|
||||
|
||||
expect(identity.isValid).to.be.true;
|
||||
expect(identity.judgements).to.have.length(1);
|
||||
expect(identity.judgements[0].judgement.isKnownGood).to.be.true;
|
||||
expect(identity.deposit).to.equal(1027400000000000000n);
|
||||
expect(identity.info.display.hasData).to.be.true;
|
||||
expect(identity.info.display.value).to.equal(toHex("display"));
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
* Identity precompile tests - set subs
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { beforeAll, describeSuite, expect } from "@moonwall/cli";
|
||||
import { BALTATHAR_PRIVATE_KEY, baltathar, charleth } from "@moonwall/util";
|
||||
import { toHex } from "viem";
|
||||
import { PRECOMPILE_IDENTITY_ADDRESS, expectEVMResult } from "../../../../helpers";
|
||||
|
||||
describeSuite({
|
||||
id: "D030307",
|
||||
title: "Precompiles - Identity precompile - set subs",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ it, log, context }) => {
|
||||
beforeAll(async function () {
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.identity.setIdentity({
|
||||
display: { raw: "display" },
|
||||
})
|
||||
.signAsync(baltathar)
|
||||
);
|
||||
|
||||
const block = await context.createBlock(
|
||||
await context.writeContract!({
|
||||
contractName: "Identity",
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
functionName: "setSubs",
|
||||
privateKey: BALTATHAR_PRIVATE_KEY,
|
||||
rawTxOnly: true,
|
||||
args: [
|
||||
[
|
||||
{
|
||||
account: charleth.address,
|
||||
data: { hasData: true, value: toHex("test") },
|
||||
},
|
||||
],
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
expectEVMResult(block.result!.events, "Succeed");
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should retrieve subs",
|
||||
test: async function () {
|
||||
const subs = (await context.readContract!({
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
contractName: "Identity",
|
||||
functionName: "subsOf",
|
||||
args: [baltathar.address],
|
||||
})) as any;
|
||||
|
||||
expect(subs.deposit).to.equal(1005300000000000000n);
|
||||
expect(subs.accounts).to.have.length(1);
|
||||
expect(subs.accounts[0]).to.be.equal(charleth.address);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T02",
|
||||
title: "should retrieve super",
|
||||
test: async function () {
|
||||
const superOf = (await context.readContract!({
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
contractName: "Identity",
|
||||
functionName: "superOf",
|
||||
args: [charleth.address],
|
||||
})) as any;
|
||||
|
||||
expect(superOf.isValid).to.be.true;
|
||||
expect(superOf.account).to.be.equal(baltathar.address);
|
||||
expect(superOf.data.hasData).to.be.true;
|
||||
expect(superOf.data.value).to.be.equal(toHex("test"));
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* Identity precompile tests - set fee
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { beforeAll, describeSuite, expect } from "@moonwall/cli";
|
||||
import { alith } from "@moonwall/util";
|
||||
import { expectEVMResult, PRECOMPILE_IDENTITY_ADDRESS } from "../../../../helpers";
|
||||
|
||||
describeSuite({
|
||||
id: "D030308",
|
||||
title: "Precompiles - Identity precompile - set fee",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ it, log, context }) => {
|
||||
beforeAll(async function () {
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.sudo.sudo(context.polkadotJs().tx.identity.addRegistrar(alith.address))
|
||||
);
|
||||
|
||||
const block = await context.createBlock(
|
||||
await context.writeContract!({
|
||||
contractName: "Identity",
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
functionName: "setFee",
|
||||
rawTxOnly: true,
|
||||
args: [0, 100],
|
||||
})
|
||||
);
|
||||
|
||||
expectEVMResult(block.result!.events, "Succeed");
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should retrieve the registrar",
|
||||
test: async function () {
|
||||
const registrars = (await context.readContract!({
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
contractName: "Identity",
|
||||
functionName: "registrars",
|
||||
})) as any;
|
||||
|
||||
expect(registrars.length).to.equal(1);
|
||||
expect(registrars[0].isValid).to.be.true;
|
||||
expect(registrars[0].index).to.equal(0);
|
||||
expect(registrars[0].account).to.equal(alith.address);
|
||||
expect(registrars[0].fee).to.equal(100n);
|
||||
expect(registrars[0].fields.display).to.be.false;
|
||||
expect(registrars[0].fields.web).to.be.false;
|
||||
expect(registrars[0].fields.legal).to.be.false;
|
||||
expect(registrars[0].fields.riot).to.be.false;
|
||||
expect(registrars[0].fields.email).to.be.false;
|
||||
expect(registrars[0].fields.pgpFingerprint).to.be.false;
|
||||
expect(registrars[0].fields.image).to.be.false;
|
||||
expect(registrars[0].fields.twitter).to.be.false;
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* Identity precompile tests - set fields
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { beforeAll, describeSuite, expect } from "@moonwall/cli";
|
||||
import { alith } from "@moonwall/util";
|
||||
import { expectEVMResult, PRECOMPILE_IDENTITY_ADDRESS } from "../../../../helpers";
|
||||
|
||||
describeSuite({
|
||||
id: "D030309",
|
||||
title: "Precompiles - Identity precompile - set fields",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ it, log, context }) => {
|
||||
beforeAll(async function () {
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.sudo.sudo(context.polkadotJs().tx.identity.addRegistrar(alith.address))
|
||||
);
|
||||
|
||||
const block = await context.createBlock(
|
||||
await context.writeContract!({
|
||||
contractName: "Identity",
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
functionName: "setFields",
|
||||
rawTxOnly: true,
|
||||
args: [
|
||||
0,
|
||||
{
|
||||
display: true,
|
||||
web: true,
|
||||
legal: true,
|
||||
riot: true,
|
||||
email: true,
|
||||
pgpFingerprint: true,
|
||||
image: true,
|
||||
twitter: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
expectEVMResult(block.result!.events, "Succeed");
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should retrieve the registrar",
|
||||
test: async function () {
|
||||
const registrars = (await context.readContract!({
|
||||
contractAddress: PRECOMPILE_IDENTITY_ADDRESS,
|
||||
contractName: "Identity",
|
||||
functionName: "registrars",
|
||||
})) as any;
|
||||
|
||||
expect(registrars.length).to.equal(1);
|
||||
expect(registrars[0].isValid).to.be.true;
|
||||
expect(registrars[0].index).to.equal(0);
|
||||
expect(registrars[0].account).to.equal(alith.address);
|
||||
expect(registrars[0].fee).to.equal(0n);
|
||||
expect(registrars[0].fields.display).to.be.true;
|
||||
expect(registrars[0].fields.web).to.be.true;
|
||||
expect(registrars[0].fields.legal).to.be.true;
|
||||
expect(registrars[0].fields.riot).to.be.true;
|
||||
expect(registrars[0].fields.email).to.be.true;
|
||||
expect(registrars[0].fields.pgpFingerprint).to.be.true;
|
||||
expect(registrars[0].fields.image).to.be.true;
|
||||
expect(registrars[0].fields.twitter).to.be.true;
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,824 @@
|
|||
import "@moonbeam-network/api-augment";
|
||||
import { beforeAll, describeSuite, expect } from "@moonwall/cli";
|
||||
import { EXTRINSIC_GAS_LIMIT, createViemTransaction } from "@moonwall/util";
|
||||
import { hexToU8a, u8aToHex } from "@polkadot/util";
|
||||
import { expectEVMResult, testVectors } from "../../../../helpers";
|
||||
import { calculateEIP7623Gas } from "../../../../helpers/fees";
|
||||
|
||||
const MODEXP_PRECOMPILE_ADDRESS = "0x0000000000000000000000000000000000000005";
|
||||
|
||||
// TODO: Gas tests (T03, T05-T21) are skipped because DataHaven uses Frontier stable2412
|
||||
// which doesn't include EIP-7623 gas calculation. Re-enable these tests after upgrading
|
||||
// to Polkadot stable2506 (which includes the newer Frontier with EIP-7623 support).
|
||||
|
||||
describeSuite({
|
||||
id: "D030108",
|
||||
title: "Precompiles - modexp",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, it, log }) => {
|
||||
let hasherAddress: `0x${string}`;
|
||||
|
||||
beforeAll(async function () {
|
||||
const { contractAddress } = await context.deployContract!("HasherChecker");
|
||||
hasherAddress = contractAddress;
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should be accessible from a smart contract",
|
||||
test: async function () {
|
||||
const rawTx = await context.writeContract!({
|
||||
contractName: "HasherChecker",
|
||||
contractAddress: hasherAddress,
|
||||
functionName: "modExpChecker",
|
||||
rawTxOnly: true,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTx);
|
||||
expectEVMResult(result!.events, "Succeed");
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T02",
|
||||
title: "EIP example 1 - calculation",
|
||||
test: async function () {
|
||||
const rawTx = await context.writeContract!({
|
||||
contractName: "HasherChecker",
|
||||
contractAddress: hasherAddress,
|
||||
functionName: "modExpVerify",
|
||||
args: [
|
||||
"3",
|
||||
"115792089237316195423570985008687907853269984665640564039457584007908834671662",
|
||||
"115792089237316195423570985008687907853269984665640564039457584007908834671663",
|
||||
],
|
||||
rawTxOnly: true,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTx);
|
||||
expectEVMResult(result!.events, "Succeed");
|
||||
|
||||
expect(
|
||||
await context.readContract!({
|
||||
contractAddress: hasherAddress,
|
||||
contractName: "HasherChecker",
|
||||
functionName: "getResult",
|
||||
})
|
||||
).to.be.equals(1n);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T03",
|
||||
title: "EIP example 1 - gas",
|
||||
modifier: "skip",
|
||||
test: async function () {
|
||||
const expectedModExpGasCost = 3728n;
|
||||
const inputData =
|
||||
"0000000000000000000000000000000000000000000000000000000000000001" + // base length
|
||||
"0000000000000000000000000000000000000000000000000000000000000020" + // exponent length
|
||||
"0000000000000000000000000000000000000000000000000000000000000020" + // modulus length
|
||||
"03" + // base
|
||||
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e" + // exponent
|
||||
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"; // modulus
|
||||
const byteArray = hexToU8a(inputData);
|
||||
const inputLength = byteArray.length;
|
||||
const numZeroBytes = byteArray.filter((a) => a === 0).length;
|
||||
const numNonZeroBytes = inputLength - numZeroBytes;
|
||||
|
||||
const rawTxn = await createViemTransaction(context, {
|
||||
to: MODEXP_PRECOMPILE_ADDRESS,
|
||||
data: ("0x" + inputData) as `0x${string}`,
|
||||
gas: EXTRINSIC_GAS_LIMIT,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTxn);
|
||||
|
||||
const receipt = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result!.hash as `0x${string}` });
|
||||
expect(receipt.status).toBe("success");
|
||||
const expectedGasUsed = calculateEIP7623Gas(
|
||||
numZeroBytes,
|
||||
numNonZeroBytes,
|
||||
expectedModExpGasCost
|
||||
);
|
||||
expect(receipt.gasUsed, "ModExp gas pricing mismatch").to.equal(expectedGasUsed);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T04",
|
||||
title: "EIP example 2",
|
||||
test: async function () {
|
||||
await context.writeContract!({
|
||||
contractName: "HasherChecker",
|
||||
contractAddress: hasherAddress,
|
||||
functionName: "modExpVerify",
|
||||
args: [
|
||||
"0",
|
||||
"115792089237316195423570985008687907853269984665640564039457584007908834671662",
|
||||
"115792089237316195423570985008687907853269984665640564039457584007908834671663",
|
||||
],
|
||||
});
|
||||
|
||||
await context.createBlock();
|
||||
expect(
|
||||
await context.readContract!({
|
||||
contractAddress: hasherAddress,
|
||||
contractName: "HasherChecker",
|
||||
functionName: "getResult",
|
||||
})
|
||||
).toBe(0n);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T05",
|
||||
title: "EIP example 2 - gas",
|
||||
modifier: "skip",
|
||||
test: async function () {
|
||||
const expectedModExpGasCost = 3728n;
|
||||
const inputData =
|
||||
"0000000000000000000000000000000000000000000000000000000000000000" + // base length
|
||||
"0000000000000000000000000000000000000000000000000000000000000020" + // exponent length
|
||||
"0000000000000000000000000000000000000000000000000000000000000020" + // modulus length
|
||||
// base length is zero so value is inferred zero
|
||||
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e" + // exponent
|
||||
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"; // modulus
|
||||
const byteArray = hexToU8a(inputData);
|
||||
const inputLength = byteArray.length;
|
||||
const numZeroBytes = byteArray.filter((a) => a === 0).length;
|
||||
const numNonZeroBytes = inputLength - numZeroBytes;
|
||||
|
||||
const rawTxn = await createViemTransaction(context, {
|
||||
to: MODEXP_PRECOMPILE_ADDRESS,
|
||||
data: ("0x" + inputData) as `0x${string}`,
|
||||
gas: EXTRINSIC_GAS_LIMIT,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTxn);
|
||||
const receipt = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result!.hash as `0x${string}` });
|
||||
expect(receipt.status).toBe("success");
|
||||
const expectedGasUsed = calculateEIP7623Gas(
|
||||
numZeroBytes,
|
||||
numNonZeroBytes,
|
||||
expectedModExpGasCost
|
||||
);
|
||||
expect(receipt.gasUsed, "ModExp gas pricing mismatch").to.equal(expectedGasUsed);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T06",
|
||||
title: "nagydani-1-square - gas",
|
||||
modifier: "skip",
|
||||
test: async function () {
|
||||
const expectedModExpGasCost = 1869n;
|
||||
const inputData =
|
||||
"0000000000000000000000000000000000000000000000000000000000000040" + // base length
|
||||
"0000000000000000000000000000000000000000000000000000000000000001" + // exponent length
|
||||
"0000000000000000000000000000000000000000000000000000000000000040" + // modulus length
|
||||
testVectors["nagydani-1-square"].base +
|
||||
testVectors["nagydani-1-square"].exponent +
|
||||
testVectors["nagydani-1-square"].modulus;
|
||||
const byteArray = hexToU8a(inputData);
|
||||
const inputLength = byteArray.length;
|
||||
const numZeroBytes = byteArray.filter((a) => a === 0).length;
|
||||
const numNonZeroBytes = inputLength - numZeroBytes;
|
||||
|
||||
const rawTxn = await createViemTransaction(context, {
|
||||
to: MODEXP_PRECOMPILE_ADDRESS,
|
||||
data: ("0x" + inputData) as `0x${string}`,
|
||||
gas: EXTRINSIC_GAS_LIMIT,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTxn);
|
||||
|
||||
const receipt = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result!.hash as `0x${string}` });
|
||||
|
||||
expect(receipt.status).toBe("success");
|
||||
const expectedGasUsed = calculateEIP7623Gas(
|
||||
numZeroBytes,
|
||||
numNonZeroBytes,
|
||||
expectedModExpGasCost
|
||||
);
|
||||
expect(receipt.gasUsed, "ModExp gas pricing mismatch").to.equal(expectedGasUsed);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T07",
|
||||
title: "nagydani-1-qube - gas",
|
||||
modifier: "skip",
|
||||
test: async function () {
|
||||
const expectedModExpGasCost = 1869n;
|
||||
const inputData =
|
||||
"0000000000000000000000000000000000000000000000000000000000000040" + // base length
|
||||
"0000000000000000000000000000000000000000000000000000000000000001" + // exponent length
|
||||
"0000000000000000000000000000000000000000000000000000000000000040" + // modulus length
|
||||
testVectors["nagydani-1-square"].base +
|
||||
testVectors["nagydani-1-qube"].exponent +
|
||||
testVectors["nagydani-1-qube"].modulus;
|
||||
const byteArray = hexToU8a(inputData);
|
||||
const inputLength = byteArray.length;
|
||||
const numZeroBytes = byteArray.filter((a) => a === 0).length;
|
||||
const numNonZeroBytes = inputLength - numZeroBytes;
|
||||
|
||||
const rawTxn = await createViemTransaction(context, {
|
||||
to: MODEXP_PRECOMPILE_ADDRESS,
|
||||
data: ("0x" + inputData) as `0x${string}`,
|
||||
gas: EXTRINSIC_GAS_LIMIT,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTxn);
|
||||
|
||||
const receipt = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result!.hash as `0x${string}` });
|
||||
expect(receipt.status).toBe("success");
|
||||
const expectedGasUsed = calculateEIP7623Gas(
|
||||
numZeroBytes,
|
||||
numNonZeroBytes,
|
||||
expectedModExpGasCost
|
||||
);
|
||||
expect(receipt.gasUsed, "ModExp gas pricing mismatch").to.equal(expectedGasUsed);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T08",
|
||||
title: "nagydani-1-pow0x10001 - gas",
|
||||
modifier: "skip",
|
||||
test: async function () {
|
||||
const expectedModExpGasCost = 2010n;
|
||||
const inputData =
|
||||
"0000000000000000000000000000000000000000000000000000000000000040" + // base length
|
||||
"0000000000000000000000000000000000000000000000000000000000000003" + // exponent length
|
||||
"0000000000000000000000000000000000000000000000000000000000000040" + // modulus length
|
||||
testVectors["nagydani-1-pow0x10001"].base +
|
||||
testVectors["nagydani-1-pow0x10001"].exponent +
|
||||
testVectors["nagydani-1-pow0x10001"].modulus;
|
||||
const byteArray = hexToU8a(inputData);
|
||||
const inputLength = byteArray.length;
|
||||
const numZeroBytes = byteArray.filter((a) => a === 0).length;
|
||||
const numNonZeroBytes = inputLength - numZeroBytes;
|
||||
|
||||
const rawTxn = await createViemTransaction(context, {
|
||||
to: MODEXP_PRECOMPILE_ADDRESS,
|
||||
data: ("0x" + inputData) as `0x${string}`,
|
||||
gas: EXTRINSIC_GAS_LIMIT,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTxn);
|
||||
|
||||
const receipt = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result!.hash as `0x${string}` });
|
||||
expect(receipt.status).toBe("success");
|
||||
const expectedGasUsed = calculateEIP7623Gas(
|
||||
numZeroBytes,
|
||||
numNonZeroBytes,
|
||||
expectedModExpGasCost
|
||||
);
|
||||
expect(receipt.gasUsed, "ModExp gas pricing mismatch").to.equal(expectedGasUsed);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T09",
|
||||
title: "nagydani-2-square - gas",
|
||||
modifier: "skip",
|
||||
test: async function () {
|
||||
const expectedModExpGasCost = 1869n;
|
||||
const inputData =
|
||||
"0000000000000000000000000000000000000000000000000000000000000080" + // base length
|
||||
"0000000000000000000000000000000000000000000000000000000000000001" + // exponent length
|
||||
"0000000000000000000000000000000000000000000000000000000000000080" + // modulus length
|
||||
testVectors["nagydani-2-square"].base +
|
||||
testVectors["nagydani-2-square"].exponent +
|
||||
testVectors["nagydani-2-square"].modulus;
|
||||
const byteArray = hexToU8a(inputData);
|
||||
const inputLength = byteArray.length;
|
||||
const numZeroBytes = byteArray.filter((a) => a === 0).length;
|
||||
const numNonZeroBytes = inputLength - numZeroBytes;
|
||||
|
||||
const rawTxn = await createViemTransaction(context, {
|
||||
to: MODEXP_PRECOMPILE_ADDRESS,
|
||||
data: ("0x" + inputData) as `0x${string}`,
|
||||
gas: EXTRINSIC_GAS_LIMIT,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTxn);
|
||||
|
||||
const receipt = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result!.hash as `0x${string}` });
|
||||
expect(receipt.status).toBe("success");
|
||||
const expectedGasUsed = calculateEIP7623Gas(
|
||||
numZeroBytes,
|
||||
numNonZeroBytes,
|
||||
expectedModExpGasCost
|
||||
);
|
||||
expect(receipt.gasUsed, "ModExp gas pricing mismatch").to.equal(expectedGasUsed);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T10",
|
||||
title: "nagydani-2-qube - gas",
|
||||
modifier: "skip",
|
||||
test: async function () {
|
||||
const expectedModExpGasCost = 1869n;
|
||||
const inputData =
|
||||
"0000000000000000000000000000000000000000000000000000000000000080" + // base length
|
||||
"0000000000000000000000000000000000000000000000000000000000000001" + // exponent length
|
||||
"0000000000000000000000000000000000000000000000000000000000000080" + // modulus length
|
||||
testVectors["nagydani-2-qube"].base +
|
||||
testVectors["nagydani-2-qube"].exponent +
|
||||
testVectors["nagydani-2-qube"].modulus;
|
||||
const byteArray = hexToU8a(inputData);
|
||||
const inputLength = byteArray.length;
|
||||
const numZeroBytes = byteArray.filter((a) => a === 0).length;
|
||||
const numNonZeroBytes = inputLength - numZeroBytes;
|
||||
|
||||
const rawTxn = await createViemTransaction(context, {
|
||||
to: MODEXP_PRECOMPILE_ADDRESS,
|
||||
data: ("0x" + inputData) as `0x${string}`,
|
||||
gas: EXTRINSIC_GAS_LIMIT,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTxn);
|
||||
|
||||
const receipt = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result!.hash as `0x${string}` });
|
||||
expect(receipt.status).toBe("success");
|
||||
const expectedGasUsed = calculateEIP7623Gas(
|
||||
numZeroBytes,
|
||||
numNonZeroBytes,
|
||||
expectedModExpGasCost
|
||||
);
|
||||
expect(receipt.gasUsed, "ModExp gas pricing mismatch").to.equal(expectedGasUsed);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T11",
|
||||
title: "nagydani-2-pow0x10001 - gas",
|
||||
modifier: "skip",
|
||||
test: async function () {
|
||||
const expectedModExpGasCost = 3034n;
|
||||
const inputData =
|
||||
"0000000000000000000000000000000000000000000000000000000000000080" + // base length
|
||||
"0000000000000000000000000000000000000000000000000000000000000003" + // exponent length
|
||||
"0000000000000000000000000000000000000000000000000000000000000080" + // modulus length
|
||||
testVectors["nagydani-2-pow0x10001"].base +
|
||||
testVectors["nagydani-2-pow0x10001"].exponent +
|
||||
testVectors["nagydani-2-pow0x10001"].modulus;
|
||||
const byteArray = hexToU8a(inputData);
|
||||
const inputLength = byteArray.length;
|
||||
const numZeroBytes = byteArray.filter((a) => a === 0).length;
|
||||
const numNonZeroBytes = inputLength - numZeroBytes;
|
||||
|
||||
const rawTxn = await createViemTransaction(context, {
|
||||
to: MODEXP_PRECOMPILE_ADDRESS,
|
||||
data: ("0x" + inputData) as `0x${string}`,
|
||||
gas: EXTRINSIC_GAS_LIMIT,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTxn);
|
||||
|
||||
const receipt = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result!.hash as `0x${string}` });
|
||||
expect(receipt.status).toBe("success");
|
||||
const expectedGasUsed = calculateEIP7623Gas(
|
||||
numZeroBytes,
|
||||
numNonZeroBytes,
|
||||
expectedModExpGasCost
|
||||
);
|
||||
expect(receipt.gasUsed, "ModExp gas pricing mismatch").to.equal(expectedGasUsed);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T12",
|
||||
title: "nagydani-3-square - gas",
|
||||
modifier: "skip",
|
||||
test: async function () {
|
||||
const expectedModExpGasCost = 2010n;
|
||||
const inputData =
|
||||
"0000000000000000000000000000000000000000000000000000000000000100" + // base length
|
||||
"0000000000000000000000000000000000000000000000000000000000000001" + // exponent length
|
||||
"0000000000000000000000000000000000000000000000000000000000000100" + // modulus length
|
||||
testVectors["nagydani-3-square"].base +
|
||||
testVectors["nagydani-3-square"].exponent +
|
||||
testVectors["nagydani-3-square"].modulus;
|
||||
const byteArray = hexToU8a(inputData);
|
||||
const inputLength = byteArray.length;
|
||||
const numZeroBytes = byteArray.filter((a) => a === 0).length;
|
||||
const numNonZeroBytes = inputLength - numZeroBytes;
|
||||
|
||||
const rawTxn = await createViemTransaction(context, {
|
||||
to: MODEXP_PRECOMPILE_ADDRESS,
|
||||
data: ("0x" + inputData) as `0x${string}`,
|
||||
gas: EXTRINSIC_GAS_LIMIT,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTxn);
|
||||
|
||||
const receipt = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result!.hash as `0x${string}` });
|
||||
expect(receipt.status).toBe("success");
|
||||
const expectedGasUsed = calculateEIP7623Gas(
|
||||
numZeroBytes,
|
||||
numNonZeroBytes,
|
||||
expectedModExpGasCost
|
||||
);
|
||||
expect(receipt.gasUsed, "ModExp gas pricing mismatch").to.equal(expectedGasUsed);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T13",
|
||||
title: "nagydani-3-qube - gas",
|
||||
modifier: "skip",
|
||||
test: async function () {
|
||||
const expectedModExpGasCost = 2010n;
|
||||
const inputData =
|
||||
"0000000000000000000000000000000000000000000000000000000000000100" + // base length
|
||||
"0000000000000000000000000000000000000000000000000000000000000001" + // exponent length
|
||||
"0000000000000000000000000000000000000000000000000000000000000100" + // modulus length
|
||||
testVectors["nagydani-3-qube"].base +
|
||||
testVectors["nagydani-3-qube"].exponent +
|
||||
testVectors["nagydani-3-qube"].modulus;
|
||||
const byteArray = hexToU8a(inputData);
|
||||
const inputLength = byteArray.length;
|
||||
const numZeroBytes = byteArray.filter((a) => a === 0).length;
|
||||
const numNonZeroBytes = inputLength - numZeroBytes;
|
||||
|
||||
const rawTxn = await createViemTransaction(context, {
|
||||
to: MODEXP_PRECOMPILE_ADDRESS,
|
||||
data: ("0x" + inputData) as `0x${string}`,
|
||||
gas: EXTRINSIC_GAS_LIMIT,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTxn);
|
||||
|
||||
const receipt = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result!.hash as `0x${string}` });
|
||||
expect(receipt.status).toBe("success");
|
||||
const expectedGasUsed = calculateEIP7623Gas(
|
||||
numZeroBytes,
|
||||
numNonZeroBytes,
|
||||
expectedModExpGasCost
|
||||
);
|
||||
expect(receipt.gasUsed, "ModExp gas pricing mismatch").to.equal(expectedGasUsed);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T14",
|
||||
title: "nagydani-3-pow0x10001 - gas",
|
||||
modifier: "skip",
|
||||
test: async function () {
|
||||
const expectedModExpGasCost = 7130n;
|
||||
const inputData =
|
||||
"0000000000000000000000000000000000000000000000000000000000000100" + // base length
|
||||
"0000000000000000000000000000000000000000000000000000000000000003" + // exponent length
|
||||
"0000000000000000000000000000000000000000000000000000000000000100" + // modulus length
|
||||
testVectors["nagydani-3-pow0x10001"].base +
|
||||
testVectors["nagydani-3-pow0x10001"].exponent +
|
||||
testVectors["nagydani-3-pow0x10001"].modulus;
|
||||
const byteArray = hexToU8a(inputData);
|
||||
const inputLength = byteArray.length;
|
||||
const numZeroBytes = byteArray.filter((a) => a === 0).length;
|
||||
const numNonZeroBytes = inputLength - numZeroBytes;
|
||||
|
||||
const rawTxn = await createViemTransaction(context, {
|
||||
to: MODEXP_PRECOMPILE_ADDRESS,
|
||||
data: ("0x" + inputData) as `0x${string}`,
|
||||
gas: EXTRINSIC_GAS_LIMIT,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTxn);
|
||||
|
||||
const receipt = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result!.hash as `0x${string}` });
|
||||
expect(receipt.status).toBe("success");
|
||||
const expectedGasUsed = calculateEIP7623Gas(
|
||||
numZeroBytes,
|
||||
numNonZeroBytes,
|
||||
expectedModExpGasCost
|
||||
);
|
||||
expect(receipt.gasUsed, "ModExp gas pricing mismatch").to.equal(expectedGasUsed);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T15",
|
||||
title: "nagydani-4-square - gas",
|
||||
modifier: "skip",
|
||||
test: async function () {
|
||||
const expectedModExpGasCost = 3034n;
|
||||
const inputData =
|
||||
"0000000000000000000000000000000000000000000000000000000000000200" + // base length
|
||||
"0000000000000000000000000000000000000000000000000000000000000001" + // exponent length
|
||||
"0000000000000000000000000000000000000000000000000000000000000200" + // modulus length
|
||||
testVectors["nagydani-4-square"].base +
|
||||
testVectors["nagydani-4-square"].exponent +
|
||||
testVectors["nagydani-4-square"].modulus;
|
||||
const byteArray = hexToU8a(inputData);
|
||||
const inputLength = byteArray.length;
|
||||
const numZeroBytes = byteArray.filter((a) => a === 0).length;
|
||||
const numNonZeroBytes = inputLength - numZeroBytes;
|
||||
|
||||
const rawTxn = await createViemTransaction(context, {
|
||||
to: MODEXP_PRECOMPILE_ADDRESS,
|
||||
data: ("0x" + inputData) as `0x${string}`,
|
||||
gas: EXTRINSIC_GAS_LIMIT,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTxn);
|
||||
|
||||
const receipt = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result!.hash as `0x${string}` });
|
||||
expect(receipt.status).toBe("success");
|
||||
const expectedGasUsed = calculateEIP7623Gas(
|
||||
numZeroBytes,
|
||||
numNonZeroBytes,
|
||||
expectedModExpGasCost
|
||||
);
|
||||
expect(receipt.gasUsed, "ModExp gas pricing mismatch").to.equal(expectedGasUsed);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T16",
|
||||
title: "nagydani-4-qube - gas",
|
||||
modifier: "skip",
|
||||
test: async function () {
|
||||
const expectedModExpGasCost = 3034n;
|
||||
const inputData =
|
||||
"0000000000000000000000000000000000000000000000000000000000000200" + // base length
|
||||
"0000000000000000000000000000000000000000000000000000000000000001" + // exponent length
|
||||
"0000000000000000000000000000000000000000000000000000000000000200" + // modulus length
|
||||
testVectors["nagydani-4-qube"].base +
|
||||
testVectors["nagydani-4-qube"].exponent +
|
||||
testVectors["nagydani-4-qube"].modulus;
|
||||
const byteArray = hexToU8a(inputData);
|
||||
const inputLength = byteArray.length;
|
||||
const numZeroBytes = byteArray.filter((a) => a === 0).length;
|
||||
const numNonZeroBytes = inputLength - numZeroBytes;
|
||||
|
||||
const rawTxn = await createViemTransaction(context, {
|
||||
to: MODEXP_PRECOMPILE_ADDRESS,
|
||||
data: ("0x" + inputData) as `0x${string}`,
|
||||
gas: EXTRINSIC_GAS_LIMIT,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTxn);
|
||||
|
||||
const receipt = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result!.hash as `0x${string}` });
|
||||
expect(receipt.status).toBe("success");
|
||||
const expectedGasUsed = calculateEIP7623Gas(
|
||||
numZeroBytes,
|
||||
numNonZeroBytes,
|
||||
expectedModExpGasCost
|
||||
);
|
||||
expect(receipt.gasUsed, "ModExp gas pricing mismatch").to.equal(expectedGasUsed);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T17",
|
||||
title: "nagydani-4-pow0x10001 - gas",
|
||||
modifier: "skip",
|
||||
test: async function () {
|
||||
const expectedModExpGasCost = 23514n;
|
||||
const inputData =
|
||||
"0000000000000000000000000000000000000000000000000000000000000200" + // base length
|
||||
"0000000000000000000000000000000000000000000000000000000000000003" + // exponent length
|
||||
"0000000000000000000000000000000000000000000000000000000000000200" + // modulus length
|
||||
testVectors["nagydani-4-pow0x10001"].base +
|
||||
testVectors["nagydani-4-pow0x10001"].exponent +
|
||||
testVectors["nagydani-4-pow0x10001"].modulus;
|
||||
const byteArray = hexToU8a(inputData);
|
||||
const inputLength = byteArray.length;
|
||||
const numZeroBytes = byteArray.filter((a) => a === 0).length;
|
||||
const numNonZeroBytes = inputLength - numZeroBytes;
|
||||
|
||||
const rawTxn = await createViemTransaction(context, {
|
||||
to: MODEXP_PRECOMPILE_ADDRESS,
|
||||
data: ("0x" + inputData) as `0x${string}`,
|
||||
gas: EXTRINSIC_GAS_LIMIT,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTxn);
|
||||
|
||||
const receipt = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result!.hash as `0x${string}` });
|
||||
expect(receipt.status).toBe("success");
|
||||
const expectedGasUsed = calculateEIP7623Gas(
|
||||
numZeroBytes,
|
||||
numNonZeroBytes,
|
||||
expectedModExpGasCost
|
||||
);
|
||||
expect(receipt.gasUsed, "ModExp gas pricing mismatch").to.equal(expectedGasUsed);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T18",
|
||||
title: "nagydani-5-square - gas",
|
||||
modifier: "skip",
|
||||
test: async function () {
|
||||
const expectedModExpGasCost = 7130n;
|
||||
const inputData =
|
||||
"0000000000000000000000000000000000000000000000000000000000000400" + // base length
|
||||
"0000000000000000000000000000000000000000000000000000000000000001" + // exponent length
|
||||
"0000000000000000000000000000000000000000000000000000000000000400" + // modulus length
|
||||
testVectors["nagydani-5-square"].base +
|
||||
testVectors["nagydani-5-square"].exponent +
|
||||
testVectors["nagydani-5-square"].modulus;
|
||||
const byteArray = hexToU8a(inputData);
|
||||
const inputLength = byteArray.length;
|
||||
const numZeroBytes = byteArray.filter((a) => a === 0).length;
|
||||
const numNonZeroBytes = inputLength - numZeroBytes;
|
||||
|
||||
const rawTxn = await createViemTransaction(context, {
|
||||
to: MODEXP_PRECOMPILE_ADDRESS,
|
||||
data: ("0x" + inputData) as `0x${string}`,
|
||||
gas: EXTRINSIC_GAS_LIMIT,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTxn);
|
||||
|
||||
const receipt = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result!.hash as `0x${string}` });
|
||||
expect(receipt.status).toBe("success");
|
||||
const expectedGasUsed = calculateEIP7623Gas(
|
||||
numZeroBytes,
|
||||
numNonZeroBytes,
|
||||
expectedModExpGasCost
|
||||
);
|
||||
expect(receipt.gasUsed, "ModExp gas pricing mismatch").to.equal(expectedGasUsed);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T19",
|
||||
title: "nagydani-5-qube - gas",
|
||||
modifier: "skip",
|
||||
test: async function () {
|
||||
const expectedModExpGasCost = 7130n;
|
||||
const inputData =
|
||||
"0000000000000000000000000000000000000000000000000000000000000400" + // base length
|
||||
"0000000000000000000000000000000000000000000000000000000000000001" + // exponent length
|
||||
"0000000000000000000000000000000000000000000000000000000000000400" + // modulus length
|
||||
testVectors["nagydani-5-qube"].base +
|
||||
testVectors["nagydani-5-qube"].exponent +
|
||||
testVectors["nagydani-5-qube"].modulus;
|
||||
const byteArray = hexToU8a(inputData);
|
||||
const inputLength = byteArray.length;
|
||||
const numZeroBytes = byteArray.filter((a) => a === 0).length;
|
||||
const numNonZeroBytes = inputLength - numZeroBytes;
|
||||
|
||||
const rawTxn = await createViemTransaction(context, {
|
||||
to: MODEXP_PRECOMPILE_ADDRESS,
|
||||
data: ("0x" + inputData) as `0x${string}`,
|
||||
gas: EXTRINSIC_GAS_LIMIT,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTxn);
|
||||
|
||||
const receipt = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result!.hash as `0x${string}` });
|
||||
expect(receipt.status).toBe("success");
|
||||
const expectedGasUsed = calculateEIP7623Gas(
|
||||
numZeroBytes,
|
||||
numNonZeroBytes,
|
||||
expectedModExpGasCost
|
||||
);
|
||||
expect(receipt.gasUsed, "ModExp gas pricing mismatch").to.equal(expectedGasUsed);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T20",
|
||||
title: "nagydani-5-pow0x10001 - gas",
|
||||
modifier: "skip",
|
||||
test: async function () {
|
||||
const expectedModExpGasCost = 89749n;
|
||||
const inputData =
|
||||
"0000000000000000000000000000000000000000000000000000000000000400" + // base length
|
||||
"0000000000000000000000000000000000000000000000000000000000000003" + // exponent length
|
||||
"0000000000000000000000000000000000000000000000000000000000000400" + // modulus length
|
||||
testVectors["nagydani-5-pow0x10001"].base +
|
||||
testVectors["nagydani-5-pow0x10001"].exponent +
|
||||
testVectors["nagydani-5-pow0x10001"].modulus;
|
||||
const byteArray = hexToU8a(inputData);
|
||||
const inputLength = byteArray.length;
|
||||
const numZeroBytes = byteArray.filter((a) => a === 0).length;
|
||||
const numNonZeroBytes = inputLength - numZeroBytes;
|
||||
|
||||
const rawTxn = await createViemTransaction(context, {
|
||||
to: MODEXP_PRECOMPILE_ADDRESS,
|
||||
data: ("0x" + inputData) as `0x${string}`,
|
||||
gas: EXTRINSIC_GAS_LIMIT,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTxn);
|
||||
|
||||
const receipt = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result!.hash as `0x${string}` });
|
||||
expect(receipt.status).toBe("success");
|
||||
const expectedGasUsed = calculateEIP7623Gas(
|
||||
numZeroBytes,
|
||||
numNonZeroBytes,
|
||||
expectedModExpGasCost
|
||||
);
|
||||
expect(receipt.gasUsed, "ModExp gas pricing mismatch").to.equal(expectedGasUsed);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T21",
|
||||
title: "Exponent > 32",
|
||||
modifier: "skip",
|
||||
test: async function () {
|
||||
// We multiply by a factor of 20 for an even mod.
|
||||
// See https://github.com/paritytech/frontier/pull/1017
|
||||
const expectedModExpGasCost = 7104n * 20n;
|
||||
const byteArray = new Uint8Array([
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x26, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x02, 0x0, 0x0,
|
||||
0xb3, 0x0, 0x0, 0x02, 0x0, 0x0, 0x7a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff,
|
||||
0xfb, 0x0, 0x0, 0x0, 0x0, 0x04, 0x26, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 96, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x02, 0x0, 0x0, 0xb3, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xf9,
|
||||
]);
|
||||
const inputData = u8aToHex(byteArray);
|
||||
const inputLength = byteArray.length;
|
||||
const numZeroBytes = byteArray.filter((a) => a === 0).length;
|
||||
const numNonZeroBytes = inputLength - numZeroBytes;
|
||||
|
||||
const rawTxn = await createViemTransaction(context, {
|
||||
to: MODEXP_PRECOMPILE_ADDRESS,
|
||||
data: inputData,
|
||||
gas: EXTRINSIC_GAS_LIMIT,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTxn);
|
||||
|
||||
const receipt = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result!.hash as `0x${string}` });
|
||||
expect(receipt.status).toBe("success");
|
||||
const isPrecompileCheckGas = 2368n;
|
||||
const expectedGasUsed = calculateEIP7623Gas(
|
||||
numZeroBytes,
|
||||
numNonZeroBytes,
|
||||
expectedModExpGasCost + isPrecompileCheckGas
|
||||
);
|
||||
expect(receipt.gasUsed, "ModExp gas pricing mismatch").to.equal(expectedGasUsed);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T22",
|
||||
title: "should pad input when too short",
|
||||
test: async function () {
|
||||
const inputData =
|
||||
"0000000000000000000000000000000000000000000000000000000000000001" + // base length
|
||||
"0000000000000000000000000000000000000000000000000000000000000001" + // exponent length
|
||||
"0000000000000000000000000000000000000000000000000000000000000002" + // modulus length
|
||||
"05" + // base
|
||||
"03" + // exponent
|
||||
"01"; // modulus
|
||||
|
||||
const rawTxn = await createViemTransaction(context, {
|
||||
to: MODEXP_PRECOMPILE_ADDRESS,
|
||||
data: ("0x" + inputData) as `0x${string}`,
|
||||
gas: EXTRINSIC_GAS_LIMIT,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTxn);
|
||||
|
||||
const receipt = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: result!.hash as `0x${string}` });
|
||||
expect(receipt.status).toBe("success");
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
import "@moonbeam-network/api-augment";
|
||||
import { beforeAll, beforeEach, describeSuite, expect, fetchCompiledContract } from "@moonwall/cli";
|
||||
import { type Abi, decodeEventLog } from "viem";
|
||||
import { Preimage, expectEVMResult, expectSubstrateEvent } from "../../../../helpers";
|
||||
|
||||
// Each test is instantiating a new proposal (Not ideal for isolation but easier to write)
|
||||
// Be careful to not reach the maximum number of proposals.
|
||||
describeSuite({
|
||||
id: "D030501",
|
||||
title: "Precompiles - Preimage precompile",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ it, log, context }) => {
|
||||
let PreimageAbi: Abi;
|
||||
let preimage: Preimage;
|
||||
|
||||
beforeAll(async function () {
|
||||
const { abi } = fetchCompiledContract("Preimage");
|
||||
PreimageAbi = abi;
|
||||
});
|
||||
|
||||
beforeEach(async function () {
|
||||
preimage = new Preimage(context);
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should allow to note Preimage",
|
||||
test: async function () {
|
||||
const call = context.polkadotJs().tx.identity.setIdentity({ display: { raw: "Me" } });
|
||||
const block = await preimage.notePreimage(call.toHex()).block();
|
||||
|
||||
// Verifies the EVM Side
|
||||
expectEVMResult(block.result!.events, "Succeed");
|
||||
const { data } = expectSubstrateEvent(block, "evm", "Log");
|
||||
const evmLog = decodeEventLog({
|
||||
abi: PreimageAbi,
|
||||
topics: data[0].topics.map((t) => t.toHex()) as any,
|
||||
data: data[0].data.toHex(),
|
||||
}) as any;
|
||||
expect(evmLog.eventName, "Wrong event").to.equal("PreimageNoted");
|
||||
expect(evmLog.args.hash).to.equal(call.hash.toHex());
|
||||
|
||||
// Verifies the Substrate side
|
||||
const preImage = await context
|
||||
.polkadotJs()
|
||||
.query.preimage.preimageFor([call.hash.toHex(), 15]);
|
||||
expect(preImage.unwrap().toHex()).to.equal(call.toHex());
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T02",
|
||||
title: "should allow to unnote a Preimage",
|
||||
test: async function () {
|
||||
const call = context.polkadotJs().tx.identity.setIdentity({ display: { raw: "You" } });
|
||||
await preimage.notePreimage(call.toHex()).block();
|
||||
const block = await preimage.unnotePreimage(call.hash.toHex()).block();
|
||||
|
||||
// Verifies the EVM Side
|
||||
expectEVMResult(block.result!.events, "Succeed");
|
||||
const { data } = expectSubstrateEvent(block, "evm", "Log");
|
||||
const evmLog = decodeEventLog({
|
||||
abi: PreimageAbi,
|
||||
topics: data[0].topics.map((t) => t.toHex()) as any,
|
||||
data: data[0].data.toHex(),
|
||||
}) as any;
|
||||
// context.readPrecompile!({functionName})
|
||||
expect(evmLog.eventName, "Wrong event").to.equal("PreimageUnnoted");
|
||||
expect(evmLog.args.hash).to.equal(call.hash.toHex());
|
||||
|
||||
// Verifies the Substrate side
|
||||
const preImage = await context
|
||||
.polkadotJs()
|
||||
.query.preimage.preimageFor([call.hash.toHex(), 1000]);
|
||||
expect(preImage.isNone).to.equal(true);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T03",
|
||||
title: "should fail to note the same Preimage twice",
|
||||
test: async function () {
|
||||
const call = context.polkadotJs().tx.identity.setIdentity({ display: { raw: "Repeated" } });
|
||||
await preimage.notePreimage(call.toHex()).block();
|
||||
await expect(
|
||||
async () => await preimage.notePreimage(call.toHex()).block(),
|
||||
"Transaction should be reverted but instead preimage noted"
|
||||
).rejects.toThrowError("AlreadyNoted");
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T04",
|
||||
title: "should fail to unnote a missing Preimage",
|
||||
test: async function () {
|
||||
const call = context
|
||||
.polkadotJs()
|
||||
.tx.identity.setIdentity({ display: { raw: "Missing Preimage" } });
|
||||
await expect(
|
||||
async () => await preimage.unnotePreimage(call.hash.toHex()).block(),
|
||||
"Transaction should be reverted but instead preimage unnoted"
|
||||
).rejects.toThrowError("NotNoted");
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,544 @@
|
|||
/**
|
||||
* Proxy precompile tests
|
||||
* Tests the Proxy precompile API for managing proxy accounts via EVM
|
||||
*/
|
||||
|
||||
import { describeSuite, expect, fetchCompiledContract } from "@moonwall/cli";
|
||||
import {
|
||||
ALITH_ADDRESS,
|
||||
BALTATHAR_ADDRESS,
|
||||
BALTATHAR_PRIVATE_KEY,
|
||||
CHARLETH_ADDRESS,
|
||||
CHARLETH_PRIVATE_KEY,
|
||||
createViemTransaction,
|
||||
sendRawTransaction,
|
||||
} from "@moonwall/util";
|
||||
import { encodeFunctionData } from "viem";
|
||||
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
|
||||
import { expectEVMResult, PRECOMPILE_PROXY_ADDRESS } from "../../../../helpers";
|
||||
|
||||
// Proxy type constants (matching Substrate proxy types from Proxy.sol)
|
||||
const CONTRACT_PROXY_TYPE_ANY = 0;
|
||||
const CONTRACT_PROXY_TYPE_NON_TRANSFER = 1;
|
||||
const CONTRACT_PROXY_TYPE_GOVERNANCE = 2;
|
||||
const CONTRACT_PROXY_TYPE_STAKING = 3;
|
||||
const CONTRACT_PROXY_TYPE_CANCEL_PROXY = 4;
|
||||
const CONTRACT_PROXY_TYPE_BALANCES = 5;
|
||||
|
||||
// Invalid proxy type for testing error handling
|
||||
const CONTRACT_PROXY_TYPE_INVALID = 99;
|
||||
|
||||
describeSuite({
|
||||
id: "D030601",
|
||||
title: "Precompile - Proxy",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ it, log, context }) => {
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should succeed adding a proxy",
|
||||
test: async () => {
|
||||
const randomAccount = privateKeyToAccount(generatePrivateKey()).address;
|
||||
|
||||
const rawTx = await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "addProxy",
|
||||
args: [randomAccount, CONTRACT_PROXY_TYPE_STAKING, 0],
|
||||
rawTxOnly: true,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTx);
|
||||
expectEVMResult(result!.events, "Succeed");
|
||||
|
||||
// Verify proxy was added via substrate
|
||||
const proxies = await context.polkadotJs().query.proxy.proxies(ALITH_ADDRESS);
|
||||
const hasProxy = proxies[0].some(
|
||||
(p: any) =>
|
||||
p.delegate.toString() === randomAccount && p.proxyType.toString() === "Staking"
|
||||
);
|
||||
expect(hasProxy).to.be.true;
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T02",
|
||||
title: "should fail re-adding the same proxy",
|
||||
test: async () => {
|
||||
const randomAccount = privateKeyToAccount(generatePrivateKey()).address;
|
||||
|
||||
// First add
|
||||
const rawTx = await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "addProxy",
|
||||
args: [randomAccount, CONTRACT_PROXY_TYPE_STAKING, 0],
|
||||
rawTxOnly: true,
|
||||
});
|
||||
await context.createBlock(rawTx);
|
||||
|
||||
// Second add should fail with exact error message
|
||||
await expect(
|
||||
async () =>
|
||||
await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "addProxy",
|
||||
args: [randomAccount, CONTRACT_PROXY_TYPE_STAKING, 0],
|
||||
})
|
||||
).rejects.toThrowError("Cannot add more than one proxy");
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T03",
|
||||
title: "should fail removing non-existent proxy",
|
||||
test: async () => {
|
||||
const randomAccount = privateKeyToAccount(generatePrivateKey()).address;
|
||||
|
||||
await expect(
|
||||
async () =>
|
||||
await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "removeProxy",
|
||||
args: [randomAccount, CONTRACT_PROXY_TYPE_STAKING, 0],
|
||||
})
|
||||
).rejects.toThrowError(/NotFound/i);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T04",
|
||||
title: "should succeed removing an existing proxy",
|
||||
test: async () => {
|
||||
const randomAccount = privateKeyToAccount(generatePrivateKey()).address;
|
||||
|
||||
// Add proxy
|
||||
const addTx = await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "addProxy",
|
||||
args: [randomAccount, CONTRACT_PROXY_TYPE_STAKING, 0],
|
||||
rawTxOnly: true,
|
||||
});
|
||||
await context.createBlock(addTx);
|
||||
|
||||
// Remove proxy
|
||||
const rawTx = await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "removeProxy",
|
||||
args: [randomAccount, CONTRACT_PROXY_TYPE_STAKING, 0],
|
||||
rawTxOnly: true,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTx);
|
||||
expectEVMResult(result!.events, "Succeed");
|
||||
|
||||
// Verify proxy was removed
|
||||
const proxies = await context.polkadotJs().query.proxy.proxies(ALITH_ADDRESS);
|
||||
const hasProxy = proxies[0].some((p: any) => p.delegate.toString() === randomAccount);
|
||||
expect(hasProxy).to.be.false;
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T05",
|
||||
title: "should succeed removing all proxies",
|
||||
test: async () => {
|
||||
// First ensure no proxies exist
|
||||
const proxiesInitial = await context.polkadotJs().query.proxy.proxies(ALITH_ADDRESS);
|
||||
if (proxiesInitial[0].length > 0) {
|
||||
const clearTx = await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "removeProxies",
|
||||
rawTxOnly: true,
|
||||
});
|
||||
await context.createBlock(clearTx);
|
||||
}
|
||||
|
||||
// Add exactly two proxies
|
||||
const account1 = privateKeyToAccount(generatePrivateKey()).address;
|
||||
const account2 = privateKeyToAccount(generatePrivateKey()).address;
|
||||
|
||||
const addTx1 = await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "addProxy",
|
||||
args: [account1, CONTRACT_PROXY_TYPE_STAKING, 0],
|
||||
rawTxOnly: true,
|
||||
});
|
||||
await context.createBlock(addTx1);
|
||||
|
||||
const addTx2 = await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "addProxy",
|
||||
args: [account2, CONTRACT_PROXY_TYPE_GOVERNANCE, 0],
|
||||
rawTxOnly: true,
|
||||
});
|
||||
await context.createBlock(addTx2);
|
||||
|
||||
const proxiesBefore = await context.polkadotJs().query.proxy.proxies(ALITH_ADDRESS);
|
||||
expect(proxiesBefore[0].length).toBe(2);
|
||||
|
||||
// Remove all proxies
|
||||
const rawTx = await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "removeProxies",
|
||||
rawTxOnly: true,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTx);
|
||||
expectEVMResult(result!.events, "Succeed");
|
||||
|
||||
const proxiesAfter = await context.polkadotJs().query.proxy.proxies(ALITH_ADDRESS);
|
||||
expect(proxiesAfter[0].length).toBe(0);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T06",
|
||||
title: "should correctly report proxy status via isProxy",
|
||||
test: async () => {
|
||||
const randomAccount = privateKeyToAccount(generatePrivateKey()).address;
|
||||
|
||||
// Check isProxy returns false before adding any proxy
|
||||
const isProxyBefore = await context.readContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "isProxy",
|
||||
args: [ALITH_ADDRESS, randomAccount, CONTRACT_PROXY_TYPE_STAKING, 0],
|
||||
});
|
||||
expect(isProxyBefore).to.be.false;
|
||||
|
||||
// Add proxy
|
||||
const rawTx = await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "addProxy",
|
||||
args: [randomAccount, CONTRACT_PROXY_TYPE_STAKING, 0],
|
||||
rawTxOnly: true,
|
||||
});
|
||||
await context.createBlock(rawTx);
|
||||
|
||||
// Check isProxy returns true for correct parameters
|
||||
const isProxy = await context.readContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "isProxy",
|
||||
args: [ALITH_ADDRESS, randomAccount, CONTRACT_PROXY_TYPE_STAKING, 0],
|
||||
});
|
||||
expect(isProxy).to.be.true;
|
||||
|
||||
// Check isProxy returns false for wrong type
|
||||
const isProxyWrongType = await context.readContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "isProxy",
|
||||
args: [ALITH_ADDRESS, randomAccount, CONTRACT_PROXY_TYPE_ANY, 0],
|
||||
});
|
||||
expect(isProxyWrongType).to.be.false;
|
||||
|
||||
// Check isProxy returns false for wrong delay
|
||||
const isProxyWrongDelay = await context.readContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "isProxy",
|
||||
args: [ALITH_ADDRESS, randomAccount, CONTRACT_PROXY_TYPE_STAKING, 2],
|
||||
});
|
||||
expect(isProxyWrongDelay).to.be.false;
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T07",
|
||||
title: "should reject proxy call from non-proxy account",
|
||||
test: async () => {
|
||||
// BALTATHAR tries to make a proxy call on behalf of ALITH without being a proxy
|
||||
const { abi } = fetchCompiledContract("Proxy");
|
||||
await expect(
|
||||
async () =>
|
||||
await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "proxy",
|
||||
args: [ALITH_ADDRESS, CHARLETH_ADDRESS, "0x00"],
|
||||
privateKey: BALTATHAR_PRIVATE_KEY,
|
||||
})
|
||||
).rejects.toThrowError("Not proxy");
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T08",
|
||||
title: "should allow proxy call from valid proxy account",
|
||||
test: async () => {
|
||||
const privateKey = generatePrivateKey();
|
||||
const randomAccount = privateKeyToAccount(privateKey).address;
|
||||
|
||||
// Add BALTATHAR as proxy for ALITH with Any type
|
||||
const rawTx = await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "addProxy",
|
||||
args: [BALTATHAR_ADDRESS, CONTRACT_PROXY_TYPE_ANY, 0],
|
||||
rawTxOnly: true,
|
||||
});
|
||||
await context.createBlock(rawTx);
|
||||
|
||||
// Use BALTATHAR to transfer value on behalf of ALITH
|
||||
const { abi } = fetchCompiledContract("Proxy");
|
||||
const proxyTx = await createViemTransaction(context, {
|
||||
to: PRECOMPILE_PROXY_ADDRESS,
|
||||
privateKey: BALTATHAR_PRIVATE_KEY,
|
||||
value: 1000n,
|
||||
data: encodeFunctionData({
|
||||
abi,
|
||||
functionName: "proxy",
|
||||
args: [ALITH_ADDRESS, randomAccount, "0x00"],
|
||||
}),
|
||||
});
|
||||
const txHash = (await sendRawTransaction(context, proxyTx)) as `0x${string}`;
|
||||
|
||||
// Create two blocks to ensure the transaction is included
|
||||
await context.createBlock();
|
||||
await context.createBlock();
|
||||
|
||||
const receipt = await context.viem().getTransactionReceipt({ hash: txHash });
|
||||
expect(receipt.status).toBe("success");
|
||||
|
||||
// Verify transfer happened
|
||||
expect(await context.viem().getBalance({ address: randomAccount })).toBe(1000n);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T09",
|
||||
title: "should succeed with proxyForceType for matching proxy type",
|
||||
test: async () => {
|
||||
const privateKey = generatePrivateKey();
|
||||
const randomAccount = privateKeyToAccount(privateKey).address;
|
||||
|
||||
// Add CHARLETH as Balances proxy for ALITH
|
||||
const rawTx = await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "addProxy",
|
||||
args: [CHARLETH_ADDRESS, CONTRACT_PROXY_TYPE_BALANCES, 0],
|
||||
rawTxOnly: true,
|
||||
});
|
||||
await context.createBlock(rawTx);
|
||||
|
||||
// Use CHARLETH to transfer value on behalf of ALITH using proxyForceType
|
||||
const { abi } = fetchCompiledContract("Proxy");
|
||||
const proxyTx = await createViemTransaction(context, {
|
||||
to: PRECOMPILE_PROXY_ADDRESS,
|
||||
privateKey: CHARLETH_PRIVATE_KEY,
|
||||
value: 500n,
|
||||
data: encodeFunctionData({
|
||||
abi,
|
||||
functionName: "proxyForceType",
|
||||
args: [ALITH_ADDRESS, CONTRACT_PROXY_TYPE_BALANCES, randomAccount, "0x00"],
|
||||
}),
|
||||
});
|
||||
const { result } = await context.createBlock(proxyTx);
|
||||
expectEVMResult(result!.events, "Succeed");
|
||||
|
||||
// Verify transfer happened
|
||||
expect(await context.viem().getBalance({ address: randomAccount })).toBe(500n);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T10",
|
||||
title: "should fail proxyForceType with mismatched proxy type",
|
||||
test: async () => {
|
||||
// CHARLETH is a Balances proxy for ALITH (from T09 or set up here)
|
||||
const proxies = await context.polkadotJs().query.proxy.proxies(ALITH_ADDRESS);
|
||||
const hasBalancesProxy = proxies[0].some(
|
||||
(p: any) =>
|
||||
p.delegate.toString() === CHARLETH_ADDRESS && p.proxyType.toString() === "Balances"
|
||||
);
|
||||
|
||||
if (!hasBalancesProxy) {
|
||||
const rawTx = await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "addProxy",
|
||||
args: [CHARLETH_ADDRESS, CONTRACT_PROXY_TYPE_BALANCES, 0],
|
||||
rawTxOnly: true,
|
||||
});
|
||||
await context.createBlock(rawTx);
|
||||
}
|
||||
|
||||
// Try to use proxyForceType with Governance type (CHARLETH only has Balances)
|
||||
await expect(
|
||||
async () =>
|
||||
await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "proxyForceType",
|
||||
args: [ALITH_ADDRESS, CONTRACT_PROXY_TYPE_GOVERNANCE, BALTATHAR_ADDRESS, "0x00"],
|
||||
privateKey: CHARLETH_PRIVATE_KEY,
|
||||
})
|
||||
).rejects.toThrowError(/Not proxy/i);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T11",
|
||||
title: "should fail addProxy with invalid proxy type value",
|
||||
test: async () => {
|
||||
const randomAccount = privateKeyToAccount(generatePrivateKey()).address;
|
||||
|
||||
await expect(
|
||||
async () =>
|
||||
await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "addProxy",
|
||||
args: [randomAccount, CONTRACT_PROXY_TYPE_INVALID, 0],
|
||||
})
|
||||
).rejects.toThrowError(/Failed decoding value to ProxyType/i);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T12",
|
||||
title: "should succeed removeProxies when no proxies exist",
|
||||
test: async () => {
|
||||
// Use a fresh account that has no proxies
|
||||
const privateKey = generatePrivateKey();
|
||||
const freshAccount = privateKeyToAccount(privateKey);
|
||||
|
||||
// Fund the fresh account so it can make transactions
|
||||
const fundTx = await createViemTransaction(context, {
|
||||
to: freshAccount.address,
|
||||
value: 10n * 10n ** 18n, // 10 tokens
|
||||
});
|
||||
await context.createBlock(fundTx);
|
||||
|
||||
// Verify no proxies exist for this account
|
||||
const proxiesBefore = await context
|
||||
.polkadotJs()
|
||||
.query.proxy.proxies(freshAccount.address);
|
||||
expect(proxiesBefore[0].length).toBe(0);
|
||||
|
||||
// removeProxies should succeed even with no proxies
|
||||
const rawTx = await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "removeProxies",
|
||||
privateKey: privateKey,
|
||||
rawTxOnly: true,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTx);
|
||||
expectEVMResult(result!.events, "Succeed");
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T13",
|
||||
title: "should correctly handle non-zero delay proxy",
|
||||
test: async () => {
|
||||
const randomAccount = privateKeyToAccount(generatePrivateKey()).address;
|
||||
const delay = 5;
|
||||
|
||||
// Add proxy with non-zero delay
|
||||
const rawTx = await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "addProxy",
|
||||
args: [randomAccount, CONTRACT_PROXY_TYPE_STAKING, delay],
|
||||
rawTxOnly: true,
|
||||
});
|
||||
const { result } = await context.createBlock(rawTx);
|
||||
expectEVMResult(result!.events, "Succeed");
|
||||
|
||||
// Verify proxy was added with correct delay via substrate
|
||||
const proxies = await context.polkadotJs().query.proxy.proxies(ALITH_ADDRESS);
|
||||
const proxyEntry = proxies[0].find(
|
||||
(p: any) =>
|
||||
p.delegate.toString() === randomAccount && p.proxyType.toString() === "Staking"
|
||||
);
|
||||
expect(proxyEntry).toBeDefined();
|
||||
expect(proxyEntry.delay.toNumber()).toBe(delay);
|
||||
|
||||
// isProxy should return true with correct delay
|
||||
const isProxyCorrectDelay = await context.readContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "isProxy",
|
||||
args: [ALITH_ADDRESS, randomAccount, CONTRACT_PROXY_TYPE_STAKING, delay],
|
||||
});
|
||||
expect(isProxyCorrectDelay).to.be.true;
|
||||
|
||||
// isProxy should return false with wrong delay (0)
|
||||
const isProxyWrongDelay = await context.readContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "isProxy",
|
||||
args: [ALITH_ADDRESS, randomAccount, CONTRACT_PROXY_TYPE_STAKING, 0],
|
||||
});
|
||||
expect(isProxyWrongDelay).to.be.false;
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T14",
|
||||
title: "should fail proxyForceType with invalid proxy type value",
|
||||
test: async () => {
|
||||
await expect(
|
||||
async () =>
|
||||
await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "proxyForceType",
|
||||
args: [ALITH_ADDRESS, CONTRACT_PROXY_TYPE_INVALID, CHARLETH_ADDRESS, "0x00"],
|
||||
privateKey: BALTATHAR_PRIVATE_KEY,
|
||||
})
|
||||
).rejects.toThrowError(/Failed decoding value to ProxyType/i);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T15",
|
||||
title: "should fail adding proxy with different type for same delegate",
|
||||
test: async () => {
|
||||
const randomAccount = privateKeyToAccount(generatePrivateKey()).address;
|
||||
|
||||
// First add with Staking type
|
||||
const rawTx = await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "addProxy",
|
||||
args: [randomAccount, CONTRACT_PROXY_TYPE_STAKING, 0],
|
||||
rawTxOnly: true,
|
||||
});
|
||||
await context.createBlock(rawTx);
|
||||
|
||||
// Try to add same delegate with different type (Any - more permissive)
|
||||
await expect(
|
||||
async () =>
|
||||
await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "addProxy",
|
||||
args: [randomAccount, CONTRACT_PROXY_TYPE_ANY, 0],
|
||||
})
|
||||
).rejects.toThrowError("Cannot add more than one proxy");
|
||||
|
||||
// Try to add same delegate with different type (Governance - less permissive)
|
||||
await expect(
|
||||
async () =>
|
||||
await context.writeContract!({
|
||||
contractAddress: PRECOMPILE_PROXY_ADDRESS,
|
||||
contractName: "Proxy",
|
||||
functionName: "addProxy",
|
||||
args: [randomAccount, CONTRACT_PROXY_TYPE_GOVERNANCE, 0],
|
||||
})
|
||||
).rejects.toThrowError("Cannot add more than one proxy");
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* RIPEMD-160 precompile tests
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { describeSuite, expect } from "@moonwall/cli";
|
||||
import { toHex } from "viem";
|
||||
import { expectEVMResult } from "../../../../helpers";
|
||||
|
||||
describeSuite({
|
||||
id: "D030105",
|
||||
title: "Precompiles - ripemd160",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, log, it }) => {
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should be valid",
|
||||
test: async function () {
|
||||
expect(
|
||||
(
|
||||
await context.viem().call({
|
||||
to: "0x0000000000000000000000000000000000000003",
|
||||
data: toHex("Hello world!"),
|
||||
})
|
||||
).data
|
||||
).equals("0x0000000000000000000000007f772647d88750add82d8e1a7a3e5c0902a346a3");
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T02",
|
||||
title: "should be accessible from a smart contract",
|
||||
test: async function () {
|
||||
const { contractAddress } = await context.deployContract!("HasherChecker");
|
||||
|
||||
// Execute the contract ripemd160 call
|
||||
const rawTxn = await context.writeContract!({
|
||||
contractAddress,
|
||||
contractName: "HasherChecker",
|
||||
functionName: "ripemd160Check",
|
||||
rawTxOnly: true,
|
||||
});
|
||||
|
||||
const { result } = await context.createBlock(rawTxn);
|
||||
|
||||
expectEVMResult(result!.events, "Succeed");
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* SHA3-FIPS precompile tests
|
||||
* Adapted from Moonbeam test suite
|
||||
*/
|
||||
|
||||
import { describeSuite, expect } from "@moonwall/cli";
|
||||
|
||||
describeSuite({
|
||||
id: "D030106",
|
||||
title: "Precompiles - sha3fips",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, it, log }) => {
|
||||
// Test taken from https://github.com/binance-chain/bsc/pull/118
|
||||
it({
|
||||
id: "T01",
|
||||
title: "sha3fips should be valid",
|
||||
test: async function () {
|
||||
expect(
|
||||
(
|
||||
await context.viem().call({
|
||||
to: "0x0000000000000000000000000000000000000400",
|
||||
data: ("0x0448250ebe88d77e0a12bcf530fe6a2cf1ac176945638d309b840d631940c93b78c2bd" +
|
||||
"6d16f227a8877e3f1604cd75b9c5a8ab0cac95174a8a0a0f8ea9e4c10bca") as `0x${string}`,
|
||||
})
|
||||
).data
|
||||
).equals("0xc7647f7e251bf1bd70863c8693e93a4e77dd0c9a689073e987d51254317dc704");
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
Loading…
Reference in a new issue