difftreelog
test add bench for nesting (#963)
in: master
* feat: added bench for nesting * fix: nitpicks * fix: remove unused deps * test(market): compilator version has been changed * use toolchain version from .env fir codestyle wf * fix: fmt * chore: update `proc-macro2` dep Updated from 1.0.59 to 1.0.63 * Fix solidity version ---------
16 files changed
.github/workflows/codestyle.ymldiffbeforeafterboth--- a/.github/workflows/codestyle.yml
+++ b/.github/workflows/codestyle.yml
@@ -16,9 +16,12 @@
- uses: actions/checkout@v3.1.0
with:
ref: ${{ github.head_ref }}
- - name: Install latest nightly
- uses: dtolnay/rust-toolchain@nightly
+ - name: Read .env file
+ uses: xom9ikk/dotenv@v2
+ - name: Install toolchain version from .env
+ uses: dtolnay/rust-toolchain@master
with:
+ toolchain: ${{ env.RUST_TOOLCHAIN }}
targets: wasm32-unknown-unknown
components: rustfmt, clippy
- name: Run cargo fmt
@@ -50,9 +53,12 @@
- uses: actions/checkout@v3.1.0
- name: Install substrate dependencies
run: sudo apt install -y libssl-dev pkg-config libclang-dev clang protobuf-compiler
- - name: Install latest nightly
- uses: dtolnay/rust-toolchain@nightly
+ - name: Read .env file
+ uses: xom9ikk/dotenv@v2
+ - name: Install toolchain version from .env
+ uses: dtolnay/rust-toolchain@master
with:
+ toolchain: ${{ env.RUST_TOOLCHAIN }}
targets: wasm32-unknown-unknown
components: rustfmt, clippy
- name: Run cargo check
.vscode/settings.jsondiffbeforeafterboth--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,16 +1,14 @@
{
- "eslint.format.enable": true,
- "[javascript]": {
- "editor.defaultFormatter": "dbaeumer.vscode-eslint"
- },
- "[typescript]": {
- "editor.defaultFormatter": "dbaeumer.vscode-eslint"
- },
- "rust-analyzer.cargo.extraEnv": {
- "SKIP_WASM_BUILD": "1"
- },
- "rust-analyzer.cargo.features": [
- "runtime-benchmarks",
- "try-runtime"
- ]
-}
\ No newline at end of file
+ "eslint.format.enable": true,
+ "[javascript]": {
+ "editor.defaultFormatter": "dbaeumer.vscode-eslint"
+ },
+ "[typescript]": {
+ "editor.defaultFormatter": "dbaeumer.vscode-eslint"
+ },
+ "rust-analyzer.cargo.extraEnv": {
+ "SKIP_WASM_BUILD": "1"
+ },
+ "rust-analyzer.cargo.features": ["runtime-benchmarks", "try-runtime"],
+ "solidity.packageDefaultDependenciesDirectory": "tests/node_modules"
+}
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -9216,9 +9216,9 @@
[[package]]
name = "proc-macro2"
-version = "1.0.59"
+version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b"
+checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
dependencies = [
"unicode-ident",
]
pallets/evm-coder-substrate/procedural/src/lib.rsdiffbeforeafterboth--- a/pallets/evm-coder-substrate/procedural/src/lib.rs
+++ b/pallets/evm-coder-substrate/procedural/src/lib.rs
@@ -52,7 +52,7 @@
let (impl_generics, ty_generics, _where_clause) = input.generics.split_for_impl();
let ident = &input.ident;
let Data::Enum(data) = &input.data else {
- return Err(Error::new_spanned(input, "PreDispatch input is enum"))
+ return Err(Error::new_spanned(input, "PreDispatch input is enum"));
};
let matching = data
pallets/structure/src/lib.rsdiffbeforeafterboth--- a/pallets/structure/src/lib.rs
+++ b/pallets/structure/src/lib.rs
@@ -399,8 +399,9 @@
if is_collection(account.as_eth()) {
fail!(<Error<T>>::CantNestTokenUnderCollection);
}
- let Some((collection, token)) = T::CrossTokenAddressMapping::address_to_token(account) else {
- return Ok(())
+ let Some((collection, token)) = T::CrossTokenAddressMapping::address_to_token(account)
+ else {
+ return Ok(());
};
let dispatch = T::CollectionDispatch::dispatch(collection)?;
tests/package.jsondiffbeforeafterboth--- a/tests/package.json
+++ b/tests/package.json
@@ -136,12 +136,15 @@
"@polkadot/util-crypto": "12.2.1",
"@polkadot/wasm-crypto-asmjs": "^7.2.1",
"@polkadot/wasm-crypto-wasm": "^7.2.1",
+ "@rmrk-team/evm-contracts": "^1.2.1",
+ "@typechain/web3-v1": "^6.0.3",
"chai-as-promised": "^7.1.1",
"chai-like": "^1.1.1",
"csv-writer": "^1.6.0",
"find-process": "^1.4.7",
"lossless-json": "^2.0.9",
- "solc": "0.8.17",
+ "solc": "0.8.18",
+ "typechain": "^8.2.0",
"web3": "1.10.0"
},
"resolutions": {
tests/src/benchmarks/nesting/ABIGEN/RMRKNestableMintable.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/benchmarks/nesting/ABIGEN/RMRKNestableMintable.ts
@@ -0,0 +1,355 @@
+/* Autogenerated file. Do not edit manually. */
+/* tslint:disable */
+/* eslint-disable */
+
+import type BN from "bn.js";
+import type { ContractOptions } from "web3-eth-contract";
+import type { EventLog } from "web3-core";
+import type { EventEmitter } from "events";
+import type {
+ Callback,
+ PayableTransactionObject,
+ NonPayableTransactionObject,
+ BlockType,
+ ContractEventLog,
+ BaseContract,
+} from "./types";
+
+export interface EventOptions {
+ filter?: object;
+ fromBlock?: BlockType;
+ topics?: string[];
+}
+
+export type AllChildrenRejected = ContractEventLog<{
+ tokenId: string;
+ 0: string;
+}>;
+export type Approval = ContractEventLog<{
+ owner: string;
+ approved: string;
+ tokenId: string;
+ 0: string;
+ 1: string;
+ 2: string;
+}>;
+export type ApprovalForAll = ContractEventLog<{
+ owner: string;
+ operator: string;
+ approved: boolean;
+ 0: string;
+ 1: string;
+ 2: boolean;
+}>;
+export type ChildAccepted = ContractEventLog<{
+ tokenId: string;
+ childIndex: string;
+ childAddress: string;
+ childId: string;
+ 0: string;
+ 1: string;
+ 2: string;
+ 3: string;
+}>;
+export type ChildProposed = ContractEventLog<{
+ tokenId: string;
+ childIndex: string;
+ childAddress: string;
+ childId: string;
+ 0: string;
+ 1: string;
+ 2: string;
+ 3: string;
+}>;
+export type ChildTransferred = ContractEventLog<{
+ tokenId: string;
+ childIndex: string;
+ childAddress: string;
+ childId: string;
+ fromPending: boolean;
+ toZero: boolean;
+ 0: string;
+ 1: string;
+ 2: string;
+ 3: string;
+ 4: boolean;
+ 5: boolean;
+}>;
+export type NestTransfer = ContractEventLog<{
+ from: string;
+ to: string;
+ fromTokenId: string;
+ toTokenId: string;
+ tokenId: string;
+ 0: string;
+ 1: string;
+ 2: string;
+ 3: string;
+ 4: string;
+}>;
+export type Transfer = ContractEventLog<{
+ from: string;
+ to: string;
+ tokenId: string;
+ 0: string;
+ 1: string;
+ 2: string;
+}>;
+
+export interface RMRKNestableMintable extends BaseContract {
+ constructor(
+ jsonInterface: any[],
+ address?: string,
+ options?: ContractOptions
+ ): RMRKNestableMintable;
+ clone(): RMRKNestableMintable;
+ methods: {
+ RMRK_INTERFACE(): NonPayableTransactionObject<string>;
+
+ VERSION(): NonPayableTransactionObject<string>;
+
+ acceptChild(
+ parentId: number | string | BN,
+ childIndex: number | string | BN,
+ childAddress: string,
+ childId: number | string | BN
+ ): NonPayableTransactionObject<void>;
+
+ addChild(
+ parentId: number | string | BN,
+ childId: number | string | BN,
+ data: string | number[]
+ ): NonPayableTransactionObject<void>;
+
+ approve(
+ to: string,
+ tokenId: number | string | BN
+ ): NonPayableTransactionObject<void>;
+
+ balanceOf(owner: string): NonPayableTransactionObject<string>;
+
+ "burn(uint256)"(
+ tokenId: number | string | BN
+ ): NonPayableTransactionObject<void>;
+
+ "burn(uint256,uint256)"(
+ tokenId: number | string | BN,
+ maxChildrenBurns: number | string | BN
+ ): NonPayableTransactionObject<string>;
+
+ childOf(
+ parentId: number | string | BN,
+ index: number | string | BN
+ ): NonPayableTransactionObject<[string, string]>;
+
+ childrenOf(
+ parentId: number | string | BN
+ ): NonPayableTransactionObject<[string, string][]>;
+
+ directOwnerOf(tokenId: number | string | BN): NonPayableTransactionObject<{
+ 0: string;
+ 1: string;
+ 2: boolean;
+ }>;
+
+ getApproved(
+ tokenId: number | string | BN
+ ): NonPayableTransactionObject<string>;
+
+ isApprovedForAll(
+ owner: string,
+ operator: string
+ ): NonPayableTransactionObject<boolean>;
+
+ mint(
+ to: string,
+ tokenId: number | string | BN
+ ): NonPayableTransactionObject<void>;
+
+ name(): NonPayableTransactionObject<string>;
+
+ nestMint(
+ to: string,
+ tokenId: number | string | BN,
+ destinationId: number | string | BN
+ ): NonPayableTransactionObject<void>;
+
+ nestTransfer(
+ to: string,
+ tokenId: number | string | BN,
+ destinationId: number | string | BN
+ ): NonPayableTransactionObject<void>;
+
+ nestTransferFrom(
+ from: string,
+ to: string,
+ tokenId: number | string | BN,
+ destinationId: number | string | BN,
+ data: string | number[]
+ ): NonPayableTransactionObject<void>;
+
+ onERC721Received(
+ _operator: string,
+ _from: string,
+ _tokenId: number | string | BN,
+ _data: string | number[]
+ ): NonPayableTransactionObject<string>;
+
+ ownerOf(tokenId: number | string | BN): NonPayableTransactionObject<string>;
+
+ pendingChildOf(
+ parentId: number | string | BN,
+ index: number | string | BN
+ ): NonPayableTransactionObject<[string, string]>;
+
+ pendingChildrenOf(
+ parentId: number | string | BN
+ ): NonPayableTransactionObject<[string, string][]>;
+
+ rejectAllChildren(
+ tokenId: number | string | BN,
+ maxRejections: number | string | BN
+ ): NonPayableTransactionObject<void>;
+
+ safeMint(to: string): NonPayableTransactionObject<void>;
+
+ "safeTransferFrom(address,address,uint256)"(
+ from: string,
+ to: string,
+ tokenId: number | string | BN
+ ): NonPayableTransactionObject<void>;
+
+ "safeTransferFrom(address,address,uint256,bytes)"(
+ from: string,
+ to: string,
+ tokenId: number | string | BN,
+ data: string | number[]
+ ): NonPayableTransactionObject<void>;
+
+ setApprovalForAll(
+ operator: string,
+ approved: boolean
+ ): NonPayableTransactionObject<void>;
+
+ supportsInterface(
+ interfaceId: string | number[]
+ ): NonPayableTransactionObject<boolean>;
+
+ symbol(): NonPayableTransactionObject<string>;
+
+ transfer(
+ to: string,
+ tokenId: number | string | BN
+ ): NonPayableTransactionObject<void>;
+
+ transferChild(
+ tokenId: number | string | BN,
+ to: string,
+ destinationId: number | string | BN,
+ childIndex: number | string | BN,
+ childAddress: string,
+ childId: number | string | BN,
+ isPending: boolean,
+ data: string | number[]
+ ): NonPayableTransactionObject<void>;
+
+ transferFrom(
+ from: string,
+ to: string,
+ tokenId: number | string | BN
+ ): NonPayableTransactionObject<void>;
+ };
+ events: {
+ AllChildrenRejected(cb?: Callback<AllChildrenRejected>): EventEmitter;
+ AllChildrenRejected(
+ options?: EventOptions,
+ cb?: Callback<AllChildrenRejected>
+ ): EventEmitter;
+
+ Approval(cb?: Callback<Approval>): EventEmitter;
+ Approval(options?: EventOptions, cb?: Callback<Approval>): EventEmitter;
+
+ ApprovalForAll(cb?: Callback<ApprovalForAll>): EventEmitter;
+ ApprovalForAll(
+ options?: EventOptions,
+ cb?: Callback<ApprovalForAll>
+ ): EventEmitter;
+
+ ChildAccepted(cb?: Callback<ChildAccepted>): EventEmitter;
+ ChildAccepted(
+ options?: EventOptions,
+ cb?: Callback<ChildAccepted>
+ ): EventEmitter;
+
+ ChildProposed(cb?: Callback<ChildProposed>): EventEmitter;
+ ChildProposed(
+ options?: EventOptions,
+ cb?: Callback<ChildProposed>
+ ): EventEmitter;
+
+ ChildTransferred(cb?: Callback<ChildTransferred>): EventEmitter;
+ ChildTransferred(
+ options?: EventOptions,
+ cb?: Callback<ChildTransferred>
+ ): EventEmitter;
+
+ NestTransfer(cb?: Callback<NestTransfer>): EventEmitter;
+ NestTransfer(
+ options?: EventOptions,
+ cb?: Callback<NestTransfer>
+ ): EventEmitter;
+
+ Transfer(cb?: Callback<Transfer>): EventEmitter;
+ Transfer(options?: EventOptions, cb?: Callback<Transfer>): EventEmitter;
+
+ allEvents(options?: EventOptions, cb?: Callback<EventLog>): EventEmitter;
+ };
+
+ once(event: "AllChildrenRejected", cb: Callback<AllChildrenRejected>): void;
+ once(
+ event: "AllChildrenRejected",
+ options: EventOptions,
+ cb: Callback<AllChildrenRejected>
+ ): void;
+
+ once(event: "Approval", cb: Callback<Approval>): void;
+ once(event: "Approval", options: EventOptions, cb: Callback<Approval>): void;
+
+ once(event: "ApprovalForAll", cb: Callback<ApprovalForAll>): void;
+ once(
+ event: "ApprovalForAll",
+ options: EventOptions,
+ cb: Callback<ApprovalForAll>
+ ): void;
+
+ once(event: "ChildAccepted", cb: Callback<ChildAccepted>): void;
+ once(
+ event: "ChildAccepted",
+ options: EventOptions,
+ cb: Callback<ChildAccepted>
+ ): void;
+
+ once(event: "ChildProposed", cb: Callback<ChildProposed>): void;
+ once(
+ event: "ChildProposed",
+ options: EventOptions,
+ cb: Callback<ChildProposed>
+ ): void;
+
+ once(event: "ChildTransferred", cb: Callback<ChildTransferred>): void;
+ once(
+ event: "ChildTransferred",
+ options: EventOptions,
+ cb: Callback<ChildTransferred>
+ ): void;
+
+ once(event: "NestTransfer", cb: Callback<NestTransfer>): void;
+ once(
+ event: "NestTransfer",
+ options: EventOptions,
+ cb: Callback<NestTransfer>
+ ): void;
+
+ once(event: "Transfer", cb: Callback<Transfer>): void;
+ once(event: "Transfer", options: EventOptions, cb: Callback<Transfer>): void;
+}
tests/src/benchmarks/nesting/ABIGEN/index.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/benchmarks/nesting/ABIGEN/index.ts
@@ -0,0 +1,4 @@
+/* Autogenerated file. Do not edit manually. */
+/* tslint:disable */
+/* eslint-disable */
+export type { RMRKNestableMintable } from "./RMRKNestableMintable";
tests/src/benchmarks/nesting/ABIGEN/types.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/benchmarks/nesting/ABIGEN/types.ts
@@ -0,0 +1,73 @@
+/* Autogenerated file. Do not edit manually. */
+/* tslint:disable */
+/* eslint-disable */
+import type BN from "bn.js";
+import type { EventEmitter } from "events";
+import type { EventLog, PromiEvent, TransactionReceipt } from "web3-core/types";
+import type { Contract } from "web3-eth-contract";
+
+export interface EstimateGasOptions {
+ from?: string;
+ gas?: number;
+ value?: number | string | BN;
+}
+
+export interface EventOptions {
+ filter?: object;
+ fromBlock?: BlockType;
+ topics?: string[];
+}
+
+export type Callback<T> = (error: Error, result: T) => void;
+export interface ContractEventLog<T> extends EventLog {
+ returnValues: T;
+}
+export interface ContractEventEmitter<T> extends EventEmitter {
+ on(event: "connected", listener: (subscriptionId: string) => void): this;
+ on(
+ event: "data" | "changed",
+ listener: (event: ContractEventLog<T>) => void
+ ): this;
+ on(event: "error", listener: (error: Error) => void): this;
+}
+
+export interface NonPayableTx {
+ nonce?: string | number | BN;
+ chainId?: string | number | BN;
+ from?: string;
+ to?: string;
+ data?: string;
+ gas?: string | number | BN;
+ maxPriorityFeePerGas?: string | number | BN;
+ maxFeePerGas?: string | number | BN;
+ gasPrice?: string | number | BN;
+}
+
+export interface PayableTx extends NonPayableTx {
+ value?: string | number | BN;
+}
+
+export interface NonPayableTransactionObject<T> {
+ arguments: any[];
+ call(tx?: NonPayableTx, block?: BlockType): Promise<T>;
+ send(tx?: NonPayableTx): PromiEvent<TransactionReceipt>;
+ estimateGas(tx?: NonPayableTx): Promise<number>;
+ encodeABI(): string;
+}
+
+export interface PayableTransactionObject<T> {
+ arguments: any[];
+ call(tx?: PayableTx, block?: BlockType): Promise<T>;
+ send(tx?: PayableTx): PromiEvent<TransactionReceipt>;
+ estimateGas(tx?: PayableTx): Promise<number>;
+ encodeABI(): string;
+}
+
+export type BlockType =
+ | "latest"
+ | "pending"
+ | "genesis"
+ | "earliest"
+ | number
+ | BN;
+export type BaseContract = Omit<Contract, "clone" | "once">;
tests/src/benchmarks/nesting/RMRKNestableMintable.soldiffbeforeafterboth--- /dev/null
+++ b/tests/src/benchmarks/nesting/RMRKNestableMintable.sol
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.18;
+
+import "@rmrk-team/evm-contracts/contracts/RMRK/nestable/RMRKNestable.sol";
+import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
+
+contract RMRKNestableMintable is RMRKNestable, IERC721Receiver {
+ uint256 private _counter;
+
+ constructor() RMRKNestable("RMRK", "nesting") {
+ _counter = 1;
+ }
+
+ function safeMint(address to) external {
+ _safeMint(to, _counter, "");
+ _counter++;
+ }
+
+ function mint(address to, uint256 tokenId) external {
+ _mint(to, tokenId, "");
+ }
+
+ function nestMint(address to, uint256 tokenId, uint256 destinationId) external {
+ _nestMint(to, tokenId, destinationId, "");
+ }
+
+ function nestTransfer(address to, uint256 tokenId, uint256 destinationId) public virtual {
+ nestTransferFrom(_msgSender(), to, tokenId, destinationId, "");
+ }
+
+ function transfer(address to, uint256 tokenId) public virtual {
+ transferFrom(_msgSender(), to, tokenId);
+ }
+
+ function onERC721Received(
+ address _operator,
+ address _from,
+ uint256 _tokenId,
+ bytes calldata _data
+ ) external returns (bytes4) {
+ return IERC721Receiver.onERC721Received.selector;
+ }
+}
tests/src/benchmarks/nesting/abigen.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/benchmarks/nesting/abigen.ts
@@ -0,0 +1,20 @@
+import {runTypeChain, glob, DEFAULT_FLAGS} from 'typechain';
+
+
+async function main() {
+ const cwd = process.cwd();
+
+ // find all files matching the glob
+ const allFiles = glob(cwd, ['./ABI/*.abi']);
+
+ await runTypeChain({
+ cwd,
+ filesToProcess: allFiles,
+ allFiles,
+ outDir: 'ABIGEN',
+ target: 'web3-v1',
+ flags: {...DEFAULT_FLAGS, alwaysGenerateOverloads: true, tsNocheck: false},
+ });
+}
+
+main().catch(console.error);
\ No newline at end of file
tests/src/benchmarks/nesting/index.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/benchmarks/nesting/index.ts
@@ -0,0 +1,227 @@
+import {EthUniqueHelper, usingEthPlaygrounds} from '../../eth/util';
+import {readFile} from 'fs/promises';
+import {
+ ICrossAccountId,
+} from '../../util/playgrounds/types';
+import {IKeyringPair} from '@polkadot/types/types';
+import {UniqueNFTCollection} from '../../util/playgrounds/unique';
+import {Contract} from 'web3-eth-contract';
+import {createObjectCsvWriter} from 'csv-writer';
+import {convertToTokens, createCollectionForBenchmarks, PERMISSIONS, PROPERTIES} from '../utils/common';
+import {makeNames} from '../../util';
+import {ContractImports} from '../../eth/util/playgrounds/types';
+import {RMRKNestableMintable} from './ABIGEN';
+import {rm} from 'fs';
+
+const {dirname} = makeNames(import.meta.url);
+
+export const CONTRACT_IMPORT: ContractImports[] = [
+ {
+ fsPath: `${dirname}/../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/nestable/RMRKNestable.sol`,
+ solPath: '@rmrk-team/evm-contracts/contracts/RMRK/nestable/RMRKNestable.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/nestable/IERC6059.sol`,
+ solPath: '@rmrk-team/evm-contracts/contracts/RMRK/nestable/IERC6059.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/core/RMRKCore.sol`,
+ solPath: '@rmrk-team/evm-contracts/contracts/RMRK/core/RMRKCore.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../node_modules/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol`,
+ solPath: '@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol`,
+ solPath: '@openzeppelin/contracts/token/ERC721/IERC721.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../node_modules/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol`,
+ solPath: '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../node_modules/@openzeppelin/contracts/utils/Address.sol`,
+ solPath: '@openzeppelin/contracts/utils/Address.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../node_modules/@openzeppelin/contracts/utils/Context.sol`,
+ solPath: '@openzeppelin/contracts/utils/Context.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol`,
+ solPath: '@openzeppelin/contracts/utils/introspection/IERC165.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/library/RMRKErrors.sol`,
+ solPath: '@rmrk-team/evm-contracts/contracts/RMRK/library/RMRKErrors.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/core/IRMRKCore.sol`,
+ solPath: '@rmrk-team/evm-contracts/contracts/RMRK/core/IRMRKCore.sol',
+ },
+ {
+ fsPath: `${dirname}/RMRKNestableMintable.sol`,
+ solPath: 'RMRKNestableMintable.sol',
+ },
+];
+
+
+const main = async () => {
+
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+
+ const donor = await privateKey('//Alice'); // Seed from account with balance on this network
+
+ const eth = await measureEth(helper, donor);
+ const sub = await measureSub(helper, donor);
+ const rmrk = await measureRMRK(helper, donor);
+ console.table({susbtrate: sub, eth: eth, rmrk: rmrk});
+ });
+};
+
+async function measureRMRK(helper: EthUniqueHelper, donor: IKeyringPair) {
+ const CONTRACT_SOURCE = (
+ await readFile(`${dirname}/RMRKNestableMintable.sol`)
+ ).toString();
+ const RELAYER_SOURCE = (await readFile(`${dirname}/relayer.sol`)).toString();
+
+ const ethSigner = await helper.eth.createAccountWithBalance(donor);
+
+ const contract = await helper.ethContract.deployByCode(
+ ethSigner,
+ 'RMRKNestableMintable',
+ CONTRACT_SOURCE,
+ CONTRACT_IMPORT,
+ 5000000,
+ );
+
+ const relayer = await helper.ethContract.deployByCode(
+ ethSigner,
+ 'Relayer',
+ RELAYER_SOURCE,
+ CONTRACT_IMPORT,
+ 5000000,
+ [contract.options.address],
+ );
+
+ const relayerAddress = relayer.options.address;
+
+ const rmrk = contract as any as RMRKNestableMintable;
+ const createTokenFor = async (receiver: string) => {
+ const tokenReceipt = await rmrk.methods.safeMint(receiver).send({from: ethSigner});
+ return tokenReceipt.events!['Transfer'].returnValues.tokenId as number;
+ };
+
+
+ const nestId = await createTokenFor(ethSigner);
+ const outerCollectionNestedId = 10;
+ const contractOwnedNestId = await createTokenFor(relayerAddress);
+ const nextTokenId = contractOwnedNestId + 1;
+
+ const nestTransfer = await helper.arrange.calculcateFee({Ethereum: ethSigner}, async () => {
+ const addChildData = rmrk.methods.addChild(nestId, outerCollectionNestedId, []).encodeABI();
+ await relayer.methods.relay(addChildData).send({from: ethSigner});
+ await rmrk.methods.acceptChild(nestId, 0, relayerAddress, outerCollectionNestedId).send({from: ethSigner});
+ });
+
+
+ const nestMint = await helper.arrange.calculcateFee({Ethereum: ethSigner}, async () => {
+ const nestMintData = rmrk.methods.nestMint(rmrk.options.address, nextTokenId, contractOwnedNestId).encodeABI();
+ await relayer.methods.relay(nestMintData).send({from: ethSigner});
+ const acceptNestedToken = rmrk.methods.acceptChild(contractOwnedNestId, 0, rmrk.options.address, nextTokenId).encodeABI();
+ await relayer.methods.relay(acceptNestedToken).send({from: ethSigner});
+ });
+
+
+ const unnestToken = await helper.arrange.calculcateFee({Ethereum: ethSigner}, async () => {
+ const unnestData = rmrk.methods.transferChild(contractOwnedNestId, ethSigner, 0, 0, rmrk.options.address, nextTokenId, false, []).encodeABI();
+ await relayer.methods.relay(unnestData).send({from: ethSigner});
+ });
+
+ return {mint: convertToTokens(nestMint), transfer: convertToTokens(nestTransfer), unnest: convertToTokens(unnestToken)};
+}
+
+async function measureEth(helper: EthUniqueHelper, donor: IKeyringPair) {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionId, contract} = await createNestingCollection(helper, owner);
+
+ // Create a token to be nested to
+ const mintingTargetNFTTokenIdResult = await contract.methods.mint(owner).send({from: owner});
+ const targetNFTTokenId = mintingTargetNFTTokenIdResult.events.Transfer.returnValues.tokenId;
+ const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetNFTTokenId);
+
+ // Create a nested token
+ const nestMint = await helper.arrange.calculcateFee({Ethereum: owner}, async () => {
+ await contract.methods.mint(targetNftTokenAddress).send({from: owner});
+ });
+
+ // Create a token to be nested and nest
+ const mintingSecondTokenIdResult = await contract.methods.mint(owner).send({from: owner});
+ const nestedTokenId = mintingSecondTokenIdResult.events.Transfer.returnValues.tokenId;
+
+ const nestTransfer = await helper.arrange.calculcateFee({Ethereum: owner}, async () => {
+ await contract.methods.transfer(targetNftTokenAddress, nestedTokenId).send({from: owner});
+ });
+
+ const unnestToken = await helper.arrange.calculcateFee({Ethereum: owner}, async () => {
+ await contract.methods.transferFrom(targetNftTokenAddress, owner, nestedTokenId).send({from: owner});
+ });
+ return {mint: convertToTokens(nestMint), transfer: convertToTokens(nestTransfer), unnest: convertToTokens(unnestToken)};
+}
+
+async function measureSub(helper: EthUniqueHelper, donor: IKeyringPair) {
+
+ const [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+
+ const targetNFTCollection = await helper.nft.mintCollection(alice);
+ const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
+
+
+ const collectionForNesting = await helper.nft.mintCollection(bob);
+ // permissions should be set:
+ await targetNFTCollection.setPermissions(alice, {
+ nesting: {tokenOwner: true},
+ });
+
+ const nestMint = await helper.arrange.calculcateFee({Substrate: bob.address}, async () => {
+ await (collectionForNesting.mintToken(bob, targetTokenBob.nestingAccount()));
+ });
+
+ const nestedToken2 = await collectionForNesting.mintToken(bob);
+ const nestTransfer = await helper.arrange.calculcateFee({Substrate: bob.address}, async () => {
+ await nestedToken2.nest(bob, targetTokenBob);
+ });
+
+ const unnestToken = await helper.arrange.calculcateFee({Substrate: bob.address}, async () => {
+ await nestedToken2.transferFrom(bob, targetTokenBob.nestingAccount(), {Substrate: bob.address});
+ });
+
+ return {mint: convertToTokens(nestMint), transfer: convertToTokens(nestTransfer), unnest: convertToTokens(unnestToken)};
+}
+
+
+const createNestingCollection = async (
+ helper: EthUniqueHelper,
+ owner: string,
+): Promise<{ collectionId: number, collectionAddress: string, contract: Contract }> => {
+ const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+
+ const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+ await contract.methods.setCollectionNesting(true).send({from: owner});
+
+ return {collectionId, collectionAddress, contract};
+};
+
+main()
+ .then(() => process.exit(0))
+ .catch((e) => {
+ console.log(e);
+ process.exit(1);
+ });
+
+
+
+
+
+
tests/src/benchmarks/nesting/relayer.soldiffbeforeafterboth--- /dev/null
+++ b/tests/src/benchmarks/nesting/relayer.sol
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.18;
+
+import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
+import "./RMRKNestableMintable.sol";
+
+contract Relayer is RMRKNestableMintable {
+ address _receiver;
+
+ constructor(address recevier) {
+ _receiver = recevier;
+ }
+
+ function relay(bytes calldata payload) external {
+ (bool succes, bytes memory _returnData) = address(_receiver).call(payload);
+ require(succes);
+ }
+}
tests/src/eth/marketplace-v2/Market.soldiffbeforeafterboth1// SPDX-License-Identifier: UNLICENSED2pragma solidity 0.8.17;34import "@openzeppelin/contracts/security/ReentrancyGuard.sol";5import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";6import "@openzeppelin/contracts/token/ERC721/IERC721.sol";7import "@openzeppelin/contracts/access/Ownable.sol";8import { UniqueNFT, CrossAddress } from "@unique-nft/solidity-interfaces/contracts/UniqueNFT.sol";9import { UniqueFungible, CrossAddress as CrossAddressF } from "@unique-nft/solidity-interfaces/contracts/UniqueFungible.sol";10import "@unique-nft/solidity-interfaces/contracts/CollectionHelpers.sol";11import "./royalty/UniqueRoyaltyHelper.sol";1213contract Market is Ownable, ReentrancyGuard {14 using ERC165Checker for address;1516 struct Order {17 uint32 id;18 uint32 collectionId;19 uint32 tokenId;20 uint32 amount;21 uint256 price;22 CrossAddress seller;23 }2425 uint32 public constant version = 0;26 uint32 public constant buildVersion = 3;27 bytes4 private constant InterfaceId_ERC721 = 0x80ac58cd;28 bytes4 private constant InterfaceId_ERC165 = 0x5755c3f2;29 CollectionHelpers private constant collectionHelpers =30 CollectionHelpers(0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F);3132 mapping(uint32 => mapping(uint32 => Order)) orders;33 uint32 private idCount = 1;34 uint32 public marketFee;35 uint64 public ctime;36 address public ownerAddress;37 mapping(address => bool) public admins;3839 event TokenIsUpForSale(uint32 version, Order item);40 event TokenRevoke(uint32 version, Order item, uint32 amount);41 event TokenIsApproved(uint32 version, Order item);42 event TokenIsPurchased(43 uint32 version,44 Order item,45 uint32 salesAmount,46 CrossAddress buyer,47 RoyaltyAmount[] royalties48 );49 event Log(string message);5051 error InvalidArgument(string info);52 error InvalidMarketFee();53 error SellerIsNotOwner();54 error TokenIsAlreadyOnSale();55 error TokenIsNotApproved();56 error CollectionNotFound();57 error CollectionNotSupportedERC721();58 error OrderNotFound();59 error TooManyAmountRequested();60 error NotEnoughMoneyError();61 error InvalidRoyaltiesError(uint256 totalRoyalty);62 error FailTransferToken(string reason);6364 modifier onlyAdmin() {65 require(msg.sender == this.owner() || admins[msg.sender], "Only admin can");66 _;67 }6869 modifier validCrossAddress(address eth, uint256 sub) {70 if (eth == address(0) && sub == 0) {71 revert InvalidArgument("Ethereum and Substrate addresses cannot be null at the same time");72 }7374 if (eth != address(0) && sub != 0) {75 revert InvalidArgument("Ethereum and Substrate addresses cannot be not null at the same time");76 }7778 _;79 }8081 constructor(uint32 fee, uint64 timestamp) {82 marketFee = fee;83 ctime = timestamp;8485 if (marketFee >= 100) {86 revert InvalidMarketFee();87 }88 }8990 /**91 * Fallback that allows this contract to receive native token.92 * We need this for self-sponsoring93 */94 fallback() external payable {}9596 /**97 * Receive also allows this contract to receive native token.98 * We need this for self-sponsoring99 */100 receive() external payable {}101102 function getErc721(uint32 collectionId) private view returns (IERC721) {103 address collectionAddress = collectionHelpers.collectionAddress(104 collectionId105 );106107 uint size;108 assembly {109 size := extcodesize(collectionAddress)110 }111112 if (size == 0) {113 revert CollectionNotFound();114 }115116 if (!collectionAddress.supportsInterface(InterfaceId_ERC721)) {117 revert CollectionNotSupportedERC721();118 }119120 return IERC721(collectionAddress);121 }122123 /**124 * Add new admin. Only owner or an existing admin can add admins.125 *126 * @param admin: Address of a new admin to add127 */128 function addAdmin(address admin) public onlyAdmin {129 admins[admin] = true;130 }131132 /**133 * Remove an admin. Only owner or an existing admin can remove admins.134 *135 * @param admin: Address of a new admin to add136 */137 function removeAdmin(address admin) public onlyAdmin {138 delete admins[admin];139 }140141 /**142 * Place an NFT or RFT token for sale. It must be pre-approved for transfers by this contract address.143 *144 * @param collectionId: ID of the token collection145 * @param tokenId: ID of the token146 * @param price: Price (with proper network currency decimals)147 * @param amount: Number of token fractions to list (must always be 1 for NFT)148 * @param seller: The seller cross-address (the beneficiary account to receive payment, may be different from transaction sender)149 */150 function put(151 uint32 collectionId,152 uint32 tokenId,153 uint256 price,154 uint32 amount,155 CrossAddress memory seller156 ) public validCrossAddress(seller.eth, seller.sub) {157 if (price == 0) {158 revert InvalidArgument("price must not be zero");159 }160 if (amount == 0) {161 revert InvalidArgument("amount must not be zero");162 }163164 if (orders[collectionId][tokenId].price > 0) {165 revert TokenIsAlreadyOnSale();166 }167168 IERC721 erc721 = getErc721(collectionId);169170 if (erc721.ownerOf(tokenId) != msg.sender) {171 revert SellerIsNotOwner();172 }173174 if (erc721.getApproved(tokenId) != address(this)) {175 revert TokenIsNotApproved();176 }177178 Order memory order = Order(179 0,180 collectionId,181 tokenId,182 amount,183 price,184 seller185 );186187 order.id = idCount++;188 orders[collectionId][tokenId] = order;189190 emit TokenIsUpForSale(version, order);191 }192193 /**194 * Get information about the listed token order195 *196 * @param collectionId: ID of the token collection197 * @param tokenId: ID of the token198 * @return The order information199 */200 function getOrder(201 uint32 collectionId,202 uint32 tokenId203 ) external view returns (Order memory) {204 return orders[collectionId][tokenId];205 }206207 /**208 * Revoke the token from the sale. Only the original lister can use this method.209 *210 * @param collectionId: ID of the token collection211 * @param tokenId: ID of the token212 * @param amount: Number of token fractions to de-list (must always be 1 for NFT)213 */214 function revoke(215 uint32 collectionId,216 uint32 tokenId,217 uint32 amount218 ) external {219 if (amount == 0) {220 revert InvalidArgument("amount must not be zero");221 }222223 Order memory order = orders[collectionId][tokenId];224225 if (order.price == 0) {226 revert OrderNotFound();227 }228229 if (amount > order.amount) {230 revert TooManyAmountRequested();231 }232233 IERC721 erc721 = getErc721(collectionId);234235 address ethAddress;236 if (order.seller.eth != address(0)) {237 ethAddress = order.seller.eth;238 } else {239 ethAddress = payable(address(uint160(order.seller.sub >> 96)));240 }241 if (erc721.ownerOf(tokenId) != ethAddress) {242 revert SellerIsNotOwner();243 }244245 order.amount -= amount;246 if (order.amount == 0) {247 delete orders[collectionId][tokenId];248 } else {249 orders[collectionId][tokenId] = order;250 }251252 emit TokenRevoke(version, order, amount);253 }254255 /**256 * Test if the token is still approved to be transferred by this contract and delete the order if not.257 *258 * @param collectionId: ID of the token collection259 * @param tokenId: ID of the token260 */261 function checkApproved(uint32 collectionId, uint32 tokenId) public onlyAdmin {262 Order memory order = orders[collectionId][tokenId];263 if (order.price == 0) {264 revert OrderNotFound();265 }266267 IERC721 erc721 = getErc721(collectionId);268269 if (erc721.getApproved(tokenId) != address(this) || erc721.ownerOf(tokenId) != getAddressFromCrossAccount(order.seller)) {270 uint32 amount = order.amount;271 order.amount = 0;272 emit TokenRevoke(version, order, amount);273274 delete orders[collectionId][tokenId];275 } else {276 emit TokenIsApproved(version, order);277 }278 }279280 function getAddressFromCrossAccount(CrossAddress memory account) private pure returns (address) {281 if (account.eth != address(0)) {282 return account.eth;283 } else {284 return address(uint160(account.sub >> 96));285 }286 }287288 /**289 * Revoke the token from the sale. Only the contract admin can use this method.290 *291 * @param collectionId: ID of the token collection292 * @param tokenId: ID of the token293 */294 function revokeAdmin(uint32 collectionId, uint32 tokenId) public onlyAdmin {295 Order memory order = orders[collectionId][tokenId];296 if (order.price == 0) {297 revert OrderNotFound();298 }299300 uint32 amount = order.amount;301 order.amount = 0;302 emit TokenRevoke(version, order, amount);303304 delete orders[collectionId][tokenId];305 }306307 /**308 * Buy a token (partially for an RFT).309 *310 * @param collectionId: ID of the token collection311 * @param tokenId: ID of the token312 * @param amount: Number of token fractions to buy (must always be 1 for NFT)313 * @param buyer: Cross-address of the buyer, eth part must be equal to the transaction signer address314 */315 function buy(316 uint32 collectionId,317 uint32 tokenId,318 uint32 amount,319 CrossAddress memory buyer320 ) public payable validCrossAddress(buyer.eth, buyer.sub) nonReentrant {321 if (msg.value == 0) {322 revert InvalidArgument("msg.value must not be zero");323 }324 if (amount == 0) {325 revert InvalidArgument("amount must not be zero");326 }327328 Order memory order = orders[collectionId][tokenId];329 if (order.price == 0) {330 revert OrderNotFound();331 }332333 if (amount > order.amount) {334 revert TooManyAmountRequested();335 }336337 uint256 totalValue = order.price * amount;338 uint256 feeValue = (totalValue * marketFee) / 100;339340 if (msg.value < totalValue) {341 revert NotEnoughMoneyError();342 }343344 IERC721 erc721 = getErc721(order.collectionId);345 if (erc721.getApproved(tokenId) != address(this)) {346 revert TokenIsNotApproved();347 }348349 order.amount -= amount;350 if (order.amount == 0) {351 delete orders[collectionId][tokenId];352 } else {353 orders[collectionId][tokenId] = order;354 }355356 address collectionAddress = collectionHelpers.collectionAddress(collectionId);357 UniqueNFT nft = UniqueNFT(collectionAddress);358359 nft.transferFromCross(360 order.seller,361 buyer,362 order.tokenId363 );364365 (uint256 totalRoyalty, RoyaltyAmount[] memory royalties) = sendRoyalties(collectionAddress, tokenId, totalValue - feeValue);366367 if (totalRoyalty >= totalValue - feeValue) {368 revert InvalidRoyaltiesError(totalRoyalty);369 }370371 sendMoney(order.seller, totalValue - feeValue - totalRoyalty);372373 if (msg.value > totalValue) {374 sendMoney(buyer, msg.value - totalValue);375 }376377 emit TokenIsPurchased(version, order, amount, buyer, royalties);378 }379380 function sendMoney(CrossAddress memory to, uint256 money) private {381 address collectionAddress = collectionHelpers.collectionAddress(0);382383 UniqueFungible fungible = UniqueFungible(collectionAddress);384385 CrossAddressF memory fromF = CrossAddressF(address(this), 0);386 CrossAddressF memory toF = CrossAddressF(to.eth, to.sub);387388 fungible.transferFromCross(fromF, toF, money);389 }390391 function sendRoyalties(address collection, uint tokenId, uint sellPrice) private returns (uint256, RoyaltyAmount[] memory) {392 RoyaltyAmount[] memory royalties = UniqueRoyaltyHelper.calculate(collection, tokenId, sellPrice);393394 uint256 totalRoyalty = 0;395396 for (uint256 i=0; i<royalties.length; i++) {397 RoyaltyAmount memory royalty = royalties[i];398399 totalRoyalty += royalty.amount;400401 sendMoney(royalty.crossAddress, royalty.amount);402 }403404 return (totalRoyalty, royalties);405 }406407 function withdraw(address transferTo) public onlyOwner {408 uint256 balance = address(this).balance;409410 if (balance > 0) {411 payable(transferTo).transfer(balance);412 }413 }414}1// SPDX-License-Identifier: UNLICENSED2pragma solidity 0.8.18;34import "@openzeppelin/contracts/security/ReentrancyGuard.sol";5import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";6import "@openzeppelin/contracts/token/ERC721/IERC721.sol";7import "@openzeppelin/contracts/access/Ownable.sol";8import { UniqueNFT, CrossAddress } from "@unique-nft/solidity-interfaces/contracts/UniqueNFT.sol";9import { UniqueFungible, CrossAddress as CrossAddressF } from "@unique-nft/solidity-interfaces/contracts/UniqueFungible.sol";10import "@unique-nft/solidity-interfaces/contracts/CollectionHelpers.sol";11import "./royalty/UniqueRoyaltyHelper.sol";1213contract Market is Ownable, ReentrancyGuard {14 using ERC165Checker for address;1516 struct Order {17 uint32 id;18 uint32 collectionId;19 uint32 tokenId;20 uint32 amount;21 uint256 price;22 CrossAddress seller;23 }2425 uint32 public constant version = 0;26 uint32 public constant buildVersion = 3;27 bytes4 private constant InterfaceId_ERC721 = 0x80ac58cd;28 bytes4 private constant InterfaceId_ERC165 = 0x5755c3f2;29 CollectionHelpers private constant collectionHelpers =30 CollectionHelpers(0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F);3132 mapping(uint32 => mapping(uint32 => Order)) orders;33 uint32 private idCount = 1;34 uint32 public marketFee;35 uint64 public ctime;36 address public ownerAddress;37 mapping(address => bool) public admins;3839 event TokenIsUpForSale(uint32 version, Order item);40 event TokenRevoke(uint32 version, Order item, uint32 amount);41 event TokenIsApproved(uint32 version, Order item);42 event TokenIsPurchased(43 uint32 version,44 Order item,45 uint32 salesAmount,46 CrossAddress buyer,47 RoyaltyAmount[] royalties48 );49 event Log(string message);5051 error InvalidArgument(string info);52 error InvalidMarketFee();53 error SellerIsNotOwner();54 error TokenIsAlreadyOnSale();55 error TokenIsNotApproved();56 error CollectionNotFound();57 error CollectionNotSupportedERC721();58 error OrderNotFound();59 error TooManyAmountRequested();60 error NotEnoughMoneyError();61 error InvalidRoyaltiesError(uint256 totalRoyalty);62 error FailTransferToken(string reason);6364 modifier onlyAdmin() {65 require(msg.sender == this.owner() || admins[msg.sender], "Only admin can");66 _;67 }6869 modifier validCrossAddress(address eth, uint256 sub) {70 if (eth == address(0) && sub == 0) {71 revert InvalidArgument("Ethereum and Substrate addresses cannot be null at the same time");72 }7374 if (eth != address(0) && sub != 0) {75 revert InvalidArgument("Ethereum and Substrate addresses cannot be not null at the same time");76 }7778 _;79 }8081 constructor(uint32 fee, uint64 timestamp) {82 marketFee = fee;83 ctime = timestamp;8485 if (marketFee >= 100) {86 revert InvalidMarketFee();87 }88 }8990 /**91 * Fallback that allows this contract to receive native token.92 * We need this for self-sponsoring93 */94 fallback() external payable {}9596 /**97 * Receive also allows this contract to receive native token.98 * We need this for self-sponsoring99 */100 receive() external payable {}101102 function getErc721(uint32 collectionId) private view returns (IERC721) {103 address collectionAddress = collectionHelpers.collectionAddress(104 collectionId105 );106107 uint size;108 assembly {109 size := extcodesize(collectionAddress)110 }111112 if (size == 0) {113 revert CollectionNotFound();114 }115116 if (!collectionAddress.supportsInterface(InterfaceId_ERC721)) {117 revert CollectionNotSupportedERC721();118 }119120 return IERC721(collectionAddress);121 }122123 /**124 * Add new admin. Only owner or an existing admin can add admins.125 *126 * @param admin: Address of a new admin to add127 */128 function addAdmin(address admin) public onlyAdmin {129 admins[admin] = true;130 }131132 /**133 * Remove an admin. Only owner or an existing admin can remove admins.134 *135 * @param admin: Address of a new admin to add136 */137 function removeAdmin(address admin) public onlyAdmin {138 delete admins[admin];139 }140141 /**142 * Place an NFT or RFT token for sale. It must be pre-approved for transfers by this contract address.143 *144 * @param collectionId: ID of the token collection145 * @param tokenId: ID of the token146 * @param price: Price (with proper network currency decimals)147 * @param amount: Number of token fractions to list (must always be 1 for NFT)148 * @param seller: The seller cross-address (the beneficiary account to receive payment, may be different from transaction sender)149 */150 function put(151 uint32 collectionId,152 uint32 tokenId,153 uint256 price,154 uint32 amount,155 CrossAddress memory seller156 ) public validCrossAddress(seller.eth, seller.sub) {157 if (price == 0) {158 revert InvalidArgument("price must not be zero");159 }160 if (amount == 0) {161 revert InvalidArgument("amount must not be zero");162 }163164 if (orders[collectionId][tokenId].price > 0) {165 revert TokenIsAlreadyOnSale();166 }167168 IERC721 erc721 = getErc721(collectionId);169170 if (erc721.ownerOf(tokenId) != msg.sender) {171 revert SellerIsNotOwner();172 }173174 if (erc721.getApproved(tokenId) != address(this)) {175 revert TokenIsNotApproved();176 }177178 Order memory order = Order(179 0,180 collectionId,181 tokenId,182 amount,183 price,184 seller185 );186187 order.id = idCount++;188 orders[collectionId][tokenId] = order;189190 emit TokenIsUpForSale(version, order);191 }192193 /**194 * Get information about the listed token order195 *196 * @param collectionId: ID of the token collection197 * @param tokenId: ID of the token198 * @return The order information199 */200 function getOrder(201 uint32 collectionId,202 uint32 tokenId203 ) external view returns (Order memory) {204 return orders[collectionId][tokenId];205 }206207 /**208 * Revoke the token from the sale. Only the original lister can use this method.209 *210 * @param collectionId: ID of the token collection211 * @param tokenId: ID of the token212 * @param amount: Number of token fractions to de-list (must always be 1 for NFT)213 */214 function revoke(215 uint32 collectionId,216 uint32 tokenId,217 uint32 amount218 ) external {219 if (amount == 0) {220 revert InvalidArgument("amount must not be zero");221 }222223 Order memory order = orders[collectionId][tokenId];224225 if (order.price == 0) {226 revert OrderNotFound();227 }228229 if (amount > order.amount) {230 revert TooManyAmountRequested();231 }232233 IERC721 erc721 = getErc721(collectionId);234235 address ethAddress;236 if (order.seller.eth != address(0)) {237 ethAddress = order.seller.eth;238 } else {239 ethAddress = payable(address(uint160(order.seller.sub >> 96)));240 }241 if (erc721.ownerOf(tokenId) != ethAddress) {242 revert SellerIsNotOwner();243 }244245 order.amount -= amount;246 if (order.amount == 0) {247 delete orders[collectionId][tokenId];248 } else {249 orders[collectionId][tokenId] = order;250 }251252 emit TokenRevoke(version, order, amount);253 }254255 /**256 * Test if the token is still approved to be transferred by this contract and delete the order if not.257 *258 * @param collectionId: ID of the token collection259 * @param tokenId: ID of the token260 */261 function checkApproved(uint32 collectionId, uint32 tokenId) public onlyAdmin {262 Order memory order = orders[collectionId][tokenId];263 if (order.price == 0) {264 revert OrderNotFound();265 }266267 IERC721 erc721 = getErc721(collectionId);268269 if (erc721.getApproved(tokenId) != address(this) || erc721.ownerOf(tokenId) != getAddressFromCrossAccount(order.seller)) {270 uint32 amount = order.amount;271 order.amount = 0;272 emit TokenRevoke(version, order, amount);273274 delete orders[collectionId][tokenId];275 } else {276 emit TokenIsApproved(version, order);277 }278 }279280 function getAddressFromCrossAccount(CrossAddress memory account) private pure returns (address) {281 if (account.eth != address(0)) {282 return account.eth;283 } else {284 return address(uint160(account.sub >> 96));285 }286 }287288 /**289 * Revoke the token from the sale. Only the contract admin can use this method.290 *291 * @param collectionId: ID of the token collection292 * @param tokenId: ID of the token293 */294 function revokeAdmin(uint32 collectionId, uint32 tokenId) public onlyAdmin {295 Order memory order = orders[collectionId][tokenId];296 if (order.price == 0) {297 revert OrderNotFound();298 }299300 uint32 amount = order.amount;301 order.amount = 0;302 emit TokenRevoke(version, order, amount);303304 delete orders[collectionId][tokenId];305 }306307 /**308 * Buy a token (partially for an RFT).309 *310 * @param collectionId: ID of the token collection311 * @param tokenId: ID of the token312 * @param amount: Number of token fractions to buy (must always be 1 for NFT)313 * @param buyer: Cross-address of the buyer, eth part must be equal to the transaction signer address314 */315 function buy(316 uint32 collectionId,317 uint32 tokenId,318 uint32 amount,319 CrossAddress memory buyer320 ) public payable validCrossAddress(buyer.eth, buyer.sub) nonReentrant {321 if (msg.value == 0) {322 revert InvalidArgument("msg.value must not be zero");323 }324 if (amount == 0) {325 revert InvalidArgument("amount must not be zero");326 }327328 Order memory order = orders[collectionId][tokenId];329 if (order.price == 0) {330 revert OrderNotFound();331 }332333 if (amount > order.amount) {334 revert TooManyAmountRequested();335 }336337 uint256 totalValue = order.price * amount;338 uint256 feeValue = (totalValue * marketFee) / 100;339340 if (msg.value < totalValue) {341 revert NotEnoughMoneyError();342 }343344 IERC721 erc721 = getErc721(order.collectionId);345 if (erc721.getApproved(tokenId) != address(this)) {346 revert TokenIsNotApproved();347 }348349 order.amount -= amount;350 if (order.amount == 0) {351 delete orders[collectionId][tokenId];352 } else {353 orders[collectionId][tokenId] = order;354 }355356 address collectionAddress = collectionHelpers.collectionAddress(collectionId);357 UniqueNFT nft = UniqueNFT(collectionAddress);358359 nft.transferFromCross(360 order.seller,361 buyer,362 order.tokenId363 );364365 (uint256 totalRoyalty, RoyaltyAmount[] memory royalties) = sendRoyalties(collectionAddress, tokenId, totalValue - feeValue);366367 if (totalRoyalty >= totalValue - feeValue) {368 revert InvalidRoyaltiesError(totalRoyalty);369 }370371 sendMoney(order.seller, totalValue - feeValue - totalRoyalty);372373 if (msg.value > totalValue) {374 sendMoney(buyer, msg.value - totalValue);375 }376377 emit TokenIsPurchased(version, order, amount, buyer, royalties);378 }379380 function sendMoney(CrossAddress memory to, uint256 money) private {381 address collectionAddress = collectionHelpers.collectionAddress(0);382383 UniqueFungible fungible = UniqueFungible(collectionAddress);384385 CrossAddressF memory fromF = CrossAddressF(address(this), 0);386 CrossAddressF memory toF = CrossAddressF(to.eth, to.sub);387388 fungible.transferFromCross(fromF, toF, money);389 }390391 function sendRoyalties(address collection, uint tokenId, uint sellPrice) private returns (uint256, RoyaltyAmount[] memory) {392 RoyaltyAmount[] memory royalties = UniqueRoyaltyHelper.calculate(collection, tokenId, sellPrice);393394 uint256 totalRoyalty = 0;395396 for (uint256 i=0; i<royalties.length; i++) {397 RoyaltyAmount memory royalty = royalties[i];398399 totalRoyalty += royalty.amount;400401 sendMoney(royalty.crossAddress, royalty.amount);402 }403404 return (totalRoyalty, royalties);405 }406407 function withdraw(address transferTo) public onlyOwner {408 uint256 balance = address(this).balance;409410 if (balance > 0) {411 payable(transferTo).transfer(balance);412 }413 }414}tests/src/eth/transferValue.test.tsdiffbeforeafterboth--- a/tests/src/eth/transferValue.test.ts
+++ b/tests/src/eth/transferValue.test.ts
@@ -36,7 +36,7 @@
'Test',
`
// SPDX-License-Identifier: UNLICENSED
- pragma solidity 0.8.17;
+ pragma solidity 0.8.18;
contract Test {
function send() public payable {
tests/yarn.lockdiffbeforeafterboth--- a/tests/yarn.lock
+++ b/tests/yarn.lock
@@ -339,6 +339,11 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
+"@openzeppelin/contracts@^4.6.0":
+ version "4.9.2"
+ resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.2.tgz#1cb2d5e4d3360141a17dbc45094a8cad6aac16c1"
+ integrity sha512-mO+y6JaqXjWeMh9glYVzVu8HYPGknAAnWyxTRhGeckOruyXQMNnlcW6w/Dx9ftLeIQk6N+ZJFuVmTwF7lEIFrg==
+
"@openzeppelin/contracts@^4.9.0":
version "4.9.1"
resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.1.tgz#afa804d2c68398704b0175acc94d91a54f203645"
@@ -1015,6 +1020,13 @@
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
+"@rmrk-team/evm-contracts@^1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@rmrk-team/evm-contracts/-/evm-contracts-1.2.1.tgz#5397958eb83b2d8cfebc88138811c65a90770ae5"
+ integrity sha512-jFElzC/B3VHDbvidNhAJkAOYUGXbm288zFOVM5OUyLZFcagipBZawwz2pb40XMM4HVVsw/BVUSd+L/fOWXWvpw==
+ dependencies:
+ "@openzeppelin/contracts" "^4.6.0"
+
"@scure/base@1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938"
@@ -1083,6 +1095,14 @@
resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9"
integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==
+"@typechain/web3-v1@^6.0.3":
+ version "6.0.3"
+ resolved "https://registry.yarnpkg.com/@typechain/web3-v1/-/web3-v1-6.0.3.tgz#e9ea16811168677ae14dcaba719ffcc4933c8369"
+ integrity sha512-bFBYiA/Wh9XSoPtZ0nnrvg0a0brAHXhL/nCsPnPS999f9EUD9MOwkdOh8zhvY5oNzi6GMD5+KEmwE7A/eTqgeQ==
+ dependencies:
+ lodash "^4.17.15"
+ ts-essentials "^7.0.1"
+
"@types/bn.js@^5.1.0", "@types/bn.js@^5.1.1":
version "5.1.1"
resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.1.tgz#b51e1b55920a4ca26e9285ff79936bbdec910682"
@@ -1175,6 +1195,11 @@
dependencies:
"@types/node" "*"
+"@types/prettier@^2.1.1":
+ version "2.7.3"
+ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f"
+ integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==
+
"@types/responselike@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29"
@@ -1398,6 +1423,13 @@
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
+ansi-styles@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+ integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+ dependencies:
+ color-convert "^1.9.0"
+
ansi-styles@^4.0.0, ansi-styles@^4.1.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
@@ -1423,6 +1455,16 @@
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
+array-back@^3.0.1, array-back@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0"
+ integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==
+
+array-back@^4.0.1, array-back@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/array-back/-/array-back-4.0.2.tgz#8004e999a6274586beeb27342168652fdb89fa1e"
+ integrity sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==
+
array-flatten@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
@@ -1741,6 +1783,15 @@
pathval "^1.1.1"
type-detect "^4.0.5"
+chalk@^2.4.2:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+ integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+ dependencies:
+ ansi-styles "^3.2.1"
+ escape-string-regexp "^1.0.5"
+ supports-color "^5.3.0"
+
chalk@^4.0.0, chalk@^4.1.0:
version "4.1.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
@@ -1832,6 +1883,13 @@
dependencies:
mimic-response "^1.0.0"
+color-convert@^1.9.0:
+ version "1.9.3"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+ integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+ dependencies:
+ color-name "1.1.3"
+
color-convert@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
@@ -1839,6 +1897,11 @@
dependencies:
color-name "~1.1.4"
+color-name@1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+ integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
+
color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
@@ -1856,6 +1919,26 @@
resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69"
integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==
+command-line-args@^5.1.1:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.1.tgz#c44c32e437a57d7c51157696893c5909e9cec42e"
+ integrity sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==
+ dependencies:
+ array-back "^3.1.0"
+ find-replace "^3.0.0"
+ lodash.camelcase "^4.3.0"
+ typical "^4.0.0"
+
+command-line-usage@^6.1.0:
+ version "6.1.3"
+ resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-6.1.3.tgz#428fa5acde6a838779dfa30e44686f4b6761d957"
+ integrity sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==
+ dependencies:
+ array-back "^4.0.2"
+ chalk "^2.4.2"
+ table-layout "^1.0.2"
+ typical "^5.2.0"
+
commander@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae"
@@ -2012,7 +2095,7 @@
dependencies:
ms "2.0.0"
-debug@4, debug@4.3.4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
+debug@4, debug@4.3.4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@@ -2055,6 +2138,11 @@
dependencies:
type-detect "^4.0.0"
+deep-extend@~0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
+ integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
+
deep-is@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
@@ -2215,6 +2303,11 @@
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
+escape-string-regexp@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+ integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
+
eslint-plugin-mocha@^10.1.0:
version "10.1.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-mocha/-/eslint-plugin-mocha-10.1.0.tgz#69325414f875be87fb2cb00b2ef33168d4eb7c8d"
@@ -2599,6 +2692,13 @@
commander "^5.1.0"
debug "^4.1.1"
+find-replace@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38"
+ integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==
+ dependencies:
+ array-back "^3.0.1"
+
find-up@5.0.0, find-up@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
@@ -2700,6 +2800,15 @@
jsonfile "^4.0.0"
universalify "^0.1.0"
+fs-extra@^7.0.0:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
+ integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==
+ dependencies:
+ graceful-fs "^4.1.2"
+ jsonfile "^4.0.0"
+ universalify "^0.1.0"
+
fs-minipass@^1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7"
@@ -2775,6 +2884,18 @@
dependencies:
is-glob "^4.0.3"
+glob@7.1.7:
+ version "7.1.7"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"
+ integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.0.4"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
glob@7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
@@ -2909,6 +3030,11 @@
ajv "^6.12.3"
har-schema "^2.0.0"
+has-flag@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+ integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
+
has-flag@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
@@ -3383,12 +3509,17 @@
dependencies:
p-locate "^5.0.0"
+lodash.camelcase@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
+ integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==
+
lodash.merge@^4.6.2:
version "4.6.2"
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
-lodash@^4.17.21:
+lodash@^4.17.15, lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@@ -3596,6 +3727,11 @@
dependencies:
minimist "^1.2.6"
+mkdirp@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
+ integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
+
mocha@^10.1.0, mocha@^10.2.0:
version "10.2.0"
resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8"
@@ -4023,6 +4159,11 @@
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
+prettier@^2.3.1:
+ version "2.8.8"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
+ integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
+
process@^0.11.10:
version "0.11.10"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
@@ -4172,6 +4313,11 @@
dependencies:
picomatch "^2.2.1"
+reduce-flatten@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27"
+ integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==
+
request@^2.79.0:
version "2.88.2"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
@@ -4437,10 +4583,10 @@
pako "^2.0.4"
ws "^8.8.1"
-solc@0.8.17:
- version "0.8.17"
- resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.17.tgz#c748fec6a64bf029ec406aa9b37e75938d1115ae"
- integrity sha512-Dtidk2XtTTmkB3IKdyeg6wLYopJnBVxdoykN8oP8VY3PQjN16BScYoUJTXFm2OP7P0hXNAqWiJNmmfuELtLf8g==
+solc@0.8.18:
+ version "0.8.18"
+ resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.18.tgz#a05ce8918540eda5f10aa91f0f52f239b9645dad"
+ integrity sha512-wVAa2Y3BYd64Aby5LsgS3g6YC2NvZ3bJ+A8TAIAukfVuQb3AjyGrLZpyxQk5YLn14G35uZtSnIgHEpab9klOLQ==
dependencies:
command-exists "^1.2.8"
commander "^8.1.0"
@@ -4480,6 +4626,11 @@
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
integrity sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==
+string-format@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/string-format/-/string-format-2.0.0.tgz#f2df2e7097440d3b65de31b6d40d54c96eaffb9b"
+ integrity sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==
+
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
@@ -4527,6 +4678,13 @@
dependencies:
has-flag "^4.0.0"
+supports-color@^5.3.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+ integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+ dependencies:
+ has-flag "^3.0.0"
+
supports-color@^7.1.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
@@ -4556,6 +4714,16 @@
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==
+table-layout@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-1.0.2.tgz#c4038a1853b0136d63365a734b6931cf4fad4a04"
+ integrity sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==
+ dependencies:
+ array-back "^4.0.1"
+ deep-extend "~0.6.0"
+ typical "^5.2.0"
+ wordwrapjs "^4.0.0"
+
tar@^4.0.2:
version "4.4.19"
resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3"
@@ -4652,6 +4820,21 @@
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
+ts-command-line-args@^2.2.0:
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz#e64456b580d1d4f6d948824c274cf6fa5f45f7f0"
+ integrity sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==
+ dependencies:
+ chalk "^4.1.0"
+ command-line-args "^5.1.1"
+ command-line-usage "^6.1.0"
+ string-format "^2.0.0"
+
+ts-essentials@^7.0.1:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-7.0.3.tgz#686fd155a02133eedcc5362dc8b5056cde3e5a38"
+ integrity sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==
+
ts-node@^10.9.1:
version "10.9.1"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b"
@@ -4740,6 +4923,22 @@
resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0"
integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==
+typechain@^8.2.0:
+ version "8.2.0"
+ resolved "https://registry.yarnpkg.com/typechain/-/typechain-8.2.0.tgz#bd4fc8f111d4405e36858bae6f744604617b60f3"
+ integrity sha512-tZqhqjxJ9xAS/Lh32jccTjMkpx7sTdUVVHAy5Bf0TIer5QFNYXotiX74oCvoVYjyxUKDK3MXHtMFzMyD3kE+jg==
+ dependencies:
+ "@types/prettier" "^2.1.1"
+ debug "^4.3.1"
+ fs-extra "^7.0.0"
+ glob "7.1.7"
+ js-sha3 "^0.8.0"
+ lodash "^4.17.15"
+ mkdirp "^1.0.4"
+ prettier "^2.3.1"
+ ts-command-line-args "^2.2.0"
+ ts-essentials "^7.0.1"
+
typedarray-to-buffer@^3.1.5:
version "3.1.5"
resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
@@ -4757,6 +4956,16 @@
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.3.tgz#8d84219244a6b40b6fb2b33cc1c062f715b9e826"
integrity sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==
+typical@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4"
+ integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==
+
+typical@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/typical/-/typical-5.2.0.tgz#4daaac4f2b5315460804f0acf6cb69c52bb93066"
+ integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==
+
uglify-js@^3.1.4:
version "3.17.4"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c"
@@ -5201,6 +5410,14 @@
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==
+wordwrapjs@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-4.0.1.tgz#d9790bccfb110a0fc7836b5ebce0937b37a8b98f"
+ integrity sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==
+ dependencies:
+ reduce-flatten "^2.0.0"
+ typical "^5.2.0"
+
workerpool@6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343"