diff --git a/EIPS/eip-1.md b/EIPS/eip-1.md index 2225d4fbd9b4f..e55c0351830a1 100644 --- a/EIPS/eip-1.md +++ b/EIPS/eip-1.md @@ -213,7 +213,7 @@ Which renders to: Permitted Execution Client Specifications URLs must anchor to a specific commit, and so must match this regular expression: ```regex -^(https://github.com/ethereum/execution-specs/blob/[0-9a-f]{40}/.*|https://github.com/ethereum/execution-specs/tree/[0-9a-f]{40}/.*)$ +^(https://github.com/ethereum/execution-specs/(blob|commit)/[0-9a-f]{40}/.*|https://github.com/ethereum/execution-specs/tree/[0-9a-f]{40}/.*)$ ``` ### Consensus Layer Specifications @@ -231,7 +231,7 @@ Which renders to: Permitted Consensus Layer Specifications URLs must anchor to a specific commit, and so must match this regular expression: ```regex -^https://github.com/ethereum/consensus-specs/blob/[0-9a-f]{40}/.*$ +^https://github.com/ethereum/consensus-specs/(blob|commit)/[0-9a-f]{40}/.*$ ``` ### Networking Specifications @@ -249,7 +249,81 @@ Which renders as: Permitted Networking Specifications URLs must anchor to a specific commit, and so must match this regular expression: ```regex -^https://github.com/ethereum/devp2p/blob/[0-9a-f]{40}/.*$ +^https://github.com/ethereum/devp2p/(blob|commit)/[0-9a-f]{40}/.*$ +``` + +### World Wide Web Consortium (W3C) + +Links to a W3C "Recommendation" status specification may be included using normal markdown syntax. For example, the following link would be allowed: + +```markdown +[Secure Contexts](https://www.w3.org/TR/2021/CRD-secure-contexts-20210918/) +``` + +Which renders as: + +[Secure Contexts](https://www.w3.org/TR/2021/CRD-secure-contexts-20210918/) + +Permitted W3C recommendation URLs MUST anchor to a specification in the technical reports namespace with a date, and so MUST match this regular expression: + +```regex +^https://www\.w3\.org/TR/[0-9][0-9][0-9][0-9]/.*$ +``` + +### Web Hypertext Application Technology Working Group (WHATWG) + +Links to WHATWG specifications may be included using normal markdown syntax, such as: + +```markdown +[HTML](https://html.spec.whatwg.org/commit-snapshots/578def68a9735a1e36610a6789245ddfc13d24e0/) +``` + +Which renders as: + +[HTML](https://html.spec.whatwg.org/commit-snapshots/578def68a9735a1e36610a6789245ddfc13d24e0/) + +Permitted WHATWG specification URLs must anchor to a specification defined in the `spec` subdomain (idea specifications are not allowed) and to a commit snapshot, and so must match this regular expression: + +```regex +^https:\/\/[a-z]*\.spec\.whatwg\.org/commit-snapshots/[0-9a-f]{40}/$ +``` + +Although not recommended by WHATWG, EIPs must anchor to a particular commit so that future readers can refer to the exact version of the living standard that existed at the time the EIP was finalized. This gives readers sufficient information to maintain compatibility, if they so choose, with the version referenced by the EIP and the current living standard. + +### Internet Engineering Task Force (IETF) + +Links to an IETF Request For Comment (RFC) specification may be included using normal markdown syntax, such as: + +```markdown +[RFC 8446](https://www.rfc-editor.org/rfc/rfc8446) +``` + +Which renders as: + +[RFC 8446](https://www.rfc-editor.org/rfc/rfc8446) + +Permitted IETF specification URLs MUST anchor to a specification with an assigned RFC number (meaning cannot reference internet drafts), and so MUST match this regular expression: + +```regex +^https:\/\/www.rfc-editor.org\/rfc\/.*$ +``` + +### Bitcoin Improvement Proposal + +Links to Bitcoin Improvement Proposals may be included using normal markdown syntax, such as: + +```markdown +[BIP 38](https://github.com/bitcoin/bips/blob/3db736243cd01389a4dfd98738204df1856dc5b9/bip-0038.mediawiki) +``` + +Which renders to: + +[BIP 38](https://github.com/bitcoin/bips/blob/3db736243cd01389a4dfd98738204df1856dc5b9/bip-0038.mediawiki) + +Permitted Bitcoin Improvement Proposal URLs must anchor to a specific commit, and so must match this regular expression: + +```regex +^(https://github.com/bitcoin/bips/blob/[0-9a-f]{40}/bip-[0-9]+\.mediawiki)$ ``` ### Digital Object Identifier System diff --git a/EIPS/eip-1153.md b/EIPS/eip-1153.md index 3ea30688b1674..6f0be621c76a0 100644 --- a/EIPS/eip-1153.md +++ b/EIPS/eip-1153.md @@ -17,8 +17,8 @@ requires: 2200, 3529 This proposal introduces transient storage opcodes, which manipulate state that behaves identically to storage, except that transient storage is discarded after every transaction. In other words, the values of transient storage are never deserialized from storage or serialized to storage. Thus transient storage is cheaper since it never requires disk access. Transient storage is accessible to smart contracts via 2 new opcodes, `TLOAD` and `TSTORE`, where “T” stands for "transient:" ``` -TLOAD (0xb3) -TSTORE (0xb4) +TLOAD (0x5c) +TSTORE (0x5d) ``` ## Motivation @@ -33,7 +33,7 @@ Potential use cases enabled or improved by this EIP include: 1. Reentrancy locks 2. On-chain computable CREATE2 addresses: constructor arguments are read from the factory contract instead of passed as part of init code hash -3. Single transaction [EIP-20](./eip-20.md) approvals, e.g. `#temporaryApprove(address spender, uint256 amount)` +3. Single transaction [ERC-20](./eip-20.md) approvals, e.g. `#temporaryApprove(address spender, uint256 amount)` 4. Fee-on-transfer contracts: pay a fee to a token contract to unlock transfers for the duration of a transaction 5. "Till" pattern: allowing users to perform all actions as part of a callback, and checking the "till" is balanced at the end 6. Proxy call metadata: pass additional metadata to an implementation contract without using calldata, e.g. values of immutable proxy constructor arguments @@ -42,7 +42,7 @@ These opcodes are more efficient to execute than the `SSTORE` and `SLOAD` opcode ## Specification -Two new opcodes are added to EVM, `TLOAD` (`0xb3`) and `TSTORE` (`0xb4`). Note that previous drafts of this EIP specified the values `0x5c` and `0x5d` for `TLOAD` and `TSTORE` respectively, but these have been modified so as not to conflict with other draft EIPs. +Two new opcodes are added to EVM, `TLOAD` (`0x5c`) and `TSTORE` (`0x5d`). (Note that previous drafts of this EIP specified the values `0xb3` and `0xb4` for `TLOAD` and `TSTORE` respectively to avoid conflict with other EIPs. The conflict has since been removed.) They use the same arguments on stack as `SLOAD` (`0x54`) and `SSTORE` (`0x55`). @@ -70,7 +70,7 @@ Another option to solve the problem of inter-frame communication is repricing th Another approach is to keep the refund counter for transient storage separate from the refund counter for other storage uses, and remove the refund cap for transient storage. However, that approach is more complex to implement and understand. For example, the 20% refund cap must be applied to the gas used _after_ subtracting the uncapped gas refund. Otherwise, the refund amount available subject to the 20% refund cap could be increased by executing transient storage writes. Thus it is preferable to have a separate mechanism that does not interact with the refund counter. Future hard forks can remove the complex refund behavior meant to support the transient storage use case, encouraging migration to contracts that are more efficient for the Ethereum clients to execute. -There is a known objection to the word-addressed storage-like interface of the `TSTORE` and `TLOAD` opcodes since transient storage is more akin to memory than storage in lifecycle. A byte-addressed memory-like interface is another option. The storage-like word-addressed interface is preferred due to the usefulness of mappings in combination with the transaction-scoped memory region. Often times, you will need to keep transient state with arbitrary keys, such as in the [EIP-20](./eip-20.md) temporary approval use case which uses a mapping of `(owner, spender)` to `allowance`. Mappings are difficult to implement using linear memory, and linear memory must also have dynamic gas costs. It is also more complicated to handle reverts with a linear memory. It is possible to have a memory-like interface while the underlying implementation uses a map to allow for storage in arbitrary offsets, but this would result in a third memory-storage hybrid interface that would require new code paths in compilers. +There is a known objection to the word-addressed storage-like interface of the `TSTORE` and `TLOAD` opcodes since transient storage is more akin to memory than storage in lifecycle. A byte-addressed memory-like interface is another option. The storage-like word-addressed interface is preferred due to the usefulness of mappings in combination with the transaction-scoped memory region. Often times, you will need to keep transient state with arbitrary keys, such as in the [ERC-20](./eip-20.md) temporary approval use case which uses a mapping of `(owner, spender)` to `allowance`. Mappings are difficult to implement using linear memory, and linear memory must also have dynamic gas costs. It is also more complicated to handle reverts with a linear memory. It is possible to have a memory-like interface while the underlying implementation uses a map to allow for storage in arbitrary offsets, but this would result in a third memory-storage hybrid interface that would require new code paths in compilers. Some think that a unique transaction identifier may obviate the need for transient storage as described in this EIP. This is a misconception: a transaction identifier used in combination with regular storage has all the same issues that motivate this EIP. The two features are orthogonal. diff --git a/EIPS/eip-1185.md b/EIPS/eip-1185.md index f46d8fcec7fed..77964d90c4e81 100644 --- a/EIPS/eip-1185.md +++ b/EIPS/eip-1185.md @@ -4,7 +4,7 @@ title: Storage of DNS Records in ENS description: A system to store and retrieve DNS records within the ENS contract. author: Jim McDonald (@mcdee) discussions-to: https://ethereum-magicians.org/t/eip1185-dns-resolver-profile-for-ens/1589 -status: Draft +status: Review type: Standards Track category: ERC created: 2018-06-26 diff --git a/EIPS/eip-2015.md b/EIPS/eip-2015.md index 6dbb8ad88aea8..6b359a5e19525 100644 --- a/EIPS/eip-2015.md +++ b/EIPS/eip-2015.md @@ -47,7 +47,7 @@ The `chainId` is the `0x`-prefixed [EIP-155](./eip-155.md)-compliant chain ID. T All keys other than the `chainId` are optional. All keys other than `chainId` are suggestions to the wallet. Wallets can choose to ignore or display other data to users. Wallets should prompt the user before switching or adding chains. Wallets should also store a default list of data for commonly-used chains, in order to avoid phishing attacks. Wallets MUST sanitize each RPC url before using it to send other requests, including ensuring that it responds correctly to the `net_version` and `eth_chainId` methods. -The `wallet_updateEthereumChain` method returns `true` if the chain was successfully added or switched to, and an error with code `4001` if the user rejected the request. +The `wallet_updateEthereumChain` method returns `true` if the active chain matches the requested chain, regardless of whether the chain was already active or was added to the wallet previously. If the user rejects the request, it must return an error with code `4001`. ## Rationale diff --git a/EIPS/eip-2612.md b/EIPS/eip-2612.md index eecb1f7dfc77b..e32295ba1afc7 100644 --- a/EIPS/eip-2612.md +++ b/EIPS/eip-2612.md @@ -12,45 +12,49 @@ requires: 20, 712 --- ## Abstract + Arguably one of the main reasons for the success of [EIP-20](./eip-20.md) tokens lies in the interplay between `approve` and `transferFrom`, which allows for tokens to not only be transferred between externally owned accounts (EOA), but to be used in other contracts under application specific conditions by abstracting away `msg.sender` as the defining mechanism for token access control. However, a limiting factor in this design stems from the fact that the EIP-20 `approve` function itself is defined in terms of `msg.sender`. This means that user's _initial action_ involving EIP-20 tokens must be performed by an EOA (_but see Note below_). If the user needs to interact with a smart contract, then they need to make 2 transactions (`approve` and the smart contract call which will internally call `transferFrom`). Even in the simple use case of paying another person, they need to hold ETH to pay for transaction gas costs. -This ERC extends the EIP-20 standard with a new function `permit`, which allows users to modify the `allowance` mapping using a signed message, instead of through `msg.sender`. +This ERC extends the EIP-20 standard with a new function `permit`, which allows users to modify the `allowance` mapping using a signed message, instead of through `msg.sender`. For an improved user experience, the signed data is structured following [EIP-712](./eip-712.md), which already has wide spread adoption in major RPC providers. **_Note:_** EIP-20 must be performed by an EOA unless the address owning the token is actually a contract wallet. Although contract wallets solves many of the same problems that motivates this EIP, they are currently only scarcely adopted in the ecosystem. Contract wallets suffer from a UX problem -- since they separate the EOA `owner` of the contract wallet from the contract wallet itself (which is meant to carry out actions on the `owner`s behalf and holds all of their funds), user interfaces need to be specifically designed to support them. The `permit` pattern reaps many of the same benefits while requiring little to no change in user interfaces. ## Motivation + While EIP-20 tokens have become ubiquitous in the Ethereum ecosystem, their status remains that of second class tokens from the perspective of the protocol. The ability for users to interact with Ethereum without holding any ETH has been a long outstanding goal and the subject of many EIPs. So far, many of these proposals have seen very little adoption, and the ones that have been adopted (such as [EIP-777](./eip-777.md)), introduce a lot of additional functionality, causing unexpected behavior in mainstream contracts. -This ERC proposes an alternative solution which is designed to be as minimal as possible and to only address _one problem_: the lack of abstraction in the EIP-20 `approve` method. +This ERC proposes an alternative solution which is designed to be as minimal as possible and to only address _one problem_: the lack of abstraction in the EIP-20 `approve` method. While it may be tempting to introduce `*_by_signature` counterparts for every EIP-20 function, they are intentionally left out of this EIP-20 for two reasons: - - the desired specifics of such functions, such as decision regarding fees for `transfer_by_signature`, possible batching algorithms, varies depending on the use case, and, - - they can be implemented using a combination of `permit` and additional helper contracts without loss of generality. +- the desired specifics of such functions, such as decision regarding fees for `transfer_by_signature`, possible batching algorithms, varies depending on the use case, and, +- they can be implemented using a combination of `permit` and additional helper contracts without loss of generality. ## Specification + Compliant contracts must implement 3 new functions in addition to EIP-20: + ```sol function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external function nonces(address owner) external view returns (uint) function DOMAIN_SEPARATOR() external view returns (bytes32) ``` + The semantics of which are as follows: -For all addresses `owner`, `spender`, uint256s `value`, `deadline` and `nonce`, uint8 `v`, bytes32 `r` and `s`, -a call to `permit(owner, spender, value, deadline, v, r, s)` will set +For all addresses `owner`, `spender`, uint256s `value`, `deadline` and `nonce`, uint8 `v`, bytes32 `r` and `s`, +a call to `permit(owner, spender, value, deadline, v, r, s)` will set `approval[owner][spender]` to `value`, increment `nonces[owner]` by 1, -and emit a corresponding `Approval` event, +and emit a corresponding `Approval` event, if and only if the following conditions are met: - - The current blocktime is less than or equal to `deadline`. - `owner` is not the zero address. - `nonces[owner]` (before the state update) is equal to `nonce`. @@ -71,9 +75,11 @@ keccak256(abi.encodePacked( deadline)) )) ``` + where `DOMAIN_SEPARATOR` is defined according to EIP-712. The `DOMAIN_SEPARATOR` should be unique to the contract and chain to prevent replay attacks from other domains, and satisfy the requirements of EIP-712, but is otherwise unconstrained. A common choice for `DOMAIN_SEPARATOR` is: + ```solidity DOMAIN_SEPARATOR = keccak256( abi.encode( @@ -86,7 +92,7 @@ DOMAIN_SEPARATOR = keccak256( ``` In other words, the message is the EIP-712 typed structure: - + ```js { "types": { @@ -129,6 +135,7 @@ In other words, the message is the EIP-712 typed structure: "type": "uint256" } ], + }, "primaryType": "Permit", "domain": { "name": erc20name, @@ -143,14 +150,14 @@ In other words, the message is the EIP-712 typed structure: "nonce": nonce, "deadline": deadline } -}} +} ``` Note that nowhere in this definition we refer to `msg.sender`. The caller of the `permit` function can be any address. - ## Rationale -The `permit` function is sufficient for enabling any operation involving EIP-20 tokens to be paid for using the token itself, rather than using ETH. + +The `permit` function is sufficient for enabling any operation involving EIP-20 tokens to be paid for using the token itself, rather than using ETH. The `nonces` mapping is given for replay protection. @@ -158,11 +165,12 @@ A common use case of `permit` has a relayer submit a `Permit` on behalf of the ` EIP-712 typed messages are included because of its wide spread adoption in many wallet providers. - ## Backwards Compatibility + There are already a couple of `permit` functions in token contracts implemented in contracts in the wild, most notably the one introduced in the `dai.sol`. Its implementation differs slightly from the presentation here in that: + - instead of taking a `value` argument, it takes a bool `allowed`, setting approval to 0 or `uint(-1)`. - the `deadline` argument is instead called `expiry`. This is not just a syntactic change, as it effects the contents of the signed message. @@ -185,4 +193,5 @@ The standard EIP-20 race condition for approvals (SWC-114) applies to `permit` a If the `DOMAIN_SEPARATOR` contains the `chainId` and is defined at contract deployment instead of reconstructed for every signature, there is a risk of possible replay attacks between chains in the event of a future chain split. ## Copyright + Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-3076.md b/EIPS/eip-3076.md index 9023b9d95f0f6..47075b8fa6c80 100644 --- a/EIPS/eip-3076.md +++ b/EIPS/eip-3076.md @@ -3,17 +3,17 @@ eip: 3076 title: Slashing Protection Interchange Format description: A JSON interchange format for proof of stake validators to migrate slashing protection data between clients. author: Michael Sproul (@michaelsproul), Sacha Saint-Leger (@sachayves), Danny Ryan (@djrtwo) -discussions-to: https://ethereum-magicians.org/t/eip-3076-validator-client-interchange-format-slashing-protection/ +discussions-to: https://ethereum-magicians.org/t/eip-3076-validator-client-interchange-format-slashing-protection/4883 status: Last Call +last-call-deadline: 2021-11-03 type: Standards Track category: Interface created: 2020-10-27 -last-call-deadline: 2021-11-03 --- ## Abstract -A standard format for transferring a key's signing history allows validators to easily switch between clients without the risk of signing conflicting messages. While a [common keystore format](https://eips.ethereum.org/EIPS/eip-2335) provides part of the solution, it does not contain any information about a key's signing history. For a validator moving their keys from client A to client B, this could lead to scenarios in which client B inadvertently signs a message that conflicts with an earlier message signed with client A. The interchange format described here provides a solution to this problem. +A standard format for transferring a key's signing history allows validators to easily switch between clients without the risk of signing conflicting messages. While a common keystore format provides part of the solution, it does not contain any information about a key's signing history. For a validator moving their keys from client A to client B, this could lead to scenarios in which client B inadvertently signs a message that conflicts with an earlier message signed with client A. The interchange format described here provides a solution to this problem. ## Motivation @@ -21,7 +21,7 @@ The proof of stake (PoS) protocol penalises validators for voting in ways that c For a validator following the protocol correctly, there is, in principle, no risk of being slashed. However, changing clients (from client A to client B, say) can result in a slashing risk if client B is unaware of the blocks and attestations that were signed with client A. -This can can occur if client A and client B do not agree on what the present time is. For example, say client A's time is accidentally set to a day in the future (225 epochs), and a validator switches from client A to client B without giving B a record of the blocks and attestations signed with A. The validator in question now runs the risk of attesting to two different blocks in the same epoch (a slashable offence) for the next 225 epochs (since they've already voted on these epochs with client A, and now stand to vote on them again with client B). Such time-skew bugs have been observed in the wild. +This can occur if client A and client B do not agree on what the present time is. For example, say client A's time is accidentally set to a day in the future (225 epochs), and a validator switches from client A to client B without giving B a record of the blocks and attestations signed with A. The validator in question now runs the risk of attesting to two different blocks in the same epoch (a slashable offence) for the next 225 epochs (since they've already voted on these epochs with client A, and now stand to vote on them again with client B). Such time-skew bugs have been observed in the wild. Another situation in which slashing protection is critical is in the case of re-orgs. During a re-org it is possible for a validator to be assigned new attestation duties for an epoch in which it has already signed an attestation. In this case it is essential that the record of the previous attestation is available, even if the validator just moved from one client to another in the space of a single epoch. @@ -168,20 +168,22 @@ A valid interchange file is one that adheres to the following JSON schema, and i After importing an interchange file with data field `data`, a signer must respect the following conditions: -1. Refuse to sign any block that is slashable with respect to the blocks contained in `data.signed_blocks`. For details of what constitutes a slashable block, see [process_proposer_slashing][pps]. If the `signing_root` is absent from a block, a signer must assume that any new block with the same `slot` is slashable with respect to the imported block. +1. Refuse to sign any block that is slashable with respect to the blocks contained in `data.signed_blocks`. For details of what constitutes a slashable block, see `process_proposer_slashing` (from `consensus-specs`). If the `signing_root` is absent from a block, a signer must assume that any new block with the same `slot` is slashable with respect to the imported block. 2. Refuse to sign any block with `slot <= min(b.slot for b in data.signed_blocks if b.pubkey == proposer_pubkey)`, except if it is a repeat signing as determined by the `signing_root`. -3. Refuse to sign any attestation that is slashable with respect to the attestations contained in `data.signed_attestations`. For details of what constitutes a slashable attestation, see [is_slashable_attestation_data][isad]. +3. Refuse to sign any attestation that is slashable with respect to the attestations contained in `data.signed_attestations`. For details of what constitutes a slashable attestation, see `is_slashable_attestation_data`. + 4. Refuse to sign any attestation with source epoch less than the minimum source epoch present in that signer's attestations (as seen in `data.signed_attestations`). In pseudocode: -```python3 -source.epoch < - min(att.source_epoch - for att in data.signed_attestations - if att.pubkey == attester_pubkey) -``` -5. Refuse to sign any attestation with target epoch less than or equal to the minimum target epoch present in that signer's attestations (as seen in `data.signed_attestations`). In pseudocode: + ```python3 + source.epoch < + min(att.source_epoch + for att in data.signed_attestations + if att.pubkey == attester_pubkey) + ``` + +5. Refuse to sign any attestation with target epoch less than or equal to the minimum target epoch present in that signer's attestations (as seen in `data.signed_attestations`), except if it is a repeat signing as determined by the `signing_root`. In pseudocode: ```python3 target_epoch <= @@ -196,14 +198,9 @@ target_epoch <= - A signed block or attestation's `signing_root` refers to the message data (hash tree root) that gets signed with a BLS signature. It allows validators to re-sign and re-broadcast blocks or attestations if asked. -- The `signed_blocks` `signing_root`s are calculated using [`compute_signing_root(block, domain)`][csr]: where `block` is the block (of type `BeaconBlock` or `BeaconBlockHeader`) that was signed, and `domain` is equal to [`compute_domain(DOMAIN_BEACON_PROPOSER, fork, metadata.genesis_validators_root)`][cd]. - -- The `signed_attestations` `signing_root`s are calculated using [`compute_signing_root(attestation, domain)`][csr]: where `attestation` is the attestation (of type `AttestationData`) that was signed, and `domain` is equal to [`compute_domain(DOMAIN_BEACON_ATTESTER, fork, metadata.genesis_validators_root)`][cd]. +- The `signed_blocks` `signing_root`s are calculated using `compute_signing_root(block, domain)`: where `block` is the block (of type `BeaconBlock` or `BeaconBlockHeader`) that was signed, and `domain` is equal to `compute_domain(DOMAIN_BEACON_PROPOSER, fork, metadata.genesis_validators_root)`. -[pps]: https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#proposer-slashings -[isad]: https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#is_slashable_attestation_data -[csr]: https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#compute_signing_root -[cd]: https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#compute_domain +- The `signed_attestations` `signing_root`s are calculated using `compute_signing_root(attestation, domain)`: where `attestation` is the attestation (of type `AttestationData`) that was signed, and `domain` is equal to `compute_domain(DOMAIN_BEACON_ATTESTER, fork, metadata.genesis_validators_root)`. ## Rationale @@ -243,20 +240,20 @@ In order to minimise risk and complexity, the format has been designed to map cl For implementers who use a complete record of signed messages to implement their slashing protection database, we make the following recommendations: -* You MUST ensure that, in addition to importing all of the messages from an interchange, all the [conditions](#conditions) are enforced. In particular, conditions (2), (4) and (5) may not have been enforced by your implementation before adopting the interchange format. Our recommendation is to enforce these rules at all times, to keep the implementation clean and minimise the attack surface. For example: your slashing protection mechanism should not sign a block with a slot number less than, or equal to, the minimum slot number of a previously signed block, _irrespective_ of whether that minimum-slot block was imported from an interchange file, or inserted as part of your database's regular operation. -* If your database records the signing roots of messages in addition to their slot/epochs, you should ensure that imported messages without signing roots are assigned a suitable dummy signing root internally. We suggest using a special "null" value which is distinct from all other signing roots, although a value like `0x0` may be used instead (as it is extremely unlikely to collide with any real signing root). -* Care must be taken to avoid signing messages within a gap in the database (an area of unknown signing activity). This could occur if two interchanges were imported with a large gap between the last entry of the first and the first entry of the second. Signing in this gap is not safe, and would violate conditions (2), (4) and (5). It can be avoided by storing an explicit low watermark in addition to the actual messages of the slashing protection database, or by pruning on import so that the oldest messages from the interchange become the oldest messages in the database. +- You MUST ensure that, in addition to importing all of the messages from an interchange, all the [conditions](#conditions) are enforced. In particular, conditions (2), (4) and (5) may not have been enforced by your implementation before adopting the interchange format. Our recommendation is to enforce these rules at all times, to keep the implementation clean and minimise the attack surface. For example: your slashing protection mechanism should not sign a block with a slot number less than, or equal to, the minimum slot number of a previously signed block, _irrespective_ of whether that minimum-slot block was imported from an interchange file, or inserted as part of your database's regular operation. +- If your database records the signing roots of messages in addition to their slot/epochs, you should ensure that imported messages without signing roots are assigned a suitable dummy signing root internally. We suggest using a special "null" value which is distinct from all other signing roots, although a value like `0x0` may be used instead (as it is extremely unlikely to collide with any real signing root). +- Care must be taken to avoid signing messages within a gap in the database (an area of unknown signing activity). This could occur if two interchanges were imported with a large gap between the last entry of the first and the first entry of the second. Signing in this gap is not safe, and would violate conditions (2), (4) and (5). It can be avoided by storing an explicit low watermark in addition to the actual messages of the slashing protection database, or by pruning on import so that the oldest messages from the interchange become the oldest messages in the database. ### Advice for Minimal Databases For implementers who wish to implement their slashing protection database by storing only the latest block and attestation for each validator, we make the following recommendations: -* During import, make sure you take the _maximum_ slot block and _maximum_ source and target attestations for each validator. Although the [conditions](#conditions) require the minimums to be enforced, taking the maximums from an interchange file and merging them with any existing values in the database is the recommended approach. For example, if the interchange file includes blocks for validator `V` at slots 4, 98 and 243, then the latest signed block for validator `V` should be updated to the one from slot 243. However, if the database has already included a block for this validator at a slot greater than 243, for example, slot 351, then the database's existing value should remain unchanged. +- During import, make sure you take the _maximum_ slot block and _maximum_ source and target attestations for each validator. Although the [conditions](#conditions) require the minimums to be enforced, taking the maximums from an interchange file and merging them with any existing values in the database is the recommended approach. For example, if the interchange file includes blocks for validator `V` at slots 4, 98 and 243, then the latest signed block for validator `V` should be updated to the one from slot 243. However, if the database has already included a block for this validator at a slot greater than 243, for example, slot 351, then the database's existing value should remain unchanged. ### General Recommendations -* To avoid exporting an outdated interchange file -- an action which creates a slashing risk -- your implementation should only allow the slashing protection database to be exported when the validator client or signer is _stopped_ -- in other words, when the client or signer is no longer adding new messages to the database. -* Similarly, your implementation should only allow an interchange file to be imported when the validator client is stopped. +- To avoid exporting an outdated interchange file -- an action which creates a slashing risk -- your implementation should only allow the slashing protection database to be exported when the validator client or signer is _stopped_ -- in other words, when the client or signer is no longer adding new messages to the database. +- Similarly, your implementation should only allow an interchange file to be imported when the validator client is stopped. ## Copyright diff --git a/EIPS/eip-3540.md b/EIPS/eip-3540.md index 80439fd64f37f..8dcb0a8c1c010 100644 --- a/EIPS/eip-3540.md +++ b/EIPS/eip-3540.md @@ -162,6 +162,7 @@ For clarity, the *container* refers to the complete account code, while *code* r 4. `CODECOPY`/`CODESIZE`/`EXTCODECOPY`/`EXTCODESIZE`/`EXTCODEHASH` keeps operating on the entire *container*. 5. The input to `CREATE`/`CREATE2` is still the entire *container*. 6. The size limit for deployed code as specified in [EIP-170](./eip-170.md) and for initcode as specified in [EIP-3860](./eip-3860.md) is applied to the entire *container* size, not to the *code* size. This also means if initcode validation fails, it is still charged the EIP-3860 `initcode_cost`. +7. When an EOF1 contract performs a `DELEGATECALL` the target must be EOF1. If it is not EOF1, the `DELEGATECALL` execution finishes as a failed call by pushing `0` to the stack. Only initial gas cost of `DELEGATECALL` is consumed (similarly to the call depth check) and the target address still becomes warm. (*Remark:* Due to [EIP-4750](./eip-4750.md), `JUMP` and `JUMPI` are disabled and therefore are not discussed in relation to EOF.) @@ -250,6 +251,10 @@ It is possible in the future that this data will be accessible with data-specifi The value for `PC` is specified to start at 0 and to be within the active *code* section. We considered keeping `PC` to operate on the whole *container* and be consistent with `CODECOPY`/`EXTCODECOPY` but in the end decided otherwise. This also feels more natural and easier to implement in EVM: the new EOF EVM should only care about traversing *code* and accessing other parts of the *container* only on special occasions (e.g. in `CODECOPY` instruction). +### EOF1 contracts can only `DELEGATECALL` EOF1 contracts + +Currently contracts can selfdestruct in three different ways (directly through `SELFDESTRUCT`, indirectly through `CALLCODE` and indirectly through `DELEGATECALL`). [EIP-3670](./eip-3670.md) disables the first two possibilities, however the third possibility remains. Allowing EOF1 contracts to only `DELEGATECALL` other EOF1 contracts allows the following strong statement: EOF1 contract can never be destructed. Attacks based on `SELFDESTRUCT` completely disappear for EOF1 contracts. These include destructed library contracts (e.g. Parity Multisig). + ## Backwards Compatibility This is a breaking change given that any code starting with `0xEF` was not deployable before (and resulted in exceptional abort if executed), but now some subset of such codes can be deployed and executed successfully. @@ -291,6 +296,10 @@ All cases should be checked for creation transaction, `CREATE` and `CREATE2`. - `EXTCODECOPY` can copy from target's EOF header - `EXTCODECOPY` can copy entire target container - Results don't differ when executed inside legacy or EOF contract +- EOF1 `DELEGATECALL` + - `DELEGATECALL` to EOF1 code succeeds + - `DELEGATECALL` to EOF0 code fails + - `DELEGATECALL` to empty container fails ## Security Considerations diff --git a/EIPS/eip-4788.md b/EIPS/eip-4788.md index 492e12e23fca3..72e787a6ca11d 100644 --- a/EIPS/eip-4788.md +++ b/EIPS/eip-4788.md @@ -14,81 +14,81 @@ created: 2022-02-10 Commit to the hash tree root of each beacon chain block in the corresponding execution payload header. -Store each of these roots in a contract that lives in the execution state and add a new opcode that reads this contract. +Store each of these roots in a stateful precompile. ## Motivation -Roots of the beacon chain blocks are cryptographic accumulators that allow proofs of arbitrary consensus state. Exposing these roots inside the EVM allows for trust-minimized access to the consensus layer. This functionality supports a wide variety of use cases that improve trust assumptions of staking pools, restaking constructions, smart contract bridges, MEV mitigations and more. +Roots of the beacon chain blocks are cryptographic accumulators that allow proofs of arbitrary consensus state. +Exposing these roots inside the EVM allows for trust-minimized access to the consensus layer. +This functionality supports a wide variety of use cases that improve trust assumptions of staking pools, +restaking constructions, smart contract bridges, MEV mitigations and more. ## Specification -| constants | value | units -|--- |--- |--- -| `FORK_TIMESTAMP` | TBD | -| `HISTORY_STORAGE_ADDRESS` | `0xfffffffffffffffffffffffffffffffffffffffd` | -| `OPCODE_VALUE` | `0x4A` | -| `G_beacon_root` | 20 | gas -| `SLOTS_PER_HISTORICAL_ROOT` | 8192 | slot(s) +| constants | value | units +|--- |--- |--- +| `FORK_TIMESTAMP` | TBD | +| `HISTORY_STORAGE_ADDRESS` | `Bytes20(0xB)` | +| `G_beacon_root` | 2100 | gas ### Background The high-level idea is that each execution block contains the parent beacon block root. Even in the event of missed slots since the previous block root does not change, -we only need a constant amount of space to represent this "oracle" in each execution block. To improve the usability of this oracle, block roots are stored -in a canonical place in the execution state analogous to a `SSTORE` in given contract's storage for each update. Roots are stored keyed by the slot(s) they pertain to. +we only need a constant amount of space to represent this "oracle" in each execution block. To improve the usability of this oracle, a small history of block roots +are stored in a stateful precompile. To bound the amount of storage this construction consumes, a ring buffer is used that mirrors a block root accumulator on the consensus layer. -The method for exposing the root data via opcode is inspired by [EIP-2935](./eip-2935.md). ### Block structure and validity -Beginning at the execution timestamp `FORK_TIMESTAMP`, execution clients **MUST**: +Beginning at the execution timestamp `FORK_TIMESTAMP`, execution clients **MUST** extend the header schema with an additional field: the `parent_beacon_block_root`. +This root consumes 32 bytes and is exactly the [hash tree root](https://github.com/ethereum/consensus-specs/blob/fa09d896484bbe240334fa21ffaa454bafe5842e/ssz/simple-serialize.md#merkleization) of the parent beacon block for the given execution block. -1. set 32 bytes of the execution block header after the `withdrawals_root` to the 32 byte [hash tree root](https://github.com/ethereum/consensus-specs/blob/fa09d896484bbe240334fa21ffaa454bafe5842e/ssz/simple-serialize.md#merkleization) of the parent beacon block. - -*NOTE*: this field is appended to the current block header structure with this EIP so that the size of the header grows after (and including) the `FORK_TIMESTAMP`. +Validity is guaranteed from the consensus layer, much like how withdrawals are handled. ### EVM changes #### Block processing -At the start of processing any execution block where `block.timestamp >= FORK_TIMESTAMP` (i.e. before processing any transactions), write the parent beacon root provided in the block header into the storage of the contract at `HISTORY_STORAGE_ADDRESS`. This data is keyed by the slot number. - -In pseudocode: +At the start of processing any execution block where `block.timestamp >= FORK_TIMESTAMP` (i.e. before processing any transactions), +write the parent beacon root provided in the block header into the storage of the contract at `HISTORY_STORAGE_ADDRESS`. -```python -start_timestamp = get_block(block_header.parent_hash).header.timestamp -start_slot = convert_to_slot(start_timestamp) +The root itself is used as a key into the contract's storage and the timestamp of the header is written as the key's value. +The timestamp (a 64-bit unsigned integer value) is encoded as 32 bytes in big-endian format. -end_timestamp = block_header.timestamp -end_slot = convert_to_slot(end_timestamp) +In Python pseudocode: +```python parent_beacon_block_root = block_header.parent_beacon_block_root +timestamp = to_uint256_be(block_header.timestamp) -for slot in range(start_slot, end_slot): - sstore(HISTORY_STORAGE_ADDRESS, slot % SLOTS_PER_HISTORICAL_ROOT, parent_beacon_block_root) +sstore(HISTORY_STORAGE_ADDRESS, parent_beacon_block_root, timestamp) ``` -When using any slot value as a key to the storage, the value under consideration must be converted to 32 bytes with big-endian encoding. +#### New stateful precompile + +Beginning at the execution timestamp `FORK_TIMESTAMP`, the code and storage at `HISTORY_STORAGE_ADDRESS` constitute a "stateful" precompile. -#### New opcode +Callers of the precompile should provide the `root` they are querying encoded as 32 bytes. -Beginning at the execution timestamp `FORK_TIMESTAMP`, introduce a new opcode `BEACON_ROOT` at `OPCODE_VALUE`. -This opcode consumes one word from the stack encoding the slot number for the desired root under big-endian discipline. -The opcode has a gas cost of `G_beacon_state_root`. +Alongside the existing gas for calling the precompile, there is an additional gas cost of `G_beacon_root` cost to reflect the implicit `SLOAD` from +the precompile's state. The timestamp of the corresponding root is returned as 32 bytes in the caller's provided return buffer and represents the +64-bit unsigned integer from the header in big-endian format. -The result of executing this opcode leaves one word on the stack corresponding to a read of the history contract's storage; in pseudocode: +In pseudocode: ```python -slot = evm.stack.pop() -sload(HISTORY_STORAGE_ADDRESS, slot % SLOTS_PER_HISTORICAL_ROOT) +root = evm.calldata[:32] +timestamp = sload(HISTORY_STORAGE_ADDRESS, root) +evm.returndata[:32].set(timestamp) ``` -If there is no root stored at the requested slot number, the opcode follows the existing EVM semantics of `sload` returning `0`. +If there is no timestamp stored at the given root, the opcode follows the existing EVM semantics of `sload` returning `0`. ## Rationale -### Gas cost of opcode +### Gas cost of precompile -The suggested gas cost is just using the value for the `BLOCKHASH` opcode as `BEACON_ROOT` is an analogous operation. +The suggested gas cost reflects a cold `SLOAD` analogous to the operation performed while executing the precompile's logic. ### Why not repurpose `BLOCKHASH`? diff --git a/EIPS/eip-4824.md b/EIPS/eip-4824.md index ed7404e6f9be1..c9dd0459c40d6 100644 --- a/EIPS/eip-4824.md +++ b/EIPS/eip-4824.md @@ -16,23 +16,24 @@ An API standard for decentralized autonomous organizations (DAOs), focused on re ## Motivation -DAOs, since being invoked in the Ethereum whitepaper, have been vaguely defined. This has led to a wide range of patterns but little standardization or interoperability between the frameworks and tools that have emerged. Standardization and interoperability are necessary to support a variety of use-cases. In particular, a standard daoURI, similar to tokenURI in [EIP-721](./eip-721), will enhance DAO discoverability, legibility, proposal simulation, and interoperability between tools. More consistent data across the ecosystem is also a prerequisite for future DAO standards. +DAOs, since being invoked in the Ethereum whitepaper, have been vaguely defined. This has led to a wide range of patterns but little standardization or interoperability between the frameworks and tools that have emerged. Standardization and interoperability are necessary to support a variety of use-cases. In particular, a standard daoURI, similar to tokenURI in [ERC-721](./eip-721), will enhance DAO discoverability, legibility, proposal simulation, and interoperability between tools. More consistent data across the ecosystem is also a prerequisite for future DAO standards. ## Specification The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119. -Every contract implementing this EIP MUST implement the `EIP4824` interface below: +Every contract implementing this EIP MUST implement the [ERC-4824](./eip-4824) interface below: ```solidity pragma solidity ^0.8.1; -/// @title EIP-4824 Common Interfaces for DAOs -/// @dev See https://eips.ethereum.org/EIPS/eip-4824 +/// @title ERC-4824 DAOs +/// @dev See +interface IERC-4824 { + event DAOURIUpdate(address daoAddress, string daoURI); -interface EIP4824 { - /// @notice A distinct Uniform Resource Identifier (URI) pointing to a JSON object following the "EIP-4824 DAO JSON-LD Schema". This JSON file splits into four URIs: membersURI, proposalsURI, activityLogURI, and governanceURI. The membersURI should point to a JSON file that conforms to the "EIP-4824 Members JSON-LD Schema". The proposalsURI should point to a JSON file that conforms to the "EIP-4824 Proposals JSON-LD Schema". The activityLogURI should point to a JSON file that conforms to the "EIP-4824 Activity Log JSON-LD Schema". The governanceURI should point to a flatfile, normatively a .md file. Each of the JSON files named above can be statically-hosted or dynamically-generated. - function daoURI() external view returns (string _daoURI); + /// @notice A distinct Uniform Resource Identifier (URI) pointing to a JSON object following the "ERC-4824 DAO JSON-LD Schema". This JSON file splits into four URIs: membersURI, proposalsURI, activityLogURI, and governanceURI. The membersURI should point to a JSON file that conforms to the "ERC-4824 Members JSON-LD Schema". The proposalsURI should point to a JSON file that conforms to the "ERC-4824 Proposals JSON-LD Schema". The activityLogURI should point to a JSON file that conforms to the "ERC-4824 Activity Log JSON-LD Schema". The governanceURI should point to a flatfile, normatively a .md file. Each of the JSON files named above can be statically-hosted or dynamically-generated. + function daoURI() external view returns (string memory _daoURI); } ``` @@ -47,55 +48,133 @@ The DAO JSON-LD Schema mentioned above: "membersURI": "", "proposalsURI": "", "activityLogURI": "", - "governanceURI": "" + "governanceURI": "", + "contractsURI": "" } ``` -A DAO MAY inherit the above interface above or it MAY create an external registration contract that is compliant with this EIP. The external registration contract MUST store the DAO’s primary address. +A DAO MAY inherit the above interface above or it MAY create an external registration contract that is compliant with this EIP. If a DAO creates an external registration contract, the registration contract MUST store the DAO’s primary address. + +If the DAO inherits the above interface, it SHOULD define a method for updating daoURI. If the DAO uses an external registration contract, the registration contract SHOULD contain some access control logic to enable efficient updating for daoURI. ```solidity pragma solidity ^0.8.1; -/// @title EIP-4824 Common Interfaces for DAOs +/// @title ERC-4824 Common Interfaces for DAOs /// @dev See +/// @title ERC-4824: DAO Registration +contract ERC-4824Registration is IERC-4824, AccessControl { + bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE"); -error NotOwner(); -error NotOffered(); - -contract EIP4824Registration is EIP4824 { string private _daoURI; - address daoAddress; - event NewURI(string daoURI); + address daoAddress; constructor() { daoAddress = address(0xdead); } - function initialize(address _daoAddress, string memory daoURI_) external { + /// @notice Set the initial DAO URI and offer manager role to an address + /// @dev Throws if initialized already + /// @param _daoAddress The primary address for a DAO + /// @param _manager The address of the URI manager + /// @param daoURI_ The URI which will resolve to the governance docs + function initialize( + address _daoAddress, + address _manager, + string memory daoURI_, + address _ERC-4824Index + ) external { + initialize(_daoAddress, daoURI_, _ERC-4824Index); + _grantRole(MANAGER_ROLE, _manager); + } + + /// @notice Set the initial DAO URI + /// @dev Throws if initialized already + /// @param _daoAddress The primary address for a DAO + /// @param daoURI_ The URI which will resolve to the governance docs + function initialize( + address _daoAddress, + string memory daoURI_, + address _ERC-4824Index + ) public { if (daoAddress != address(0)) revert AlreadyInitialized(); daoAddress = _daoAddress; - _daoURI = daoURI_; + _setURI(daoURI_); + + _grantRole(DEFAULT_ADMIN_ROLE, _daoAddress); + _grantRole(MANAGER_ROLE, _daoAddress); + + ERC-4824Index(_ERC-4824Index).logRegistration(address(this)); + } + + /// @notice Update the URI for a DAO + /// @dev Throws if not called by dao or manager + /// @param daoURI_ The URI which will resolve to the governance docs + function setURI(string memory daoURI_) public onlyRole(MANAGER_ROLE) { + _setURI(daoURI_); } - function setURI(string memory daoURI_) external { - if (msg.sender != daoAddress) revert NotOwner(); + function _setURI(string memory daoURI_) internal { _daoURI = daoURI_; - emit NewURI(daoURI_); + emit DAOURIUpdate(daoAddress, daoURI_); } function daoURI() external view returns (string memory daoURI_) { return _daoURI; } + + function supportsInterface( + bytes4 interfaceId + ) public view virtual override returns (bool) { + return + interfaceId == type(IERC-4824).interfaceId || + super.supportsInterface(interfaceId); + } +} +``` + +### Indexing + +If a DAO inherits the ERC-4824 interface from a 4824-compliant DAO factory, then the DAO factory SHOULD incorporate a call to an indexer contract as part of the DAO's initialization to enable efficient network indexing. If the DAO is [ERC-165](./eip-165)-compliant, the factory can do this without additional permissions. If the DAO is _not_ compliant with ERC-165, the factory SHOULD first obtain access control rights to the indexer contract and then call logRegistration directly with the address of the new DAO and the daoURI of the new DAO. Note that any user, including the DAO itself, MAY call logRegistration and submit a registration for a DAO which inherits the ERC-4824 interface and which is also ERC-165-compliant. + +```solidity +pragma solidity ^0.8.1; + +error ERC-4824InterfaceNotSupported(); + +contract ERC-4824Index is AccessControl { + using ERC165Checker for address; + + bytes32 public constant REGISTRATION_ROLE = keccak256("REGISTRATION_ROLE"); + + event DAOURIRegistered(address daoAddress); + + constructor() { + _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); + _grantRole(REGISTRATION_ROLE, msg.sender); + } + + function logRegistrationPermissioned( + address daoAddress + ) external onlyRole(REGISTRATION_ROLE) { + emit DAOURIRegistered(daoAddress); + } + + function logRegistration(address daoAddress) external { + if (!daoAddress.supportsInterface(type(IERC-4824).interfaceId)) + revert ERC-4824InterfaceNotSupported(); + emit DAOURIRegistered(daoAddress); + } } ``` -If a DAO uses an external registration contract, the DAO SHOULD use a common registration factory contract to enable efficient network indexing. +If a DAO uses an external registration contract, the DAO SHOULD use a common registration factory contract linked to a common indexer to enable efficient network indexing. ```solidity pragma solidity ^0.8.1; -/// @title EIP-4824 Common Interfaces for DAOs +/// @title ERC-4824 Common Interfaces for DAOs /// @dev See contract CloneFactory { @@ -118,30 +197,69 @@ contract CloneFactory { } } -contract EIP4824RegistrationFactory is CloneFactory { +contract ERC-4824RegistrationSummoner { event NewRegistration( address indexed daoAddress, string daoURI, address registration ); + address public ERC-4824Index; address public template; /*Template contract to clone*/ - constructor(address _template) public { + constructor(address _template, address _ERC-4824Index) { template = _template; + ERC-4824Index = _ERC-4824Index; } - function summonRegistration(string calldata daoURI_) external { - EIP4824Registration reg = EIP4824Registration(createClone(template)); /*Create a new clone of the template*/ - reg.initialize(msg.sender, daoURI_); - emit NewRegistration(msg.sender, daoURI_, address(reg)); + function registrationAddress( + address by, + bytes32 salt + ) external view returns (address addr, bool exists) { + addr = Clones.predictDeterministicAddress( + template, + _saltedSalt(by, salt), + address(this) + ); + exists = addr.code.length > 0; + } + + function summonRegistration( + bytes32 salt, + string calldata daoURI_, + address manager, + address[] calldata contracts, + bytes[] calldata data + ) external returns (address registration, bytes[] memory results) { + registration = Clones.cloneDeterministic( + template, + _saltedSalt(msg.sender, salt) + ); + + if (manager == address(0)) { + ERC-4824Registration(registration).initialize( + msg.sender, + daoURI_, + ERC-4824Index + ); + } else { + ERC-4824Registration(registration).initialize( + msg.sender, + manager, + daoURI_, + ERC-4824Index + ); + } + + results = _callContracts(contracts, data); + + emit NewRegistration(msg.sender, daoURI_, registration); } -} ``` ### Members -Members JSON-LD Schema. +Members JSON-LD Schema. Every contract implementing this EIP SHOULD implement a membersuRI pointing to a JSON object satisfying this schema. ```json { @@ -163,7 +281,7 @@ Members JSON-LD Schema. ### Proposals -Proposals JSON-LD Schema. Every contract implementing this EIP should implement a proposalsURI pointing to a JSON object satisfying this schema. +Proposals JSON-LD Schema. Every contract implementing this EIP SHOULD implement a proposalsURI pointing to a JSON object satisfying this schema. In particular, any on-chain proposal MUST be associated to an id of the form CAIP10_ADDRESS + “?proposalId=” + PROPOSAL_COUNTER, where CAIP10_ADDRESS is an address following the CAIP-10 standard and PROPOSAL_COUNTER is an arbitrary identifier such as a uint256 counter or a hash that is locally unique per CAIP-10 address. Off-chain proposals MAY use a similar id format where CAIP10_ADDRESS is replaced with an appropriate URI or URL. @@ -196,7 +314,7 @@ In particular, any on-chain proposal MUST be associated to an id of the form CAI ### Activity Log -Activity Log JSON-LD Schema. +Activity Log JSON-LD Schema. Every contract implementing this EIP SHOULD implement a activityLogURI pointing to a JSON object satisfying this schema. ```json { @@ -208,8 +326,8 @@ Activity Log JSON-LD Schema. "id": "", "type": "activity", "proposal": { - "id": "", "type": "proposal" + "id": "", }, "member": { "type": "EthereumAddress", @@ -222,8 +340,8 @@ Activity Log JSON-LD Schema. "id": "", "type": "activity", "proposal": { - "id": "", "type": "proposal" + "id": "", }, "member": { "type": "EthereumAddress", @@ -234,9 +352,43 @@ Activity Log JSON-LD Schema. } ``` +### Contracts + +Contracts JSON-LD Schema. Every contract implementing this EIP SHOULD implement a contractsURI pointing to a JSON object satisfying this schema. + +Further, every contractsURI SHOULD include at least the contract inheriting the ERC-4824 interface. + +``` +{ + "@context": "", + "type": "DAO", + "name": "", + "contracts": [ + { + "type": "EthereumAddress", + "id": "
", + "name": "", + "description": "" + }, + { + "type": "EthereumAddress", + "id": "
", + "name": "", + "description": "" + } + { + "type": "EthereumAddress", + "id": "
", + "name": "", + "description": "" + } + ] +} +``` + ## Rationale -In this standard, we assume that all DAOs possess at least two primitives: *membership* and *behavior*. *Membership* is defined by a set of addresses. *Behavior* is defined by a set of possible contract actions, including calls to external contracts and calls to internal functions. *Proposals* relate membership and behavior; they are objects that members can interact with and which, if and when executed, become behaviors of the DAO. +In this standard, we assume that all DAOs possess at least two primitives: _membership_ and _behavior_. _Membership_ is defined by a set of addresses. _Behavior_ is defined by a set of possible contract actions, including calls to external contracts and calls to internal functions. _Proposals_ relate membership and behavior; they are objects that members can interact with and which, if and when executed, become behaviors of the DAO. ### APIs, URIs, and off-chain data @@ -277,7 +429,7 @@ Proposals have become a standard way for the members of a DAO to trigger on-chai The activity log JSON is intended to capture the interplay between a member of a DAO and a given proposal. Examples of activities include the creation/submission of a proposal, voting on a proposal, disputing a proposal, and so on. -*Alternatives we considered: history, interactions* +_Alternatives we considered: history, interactions_ ### governanceURI @@ -285,7 +437,13 @@ Membership, to be meaningful, usually implies rights and affordances of some sor We chose the word “governance” as an appropriate word that reflects (1) the widespread use of the word in the DAO ecosystem and (2) the common practice of emitting a governance.md file in open-source software projects. -*Alternative names considered: description, readme, constitution* +_Alternative names considered: description, readme, constitution_ + +### contractsURI + +Over the course of community conversations, multiple parties raised the need to report on, audit, and index the different contracts belonging to a given DAO. Some of these contracts are deployed as part of the modular design of a single DAO framework, e.g. the core, voting, and timelock contracts within Open Zeppelin / Compound Governor. In other cases, a DAO might deploy multiple multsigs as treasuries and/or multiple subDAOs that are effectively controlled by the DAO. ContractsURI offers a generic way of declaring these many instruments. + +_Alternative names considered: contractsRegistry, contractsList_ ### Why JSON-LD @@ -300,6 +458,7 @@ The initial draft standard was developed as part of the DAOstar One roundtable s In-person events will be held at Schelling Point 2022 and at ETHDenver 2022, where we hope to receive more comments from the community. We also plan to schedule a series of community calls through early 2022. ## Backwards Compatibility + Existing contracts that do not wish to use this specification are unaffected. DAOs that wish to adopt the standard without updating or migrating contracts can do so via an external registration contract. ## Security Considerations @@ -309,5 +468,6 @@ This standard defines the interfaces for the DAO URIs but does not specify the r Indexers that rely on the data returned by the URI should take caution if DAOs return executable code from the URIs. This executable code might be intended to get the freshest information on membership, proposals, and activity log, but it could also be used to run unrelated tasks. ## Copyright + Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-4844.md b/EIPS/eip-4844.md index c8b35be69e424..f0eb6a364aaf5 100644 --- a/EIPS/eip-4844.md +++ b/EIPS/eip-4844.md @@ -31,7 +31,7 @@ However, data sharding will still take a considerable amount of time to finish i This EIP provides a stop-gap solution until that point by implementing the _transaction format_ that would be used in sharding, but not actually sharding those transactions. Instead, the data from this transaction format is simply part of the beacon chain and is fully downloaded by all consensus nodes (but can be deleted after only a relatively short delay). -Compared to full data sharding, this EIP has a reduced cap on the number of these transactions that can be included, corresponding to a target of ~0.25 MB per block and a limit of ~0.5 MB. +Compared to full data sharding, this EIP has a reduced cap on the number of these transactions that can be included, corresponding to a target of ~0.375 MB per block and a limit of ~0.75 MB. ## Specification @@ -45,10 +45,10 @@ Compared to full data sharding, this EIP has a reduced cap on the number of thes | `BLOB_COMMITMENT_VERSION_KZG` | `Bytes1(0x01)` | | `POINT_EVALUATION_PRECOMPILE_ADDRESS` | `Bytes20(0x14)` | | `POINT_EVALUATION_PRECOMPILE_GAS` | `50000` | -| `MAX_DATA_GAS_PER_BLOCK` | `2**19` | -| `TARGET_DATA_GAS_PER_BLOCK` | `2**18` | +| `MAX_DATA_GAS_PER_BLOCK` | `786432` | +| `TARGET_DATA_GAS_PER_BLOCK` | `393216` | | `MIN_DATA_GASPRICE` | `1` | -| `DATA_GASPRICE_UPDATE_FRACTION` | `2225652` | +| `DATA_GASPRICE_UPDATE_FRACTION` | `3338477` | | `MAX_VERSIONED_HASHES_LIST_SIZE` | `2**24` | | `MAX_CALLDATA_SIZE` | `2**24` | | `MAX_ACCESS_LIST_SIZE` | `2**24` | @@ -99,18 +99,19 @@ def fake_exponential(factor: int, numerator: int, denominator: int) -> int: return output // denominator ``` -### New transaction type +### Blob transaction -We introduce a new [EIP-2718](./eip-2718.md) transaction, "blob transaction", where the `TransactionType` is `BLOB_TX_TYPE` and the `TransactionPayload` is the following RLP value: +We introduce a new [EIP-2718](./eip-2718.md) transaction, "blob transaction", where the `TransactionType` is `BLOB_TX_TYPE` and the `TransactionPayload` is the RLP serialization of the following `TransactionPayloadBody`: ``` -rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data, access_list, max_fee_per_data_gas, blob_versioned_hashes, y_parity, r, s])`. +[chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data, access_list, max_fee_per_data_gas, blob_versioned_hashes, y_parity, r, s] ``` -The `max_priority_fee_per_gas` and `max_fee_per_gas` fields follow [EIP-1559](./eip-1559.md) semantics -and `access_list` follows [EIP-2930](./eip-2930.md). +The fields `chain_id`, `nonce`, `max_priority_fee_per_gas`, `max_fee_per_gas`, `gas_limit`, `value`, `data`, and `access_list` follow the same semantics as [EIP-1559](./eip-1559.md). -The `max_fee_per_data_gas` is `uint256` and the `blob_versioned_hashes` field represents a list hash outputs from `kzg_to_versioned_hash`. +The field `to` deviates slightly from the semantics with the exception that it MUST NOT be `nil` and therefore must always represent a 20-byte address. This means that blob transactions cannot have the form of a create transaction. + +The field `max_fee_per_data_gas` is a `uint256` and the field `blob_versioned_hashes` represents a list of hash outputs from `kzg_to_versioned_hash`. The [EIP-2718](./eip-2718.md) `ReceiptPayload` for this transaction is `rlp([status, cumulative_transaction_gas_used, logs_bloom, logs])`. @@ -122,7 +123,7 @@ The signature values `y_parity`, `r`, and `s` are calculated by constructing a s ### Header extension -The current header encoding is extended with a new 256-bit unsigned integer field `excess_data_gas`. This is the running total of excess data gas consumed on chain since this EIP was activated. If the total amount of data gas is below the +The current header encoding is extended with a new 64-bit unsigned integer field `data_gas_used` and a 64-bit unsigned integer field `excess_data_gas`. This is the running total of excess data gas consumed on chain since this EIP was activated. If the total amount of data gas is below the target, `excess_data_gas` is capped at zero. The resulting RLP encoding of the header is therefore: @@ -146,38 +147,22 @@ rlp([ 0x0000000000000000, # nonce base_fee_per_gas, withdrawals_root, - excess_data_gas + data_gas_used, + excess_data_gas, ]) ``` -The value of `excess_data_gas` can be calculated using the parent header and number of blobs in the block. +The value of `excess_data_gas` can be calculated using the parent header. ```python -def calc_excess_data_gas(parent: Header, new_blobs: int) -> int: - consumed_data_gas = new_blobs * DATA_GAS_PER_BLOB - if parent.excess_data_gas + consumed_data_gas < TARGET_DATA_GAS_PER_BLOCK: +def calc_excess_data_gas(parent: Header) -> int: + if parent.excess_data_gas + parent.data_gas_used < TARGET_DATA_GAS_PER_BLOCK: return 0 else: - return parent.excess_data_gas + consumed_data_gas - TARGET_DATA_GAS_PER_BLOCK + return parent.excess_data_gas + parent.data_gas_used - TARGET_DATA_GAS_PER_BLOCK ``` -For the first post-fork block, `parent.excess_data_gas` is evaluated as `0`. - -### Beacon chain validation - -On the consensus-layer the blobs are now referenced, but not fully encoded, in the beacon block body. -Instead of embedding the full contents in the body, the blobs are propagated separately, as a "sidecar". - -This "sidecar" design provides forward compatibility for further data increases by black-boxing `is_data_available()`: -with full sharding `is_data_available()` can be replaced by data-availability-sampling (DAS) thus avoiding all blobs being downloaded by all beacon nodes on the network. - -Note that the consensus-layer is tasked with persisting the blobs for data availability, the execution-layer is not. - -The `ethereum/consensus-specs` repository defines the following beacon-node changes involved in this EIP: - -- Beacon chain: process updated beacon blocks and ensure blobs are available. -- P2P network: gossip and sync updated beacon block types and new blobs sidecars. -- Honest validator: produce beacon blocks with blobs, publish the blobs sidecars. +For the first post-fork block, both `parent.data_gas_used` and `parent.excess_data_gas` are evaluated as `0`. ### Opcode to get versioned hashes @@ -199,7 +184,7 @@ def point_evaluation_precompile(input: Bytes) -> Bytes: Verify p(z) = y given commitment that corresponds to the polynomial p(x) and a KZG proof. Also verify that the provided commitment matches the provided versioned_hash. """ - # The data is encoded as follows: versioned_hash | z | y | commitment | proof | + # The data is encoded as follows: versioned_hash | z | y | commitment | proof | with z and y being padded 32 byte big endian values assert len(input) == 192 versioned_hash = input[:32] z = input[32:64] @@ -210,7 +195,7 @@ def point_evaluation_precompile(input: Bytes) -> Bytes: # Verify commitment matches versioned_hash assert kzg_to_versioned_hash(commitment) == versioned_hash - # Verify KZG proof + # Verify KZG proof with z and y in big endian format assert verify_kzg_proof(commitment, z, y, proof) # Return FIELD_ELEMENTS_PER_BLOB and BLS_MODULUS as padded 32 byte big endian values @@ -225,8 +210,8 @@ We introduce data gas as a new type of gas. It is independent of normal gas and We use the `excess_data_gas` header field to store persistent data needed to compute the data gas price. For now, only blobs are priced in data gas. ```python -def calc_data_fee(tx: SignedBlobTransaction, parent: Header) -> int: - return get_total_data_gas(tx) * get_data_gasprice(parent) +def calc_data_fee(header: Header, tx: SignedBlobTransaction) -> int: + return get_total_data_gas(tx) * get_data_gasprice(header) def get_total_data_gas(tx: SignedBlobTransaction) -> int: return DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes) @@ -239,54 +224,93 @@ def get_data_gasprice(header: Header) -> int: ) ``` -The block validity conditions are modified to include data gas checks: +The block validity conditions are modified to include data gas checks (see the [Execution layer validation](#execution-layer-validation) section below). + +The actual `data_fee` as calculated via `calc_data_fee` is deducted from the sender balance before transaction execution and burned, and is not refunded in case of transaction failure. + +### Consensus layer validation + +On the consensus layer the blobs are referenced, but not fully encoded, in the beacon block body. +Instead of embedding the full contents in the body, the blobs are propagated separately, as "sidecars". + +This "sidecar" design provides forward compatibility for further data increases by black-boxing `is_data_available()`: +with full sharding `is_data_available()` can be replaced by data-availability-sampling (DAS) thus avoiding all blobs being downloaded by all beacon nodes on the network. + +Note that the consensus layer is tasked with persisting the blobs for data availability, the execution layer is not. + +The `ethereum/consensus-specs` repository defines the following consensus layer changes involved in this EIP: + +- Beacon chain: process updated beacon blocks and ensure blobs are available. +- P2P network: gossip and sync updated beacon block types and new blob sidecars. +- Honest validator: produce beacon blocks with blobs; sign and publish the associated blob sidecars. + +### Execution layer validation + +On the execution layer, the block validity conditions are extended as follows: ```python def validate_block(block: Block) -> None: ... + + # check that the excess data gas was updated correctly + assert block.header.excess_data_gas == calc_excess_data_gas(block.parent.header) - num_blobs = 0 + data_gas_used = 0 + for tx in block.transactions: ... - # the signer must be able to afford the transaction - assert signer(tx).balance >= tx.gas * tx.max_fee_per_gas + get_total_data_gas(tx) * tx.max_fee_per_data_gas + # modify the check for sufficient balance + max_total_fee = tx.gas * tx.max_fee_per_gas + if type(tx) is SignedBlobTransaction: + max_total_fee += get_total_data_gas(tx) * tx.max_fee_per_data_gas + assert signer(tx).balance >= max_total_fee - # ensure that the user was willing to at least pay the current data gasprice - assert tx.max_fee_per_data_gas >= get_data_gasprice(parent(block).header) + ... - num_blobs += len(tx.blob_versioned_hashes) + # add validity logic specific to blob txs + if type(tx) is SignedBlobTransaction: + # there must be at least one blob + assert len(tx.blob_versioned_hashes) > 0 - # check that the excess data gas is correct - expected_edg = calc_excess_data_gas(parent(block).header, num_blobs) - assert expected_edg == block.excess_data_gas -``` + # all versioned blob hashes must start with BLOB_COMMITMENT_VERSION_KZG + for h in tx.blob_versioned_hashes: + assert h[0] == BLOB_COMMITMENT_VERSION_KZG -The actual `data_fee` as calculated via `calc_data_fee` is deducted from the sender balance before transaction execution and burned, and is not refunded in case of transaction failure. + # ensure that the user was willing to at least pay the current data gasprice + assert tx.max_fee_per_data_gas >= get_data_gasprice(block.header) + + # keep track of total data gas spent in the block + data_gas_used += get_total_data_gas(tx) + + # ensure the total data gas spent is at most equal to the limit + assert data_gas_used <= MAX_DATA_GAS_PER_BLOCK + + # ensure data_gas_used matches header + assert block.header.data_gas_used == data_gas_used + +``` ### Networking Blob transactions have two network representations. During transaction gossip responses (`PooledTransactions`), the EIP-2718 `TransactionPayload` of the blob transaction is wrapped to become: ``` -rlp([blob_tx_payload, blob_kzgs, blobs, blob_kzg_proofs]) +rlp([tx_payload_body, blobs, commitments, proofs]) ``` Each of these elements are defined as follows: -- `blob_tx_payload` - standard EIP-2718 blob transaction `TransactionPayload` -- `blob_kzgs` - list of `KZGCommitment` -- `blobs` - list of `blob` where `blob` is a list of `BLSFieldElement` -- `kzg_aggregated_proof` - `KZGProof` +- `tx_payload_body` - is the `TransactionPayloadBody` of standard EIP-2718 [blob transaction](#blob-transaction) +- `blobs` - list of `blob` bytes where each `blob` is its `BLSFieldElement` list flattened in `big endian` +- `commitments` - list of `KZGCommitment` of the corresponding `blobs` +- `proofs` - list of `KZGProof` of the corresponding `blobs` and `commitments` -The node MUST validate `blob_tx_payload` and verify the wrapped data against it. To do so, ensure that: +The node MUST validate `tx_payload_body` and verify the wrapped data against it. To do so, ensure that: -- `blob_tx_payload.blob_versioned_hashes` must not be empty -- All hashes in `blob_tx_payload.blob_versioned_hashes` must start with the byte `BLOB_COMMITMENT_VERSION_KZG` -- There must be at most `MAX_DATA_GAS_PER_BLOCK // DATA_GAS_PER_BLOB` total blob commitments in the transaction. -- There are an equal number of versioned hashes, kzg commitments, and blobs. -- The KZG commitments hash to the versioned hashes, i.e. `kzg_to_versioned_hash(kzg[i]) == versioned_hash[i]` -- The KZG commitments match the blob contents. (Note: this can be optimized using `blob_kzg_proofs`, with a proof for a +- There are an equal number of `tx_payload_body.blob_versioned_hashes`, `blobs`, `commitments`, and `proofs`. +- The KZG `commitments` hash to the versioned hashes, i.e. `kzg_to_versioned_hash(commitments[i]) == tx_payload_body.blob_versioned_hashes[i]` +- The KZG `commitments` match the corresponding `blobs` and `proofs`. (Note: this can be optimized using `blob_kzg_proofs`, with a proof for a random evaluation at a point derived from the commitment and blob data for each blob) For body retrieval responses (`BlockBodies`), the standard EIP-2718 blob transaction `TransactionPayload` is used. @@ -299,7 +323,7 @@ Instead, those transactions are only announced using `NewPooledTransactionHashes ### On the path to sharding This EIP introduces blob transactions in the same format in which they are expected to exist in the final sharding specification. -This provides a temporary but significant scaling relief for rollups by allowing them to initially scale to 0.25 MB per slot, +This provides a temporary but significant scaling relief for rollups by allowing them to initially scale to 0.375 MB per slot, with a separate fee market allowing fees to be very low while usage of this system is limited. The core goal of rollup scaling stopgaps is to provide temporary scaling relief, @@ -376,7 +400,7 @@ The parameter `DATA_GASPRICE_UPDATE_FRACTION` controls the maximum rate of chang ### Throughput -The values for `TARGET_DATA_GAS_PER_BLOCK` and `MAX_DATA_GAS_PER_BLOCK` are chosen to correspond to a target of 2 blobs (0.25 MB) and maximum of 4 blobs (0.5 MB) per block. These small initial limits are intended to minimize the strain on the network created by this EIP and are expected to be increased in future upgrades as the network demonstrates reliability under larger blocks. +The values for `TARGET_DATA_GAS_PER_BLOCK` and `MAX_DATA_GAS_PER_BLOCK` are chosen to correspond to a target of 3 blobs (0.375 MB) and maximum of 6 blobs (0.75 MB) per block. These small initial limits are intended to minimize the strain on the network created by this EIP and are expected to be increased in future upgrades as the network demonstrates reliability under larger blocks. ## Backwards Compatibility @@ -384,7 +408,7 @@ The values for `TARGET_DATA_GAS_PER_BLOCK` and `MAX_DATA_GAS_PER_BLOCK` are chos This EIP introduces a transaction type that has a distinct mempool version and execution-payload version, with only one-way convertibility between the two. The blobs are in the network representation and not in the consensus representation; -instead, they go into the `BeaconBlockBody`. This means that there is now a part of a transaction that will not be accessible from the web3 API. +instead, they are coupled with the beacon block. This means that there is now a part of a transaction that will not be accessible from the web3 API. ### Mempool issues @@ -403,9 +427,9 @@ TBD ## Security Considerations -This EIP increases the storage requirements per Beacon block by a maximum of ~0.5 MB. -This is 4x larger than the theoretical maximum size of a block today (30M gas / 16 gas per calldata byte = 1.875M bytes), and so it will not greatly increase worst-case bandwidth. -Post-merge, block times are expected to be static rather than an unpredictable Poisson distribution, giving a guaranteed period of time for large blocks to propagate. +This EIP increases the bandwidth requirements per beacon block by a maximum of ~0.75 MB. +This is 40% larger than the theoretical maximum size of a block today (30M gas / 16 gas per calldata byte = 1.875M bytes), and so it will not greatly increase worst-case bandwidth. +Post-merge, block times are static rather than an unpredictable Poisson distribution, giving a guaranteed period of time for large blocks to propagate. The _sustained_ load of this EIP is much lower than alternatives that reduce calldata costs, even if the calldata is limited, because there is no existing software that stores the blobs indefinitely and there is no expectation that they need to be stored for as long as an execution payload. diff --git a/EIPS/eip-4955.md b/EIPS/eip-4955.md index ee650ebae1e77..9a3b98b74f53d 100644 --- a/EIPS/eip-4955.md +++ b/EIPS/eip-4955.md @@ -17,7 +17,7 @@ This EIP standardizes a schema for NFTs metadata to add new field namespaces to ## Motivation -A standardized NFT metadata schema allows wallets, marketplaces, metaverses, and sililar applications to interoperate with any NFT. Applications such as NFT marketplaces and metaverses could usefully leverage NFTs by rendering them using custom 3D representations or any other new attributes. +A standardized NFT metadata schema allows wallets, marketplaces, metaverses, and similar applications to interoperate with any NFT. Applications such as NFT marketplaces and metaverses could usefully leverage NFTs by rendering them using custom 3D representations or any other new attributes. Some projects like Decentraland, TheSandbox, Cryptoavatars, etc. need their own 3D model in order to represent an NFT. These models are not cross-compatible because of distinct aesthetics and data formats. diff --git a/EIPS/eip-5007.md b/EIPS/eip-5007.md index adea9ce2704c5..a378410137f03 100755 --- a/EIPS/eip-5007.md +++ b/EIPS/eip-5007.md @@ -4,8 +4,7 @@ title: Time NFT, ERC-721 Time Extension description: Add start time and end time to ERC-721 tokens. author: Anders (@0xanders), Lance (@LanceSnow), Shrug discussions-to: https://ethereum-magicians.org/t/eip-5007-eip-721-time-extension/8924 -status: Last Call -last-call-deadline: 2023-05-15 +status: Final type: Standards Track category: ERC created: 2022-04-13 diff --git a/EIPS/eip-5169.md b/EIPS/eip-5169.md index 85a48184e274e..03fb383158885 100644 --- a/EIPS/eip-5169.md +++ b/EIPS/eip-5169.md @@ -4,8 +4,7 @@ title: Client Script URI for Token Contracts description: Add a scriptURI to point to an executable script associated with the functionality of the token. author: James (@JamesSmartCell), Weiwu (@weiwu-zhang) discussions-to: https://ethereum-magicians.org/t/eip-5169-client-script-uri-for-token-contracts/9674 -status: Last Call -last-call-deadline: 2023-05-12 +status: Final type: Standards Track category: ERC created: 2022-05-03 diff --git a/EIPS/eip-5202.md b/EIPS/eip-5202.md index b7b35009adcdf..bfd327a2f974b 100644 --- a/EIPS/eip-5202.md +++ b/EIPS/eip-5202.md @@ -4,7 +4,8 @@ title: Blueprint contract format description: Define a bytecode container format for indexing and utilizing blueprint contracts author: Charles Cooper (@charles-cooper), Edward Amor (@skellet0r) discussions-to: https://ethereum-magicians.org/t/erc-5202-standard-factory-contract-format/9851 -status: Review +status: Last Call +last-call-deadline: 2023-06-01 type: Standards Track category: ERC created: 2022-06-23 @@ -12,15 +13,18 @@ requires: 170 --- ## Abstract + Define a standard for "blueprint" contracts, or contracts which represent initcode that is stored on-chain. ## Motivation + To decrease deployer contract size, a useful pattern is to store initcode on chain as a "blueprint" contract, and then use `EXTCODECOPY` to copy the initcode into memory, followed by a call to `CREATE` or `CREATE2`. However, this comes with the following problems: - It is hard for external tools and indexers to detect if a contract is a "regular" runtime contract or a "blueprint" contract. Heuristically searching for patterns in bytecode to determine if it is initcode poses maintenance and correctness problems. - Storing initcode byte-for-byte on-chain is a correctness and security problem. Since the EVM does not have a native way to distinguish between executable code and other types of code, unless the initcode explicitly implements ACL rules, *anybody* can call such a "blueprint" contract and execute the initcode directly as ordinary runtime code. This is particularly problematic if the initcode stored by the blueprint contract has side effects such as writing to storage or calling external contracts. If the initcode stored by the blueprint contract executes a `SELFDESTRUCT` opcode, the blueprint contract could even be removed, preventing the correct operation of downstream deployer contracts that rely on the blueprint existing. For this reason, it would be good to prefix blueprint contracts with a special preamble to prevent execution. ## Specification + The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119. A blueprint contract MUST use the preamble `0xFE71`. 6 bits are allocated to the version, and 2 bits to the length encoding. The first version begins at 0 (`0b000000`), and versions increment by 1. The value `0b11` for `` is reserved. In the case that the length bits are `0b11`, the third byte is considered a continuation byte (that is, the version requires multiple bytes to encode). The exact encoding of a multi-byte version is left to a future ERC. @@ -30,6 +34,7 @@ A blueprint contract MUST contain at least one byte of initcode. A blueprint contract MAY insert any bytes (data or code) between the version byte(s) and the initcode. If such variable length data is used, the preamble must be `0xFE71`. The `` represent a number between 0 and 2 (inclusive) describing how many bytes `` takes, and `` is the big-endian encoding of the number of bytes that `` takes. ## Rationale + - To save gas and storage space, the preamble should be as minimal as possible. - It is considered "bad" behavior to try to CALL a blueprint contract directly, therefore the preamble starts with `INVALID (0xfe)` to end execution with an exceptional halting condition (rather than a "gentler" opcode like `STOP (0x00)`). @@ -44,11 +49,36 @@ A blueprint contract MAY insert any bytes (data or code) between the version byt - The length of the initcode itself is not included by default in the preamble because it takes space, and it can be trivially determined using `EXTCODESIZE`. -- The EOF ([EIP-3540](./eip-3540.md)) could provide another way of specifying blueprint contracts, by adding another section kind (3 - initcode). However, it is not yet in the EVM, and we would like to be able to standardize blueprint contracts today, without relying on EVM changes. If, at some future point, section kind 3 becomes part of the EOF spec, and the EOF becomes part of the EVM, this ERC will be considered to be obsolesced since the EOF validation spec provides much stronger guarantees than this ERC. +- The Ethereum Object Format (EOF) could provide another way of specifying blueprint contracts, by adding another section kind (3 - initcode). However, it is not yet in the EVM, and we would like to be able to standardize blueprint contracts today, without relying on EVM changes. If, at some future point, section kind 3 becomes part of the EOF spec, and the EOF becomes part of the EVM, this ERC will be considered to be obsolesced since the EOF validation spec provides much stronger guarantees than this ERC. ## Backwards Compatibility -Needs discussion + +No known issues + +## Test Cases + +- An example (and trivial!) blueprint contract with no data section, whose initcode is just the `STOP` instruction: + +``` +0xFE710000 +``` + +- An example blueprint contract whose initcode is the trivial `STOP` instruction and whose data section contains the byte `0xFF` repeated seven times: + +``` +0xFE710107FFFFFFFFFFFFFF00 +``` + +Here, 0xFE71 is the magic header, `0x01` means version 0 + 1 length bit, `0x07` encodes the length in bytes of the data section. These are followed by the data section, and then the initcode. For illustration, the above code with delimiters would be `0xFE71|01|07|FFFFFFFFFFFFFF|00`. + +- An example blueprint whose initcode is the trivial `STOP` instruction and whose data section contains the byte `0xFF` repeated 256 times: + +``` +0xFE71020100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +``` + +Delimited, that would be `0xFE71|02|0100|FF...FF|00`. ## Reference Implementation @@ -95,6 +125,23 @@ def parse_blueprint_preamble(bytecode: bytes) -> Tuple[int, Optional[bytes], byt return erc_version, preamble_data, initcode ``` +The following reference function takes the desired initcode for a blueprint as a parameter, and returns EVM code which will deploy a corresponding blueprint contract (with no data section): + +```python +def blueprint_deployer_bytecode(initcode: bytes) -> bytes: + blueprint_preamble = b"\xFE\x71\x00" # ERC5202 preamble + blueprint_bytecode = blueprint_preamble + initcode + + # the length of the deployed code in bytes + len_bytes = len(blueprint_bytecode).to_bytes(2, "big") + + # copy to memory and `RETURN` it per EVM creation semantics + # PUSH2 RETURNDATASIZE DUP2 PUSH1 10 RETURNDATASIZE CODECOPY RETURN + deploy_bytecode = b"\x61" + len_bytes + b"\x3d\x81\x60\x0a\x3d\x39\xf3" + + return deploy_bytecode + blueprint_bytecode +``` + ## Security Considerations There could be contracts on-chain already which happen to start with the same prefix as proposed in this ERC. However, this is not considered a serious risk, because the way it is envisioned that indexers will use this is to verify source code by compiling it and prepending the preamble. @@ -102,4 +149,5 @@ There could be contracts on-chain already which happen to start with the same pr As of 2022-07-08, no contracts deployed on the Ethereum mainnet have a bytecode starting with `0xFE71`. ## Copyright + Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-5564.md b/EIPS/eip-5564.md index 9fc6da2ad8fee..e2a2e03dac216 100644 --- a/EIPS/eip-5564.md +++ b/EIPS/eip-5564.md @@ -101,12 +101,13 @@ This specification additionally defines a singleton `ERC5564Messenger` contract ```solidity /// @notice Interface for announcing when something is sent to a stealth address. -contract IERC5564Messenger is StakeManager{ +contract IERC5564Messenger { /// @dev Emitted when sending something to a stealth address. /// @dev See the `announce` method for documentation on the parameters. event Announcement ( uint256 indexed schemeId, address indexed stealthAddress, + address indexed caller, bytes ephemeralPubKey, bytes metadata ); @@ -141,57 +142,11 @@ contract IERC5564Messenger is StakeManager{ ) external { - emit Announcement(schemeId, stealthAddress, ephemeralPubKey, metadata); + emit Announcement(schemeId, stealthAddress, msg.sender, ephemeralPubKey, metadata); } } ``` -The `ERC5564Messenger` contract inherits the `StakeManager` contract allowing users to stake ETH that is used as an anti-DoS measure. More details in the [DoS Countermeasures](#dos-countermeasures) section. - -```solidity -/// @notice Interface for the Stake Manager contract. -contract StakeManager{ - - /// @dev Emitted when stake is deposited. - /// @param account The address of the staker who deposited the stake. - /// @param totalStaked The new total amount of staked tokens for the account. - event StakeDeposit ( - address indexed account, - uint256 totalStaked - ); - - /// @dev Emitted when stake is withdrawn. - /// @param account The address of the staker who withdrew the stake. - /// @param withdrawAddress The address to which the withdrawn amount was sent. - /// @param amount The amount of tokens withdrawn. - event StakeWithdrawal ( - address indexed account, - address withdrawAddress, - uint256 amount - ); - - /** - * @notice Returns the stake of the account. - * @param account The address of the staker to check the stake for. - * @return uint256 The amount of staked tokens for the account. - */ - function balanceOf(address account) external view returns (uint256); - - /** - * @notice Adds the specified amount to the account's stake. - * @dev The function is payable, so the amount is sent as value with the transaction. - * @param staker The address of the staker to add the stake for. - */ - function addStake(address staker) external payable; - - /** - * @notice Withdraws the stake for the caller and sends it to the specified address. - * @param withdrawAddress The address to send the withdrawn amount to. - */ - function withdrawStake(address payable withdrawAddress) external; -} -``` - ### Stealth meta-address format @@ -289,13 +244,13 @@ The view tags approach is introduced to reduce the parsing time by around 6x. Us ## Rationale -This EIP emerged from the need of having privacy-preserving ways to transfer ownership without disclosing any information about the recipients' identities. Token ownership can expose sensitive personal information. While individuals may wish to donate to a specific organization or country, they might prefer not to disclose a link between themselves and the recipient at the same time. Standardizing stealth address generation represents a significant step towards unlinkable interactions, since such privacy-enhancing solutions require standards to achieve widespread adoption. Consequently, it is crucial to concentrate on developing generalizable approaches for implementing related solutions. +This EIP emerged from the need for privacy-preserving ways to transfer ownership without disclosing any information about the recipients' identities. Token ownership can expose sensitive personal information. While individuals may wish to donate to a specific organization or country, they might prefer not to disclose a link between themselves and the recipient simultaneously. Standardizing stealth address generation represents a significant step towards unlinkable interactions, since such privacy-enhancing solutions require standards to achieve widespread adoption. Consequently, it is crucial to focus on developing generalizable approaches for implementing related solutions. The stealth address specification standardizes a protocol for generating and locating stealth addresses, facilitating the transfer of assets without requiring prior interaction with the recipient. This enables recipients to verify the receipt of a transfer without the need to interact with the blockchain and query account balances. Importantly, stealth addresses enable token transfer recipients to verify receipt while maintaining their privacy, as only the recipient can recognize themselves as the recipient of the transfer. The authors recognize the trade-off between on- and off-chain efficiency. Although incorporating a Monero-like view tags mechanism enables recipients to parse announcements more efficiently, it adds complexity to the announcement event. -The address of the recipient and the `viewTag` MUST be included in the announcement event, allowing users to quickly verify ownership without querying the chain for positive account balances. +The recipient's address and the `viewTag` MUST be included in the announcement event, allowing users to quickly verify ownership without querying the chain for positive account balances. ## Backwards Compatibility @@ -310,16 +265,18 @@ You can find an implementation of this standard in TBD. ### DoS Countermeasures There are potential denial of service (DoS) attack vectors that are not mitigated by network transaction fees. Stealth transfer senders cause an externality for recipients, as parsing announcement events consumes computational resources that are not compensated with gas. Therefore, spamming announcement events *can* be a detriment to the user experience, as it *can* lead to longer parsing times. -We consider the incentives to carry out such an attack to be low because **no monetary benefit can be obtained** and, in theory, nothing prevents parsing providers from ignoring the spamming when serving announcements to users. -However, sophisticated spamming (*sybil attacks*), which are not considered worth the associated costs, could make it difficult for parsing providers to develop filters for such announcement events. -Therefore, to counter spamming directly, a staking mechanism is introduced in the EIP that allows users to stake an unslashable amount of ETH. Staking allows parsing providers to better tackle potential spam through *sybil attacks*, enabling them to filter spam more effectively. +We consider the incentives to carry out such an attack to be low because **no monetary benefit can be obtained** +However, to tackle potential spam, parsing providers may adopt their own anti-DoS attack methods. These may include ignoring the spamming users when serving announcements to users or, less harsh, de-prioritizing them when ordering the announcements. The indexed `caller` keyword may help parsing providers to effectively filter known spammers. -Similarly to [ERC-4337](./eip-4337), parsing providers agree on a `MINIMUM_STAKE`, such that the minimum required stake is not enforced on-chain. Users *can* withdraw their stake at any time without any delay. Parsing providers can de-prioritize senders who have not staked a certain minimum amount or withdrew their stake immediately. +Furthermore, parsing providers have a few options to counter spam, such as introducing staking mechanisms or requiring senders to pay a `toll` before including their `Announcement`. Moreover, a Staking mechanism may allow users to stake an unslashable amount of ETH (similarly to [ERC-4337](./eip-4337)), to help mitigate potential spam through *sybil attacks* and enable parsing providers filtering spam more effectively. +Introducing a `toll`, paid by sending users, would simply put a cost on each stealth address transaction, making spamming economically unattractive. ### Recipients' transaction costs The funding of the stealth address wallet represents a known issue that might breach privacy. The wallet that funds the stealth address MUST NOT have any physical connection to the stealth address owner in order to fully leverage the privacy improvements. +Thus, the sender may attach a small amount of ETH to each stealth address transaction, thereby sponsoring subsequent transactions of the recipient. + ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-5570.md b/EIPS/eip-5570.md index 65218c966c2e2..90e4c547d7d84 100644 --- a/EIPS/eip-5570.md +++ b/EIPS/eip-5570.md @@ -4,8 +4,7 @@ title: Digital Receipt Non-Fungible Tokens description: Non-Fungible Tokens as digital receipts for physical purchases, where the metadata represents a JSON receipt author: Sean Darcy (@darcys22) discussions-to: https://ethereum-magicians.org/t/idea-standard-digital-receipts-using-erc-721/9908 -status: Last Call -last-call-deadline: 2023-05-16 +status: Final type: Standards Track category: ERC created: 2022-09-01 @@ -163,7 +162,7 @@ The JSON schema is composed of 2 parts. The root schema contains high level deta "title": "Comments", "description": "Any messages/comments the issuer wishes to convey to the customer", "type": "string" - }, + } } }, "image": { @@ -175,7 +174,7 @@ The JSON schema is composed of 2 parts. The root schema contains high level deta "title": "Signature", "description": "Digital signature by the vendor of receipts data", "type": "string" - } + }, "extra": { "title": "Extra", "description": "Extra information about the business/receipt as needed", diff --git a/EIPS/eip-5656.md b/EIPS/eip-5656.md index 3682a57c25377..be0b1a26a2db1 100644 --- a/EIPS/eip-5656.md +++ b/EIPS/eip-5656.md @@ -56,7 +56,7 @@ where it is identified as a significant overhead. ## Specification -The instruction `MCOPY` is introduced at `0xb7`. +The instruction `MCOPY` is introduced at `0x5E`. ### Input stack diff --git a/EIPS/eip-5920.md b/EIPS/eip-5920.md index ce304eab67686..2eb994c6b8a49 100644 --- a/EIPS/eip-5920.md +++ b/EIPS/eip-5920.md @@ -24,20 +24,19 @@ Currently, to send ether to an address requires you to call a function of that a | Parameter | Value | | ------------------- | ------- | | `PAY_OPCODE` | `0xf9` | -| `GAS_COST` | `3000` | A new opcode is introduced: `PAY` (`PAY_OPCODE`), which: - Pops two values from the stack: `addr` then `val`. -- Transfers `val` wei from the executing address to the address `addr`. If `addr` is the zero address, instead, `val` wei is burned from the executing address. +- Transfers `val` wei from the executing address to the address `addr`, even if `addr` is the zero address. -The cost of this opcode is `GAS_COST`. If `addr` is not the zero address, the [EIP-2929](./eip-2929.md) account access costs are also incurred (this includes the 25k gas cost for adding a new account to the state). +The base cost of this opcode is the additional cost of having a nonzero `msg.value` in a `CALL` opcode (currently `9000`). If `addr` is not the zero address, the [EIP-2929](./eip-2929.md) account access costs for `addr` (but NOT the current account) are also incurred: 100 gas for a warm account, 2600 gas for a cold account, and 25000 gas for a new account. If any of these costs are changed, the pricing for the `PAY` opcode must also be changed. ## Rationale ### Gas pricing -The gas pricing is that of a `CALL` with a positive `msg.value`, but without any memory expansion costs or "gas sent with call" costs, with a gas reduction of `500` to compensate for the reduced amount of computation. +The additional nonzero `msg.value` cost of the `CALL` should equal the cost of transferring ether. Therefore, that is the base cost of this opcode. Additionally, the access costs for the receiving account make sense, since the account needs to be accessed. However, it is reasonable to assume that optimized execution clients have the data for the executing contract cached. ### Argument order diff --git a/EIPS/eip-6065.md b/EIPS/eip-6065.md index fcb237a52c204..f36cf08b809a2 100644 --- a/EIPS/eip-6065.md +++ b/EIPS/eip-6065.md @@ -4,7 +4,7 @@ title: Real Estate Token description: An interface for real estate NFTs that extends ERC-721 author: Alex (@Alex-Klasma), Ben Fusek (@bfusek), Daniel Fallon-Cyr (@dfalloncyr) discussions-to: https://ethereum-magicians.org/t/updated-eip-6065-real-estate-token/11936 -status: Draft +status: Review type: Standards Track category: ERC created: 2022-11-29 @@ -19,7 +19,7 @@ This proposal introduces an open structure for physical real estate and property Real estate is the largest asset class in the world. By tokenizing real estate, barriers to entry are lowered, transaction costs are minimized, information asymmetry is reduced, ownership structures become more malleable, and a new building block for innovation is formed. However, in order to tokenize this asset class, a common standard is needed that accounts for its real world particularities while remaining flexible enough to adapt to various jurisdictions and regulatory environments. -Ethereum tokens involving real world assets are notoriously tricky. This is because Ethereum tokens exist on-chain, while real estate exists off-chain. As such, the two are subject to entirely different consensus environments. For Ethereum tokens, consensus is reached through a formalized process of distributed validators. When a purely-digital NFT is transferred, the new owner has a cryptographic guarantee of ownership. For real estate, consensus is supported by legal contracts, property law, and enforced by the court system. With existing asset-backed ERC-721 tokens, a transfer of the token to another individual does not necessarily have any impact on the legal ownership of the physical asset. +Ethereum tokens involving real world assets (RWAs) are notoriously tricky. This is because Ethereum tokens exist on-chain, while real estate exists off-chain. As such, the two are subject to entirely different consensus environments. For Ethereum tokens, consensus is reached through a formalized process of distributed validators. When a purely-digital NFT is transferred, the new owner has a cryptographic guarantee of ownership. For real estate, consensus is supported by legal contracts, property law, and enforced by the court system. With existing asset-backed ERC-721 tokens, a transfer of the token to another individual does not necessarily have any impact on the legal ownership of the physical asset. This standard attempts to solve the real world reconciliation issue, enabling real estate NFTs to function seamlessly on-chain, just like their purely-digital counterparts. @@ -55,18 +55,7 @@ interface IERC6065 is IERC721 { event Foreclosed(uint256 id); /* - Next getter functions return immutable data for NFT. You may implement in a struct like: - - struct EIP6065Immutable { - string legal_description_of_property; - string street_address; - string geo_json; - string parcel_id; - string legal_owner; - bytes32 operating_agreement_hash; - } - - and store that in a mapping, however this specific storage method is left to the implementor. + Next getter functions return immutable data for NFT. */ function legalDescriptionOf(uint256 _id) external view returns (string memory); function addressOf(uint256 _id) external view returns (string memory); @@ -81,17 +70,7 @@ interface IERC6065 is IERC721 { It's recommended that administrators only use a single token type to denominate the debt. It's unrealistic to require integrating smart contracts to implement possibly unbounded tokens denominating the off-chain debt of an asset. - If the foreclosed status == true, then the RWA asset can be seen as severed from the NFT. The NFT is now "unbacked" by the RWA. - - You may implement in a struct like: - - struct EIP6065Mutable { - address debt_token; - int256 debt_amt; - bool foreclosed; - } - - and store that in a mapping, however this specific storage method is left to the implementor. + If the foreclosed status == true, then the RWA can be seen as severed from the NFT. The NFT is now "unbacked" by the RWA. */ function debtOf(uint256 _id) external view returns (address debtToken, int256 debtAmt, bool foreclosed); @@ -106,7 +85,7 @@ interface IERC6065 is IERC721 { Real world assets operate in messy, non-deterministic environments. Because of this, validating the true state of an asset can be murky, expensive, or time-consuming. For example, in the U.S., change of property ownership is usually recorded at the County Recorder’s office, sometimes using pen and paper. It would be infeasible to continuously update this manual record every time an NFT transaction occurs on the blockchain. Additionally, since real world property rights are enforced by the court of law, it is essential that property ownership be documented in such a way that courts are able to interpret and enforce ownership if necessary. -For these reasons, it is necessary to have a trusted party tasked with the responsibility of ensuring the state of the on-chain property NFT accurately mirrors its physical counterpart. By having an Administrator for the property who issues a legally-binding digital representation of the physical property, we are able to solve for both the atomic transfer of the property rights with the transfer of the NFT, as well as institute a seamless process for making the necessary payments and filings associated with property ownership. This is made possible by eliminating the change in legal ownership each time the NFT changes hands. An example Administrator legal structure implemented by Klasma Inc. for property tokenization in the U.S. is provided in the [Reference Implementation](#reference-implementation). While a token that implements this standard must have a legal entity to conduct the off-chain dealings for the property, this implementation is not mandatory. +For these reasons, it is necessary to have a trusted party tasked with the responsibility of ensuring the state of the on-chain property NFT accurately mirrors its physical counterpart. By having an Administrator for the property who issues a legally-binding digital representation of the physical property, we are able to solve for both the atomic transfer of the property rights with the transfer of the NFT, as well as institute a seamless process for making the necessary payments and filings associated with property ownership. This is made possible by eliminating the change in legal ownership each time the NFT changes hands. An example Administrator legal structure implemented for property tokenization in the U.S. is provided in the [Reference Implementation](#reference-implementation). While a token that implements this standard must have a legal entity to conduct the off-chain dealings for the property, this implementation is not mandatory. ### Guiding Objectives @@ -146,9 +125,9 @@ These identifiers, especially `legalOwnerOf`, allow for individuals to verify of ### debtOf -A readable value of debt and denoted currency that is accrued to the property. A positive balance signifies a debt against the property, while a negative balance signifies a credit. +A readable value of debt and denoted currency that is accrued to the property. A positive balance signifies a debt against the property, while a negative balance signifies a credit which can be claimed by the NFT owner. This is a way for the property administrator to charge the NFT holder for any necessary payments towards the property, like property tax, or other critical repairs or maintenance in the "real world". A credit might be given to the NFT holder via this same function, perhaps the administrator and the NFT holder had worked out a property management or tenancy revenue-sharing agreement. -The `debtOf` function also returns the boolean foreclosure status of the asset represented by the NFT. A true result indicates the associated property is no longer backing the NFT, a false result indicates the associated property is still backing the NFT. +The `debtOf` function also returns the boolean foreclosure status of the asset represented by the NFT. A true result indicates the associated property is no longer backing the NFT, a false result indicates the associated property is still backing the NFT. An administrator can foreclose an asset for any reason as specified in the `Operating Agreement`, an example would be excessive unpaid debts. Smart contracts can check the foreclosure state by calling this function. If the asset is foreclosed, it should be understood that the RWA backing the NFT has been removed, and smart contracts should take this into account when doing any valuations or other calculations. There are no standard requirements for how these values are updated as those details will be decided by the implementor. This EIP does however standardize how these values are indicated and read for simplicity of integration. @@ -164,9 +143,9 @@ This EIP is backwards compatible with ERC-721. However, it is important to note ## Reference Implementation -Klasma Labs offers a work in progress reference implementation (*see pull request above*). The technical implementation includes the following additional components for reference, this implementation is not required. +Klasma Labs offers a work in progress [reference implementation](../assets/eip-6065/Implementation.sol). The technical implementation includes the following additional components for reference, this implementation is not required. -Summary of Klasma Inc's implementation: +Summary of this implementation: * NFT burn and mint function * Immutable NFT data (unique identifiers and operating agreement hash) @@ -177,23 +156,23 @@ Summary of Klasma Inc's implementation: ### Legal Structure Implementation -This section explains the legal structure and implementation Klasma Inc. employs as an Administrator of this token. The structure detailed below is specific to property tokenization in the U.S. in the 2023 regulatory environment. +This section explains the legal structure and implementation a company may employ as an Administrator of this token. The structure detailed below is specific to property tokenization in the U.S. in the 2023 regulatory environment. -This section details an implementation of the legal standard by Klasma Inc. specifically for property tokenization in the U.S. in the 2022 regulatory environment. +This section details an implementation of the legal standard that could be used by a company specifically for property tokenization in the U.S. in the 2022 regulatory environment. -![corporate-structure|690x388](../assets/eip-6065/corporate-structure.png) +![Corporate Structure Image](../assets/eip-6065/corporate-structure.png) -The Klasma Inc. legal structure for U.S. this token is as follows: +The legal structure for this token is as follows: -* Klasma Inc., a parent company and property Administrator, owns a bankruptcy remote LLC for each individual property they act as Administrator for. +* A parent company and property Administrator, owns a bankruptcy remote LLC for each individual property they act as Administrator for. * The bankruptcy remote LLC is the owner and manager of a DAO LLC. The DAO LLC is on the title and deed and issues the corresponding NFT and operating agreement for the property. * This structure enables the following three outcomes: 1. Homeowners are shielded from any financial stress or bankruptcy their physical asset Administrator encounters. In the event of an Administrator bankruptcy or dissolution the owner of the NFT is entitled to transfer of the DAO LLC, or the sale and distribution of proceeds from the property. 2. Transfer of the rights to the property are atomic with the transfer of the NFT. The NFT represents a right to claim the asset and have the title transferred to the NFT owner, as well as the right to use the asset. This ensures the rights to the physical property are passed digitally with the transfer of the NFT, without having to update the legal owner of the property after each transfer. -Security note: In the event of a private key hack Klasma will not be able to reissue a Home NFT. Klasma home NFT owners who are not confident in their ability to safely store their home NFT will have varying levels of security options (multi-sigs, custodians, etc.). For public, large protocol hacks, Klasma may freeze the assets using the Blocklist function and reissue the home NFTs to the original owners. +Security note: In the event of a private key hack the company will likely not be able to reissue a Home NFT. Home NFT owners who are not confident in their ability to safely store their home NFT will have varying levels of security options (multi-sigs, custodians, etc.). For public, large protocol hacks, the company may freeze the assets using the Blocklist function and reissue the home NFTs to the original owners. Blocklist functionality is to-be-implemented in the reference implementation above. ## Security Considerations diff --git a/EIPS/eip-6093.md b/EIPS/eip-6093.md index b932c65be7c37..e82cc65cfed59 100644 --- a/EIPS/eip-6093.md +++ b/EIPS/eip-6093.md @@ -4,7 +4,8 @@ title: Custom errors for commonly-used tokens description: Lists custom errors for common token implementations author: Ernesto García (@ernestognw), Francisco Giordano (@frangio), Hadrien Croubois (@Amxx) discussions-to: https://ethereum-magicians.org/t/eip-6093-custom-errors-for-erc-tokens/12043 -status: Draft +status: Last Call +last-call-deadline: 2023-08-15 type: Standards Track category: ERC created: 2022-12-06 @@ -13,7 +14,7 @@ requires: 20, 721, 1155 ## Abstract -This EIP defines a standard set of custom errors for commonly-used tokens, which are defined as [EIP-20](./eip-20.md), [EIP-721](./eip-721.md), and [EIP-1155](./eip-1155.md) tokens. +This EIP defines a standard set of custom errors for commonly-used tokens, which are defined as [ERC-20](./eip-20.md), [ERC-721](./eip-721.md), and [ERC-1155](./eip-1155.md) tokens. Ethereum applications and wallets have historically relied on revert reason strings to display the cause of transaction errors to users. Recent Solidity versions offer rich revert reasons with error-specific decoding (sometimes called "custom errors"). This EIP defines a standard set of errors designed to give at least the same relevant information as revert reason strings, but in a structured and expected way that clients can implement decoding for. @@ -21,7 +22,7 @@ Ethereum applications and wallets have historically relied on revert reason stri Since the introduction of Solidity custom errors in v0.8.4, these have provided a way to show failures in a more expressive and gas efficient manner with dynamic arguments, while reducing deployment costs. -However, [EIP-20](./eip-20.md), [EIP-721](./eip-721.md), [EIP-1155](./eip-1155.md) were already finalized when custom errors were released, so no errors are included in their specification. +However, [ERC-20](./eip-20.md), [ERC-721](./eip-721.md), [ERC-1155](./eip-1155.md) were already finalized when custom errors were released, so no errors are included in their specification. Standardized errors allow users to expect more consistent error messages across applications or testing environments, while exposing pertinent arguments and overall reducing the need of writing expensive revert strings in the deployment bytecode. @@ -31,26 +32,29 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S The following errors were designed according to the criteria described in [Rationale](#rationale). -This EIP defines standard errors that may be used by implementations in certain scenarios, but does not specify whether implementations should revert in those scenarios, which remains up to the implementers, unless a revert is mandated by the corresponding EIPs. +This EIP defines standard errors that may be used by implementations in certain scenarios but it does not specify whether implementations should revert in those scenarios, which remains up to the implementers unless a revert is mandated by the corresponding EIPs. -The names of the error arguments are defined in the [Parameter Glossary](#parameter-glossary), and MUST be used according to those definitions. +The names of the error arguments are defined in the [Parameter Glossary](#parameter-glossary) and MUST be used according to those definitions. -### [EIP-20](./eip-20.md) +### [ERC-20](./eip-20.md) #### `ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed)` Indicates an error related to the current `balance` of a `sender`. Used in transfers. -- MUST be used when `balance` is less than `needed`. -- MUST NOT be used if `balance` is greater than or equal to `needed`. +Usage guidelines: + +- `balance` MUST be less than `needed`. #### `ERC20InvalidSender(address sender)` Indicates a failure with the token `sender`. Used in transfers. -- MUST be used for disallowed transfers from the zero address. +Usage guidelines: + +- RECOMMENDED for disallowed transfers from the zero address. - MUST NOT be used for approval operations. - MUST NOT be used for balance or allowance requirements. - Use `ERC20InsufficientBalance` or `ERC20InsufficientAllowance` instead. @@ -60,8 +64,10 @@ Used in transfers. Indicates a failure with the token `receiver`. Used in transfers. -- MUST be used for disallowed transfers to the zero address. -- MUST be used for disallowed transfers to non-compatible addresses (eg. contract addresses). +Usage guidelines: + +- RECOMMENDED for disallowed transfers to the zero address. +- RECOMMENDED for disallowed transfers to non-compatible addresses (eg. contract addresses). - MUST NOT be used for approval operations. #### `ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed)` @@ -69,15 +75,18 @@ Used in transfers. Indicates a failure with the `spender`'s `allowance`. Used in transfers. -- MUST be used when `allowance` is less than `needed`. -- MUST NOT be used if `allowance` is greater than or equal to `needed`. +Usage guidelines: + +- `allowance` MUST be less than `needed`. #### `ERC20InvalidApprover(address approver)` Indicates a failure with the `approver` of a token to be approved. Used in approvals. -- MUST be used for disallowed approvals from the zero address. +Usage guidelines: + +- RECOMMENDED for disallowed approvals from the zero address. - MUST NOT be used for transfer operations. #### `ERC20InvalidSpender(address spender)` @@ -85,38 +94,65 @@ Used in approvals. Indicates a failure with the `spender` to be approved. Used in approvals. -- MUST be used for disallowed approvals to the zero address. -- MUST be used for disallowed approvals to the owner itself. +Usage guidelines: + +- RECOMMENDED for disallowed approvals to the zero address. +- RECOMMENDED for disallowed approvals to the owner itself. - MUST NOT be used for transfer operations. - Use `ERC20InsufficientAllowance` instead. -### [EIP-721](./eip-721.md) +### [ERC-721](./eip-721.md) + +#### `ERC721InvalidOwner(address owner)` + +Indicates that an address can't be an owner. +Used in balance queries. -#### `ERC721InvalidOwner(address sender, uint256 tokenId, address owner)` +Usage guidelines: + +- RECOMMENDED for addresses whose ownership is disallowed (eg. ERC-721 explicitly disallows `address(0)` to be an owner). +- MUST NOT be used for transfers. + - Use `ERC721IncorrectOwner` instead. + +#### `ERC721NonexistentToken(uint256 tokenId)` + +Indicates a `tokenId` whose `owner` is the zero address. + +Usage guidelines: + +- The `tokenId` MUST BE a non-minted or burned token. + +#### `ERC721IncorrectOwner(address sender, uint256 tokenId, address owner)` Indicates an error related to the ownership over a particular token. Used in transfers. -- MUST be used when `sender` is not `owner`. +Usage guidelines: + +- `sender` MUST NOT be `owner`. - MUST NOT be used for approval operations. #### `ERC721InvalidSender(address sender)` -Indicates a failure with the token sender. +Indicates a failure with the token `sender`. Used in transfers. -- MUST be used for disallowed transfers from the zero address. +Usage guidelines: + +- RECOMMENDED for disallowed transfers from the zero address. - MUST NOT be used for approval operations. - MUST NOT be used for ownership or approval requirements. - - Use `ERC721InvalidOwner` or `ERC721InsufficientApproval` instead. + - Use `ERC721IncorrectOwner` or `ERC721InsufficientApproval` instead. #### `ERC721InvalidReceiver(address receiver)` -Indicates a failure with the token receiver. +Indicates a failure with the token `receiver`. Used in transfers. -- MUST be used for disallowed transfers to the zero address. -- MUST be used for disallowed transfers to non-`ERC721TokenReceiver` contracts or those that reject a transfer. (eg. returning an invalid response in `onERC721Received`). +Usage guidelines: + +- RECOMMENDED for disallowed transfers to the zero address. +- RECOMMENDED for disallowed transfers to non-`ERC721TokenReceiver` contracts or those that reject a transfer. (eg. returning an invalid response in `onERC721Received`). - MUST NOT be used for approval operations. #### `ERC721InsufficientApproval(address operator, uint256 tokenId)` @@ -124,15 +160,19 @@ Used in transfers. Indicates a failure with the `operator`'s approval. Used in transfers. -- MUST be used when operator `isApprovedForAll(owner, operator)` is false. -- MUST be used when operator `getApproved(tokenId)` is not `operator`. +Usage guidelines: + +- `isApprovedForAll(owner, operator)` MUST be false for the `tokenId`'s owner and `operator`. +- `getApproved(tokenId)` MUST not be `operator`. #### `ERC721InvalidApprover(address approver)` Indicates a failure with the `owner` of a token to be approved. Used in approvals. -- MUST be used for disallowed approvals from the zero address. +Usage guidelines: + +- RECOMMENDED for disallowed approvals from the zero address. - MUST NOT be used for transfer operations. #### `ERC721InvalidOperator(address operator)` @@ -140,53 +180,64 @@ Used in approvals. Indicates a failure with the `operator` to be approved. Used in approvals. -- MUST be used for disallowed approvals to the zero address. -- MUST be used for disallowed approvals to the owner itself. +Usage guidelines: + +- RECOMMENDED for disallowed approvals to the zero address. +- The `operator` MUST NOT be the owner of the approved token. - MUST NOT be used for transfer operations. - Use `ERC721InsufficientApproval` instead. -### [EIP-1155](./eip-1155.md) +### [ERC-1155](./eip-1155.md) #### `ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId)` -Indicates an error related to the current `balance` of a sender. +Indicates an error related to the current `balance` of a `sender`. Used in transfers. -- MUST be used when `balance` is less than `needed` for a `tokenId`. -- MUST NOT be used if `balance` is greater than or equal to `needed` for a `tokenId`. +Usage guidelines: + +- `balance` MUST be less than `needed` for a `tokenId`. #### `ERC1155InvalidSender(address sender)` -Indicates a failure with the token sender. +Indicates a failure with the token `sender`. Used in transfers. -- MUST be used for disallowed transfers from the zero address. +Usage guidelines: + +- RECOMMENDED for disallowed transfers from the zero address. - MUST NOT be used for approval operations. - MUST NOT be used for balance or allowance requirements. - - Use `ERC1155InsufficientBalance` or `ERC1155InsufficientApproval` instead. + - Use `ERC1155InsufficientBalance` or `ERC1155InsufficientApprovalForAll` instead. #### `ERC1155InvalidReceiver(address receiver)` -Indicates a failure with the token receiver. +Indicates a failure with the token `receiver`. Used in transfers. -- MUST be used for disallowed transfers to the zero address. -- MUST be used for disallowed transfers to non-`ERC1155TokenReceiver` contracts or those that reject a transfer. (eg. returning an invalid response in `onERC1155Received`). +Usage guidelines: + +- RECOMMENDED for disallowed transfers to the zero address. +- RECOMMENDED for disallowed transfers to non-`ERC1155TokenReceiver` contracts or those that reject a transfer. (eg. returning an invalid response in `onERC1155Received`). - MUST NOT be used for approval operations. -#### `ERC1155InsufficientApproval(address operator, uint256 tokenId)` +#### `ERC1155InsufficientApprovalForAll(address operator, address owner)` Indicates a failure with the `operator`'s approval in a transfer. Used in transfers. -- MUST be used when operator `isApprovedForAll(owner, operator, tokenId)` is false. +Usage guidelines: + +- `isApprovedForAll(owner, operator)` MUST be false for the `tokenId`'s owner and `operator`. #### `ERC1155InvalidApprover(address approver)` Indicates a failure with the `approver` of a token to be approved. Used in approvals. -- MUST be used for disallowed approvals from the zero address. +Usage guidelines: + +- RECOMMENDED for disallowed approvals from the zero address. - MUST NOT be used for transfer operations. #### `ERC1155InvalidOperator(address operator)` @@ -194,7 +245,9 @@ Used in approvals. Indicates a failure with the `operator` to be approved. Used in approvals. -- MUST be used for disallowed approvals to the zero address. +Usage guidelines: + +- RECOMMENDED for disallowed approvals to the zero address. - MUST be used for disallowed approvals to the owner itself. - MUST NOT be used for transfer operations. - Use `ERC1155InsufficientApproval` instead. @@ -204,7 +257,9 @@ Used in approvals. Indicates an array length mismatch between `ids` and `values` in a `safeBatchTransferFrom` operation. Used in batch transfers. -- MUST be used only if `idsLength` is different from `valuesLength` +Usage guidelines: + +- `idsLength` MUST NOT be `valuesLength`. ### Parameter Glossary @@ -234,14 +289,14 @@ Considering this, the error names are designed following a basic grammatical str ### Actions and subjects -The main actions that can be performed within a token are: +An error is defined based on the following **actions** that can be performed on a token and its involved _subjects_: - **Transfer**: An operation in which a _sender_ moves to a _receiver_ any number of tokens (fungible _balance_ and/or non-fungible _token ids_). - **Approval**: An operation in which an _approver_ grants any form of _approval_ to an _operator_. -The subjects outlined above are expected to exhaustively represent _what_ can go wrong in a token transaction, deriving a specific error by adding an [error prefix](#error-prefixes). +These attempt to exhaustively represent what can go wrong in a token operation. Therefore, the errors can be constructed by specifying which _subject_ failed during an **action** execution, and prefixing with an [error prefix](#error-prefixes). -Note that the action is never seen as the subject of an error. Additionally, the token itself is not seen as the subject of an error but rather the context in which it happens, as identified in the domain. +Note that the action is never seen as the subject of an error. If a subject is called different on a particular token standard, the error should be consistent with the standard's naming convention. @@ -337,7 +392,9 @@ interface ERC20Errors { /// @dev See https://eips.ethereum.org/EIPS/eip-721 /// https://eips.ethereum.org/EIPS/eip-6093 interface ERC721Errors { - error ERC721InvalidOwner(address sender, uint256 tokenId, address owner); + error ERC721InvalidOwner(address owner); + error ERC721NonexistentToken(uint256 tokenId); + error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); error ERC721InvalidSender(address sender); error ERC721InvalidReceiver(address receiver); error ERC721InsufficientApproval(address operator, uint256 tokenId); @@ -352,7 +409,7 @@ interface ERC1155Errors { error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); error ERC1155InvalidSender(address sender); error ERC1155InvalidReceiver(address receiver); - error ERC1155InsufficientApproval(address operator, uint256 tokenId); + error ERC1155InsufficientApprovalForAll(address operator, address owner) error ERC1155InvalidApprover(address approver); error ERC1155InvalidOperator(address operator); error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); diff --git a/EIPS/eip-6122.md b/EIPS/eip-6122.md index 79f81422c19f6..0a02be5ba0642 100644 --- a/EIPS/eip-6122.md +++ b/EIPS/eip-6122.md @@ -4,7 +4,7 @@ title: Forkid checks based on timestamps description: Modifies the forkid checks to work with timestamps and block numbers author: Marius van der Wijden (@MariusVanDerWijden) discussions-to: https://ethereum-magicians.org/t/eip-6122-forkid-checks-based-on-timestamps/12130 -status: Draft +status: Review type: Standards Track category: Networking created: 2022-12-13 diff --git a/EIPS/eip-6239.md b/EIPS/eip-6239.md new file mode 100644 index 0000000000000..02dc13b63b44e --- /dev/null +++ b/EIPS/eip-6239.md @@ -0,0 +1,302 @@ +--- +eip: 6239 +title: Semantic Soulbound Tokens +description: Adding RDF triples to ERC-5192 token metadata to capture social meaning +author: Jessica Chang (@JessicaChg) +discussions-to: https://ethereum-magicians.org/t/eip-6239-semantic-soulbound-tokens/12334 +status: Review +type: Standards Track +category: ERC +created: 2022-12-30 +requires: 165, 721, 5192 +--- + +## Abstract + +This proposal extends [ERC-721](./eip-721.md) and [ERC-5192](./eip-5192.md) by introducing Resource Description Framework (RDF) triples to Soulbound Tokens' (‘SBTs‘) metadata. + + + +## Motivation + +A Soulbound Token represents the commitments, credentials, and affiliations of accounts. RDF is a standard data model developed by the World Wide Web Consortium (‘W3C’) and is used to represent information in a structured format. Semantic SBTs are built on existing [ERC-721](./eip-721.md) and [ERC-5192](./eip-5192.md) standards to include RDF triples in metadata to capture and store the meaning of social metadata as a network of accounts and attributes. + +Semantic SBT provides a foundation for publishing, linking, and integrating data from multiple sources, and enables the ability to query and retrieve information across these sources, using inference to uncover new insights from existing social relations. For example, form the on-chain united social graph, assign trusted contacts for social recovery, and supports fair governance. + +While the existence of SBTs can create a decentralized social framework, there still needs to specify a common data model to manage the social metadata on-chain in a trustless manner, describing social metadata in an interconnected way, make it easy to be exchanged, integrated and discovered. And to further fuel the boom of the SBTs ecosystem, we need a bottom-up and decentralized way to maintain people’s social identity related information. + +Semantic SBTs address this by storing social metadata, attestations, and access permissions on-chain to bootstrap the social identity layer and a linked data layer natively on Ethereum, and bring semantic meanings to the tons of bits of on-chain data. + +### Connectedness + +Semantic SBTs store social data as RDF triples in the Subject-Predicate-Object format, making it easy to create relationships between accounts and attributes. RDF is a standard for data interchange used to represent highly interconnected data. Representing data in RDF triples makes it simpler for automated systems to identify, clarify, and connect information. + +### Linked Data + +Semantic SBTs allow the huge amount of social data on-chain to be available in a standard format (RDF) and be reachable and manageable. The interrelated datasets on-chain can create the linked data layer that allows social data to be mixed, exposed, and shared across different applications, providing a convenient, cheap, and reliable way to retrieve data, regardless of the number of users. + +### Social Identity + +Semantic SBTs allow people to publish or attest their own identity-related data in a bottom-up and decentralized way, without reliance on any centralized intermediaries while setting every party free. The data is fragmentary in each Semantic SBT and socially interrelated. RDF triples enable various community detection algorithms to be built on top. + +This proposal outlines the semantic data modeling of SBTs that allows implementers to model the social relations among Semantic SBTs, especially in the social sector. + +## Specification + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119. + +- The token **MUST** implement the following interfaces: + 1. [ERC-165](./eip-165.md)’s `ERC165` (`0x01ffc9a7`) + 1. [ERC-721](./eip-721.md)’s `ERC721` (`0x80ac58cd`) + 1. [ERC-721](./eip-721.md)’s `ERC721Metadata` (`0x5b5e139f`) + 1. [ERC-5192](./eip-5192.md)’s `ERC5192` (`0xb45a3c0e`) + +### RDF Statement + +RDF statements come in various formats, we have selected the six most commonly used formats: `nt(N-Triples)`,`ttl(Turtle)`,`rdf(RDF/XML)`,`rj(RDF/JSON)`,`nq(N-Quads)` and `trig(TriG)`. + +The complete format of an RDF statement: + +```text +rdfStatements = {[format]} +``` + +In the following section, fragments surrounded by `{}` characters are OPTIONAL. + +In the following section, fragments surrounded by `<>` characters are REQUIRED. + +format: nt/ttl/rdf/rj/nq/trig + +When no format is selected: statements = [ttl]statements + +- `nt(n-triples)` + +`nt` uses space to separate the subject, predicate, object of a triple, and a period . to indicate the end of a triple. + +The basic structure is: + +```text +subject predicate object . +``` + +In this format, the subject is in the format of IRIREF or BLANK_NODE_LABEL, the predicate is in the format of IRIREF, and the object is in the format of IRIREF, BLANK_NODE_LABEL, or STRING_LITERAL_QUOTE. + +For example: + +```text + . + "Alice" . +``` + +- `ttl(Turtle)` + +Compared to `nt`, `ttl` uses prefixes to simplify the IRIREF format, and the same predicate under the same subject can be merged without repeating it. "a" can be used to represent ``. + + +For example: + +```text +@prefix : . +@prefix p: . + +:user1 a :User; + p:name ”Alice” . +``` + +- `rdf(RDF/XML)` + +`rdf` describes RDF in XML format, using rdf:RDF as the top-level element, and xmlns to describe prefixes. rdf:Description begins describing a node, rdf:about defines the node to be described, and rdf:resource fills in the property value in the format of IRI. If the property value is a string, the property value can be directly written as the text of the property node. + +The basic structure is: + +```xml + + + + + + object + + +``` + +For example: + +```xml + + + + + + Alice + + +``` + +- `rj(RDF/JSON)` + + +`rj` describes RDF in JSON format. A triple is described as: + + +```text + {"subject":{"predicate":[object]}} +``` + +Note that each root object is a unique primary key and duplicates are not allowed. There will be no duplicate subjects as keys, and there will be no duplicate predicates under a single subject. + +For example: + +```json + { + "http://example.org/entity/user1": { + "http://www.w3.org/1999/02/22-rdf-syntax-ns#type": [ + "http://example.org/entity/User" + ], + "http://example.org/property/name": [ + "Alice" + ] + } +} + +``` + +- `nq(N-Quads)` + +`nq` is based on `nt` but includes a graph label that describes the dataset to which an RDF triple belongs. The graph label can be in the format of IRIREF or BLANK_NODE_LABEL. + +The basic structure is: + +```text +subject predicate object graphLabel. +``` + +For example: + +```text + . + "Alice" . +``` + +- `trig(TriG)` + + +`trig` is an extension of `ttl` that includes a graph label to describe the dataset to which an RDF triple belongs. The triple statements are enclosed in curly braces {}. + +For example: + +```text +@prefix : . +@prefix p: . + + + { + :user1 a :User; + p:name ”Alice” . + + } +``` + +In the contract events: `CreateRDF`, `UpdateRDF`, `RemoveRDF`, and the `rdfOf method`, the `rdfStatements` is used in `ttl` format by default. If other formats listed above are used, a format identifier needs to be added for identification. + +The format identifier starts with `[` and ends with `]` with the format in the middle, i.e., `[format]`. + +For example, the `rdfStatements` in `nt` format should include the prefix `[nt]`. + +```text +[nt]subject predicate object . +``` + + +### Contract Interface + +```solidity +/** + * @title Semantic Soulbound Token + * Note: the ERC-165 identifier for this interface is 0xfbafb698 + */ +interface ISemanticSBT{ + /** + * @dev This emits when minting a Semantic Soulbound Token. + * @param tokenId The identifier for the Semantic Soulbound Token. + * @param rdfStatements The RDF statements for the Semantic Soulbound Token. + */ + event CreateRDF ( + uint256 indexed tokenId, + string rdfStatements + ); + /** + * @dev This emits when updating the RDF data of Semantic Soulbound Token. RDF data is a collection of RDF statements that are used to represent information about resources. + * @param tokenId The identifier for the Semantic Soulbound Token. + * @param rdfStatements The RDF statements for the semantic soulbound token. + */ + event UpdateRDF ( + uint256 indexed tokenId, + string rdfStatements + ); + /** + * @dev This emits when burning or revoking Semantic Soulbound Token. + * @param tokenId The identifier for the Semantic Soulbound Token. + * @param rdfStatements The RDF statements for the Semantic Soulbound Token. + */ + event RemoveRDF ( + uint256 indexed tokenId, + string rdfStatements + ); + /** + * @dev Returns the RDF statements of the Semantic Soulbound Token. + * @param tokenId The identifier for the Semantic Soulbound Token. + * @return rdfStatements The RDF statements for the Semantic Soulbound Token. + */ + function rdfOf(uint256 tokenId) external view returns (string memory rdfStatements); +} +``` + +`ISemanticRDFSchema`, an extension of ERC-721 Metadata, is **OPTIONAL** for this standard, it is used to get the Schema URI for the RDF data. + +```solidity +interface ISemanticRDFSchema{ + /** + * @notice Get the URI of schema for this contract. + * @return The URI of the contract which point to a configuration profile. + */ + function schemaURI() external view returns (string memory); +} +``` + + +### Method Specification + +`rdfOf (uint256 tokenId)`: Query the RDF data for the Semantic Soulbound Token by `tokenId`. The returned RDF data format conforms to the W3C RDF standard. RDF data is a collection of RDF statements that are used to represent information about resources. An RDF statement, also known as a triple, is a unit of information in the RDF data model. It consists of three parts: a subject, a predicate, and an object. + +`schemaURI()`: This **OPTIONAL** method is used to query the URIs of the schema for the RDF data. RDF Schema is an extension of the basic RDF vocabulary and provides a data-modelling vocabulary for RDF data. It is **RECOMMENDED** to store the RDF Schema in decentralized storage such as Arweave or IPFS. The URIs are then stored in the contract and can be queried by this method. + +### Event Specification + +`CreateRDF`: When minting a Semantic Soulbound Token, this event **MUST** be triggered to notify the listener to perform operations with the created RDF data. When calling the event, the input RDF data **MUST** be RDF statements, which are units of information consisting of three parts: a subject, a predicate, and an object. + +`UpdateRDF`: When updating RDF data for a Semantic Soulbound Token, this event **MUST** be triggered to notify the listener to perform update operations accordingly with the updated RDF data. When calling the event, the input RDF data **MUST** be RDF statements, which are units of information consisting of three parts: a subject, a predicate, and an object. + +`RemoveRDF`: When burning or revoking a Semantic Soulbound Token, this event **MUST** be triggered to notify the listener to perform operations with the removed RDF data for the Semantic SBT. When calling the event, the input RDF data **MUST** be RDF statements, which are units of information consisting of three parts: a subject, a predicate, and an object. + +## Rationale + + +RDF is a flexible and extensible data model based on creating subject-predicate-object relationships, often used to model graph data due to its semantic web standards, Linked Data concept, flexibility, and query capabilities. RDF allows graph data to be easily integrated with other data sources on the web, making it possible to create more comprehensive and interoperable models. The advantage of using RDF for semantic description is that it can describe richer information, including terms, categories, properties, and relationships. RDF uses standard formats and languages to describe metadata, making the expression of semantic information more standardized and unified. This helps to establish more accurate and reliable semantic networks, promoting interoperability between different systems. Additionally, RDF supports semantic reasoning, which allows the system to automatically infer additional relationships and connections between nodes in the social graph based on the existing data. + + +There are multiple formats for RDF statements. We list six most widely adopted RDF statement formats in the EIP: `Turtle`, `N-Triples`, `RDF/XML`, `RDF/JSON`,`N-Quads`, and `TriG`. These formats have different advantages and applicability in expressing, storing, and parsing RDF statements. Among these, `Turtle` is a popular format in RDF statements, due to its good human-readability and concision. It is typically used as the default format in this EIP for RDF statements. Using the Turtle format can make RDF statements easier to understand and maintain, while reducing the need for storage, suitable for representing complex RDF graphs. + + +## Backwards Compatibility + +This proposal is fully backward compatible with [ERC-721](./eip-721.md) and [ERC-5192](./eip-5192.md). + +## Security Considerations + +There are no security considerations related directly to the implementation of this standard. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-6381.md b/EIPS/eip-6381.md index 1fa3003cfd206..69b6f79e3f5a1 100644 --- a/EIPS/eip-6381.md +++ b/EIPS/eip-6381.md @@ -5,7 +5,7 @@ description: React to any Non-Fungible Tokens using Unicode emojis. author: Bruno Škvorc (@Swader), Steven Pineda (@steven2308), Stevan Bogosavljevic (@stevyhacker), Jan Turk (@ThunderDeliverer) discussions-to: https://ethereum-magicians.org/t/eip-6381-emotable-extension-for-non-fungible-tokens/12710 status: Last Call -last-call-deadline: 2023-05-02 +last-call-deadline: 2023-06-21 type: Standards Track category: ERC created: 2023-01-22 @@ -49,7 +49,7 @@ The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL ```solidity /// @title ERC-6381 Emotable Extension for Non-Fungible Tokens /// @dev See https://eips.ethereum.org/EIPS/eip-6381 -/// @dev Note: the ERC-165 identifier for this interface is 0x08eb97a6. +/// @dev Note: the ERC-165 identifier for this interface is 0xd9fac55a. pragma solidity ^0.8.16; @@ -84,6 +84,19 @@ interface IERC6381 /*is IERC165*/ { bytes4 emoji ) external view returns (uint256); + /** + * @notice Used to get the number of emotes for a specific emoji on a set of tokens. + * @param collection An array of addresses of the collections containing the tokens being checked for emoji count + * @param tokenIds An array of IDs of the tokens to check for emoji count + * @param emojis An array of unicode identifiers of the emojis + * @return An array of numbers of emotes with the emoji on the tokens + */ + function bulkEmoteCountOf( + address[] memory collections, + uint256[] memory tokenIds, + bytes4[] memory emojis + ) external view returns (uint256[] memory); + /** * @notice Used to get the information on whether the specified address has used a specific emoji on a specific * token. @@ -101,11 +114,65 @@ interface IERC6381 /*is IERC165*/ { bytes4 emoji ) external view returns (bool); + /** + * @notice Used to get the information on whether the specified addresses have used specific emojis on specific + * tokens. + * @param collections An array of addresses of the collection smart contracts containing the tokens being checked + * for emoji reactions + * @param emoters An array of addresses of the accounts we are checking for reactions to tokens + * @param tokenIds An array of IDs of the tokens being checked for emoji reactions + * @param emojis An array of the ASCII emoji codes being checked for reactions + * @return An array of boolean values indicating whether the `emoter`s has used the `emoji`s on the tokens (`true`) + * or not (`false`) + */ + function haveEmotersUsedEmotes( + address[] memory emoters, + address[] memory collections, + uint256[] memory tokenIds, + bytes4[] memory emojis + ) external view returns (bool[] memory); + + /** + * @notice Used to get the message to be signed by the `emoter` in order for the reaction to be submitted by someone + * else. + * @param collection The address of the collection smart contract containing the token being emoted at + * @param tokenId ID of the token being emoted + * @param emoji Unicode identifier of the emoji + * @param state Boolean value signifying whether to emote (`true`) or undo (`false`) emote + * @param deadline UNIX timestamp of the deadline for the signature to be submitted + * @return The message to be signed by the `emoter` in order for the reaction to be submitted by someone else + */ + function prepareMessageToPresignEmote( + address collection, + uint256 tokenId, + bytes4 emoji, + bool state, + uint256 deadline + ) external view returns (bytes32); + + /** + * @notice Used to get multiple messages to be signed by the `emoter` in order for the reaction to be submitted by someone + * else. + * @param collections An array of addresses of the collection smart contracts containing the tokens being emoted at + * @param tokenIds An array of IDs of the tokens being emoted + * @param emojis An arrau of unicode identifiers of the emojis + * @param states An array of boolean values signifying whether to emote (`true`) or undo (`false`) emote + * @param deadlines An array of UNIX timestamps of the deadlines for the signatures to be submitted + * @return The array of messages to be signed by the `emoter` in order for the reaction to be submitted by someone else + */ + function prepareMessageToPresignEmote( + address collection, + uint256 tokenId, + bytes4 emoji, + bool state, + uint256 deadline + ) external view returns (bytes32); + /** * @notice Used to emote or undo an emote on a token. * @dev Does nothing if attempting to set a pre-existent state. * @dev MUST emit the `Emoted` event is the state of the emote is changed. - * @param collection Address of the collection containing the token being checked for emoji count + * @param collection Address of the collection containing the token being emoted at * @param tokenId ID of the token being emoted * @param emoji Unicode identifier of the emoji * @param state Boolean value signifying whether to emote (`true`) or undo (`false`) emote @@ -116,9 +183,125 @@ interface IERC6381 /*is IERC165*/ { bytes4 emoji, bool state ) external; + + /** + * @notice Used to emote or undo an emote on multiple tokens. + * @dev Does nothing if attempting to set a pre-existent state. + * @dev MUST emit the `Emoted` event is the state of the emote is changed. + * @dev MUST revert if the lengths of the `collections`, `tokenIds`, `emojis` and `states` arrays are not equal. + * @param collections An array of addresses of the collections containing the tokens being emoted at + * @param tokenIds An array of IDs of the tokens being emoted + * @param emojis An array of unicode identifiers of the emojis + * @param states An array of boolean values signifying whether to emote (`true`) or undo (`false`) emote + */ + function bulkEmote( + address[] memory collections, + uint256[] memory tokenIds, + bytes4[] memory emojis, + bool[] memory states + ) external; + + /** + * @notice Used to emote or undo an emote on someone else's behalf. + * @dev Does nothing if attempting to set a pre-existent state. + * @dev MUST emit the `Emoted` event is the state of the emote is changed. + * @dev MUST revert if the lengths of the `collections`, `tokenIds`, `emojis` and `states` arrays are not equal. + * @dev MUST revert if the `deadline` has passed. + * @dev MUST revert if the recovered address is the zero address. + * @param emoter The address that presigned the emote + * @param collection The address of the collection smart contract containing the token being emoted at + * @param tokenId IDs of the token being emoted + * @param emoji Unicode identifier of the emoji + * @param states Boolean value signifying whether to emote (`true`) or undo (`false`) emote + * @param deadline UNIX timestamp of the deadline for the signature to be submitted + * @param v `v` value of an ECDSA signature of the message obtained via `prepareMessageToPresignEmote` + * @param r `r` value of an ECDSA signature of the message obtained via `prepareMessageToPresignEmote` + * @param s `s` value of an ECDSA signature of the message obtained via `prepareMessageToPresignEmote` + */ + function presignedEmote( + address emoter, + address collection, + uint256 tokenId, + bytes4 emoji, + bool state, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + /** + * @notice Used to bulk emote or undo an emote on someone else's behalf. + * @dev Does nothing if attempting to set a pre-existent state. + * @dev MUST emit the `Emoted` event is the state of the emote is changed. + * @dev MUST revert if the lengths of the `collections`, `tokenIds`, `emojis` and `states` arrays are not equal. + * @dev MUST revert if the `deadline` has passed. + * @dev MUST revert if the recovered address is the zero address. + * @param emoters An array of addresses of the accounts that presigned the emotes + * @param collections An array of addresses of the collections containing the tokens being emoted at + * @param tokenIds An array of IDs of the tokens being emoted + * @param emojis An array of unicode identifiers of the emojis + * @param states An array of boolean values signifying whether to emote (`true`) or undo (`false`) emote + * @param deadline UNIX timestamp of the deadline for the signature to be submitted + * @param v An array of `v` values of an ECDSA signatures of the messages obtained via `prepareMessageToPresignEmote` + * @param r An array of `r` values of an ECDSA signatures of the messages obtained via `prepareMessageToPresignEmote` + * @param s An array of `s` values of an ECDSA signatures of the messages obtained via `prepareMessageToPresignEmote` + */ + function bulkPresignedEmote( + address[] memory emoters, + address[] memory collections, + uint256[] memory tokenIds, + bytes4[] memory emojis, + bool[] memory states, + uint256[] memory deadlines, + uint8[] memory v, + bytes32[] memory r, + bytes32[] memory s + ) external; } ``` +### Message format for presigned emotes + +The message to be signed by the `emoter` in order for the reaction to be submitted by someone else is formatted as follows: + +```solidity +keccak256( + abi.encode( + DOMAIN_SEPARATOR, + collection, + tokenId, + emoji, + state, + deadline + ) + ); +``` + +The values passed when generating the message to be signed are: + +- `DOMAIN_SEPARATOR` - The domain separator of the Emotable repository smart contract +- `collection` - Address of the collection containing the token being emoted at +- `tokenId` - ID of the token being emoted +- `emoji` - Unicode identifier of the emoji +- `state` - Boolean value signifying whether to emote (`true`) or undo (`false`) emote +- `deadline` - UNIX timestamp of the deadline for the signature to be submitted + +The `DOMAIN_SEPARATOR` is generated as follows: + +```solidity +keccak256( + abi.encode( + "ERC-6381: Public Non-Fungible Token Emote Repository", + "1", + block.chainid, + address(this) + ) + ); +``` + +Each chain, that the Emotable repository smart contract is deployed on, will have a different `DOMAIN_SEPARATOR` value due to chain IDs being different. + ### Pre-determined address of the Emotable repository The address of the Emotable repository smart contract is designed to resemble the function it serves. It starts with `0x311073` which is the abstract representation of `EMOTE`. The address is: @@ -138,6 +321,18 @@ The impressions could have been done using user-supplied strings or numeric valu 3. **Should the proposal establish an emotable extension or a common-good repository?**\ Initially we set out to create an emotable extension to be used with any ERC-721 compilant tokens. However, we realized that the proposal would be more useful if it was a common-good repository of emotable tokens. This way, the tokens that can be reacted to are not only the new ones but also the old ones that have been around since before the proposal.\ In line with this decision, we decided to calculate a deterministic address for the repository smart contract. This way, the repository can be used by any NFT collection without the need to search for the address on the given chain. +4. **Should we include only single-action operations, only multi-action operations, or both?**\ +We've considered including only single-action operations, where the user is only able to react with a single emoji to a single token, but we decided to include both single-action and multi-action operations. This way, the users can choose whether they want to emote or undo emote on a single token or on multiple tokens at once.\ +This decision was made for the long-term viability of the proposal. Based on the gas cost of the network and the number of tokens in the collection, the user can choose the most cost-effective way of emoting. +5. **Should we add the ability to emote on someone else's behalf?**\ +While we did not intend to add this as part of the proposal when drafting it, we realized that it would be a useful feature for it. This way, the users can emote on behalf of someone else, for example, if they are not able to do it themselves or if the emote is earned through an off-chain activity. +6. **How do we ensure that emoting on someone else's behalf is legitimate?**\ +We could add delegates to the proposal; when a user delegates their right to emote to someone else, the delegate can emote on their behalf. However, this would add a lot of complexity and additional logic to the proposal.\ +Using ECDSA signatures, we can ensure that the user has given their consent to emote on their behalf. This way, the user can sign a message with the parameters of the emote and the signature can be submitted by someone else. +7. **Should we add chain ID as a parameter when reacting to a token?**\ +During the course of discussion of the proposal, a suggestion arose that we could add chain ID as a parameter when reacting to a token. This would allow the users to emote on the token of one chain on another chain.\ +We decided against this as we feel that additional parameter would rarely be used and would add additional cost to the reaction transactions. If the collection smart contract wants to utilize on-chain emotes to tokens they contain, they require the reactions to be recorded on the same chain. Marketplaces and wallets integrating this proposal will rely on reactions to reside in the same chain as well, because if chain ID parameter was supported this would mean that they would need to query the repository smart contract on all of the chains the repository is deployed in order to get the reactions for a given token.\ +Additionally, if the collection creator wants users to record their reactions on a different chain, they can still direct the users to do just that. The repository does not validate the existence of the token being reacted to, which in theory means that you can react to non-existent token or to a token that does not exist yet. The likelihood of a different collection existing at the same address on another chain is significantly low, so the users can react using the collection's address on another chain and it is very unlikely that they will unintentionally react to another collection's token. ## Backwards Compatibility @@ -161,7 +356,11 @@ See [`EmotableRepository.sol`](../assets/eip-6381/contracts/EmotableRepository.s ## Security Considerations -The same security considerations as with [ERC-721](./eip-721.md) apply: hidden logic may be present in any of the functions, including burn, add asset, accept asset, and more. +The proposal does not envision handling any form of assets from the user, so the assets should not be at risk when interacting with an Emote repository. + +The ability to use ECDSA signatures to emote on someone else's behalf introduces the risk of a replay attack, which the format of the message to be signed guards against. The `DOMAIN_SEPARATOR` used in the message to be signed is unique to the repository smart contract of the chain it is deployed on. This means that the signature is invalid on any other chain and the Emote repositories deployed on them should revert the operation if a replay attack is attempted. + +Another thing to consider is the ability of presigned message reuse. Since the message includes the signature validity deadline, the message can be reused any number of times before the deadline is reached. The proposal only allows for a single reaction with a given emoji to a specific token to be active, so the presigned message can not be abused to increase the reaction count on the token. However, if the service using the repository relies on the ability to revoke the reaction after certain actions, a valid presigned message can be used to re-react to the token. We suggest that the services using the repository in cnjunction with presigned messages use deadlines that invalidate presigned messages after a reasonalby short period of time. Caution is advised when dealing with non-audited contracts. diff --git a/EIPS/eip-6454.md b/EIPS/eip-6454.md index 10140dd1015ef..bd51bd4363813 100644 --- a/EIPS/eip-6454.md +++ b/EIPS/eip-6454.md @@ -4,8 +4,7 @@ title: Minimal Transferable NFT detection interface description: A minimal extension to identify the transferability of Non-Fungible Tokens. author: Bruno Škvorc (@Swader), Francesco Sullo (@sullof), Steven Pineda (@steven2308), Stevan Bogosavljevic (@stevyhacker), Jan Turk (@ThunderDeliverer) discussions-to: https://ethereum-magicians.org/t/minimalistic-transferable-interface/12517 -status: Last Call -last-call-deadline: 2023-04-07 +status: Final type: Standards Track category: ERC created: 2023-01-31 diff --git a/EIPS/eip-6492.md b/EIPS/eip-6492.md index a5593d7261022..78d7f4f6fb669 100644 --- a/EIPS/eip-6492.md +++ b/EIPS/eip-6492.md @@ -17,7 +17,7 @@ Contracts can sign verifyable messages via [ERC-1271](./eip-1271.md). However, if the contract is not deployed yet, [ERC-1271](./eip-1271.md) verification is impossible, as you can't call the `isValidSignature` function on said contract. -We propose a standard way for any contract or off-chain actor to verify whether a signature on behalf of a given counterfactual contract (that is not deployed yet) is valid. This standarad way extends [ERC-1271](./eip-1271.md). +We propose a standard way for any contract or off-chain actor to verify whether a signature on behalf of a given counterfactual contract (that is not deployed yet) is valid. This standard way extends [ERC-1271](./eip-1271.md). ## Motivation diff --git a/EIPS/eip-6551.md b/EIPS/eip-6551.md index f9b3c74ccf9b9..9fcbe3a4a682d 100644 --- a/EIPS/eip-6551.md +++ b/EIPS/eip-6551.md @@ -337,7 +337,7 @@ contract ERC6551Registry is IERC6551Registry { uint256 salt, bytes calldata initData ) external returns (address) { - bytes memory code = _creationCode(implementation, chainId, tokenContract, tokenId, salt) + bytes memory code = _creationCode(implementation, chainId, tokenContract, tokenId, salt); address _account = Create2.computeAddress( bytes32(salt), diff --git a/EIPS/eip-6785.md b/EIPS/eip-6785.md new file mode 100644 index 0000000000000..b02f62f48c4ca --- /dev/null +++ b/EIPS/eip-6785.md @@ -0,0 +1,210 @@ +--- +eip: 6785 +title: ERC-721 Utilities Information Extension +description: Provide easy access to information about the `utility` of an NFT via functions and the NFT's metadata +author: Otniel Nicola (@OT-kthd), Bogdan Popa (@BogdanKTHD) +discussions-to: https://ethereum-magicians.org/t/eip-6785-erc-721-utilities-extension/13568 +status: Draft +type: Standards Track +category: ERC +created: 2023-03-27 +requires: 165, 721 +--- + +## Abstract + +This specification defines standard functions and an extension of the metadata schema that outlines what a +token's utility entails and how the utility may be used and/or accessed. +This specification is an optional extension of [ERC-721](./eip-721.md). + +## Motivation + +This specification aims to clarify what the utility associated with an NFT is and how to access this utility. +Relying on third-party platforms to obtain information regarding the utility of the NFT that one owns can lead to scams, +phishing or other forms of fraud. + +Currently, utilities that are offered with NFTs are not captured on-chain. We want the utility of an NFT to be part of +the metadata of an NFT. The metadata information would include: a) type of utility, b) description +of utility, c) frequency and duration of utility, and d) expiration of utility. This will provide transparency as to the +utility terms, and greater accountability on the creator to honor these utilities. + +As the instructions on how to access a given utility may change over time, there should be a historical record of these +changes for transparency. + +## Specification + +The keywords “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and +“OPTIONAL” in this document are to be interpreted as described in RFC 2119. + +Every contract compliant with [ERC-6785](./eip-6785.md) MUST implement the interface defined as follows: + +### Contract Interface + +```solidity +// @title NFT Utility description +/// Note: the EIP-165 identifier for this interface is ed231d73 + +interface IERC6785 { + + // Logged when the utility description URL of an NFT is changed + /// @notice Emitted when the utilityURL of an NFT is changed + /// The empty string for `utilityUri` indicates that there is no utility associated + event UpdateUtility(uint256 indexed tokenId, string utilityUri); + + /// @notice set the new utilityUri - remember the date it was set on + /// @dev The empty string indicates there is no utility + /// Throws if `tokenId` is not valid NFT + /// @param utilityUri The new utility description of the NFT + /// 4a048176 + function setUtilityUri(uint256 tokenId, string utilityUri) external; + + /// @notice Get the utilityUri of an NFT + /// @dev The empty string for `utilityUri` indicates that there is no utility associated + /// @param tokenId The NFT to get the user address for + /// @return The utility uri for this NFT + /// 5e470cbc + function utilityUriOf(uint256 tokenId) external view returns (string memory); + + /// @notice Get the changes made to utilityUri + /// @param tokenId The NFT to get the user address for + /// @return The history of changes to `utilityUri` for this NFT + /// f96090b9 + function utilityHistoryOf(uint256 tokenId) external view returns (string[] memory); +} +``` + +All functions defined as view MAY be implemented as pure or view + +Function `setUtilityUri` MAY be implemented as public or external. Also, the ability to set the `utilityUri` SHOULD be +restricted to the one who's offering the utility, whether that's the NFT creator or someone else. + +The event `UpdateUtility` MUST be emitted when the `setUtilityUri` function is called or any other time that the utility +of the token is changed, like in batch updates. + +The method `utilityHistoryOf` MUST reflect all changes made to the `utilityUri` of a tokenId, whether that's done +through `setUtilityUri` or by any other means, such as bulk updates + +The `supportsInterface` method MUST return true when called with `ed231d73` + +The original metadata SHOULD conform to the “ERC-6785 Metadata with utilities JSON Schema” which is a compatible +extension of the “ERC-721 Metadata JSON Schema” defined in ERC-721. + +“ERC-6785 Metadata with utilities JSON Schema” : + +```json +{ + "title": "Asset Metadata", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Identifies the asset to which this NFT represents" + }, + "description": { + "type": "string", + "description": "Describes the asset to which this NFT represents" + }, + "image": { + "type": "string", + "description": "A URI pointing to a resource with mime type image/* representing the asset to which this NFT represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive." + }, + "utilities": { + "type": "object", + "required": [ + "type", + "description", + "t&c" + ], + "properties": { + "type": { + "type": "string", + "description": "Describes what type of utility this is" + }, + "description": { + "type": "string", + "description": "A brief description of the utility" + }, + "properties": { + "type": "array", + "description": "An array of possible properties describing the utility, defined as key-value pairs", + "items": { + "type": "object" + } + }, + "expiry": { + "type": "number", + "description": "The period of time for the validity of the utility, since the minting of the NFT. Expressed in seconds" + }, + "t&c": { + "type": "string", + "description": "" + } + } + } + } +} +``` + +## Rationale + +Since the `utilityUri` could contain information that has to be restricted to some level and could be dependent on an +off-chain tool for displaying said information, the creator needs the ability to modify it in the event the off-chain +tool or platform becomes unavailable or inaccessible. + +For transparency purposes, having a `utilityHistoryOf` method will make it clear how the `utilityUri` has changed over +time. + +For example, if a creator sells an NFT that gives holders a right to a video call with the creator, the metadata for +this utility NFT would read as follows: + +```json +{ + "name": "...", + "description": "...", + "image": "...", + "utilities": { + "type": "Video call", + "description": "I will enter a private video call with whoever owns the NFT", + "properties": [ + { + "sessions": 2 + }, + { + "duration": 30 + }, + { + "time_unit": "minutes" + } + ], + "expiry": 1.577e+7, + "t&c": "https://...." + } +} +``` + +In order to get access to the details needed to enter the video call, the owner would access the URI returned by +the `getUtilityUri` method for the NFT that they own. Additionally, access to the details could be conditioned by the +authentication with the wallet that owns the NFT. + +The current status of the utility would also be included in the URI (eg: how many sessions are still available, etc.) + +## Backwards Compatibility + +This standard is compatible with current ERC-721 standard. There are no other standards that define similar methods for +NFTs and the method names are not used by other ERC-721 related standards. + +## Test Cases + +Test cases are available [here](../assets/eip-6785/test/ERC6785.test.js) + +## Reference Implementation + +The reference implementation can be found [here](../assets/eip-6785/contracts/ERC6785.sol). + +## Security Considerations + +There are no security considerations related directly to the implementation of this standard. + +## Copyright + +Copyright and related rights waived via [CC0-1.0](../LICENSE.md). diff --git a/EIPS/eip-6786.md b/EIPS/eip-6786.md new file mode 100644 index 0000000000000..125c145e5cfab --- /dev/null +++ b/EIPS/eip-6786.md @@ -0,0 +1,105 @@ +--- +eip: 6786 +title: Registry for royalties payment for NFTs +description: A registry used for paying royalties for any NFT with information about the creator +author: Otniel Nicola (@OT-kthd), Bogdan Popa (@BogdanKTHD) +discussions-to: https://ethereum-magicians.org/t/eip-6786-royalty-debt-registry/13569 +status: Draft +type: Standards Track +category: ERC +created: 2023-03-27 +requires: 165, 2981 +--- + +## Abstract + +This standard allows anyone to pay royalties for a certain NFT and also to keep track of the royalties amount paid. It will cumulate the value each time a payment is executed through it and make the information public. + +## Motivation + +There are many marketplaces which do not enforce any royalty payment to the NFT creator every time the NFT is sold or re-sold and/or providing a way for doing it. There are some marketplaces which use specific system of royalties, however that system is applicable for the NFTs creates on their platform. + +In this context, there is a need of a way for paying royalties, as it is a strong incentive for creators to keep contributing to the NFTs ecosystem. + +Additionally, this standard will provide a way of computing the amount of royalties paid to a creator for a certain NFT. This could be useful in the context of categorising NFTs in terms of royalties. The term “debt“ is used because the standard aims to provide a way of knowing if there are any royalties left unpaid for the NFTs trades that took place in a marketplace that does not support them and, in that case, expose a way of paying them. + +With a lot of places made for trading NFTs dropping down the royalty payment or having a centralised approach, we want to provide a way for anyone to pay royalties to the creators. + +Not only the owner of it, but anyone could pay royalties for a certain NFT. This could be a way of supporting a creator for his work. + +## Specification + +The keywords “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119. + +Every contract compliant with [ERC-6786](./eip-6786.md) MUST implement the interface defined as follows: + +### Contract Interface + +```solidity +// @title Royalty Debt Registry +/// Note: the ERC-165 identifier for this interface is 0x253b27b0 + +interface IERC6786 { + + // Logged when royalties were paid for a NFT + /// @notice Emitted when royalties are paid for the NFT with address tokenAddress and id tokenId + event RoyaltiesPaid(address indexed tokenAddress, uint256 indexed tokenId, uint256 amount); + + /// @notice sends msg.value to the creator of a NFT + /// @dev Reverts if there are no on-chain informations about the creator + /// @param tokenAddress The address of NFT contract + /// @param tokenId The NFT id + function payRoyalties(address tokenAddress, uint256 tokenId) external payable; + + /// @notice Get the amount of royalties which was paid for a NFT + /// @dev + /// @param tokenAddress The address of NFT contract + /// @param tokenId The NFT id + /// @return The amount of royalties paid for the NFT + function getPaidRoyalties(address tokenAddress, uint256 tokenId) external view returns (uint256); +} +``` + +All functions defined as view MAY be implemented as pure or view + +Function `payRoyalties` MAY be implemented as public or external + +The event `RoyaltiesPaid` MUST be emitted when the payRoyalties function is called + +The `supportsInterface` function MUST return true when called with `0x253b27b0` + +## Rationale + +The payment can be made in native coins, so it is easy to aggregate the amount of paid royalties. We want this information to be public, so anyone could tell if a creator received royalties in case of under the table trading or in case of marketplaces which don’t support royalties. + +The function used for payment can be called by anyone (not only the NFTs owner) to support the creator at any time. There is a way of seeing the amount of paid royalties in any token, also available for anyone. + +For fetching creator on-chain data we will use [ERC-2981](./eip-2981.md), but any other on-chain method of getting the creator address is accepted. + +## Backwards Compatibility + +This ERC is not introducing any backward incompatibilities. + +## Test Cases + +Tests are included in [`ERC6786.test.js`](../assets/eip-6786/test/ERC6786.test.js). + +To run them in terminal, you can use the following commands: + +``` +cd ../assets/eip-6786 +npm install +npx hardhat test +``` + +## Reference Implementation + +See [`ERC6786.sol`](../assets/eip-6786/contracts/ERC6786.sol). + +## Security Considerations + +There are no security considerations related directly to the implementation of this standard. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE). diff --git a/EIPS/eip-6787.md b/EIPS/eip-6787.md new file mode 100644 index 0000000000000..0656bb65ba3d6 --- /dev/null +++ b/EIPS/eip-6787.md @@ -0,0 +1,93 @@ +--- +eip: 6787 +title: Order Book DEX with Two Phase Withdrawal +description: An order book-based DEX Interface that ensures the asset security of both users and the exchange +author: Jessica (@qizheng09), Roy (@royshang), Jun (@SniperUsopp) +discussions-to: https://ethereum-magicians.org/t/order-book-dex-standard/13573 +status: Draft +type: Standards Track +category: ERC +created: 2023-03-27 +--- + + +## Abstract + +The Order Book DEX Standard is a proposed set of interface specifications that define a decentralized exchange (DEX) protocol for trading assets using order books. This standard provides a set of functions that allow users to deposit, withdraw, and trade assets on a decentralized exchange. Additionally, it proposes a novel two-phase withdrawal scheme to ensure the asset security of both users and the exchange, addressing users' trust issues with the exchange. + +## Motivation + +Decentralized exchanges (DEXs) have become increasingly popular in recent years due to their ability to provide users with greater control over their assets and reduce reliance on centralized intermediaries. However, many existing DEX protocols suffer from issues such as low liquidity and inefficient price discovery. Order book-based DEXs based Layer2 have emerged as a popular alternative, but there is currently no standardized interface for implementing such exchanges. + +The Order Book DEX Standard aims to provide developers with a common interface for building interoperable order book-based DEXs that can benefit from network effects. By establishing a standard set of functions for depositing, withdrawing, and forced withdrawals, the Order Book DEX Standard can fully ensure the security of user assets. At the same time, the two-phase forced withdrawal mechanism can also prevent malicious withdrawals from users targeting the exchange. + +The two phase commit protocol is an important distributed consistency protocol, aiming to ensure data security and consistency in distributed systems. In the Layer2 order book DEX system, to enhance user experience and ensure financial security, we adopt a 1:1 reserve strategy, combined with a decentralized clearing and settlement interface, and a forced withdrawal function to fully guarantee users' funds. + +However, such design also faces potential risks. When users engage in perpetual contract transactions, they may incur losses. In this situation, malicious users might exploit the forced withdrawal function to evade losses. To prevent this kind of attack, we propose a two-phase forced withdrawal mechanism. + +By introducing the two phase forced withdrawal function, we can protect users' financial security while ensuring the security of the exchange's assets. In the first phase, the system will conduct a preliminary review of the user's withdrawal request to confirm the user's account status. In the second phase, after the forced withdrawal inspection period, users can directly submit the forced withdrawal request to complete the forced withdrawal process. In this way, we can not only prevent users from exploiting the forced withdrawal function to evade losses but also ensure the asset security for both the exchange and the users. + +In conclusion, by adopting the two phase commit protocol and the two phase forced withdrawal function, we can effectively guard against malicious behaviors and ensure data consistency and security in distributed systems while ensuring user experience and financial security. + +## Specification + +### Interfaces + +The Order Book DEX Standard defines the following Interfaces: + +#### `deposit` + +`function deposit(address token, uint256 amount) external;` + +The **deposit** function allows a user to deposit a specified amount of a particular token to the exchange. The *token* parameter specifies the address of the token contract, and the *amount* parameter specifies the amount of the token to be deposited. + +#### `withdraw` + +`function withdraw(address token, uint256 amount) external;` + +The **withdraw** function allows a user to withdraw a specified amount of a particular token from the exchange. The *token* parameter specifies the address of the token contract, and the *amount* parameter specifies the amount of the token to be withdrawn. + +#### `prepareForceWithdraw` + +`function prepareForceWithdraw(address token, uint256 amount) external returns (uint256 requestID);` + +The assets deposited by users will be stored in the exchange contract's account, and the exchange can achieve real-time 1:1 reserve proof. The **prepareForceWithdraw** function is used for users to initiate a forced withdrawal of a certain amount of a specified token. This function indicates that the user wants to perform a forced withdrawal and can submit the withdrawal after the default timeout period. Within the timeout period, the exchange needs to confirm that the user's order status meets the expected criteria, and forcibly cancel the user's order and settle the trade to avoid malicious attacks by the user. This function takes the following parameters: + +1. *token*: the address of the token to be withdrawn +2. *amount*: the amount of the token to be withdrawn + +Since an account may initiate multiple two phase forced withdrawals in parallel, each forced withdrawal needs to return a unique *requestID*. The function returns a unique *requestID* that can be used to submit the forced withdrawal using the commitForceWithdraw function. + +#### `commitForceWithdraw` + +`function commitForceWithdraw(uint256 requestID) external;` + +1. *requestID*: the request ID of the two phase Withdraw + +The **commitForceWithdraw** function is used to execute a forced withdrawal operation after the conditions are met. The function takes a *requestID* parameter, which specifies the ID of the forced withdrawal request to be executed. The request must have been previously initiated using the prepareForceWithdraw function. + +### Events + +#### `PrepareForceWithdraw` + +MUST trigger when user successful call to PrepareForceWithdraw. + +`event PrepareForceWithdraw(address indexed user, address indexed tokenAddress, uint256 amount);` + +## Rationale + +The flow charts for two-phase withdrawal are shown below: + +![](../assets/eip-6787/image1.png) + +## Backwards Compatibility + +No backward compatibility issues found. + +## Security Considerations + +Needs discussion. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-6806.md b/EIPS/eip-6806.md new file mode 100644 index 0000000000000..b37562b02c29a --- /dev/null +++ b/EIPS/eip-6806.md @@ -0,0 +1,132 @@ +--- +eip: 6806 +title: ERC-721 Holding Time Tracking +description: Add holding time information to ERC-721 tokens +author: Saitama (@saitama2009), Combo , Luigi +discussions-to: https://ethereum-magicians.org/t/draft-eip-erc721-holding-time-tracking/13605 +status: Draft +type: Standards Track +category: ERC +created: 2023-03-30 +requires: 721 +--- + +## Abstract + +This standard is an extension of [ERC-721](./eip-721.md). It adds an interface that tracks and describes the holding time of a Non-Fungible Token (NFT) by an account. + +## Motivation + +In some use cases, it is valuable to know the duration for which a NFT has been held by an account. This information can be useful for rewarding long-term holders, determining access to exclusive content, or even implementing specific business logic based on holding time. However, the current ERC-721 standard does not have a built-in mechanism to track NFT holding time. + +This proposal aims to address these limitations by extending the ERC-721 standard to include holding time tracking functionality. + +## Specification + +The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119. + +**Interface** + +The following interface extends the existing ERC-721 standard: + +```solidity +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.0 + +interface IERC6806 { + function getHoldingInfo( + uint256 tokenId + ) external view returns (address holder, uint256 holdingTime); +} +``` + +**Functions** + +### getHoldingInfo + +``` +function getHoldingInfo(uint256 tokenId) external view returns (address holder, uint256 holdingTime); +``` + +This function returns the current holder of the specified NFT and the length of time (in seconds) the NFT has been held by the current account. + +* `tokenId`: The unique identifier of the NFT. +* Returns: A tuple containing the current holder's address and the holding time (in seconds). + +## Rationale + +The addition of the `getHoldingInfo` function to an extension of the ERC-721 standard enables developers to implement NFT-based applications that require holding time information. This extension maintains compatibility with existing ERC-721 implementations while offering additional functionality for new use cases. + +The `getHoldingInfo` function provides a straightforward method for retrieving the holding time and holder address of an NFT. By using seconds as the unit of time for holding duration, it ensures precision and compatibility with other time-based functions in smart contracts. + +`getHoldingInfo` returns both `holder` and `holdingTime` so that some token owners (as decided by the implementation) can be ignored for the purposes of calculating holding time. For example, a contract may take ownership of an NFT as collateral for a loan. Such a loan contract could be ignored, so the real owner's holding time increases properly. + +## Backwards Compatibility + +This proposal is fully backwards compatible with the existing ERC-721 standard, as it extends the standard with new functions that do not affect the core functionality. + +## Reference Implementation + +```solidity +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "./IERC6806.sol"; + +contract ERC6806 is ERC721, Ownable, IERC6806 { + mapping(uint256 => address) private _holder; + mapping(uint256 => uint256) private _holdStart; + mapping(address => bool) private _holdingTimeWhitelist; + + constructor( + string memory name_, + string memory symbol_ + ) ERC721(name_, symbol_) {} + + function _afterTokenTransfer( + address from, + address to, + uint256 firstotTokenId, + uint256 + ) internal override { + if (_holdingTimeWhitelist[from] || _holdingTimeWhitelist[to]) { + return; + } + + if (_holder[firstotTokenId] != to) { + _holder[firstotTokenId] = to; + _holdStart[firstotTokenId] = block.timestamp; + } + } + + function getHoldingInfo( + uint256 tokenId + ) public view returns (address holder, uint256 holdingTime) { + return (_holder[tokenId], block.timestamp - _holdStart[tokenId]); + } + + function setHoldingTimeWhitelistedAddress( + address account, + bool ignoreReset + ) public onlyOwner { + _holdingTimeWhitelist[account] = ignoreReset; + emit HoldingTimeWhitelistSet(account, ignoreReset); + } +} +``` + +## Security Considerations + +This EIP introduces additional state management for tracking holding times, which may have security implications. Implementers should be cautious of potential vulnerabilities related to holding time manipulation, especially during transfers. + +When implementing this EIP, developers should be mindful of potential attack vectors, such as reentrancy and front-running attacks, as well as general security best practices for smart contracts. Adequate testing and code review should be performed to ensure the safety and correctness of the implementation. + +Furthermore, developers should consider the gas costs associated with maintaining and updating holding time information. Optimizations may be necessary to minimize the impact on contract execution costs. + +It is also important to note that the accuracy of holding time information depends on the accuracy of the underlying blockchain's timestamp. While block timestamps are generally reliable, they can be manipulated by miners to some extent. As a result, holding time data should not be relied upon as a sole source of truth in situations where absolute precision is required. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-6808.md b/EIPS/eip-6808.md index f6cfbed526335..73eb8bba4f3dd 100644 --- a/EIPS/eip-6808.md +++ b/EIPS/eip-6808.md @@ -1,10 +1,10 @@ --- eip: 6808 title: Fungible Key Bound Token -description: An interface for Fungible Key Bound Tokens, also known as an FKBT. +description: An interface for Fungible Key Bound Tokens, also known as a FKBT. author: Mihai Onila (@MihaiORO), Nick Zeman (@NickZCZ), Narcis Cotaie (@NarcisCRO) discussions-to: https://ethereum-magicians.org/t/fungible-key-bound-token-kbt/13624 -status: Draft +status: Review type: Standards Track category: ERC created: 2023-03-31 @@ -15,11 +15,11 @@ requires: 20 A standard interface for Fungible Key Bound Tokens (**FKBT/s**), a subset of the more general Key Bound Tokens (**KBT/s**). -The following standardizes an API for tokens within smart contracts and provides basic functionality to the [addBindings](#addbindings-function) function. This function designates **Key Wallets**[^1], which are responsible for conducting a **Safe Transfer**[^2]. During this process, **FKBTs** are safely approved so they can be spent by the user or an on-chain third-party entity. +The following standardizes an API for tokens within smart contracts and provides basic functionality to the [addBindings](#addbindings-function) function. This function designates **Key Wallets**[^1], which are responsible for conducting a **Safe Transfer**[^2]. During this process, **FKBT's** are safely approved so they can be spent by the user or an on-chain third-party entity. -The premise of **FKBTs** is to provide fully optional security features built directly into the fungible asset, via the concept of _allow_ found in the [allowTransfer](#allowtransfer-function) and [allowApproval](#allowapproval-function) functions. These functions are called by one of the **Key Wallets**[^1] and _allow_ the **Holding Wallet**[^3] to either call the already familiar `transfer` and `approve` function found in [ERC-20](./eip-20.md). Responsibility for the **FKBT** is therefore split. The **Holding Wallet** contains the asset and **Key Wallets** have authority over how the assets can be spent or approved. **Default Behaviors**[^4] of a traditional fungible ERC-20 can be achieved by simply never using the [addBindings](#addbindings-function) function. +The premise of **FKBT's** is to provide fully optional security features built directly into the fungible asset, via the concept of _allow_ found in the [allowTransfer](#allowtransfer-function) and [allowApproval](#allowapproval-function) functions. These functions are called by one of the **Key Wallets**[^1] and _allow_ the **Holding Wallet**[^3] to either call the already familiar `transfer` and `approve` function found in [ERC-20](./eip-20.md). Responsibility for the **FKBT** is therefore split. The **Holding Wallet** contains the asset and **Key Wallets** have authority over how the assets can be spent or approved. **Default Behaviors**[^4] of a traditional fungible ERC-20 can be achieved by simply never using the [addBindings](#addbindings-function) function. -We considered **FKBTs** being used by every individual who wishes to add additional security to their fungible assets, as well as consignment to third-party wallets/brokers/banks/insurers. **FKBTs** allow tokens to be more resilient to attacks/thefts, by providing additional protection to the asset itself on a self-custodial level. +We considered **FKBTs** being used by every individual who wishes to add additional security to their fungible assets, as well as consignment to third-party wallets/brokers/banks/insurers. **FKBTs** are resilient to attacks/thefts, by providing additional protection to the asset itself on a self-custodial level. ## Motivation @@ -27,31 +27,31 @@ In this fast-paced technologically advancing world, people learn and mature at d From January 2021 through March 2022, the United States Federal Trade Commission received more than 46,000[^5] crypto scam reports. This directly impacted crypto users and resulted in a net consumer loss exceeding $1 Billion[^6]. Theft and malicious scams are an issue in any financial sector and oftentimes lead to stricter regulation. However, government-imposed regulation goes against one of this space’s core values. Efforts have been made to increase security within the space through centralized and decentralized means. Up until now, no one has offered a solution that holds onto the advantages of both whilst eliminating their disadvantages. -We asked ourselves the same question as many have in the past, “How does one protect the wallet?”. After a while, realizing the question that should be asked is “How does one protect the asset?”. Creating the wallet is free, the asset is what has value and is worth protecting. This question led to the development of **KBTs**. A solution that is fully optional and can be tailored so far as the user is concerned. Individual assets remain protected even if the seed phrase or private key is publicly released, as long as the security feature was activated. +We asked ourselves the same question as many have in the past, “How does one protect the wallet?”. After a while, realizing the question that should be asked is “How does one protect the asset?”. Creating the wallet is free, the asset is what has value and is worth protecting. This question led to the development of **KBT's**. A solution that is fully optional and can be tailored so far as the user is concerned. Individual assets remain protected even if the seed phrase or private key is publicly released, as long as the security feature was activated. -**FKBTs** saw the need to improve on the widely used fungible ERC-20 token standard. The security of fungible assets is a topic that concerns every entity in the crypto space, as their current and future use cases continue to be explored. **FKBTs** provide a scalable decentralized security solution that takes security one step beyond wallet security, focusing on the token's ability to remain secure. The security is on the blockchain itself, which allows every demographic that has access to the internet to secure their assets without the need for current hardware or centralized solutions. Made to be a promising alternative, **FKBTs** inherit all the characteristics of an ERC-20. This was done so **FKBTs** could be used on every dApp that is configured to use traditional fungible tokens. +**FKBTs** saw the need to improve on the widely used fungible ERC-20 token standard. The security of fungible assets is a topic that concerns every entity in the crypto space, as their current and future use cases are continuously explored. **FKBTs** provide a scalable decentralized security solution that takes security one step beyond wallet security, focusing on the token's ability to remain secure. The security is on the blockchain itself, which allows every demographic that has access to the internet to secure their assets without the need for current hardware or centralized solutions. Made to be a promising alternative, **FKBTs** inherit all the characteristics of an ERC-20. This was done so **FKBTs** could be used on every dApp that is configured to use traditional fungible tokens. -During the development process, the potential advantages **KBTs** explored were the main motivation factors leading to their creation; +During the development process, the potential advantages **KBT's** explored were the main motivation factors leading to their creation; 1. **Completely Decentralized:** The security features are fully decentralized meaning no third-party will have access to user funds when activated. This was done to truly stay in line with the premise of self-custodial assets, responsibility and values. -2. **Limitless Scalability:** Centralized solutions require the creation of an account and their availability may be restricted based on location. **FKBTs** do not face regional restrictions or account creation. Decentralized security solutions such as hardware options face scalability issues requiring transport logistics, secure shipping and vendor. **FKBTs** can be used anywhere around the world by anyone who so wishes, provided they have access to the internet. +2. **Limitless Scalability:** Centralized solutions require the creation of an account and their availability may be restricted based on location. **FKBT's** do not face regional restrictions or account creation. Decentralized security solutions such as hardware options face scalability issues requiring transport logistics, secure shipping and vendor. **FKBT's** can be used anywhere around the world by anyone who so wishes, provided they have access to the internet. -3. **Fully Optional Security:** Security features are optional, customizable and removable. It’s completely up to the user to decide the level of security they would like when using **FKBTs**. +3. **Fully Optional Security:** Security features are optional, customizable and removable. It’s completely up to the user to decide the level of security they would like when using **FKBT's**. -4. **Default Functionality:** If the user would like to use **FKBTs** as a traditional ERC-20, the security features do not have to be activated. As the token inherits all of the same characteristics, it results in the token acting with traditional fungible **Default Behaviors**[^4]. However, even when the security features are activated, the user will still have the ability to customize the functionality of the various features based on their desired outcome. The user can pass a set of custom and or **Default Values**[^7] manually or through a dApp. +4. **Default Functionality:** If the user would like to use **FKBT's** as a traditional ERC-20, the security features do not have to be activated. As the token inherits all of the same characteristics, it results in the token acting with traditional fungible **Default Behaviors**[^4]. However, even when the security features are activated, the user will still have the ability to customize the functionality of the various features based on their desired outcome. The user can pass a set of custom and or **Default Values**[^7] manually or through a dApp. -5. **Unmatched Security:** By calling the [addBindings](#addbindings-function) function a **Key Wallet**[^1] is now required for the [allowTransfer](#allowtransfer-function) or [allowApproval](#allowapproval-function) function. The [allowTransfer](#allowtransfer-function) function requires 4 parameters, `_amount`[^8], `_time`[^9], `_address`[^10], and `_allFunds`[^11], where as the [allowApproval](#allowapproval-function) function has 2 parameters, `_time`[^12] and `_numberOfTransfers`[^13]. In addition to this, **FKBTs** have a [safeFallback](#safefallback-function) and [resetBindings](#resetbindings-function) function. The combination of all these prevent and virtually cover every single point of failure that is present with a traditional ERC-20, when properly used. +5. **Unmatched Security:** By calling the [addBindings](#addbindings-function) function a **Key Wallet**[^1] is now required for the [allowTransfer](#allowtransfer-function) or [allowApproval](#allowapproval-function) function. The [allowTransfer](#allowtransfer-function) function requires 4 parameters, `_amount`[^8], `_time`[^9], `_address`[^10], and `_allFunds`[^11], where as the [allowApproval](#allowapproval-function) function has 2 parameters, `_time`[^12] and `_numberOfTransfers`[^13]. In addition to this, **FKBT's** have a [safeFallback](#safefallback-function) and [resetBindings](#resetbindings-function) function. The combination of all these prevent and virtually cover every single point of failure that is present with a traditional ERC-20, when properly used. -6. **Security Fail-Safes:** With **FKBTs**, users can be confident that their tokens are safe and secure, even if the **Holding Wallet**[^3] or one of the **Key Wallets**[^1] has been compromised. If the owner suspects that the **Holding Wallet** has been compromised or lost access, they can call the [safeFallback](#safefallback-function) function from one of the **Key Wallets**. This moves the assets to the other **Key Wallet** preventing a single point of failure. If the owner suspects that one of the **Key Wallets** has been comprised or lost access, the owner can call the [resetBindings](#resetbindings-function) function from `_keyWallet1`[^15] or `_keyWallet2`[^16]. This resets the **FKBTs** security feature and allows the **Holding Wallet** to call the [addBindings](#addbindings-function) function again. New **Key Wallets** can therefore be added and a single point of failure can be prevented. +6. **Security Fail-Safes:** With **FKBTs**, users can be confident that their tokens are safe and secure, even if the **Holding Wallet**[^3] or one of the **Key Wallets**[^1] has been compromised. If the owner suspects that the **Holding Wallet** has been compromised or lost access, they can call the [safeFallback](#safefallback-function) function from one of the **Key Wallets**. This moves the assets to the other **Key Wallet** preventing a single point of failure. If the owner suspects that one of the **Key Wallets** has been comprised or lost access, the owner can call the [resetBindings](#resetbindings-function) function from `_keyWallet1`[^15] or `_keyWallet2`[^16]. This resets the **FKBT's** security feature and allows the **Holding Wallet** to call the [addBindings](#addbindings-function) function again. New **Key Wallets** can therefore be added and a single point of failure can be prevented. -7. **Anonymous Security:** Frequently, centralized solutions ask for personal information that is stored and subject to prying eyes. Purchasing decentralized hardware solutions are susceptible to the same issues e.g. a shipping address, payment information, or a camera recording during a physical cash pick-up. This may be considered by some as infringing on their privacy and asset anonymity. **FKBTs** ensure user confidentially as everything can be done remotely under a pseudonym on the blockchain. +7. **Anonymous Security:** Frequently, centralized solutions ask for personal information that is stored and subject to prying eyes. Purchasing decentralized hardware solutions are susceptible to the same issues e.g. a shipping address, payment information, or a camera recording during a physical cash pick-up. This may be considered by some as infringing on their privacy and asset anonymity. **FKBT's** ensure user confidentially as everything can be done remotely under a pseudonym on the blockchain. -8. **Low-Cost Security:** The cost of using **FKBTs** security features correlate to on-chain fees, the current _GWEI_ at the given time. As a standalone solution, they are a viable cost-effective security measure feasible to the majority of the population. +8. **Low-Cost Security:** The cost of using **FKBT's** security features correlate to on-chain fees, the current _GWEI_ at the given time. As a standalone solution, they are a viable cost-effective security measure feasible to the majority of the population. -9. **Environmentally Friendly:** Since the security features are coded into the **FKBT**, there is no need for centralized servers, shipping, or the production of physical object/s. Thus leading to a minimal carbon footprint by the use of **FKBTs**, working hand in hand with Ethereum’s change to a _PoS_[^14] network. +9. **Environmentally Friendly:** Since the security features are coded into the **FKBT**, there is no need for centralized servers, shipping, or the production of physical object/s. Thus leading to a minimal carbon footprint by the use of **FKBT's**, working hand in hand with Ethereum’s change to a _PoS_[^14] network. -10. **User Experience:** The security feature can be activated by a simple call to the [addBindings](#addbindings-function) function. The user will only need two other wallets, which will act as `_keyWallet1`[^15] and `_keyWallet2`[^16], to gain access to all of the benefits **FKBTs** offer. The optional security features improve the overall user experience and Ethereum ecosystem by ensuring a safety net for those who decide to use it. Those that do not use the security features are not hindered in any way. This safety net can increase global adoption as people can remain confident in the security of their assets, even in the scenario of a compromised wallet. +10. **User Experience:** The security feature can be activated by a simple call to the [addBindings](#addbindings-function) function. The user will only need two other wallets, which will act as `_keyWallet1`[^15] and `_keyWallet2`[^16], to gain access to all of the benefits **FKBT's** offer. The optional security features improve the overall user experience and Ethereum ecosystem by ensuring a safety net for those who decide to use it. Those that do not use the security features are not hindered in any way. This safety net can increase global adoption as people can remain confident in the security of their assets, even in the scenario of a compromised wallet. ## Specification @@ -424,13 +424,13 @@ function transferFrom(address _from, address _to, uint256 _amount) external retu ## Rationale -The intent from individual technical decisions made during the development of **FKBTs** focused on maintaining consistency and backward compatibility with ERC-20s, all the while offering self-custodial security features to the user. It was important that **FKBTs** inherited all of ERC-20s characteristics to comply with requirements found in dApps which use fungible tokens on their platform. In doing so, it allowed for flawless backward compatibility to take place and gave the user the choice to decide if they want their **FKBTs** to act with **Default Behaviors**[^4]. We wanted to ensure that wide-scale implementation and adoption of **FKBTs** could take place immediately, without the greater collective needing to adapt and make changes to the already flourishing decentralized ecosystem. +The intent from individual technical decisions made during the development of **FKBTs** focused on maintaining consistency and backward compatibility with ERC-20s, all the while offering self-custodial security features to the user. It was important that **FKBT's** inherited all of ERC-20s characteristics to comply with requirements found in dApps which use fungible tokens on their platform. In doing so, it allowed for flawless backward compatibility to take place and gave the user the choice to decide if they want their **FKBTs** to act with **Default Behaviors**[^4]. We wanted to ensure that wide-scale implementation and adoption of **FKBTs** could take place immediately, without the greater collective needing to adapt and make changes to the already flourishing decentralized ecosystem. For developers and users alike, the [allowTransfer](#allowtransfer-function) and [allowApproval](#allowapproval-function) functions both return bools on success and revert on failures. This decision was done purposefully, to keep consistency with the already familiar ERC-20. Additional technical decisions related to self-custodial security features are broken down and located within the [Security Considerations](#security-considerations) section. ## Backwards Compatibility -**KBTs** are designed to be backward-compatible with existing token standards and wallets. Existing tokens and wallets will continue to function as normal, and will not be affected by the implementation of **FKBTs**. +**KBT's** are designed to be backward-compatible with existing token standards and wallets. Existing tokens and wallets will continue to function as normal, and will not be affected by the implementation of **FKBT's**. ## Test Cases @@ -450,41 +450,41 @@ The implementation is located in the [assets](../assets/eip-6808/README.md) dire ## Security Considerations -**FKBTs** were designed with security in mind every step of the way. Below are some design decisions that were rigorously discussed and thought through during the development process. +**FKBT's** were designed with security in mind every step of the way. Below are some design decisions that were rigorously discussed and thought through during the development process. -**Key Wallets**[^1]: When calling the [addBindings](#addbindings-function) function for an **FKBT**, the user must input 2 wallets that will then act as `_keyWallet1`[^15] and `_keyWallet2`[^16]. They are added simultaneously to reduce user fees, minimize the chance of human error and prevent a pitfall scenario. If the user had the ability to add multiple wallets it would not only result in additional fees and avoidable confusion but would enable a potentially disastrous [safeFallback](#safefallback-function) situation to occur. For this reason, all **KBTs** work under a 3-wallet system when security features are activated. +**Key Wallets**[^1]: When calling the [addBindings](#addbindings-function) function for an **FKBT**, the user must input 2 wallets that will then act as `_keyWallet1`[^15] and `_keyWallet2`[^16]. They are added simultaneously to reduce user fees, minimize the chance of human error and prevent a pitfall scenario. If the user had the ability to add multiple wallets it would not only result in additional fees and avoidable confusion but would enable a potentially disastrous [safeFallback](#safefallback-function) situation to occur. For this reason, all **KBT's** work under a 3-wallet system when security features are activated. -Typically if a wallet is compromised, the fungible assets within are at risk. With **FKBTs** there are two different functions that can be called from a **Key Wallet**[^1] depending on which wallet has been compromised. +Typically if a wallet is compromised, the fungible assets within are at risk. With **FKBT's** there are two different functions that can be called from a **Key Wallet**[^1] depending on which wallet has been compromised. Scenario: **Holding Wallet**[^3] has been compromised, call [safeFallback](#safefallback-function). -[safeFallback](#safefallback-function): This function was created in the event that the owner believes the **Holding Wallet**[^3] has been compromised. It can also be used if the owner losses access to the **Holding Wallet**. In this scenario, the user has the ability to call [safeFallback](#safefallback-function) from one of the **Key Wallets**[^1]. **FKBTs** are then redirected from the **Holding Wallet** to the other **Key Wallet**. +[safeFallback](#safefallback-function): This function was created in the event that the owner believes the **Holding Wallet**[^3] has been compromised. It can also be used if the owner losses access to the **Holding Wallet**. In this scenario, the user has the ability to call [safeFallback](#safefallback-function) from one of the **Key Wallets**[^1]. **FKBT's** are then redirected from the **Holding Wallet** to the other **Key Wallet**. -By redirecting the **FKBTs** it prevents a single point of failure. If an attacker were to call [safeFallback](#safefallback-function) and the **FKBTs** redirected to the **Key Wallet**[^1] that called the function, they would gain access to all the **FKBTs**. +By redirecting the **FKBT's** it prevents a single point of failure. If an attacker were to call [safeFallback](#safefallback-function) and the **FKBT's** redirected to the **Key Wallet**[^1] that called the function, they would gain access to all the **FKBT's**. Scenario: **Key Wallet**[^1] has been compromised, call [resetBindings](#resetbindings-function). -[resetBindings](#resetbindings-function): This function was created in the event that the owner believes `_keyWallet1`[^15] or `_keyWallet2`[^16] has been compromised. It can also be used if the owner losses access to one of the **Key Wallets**[^1]. In this instance, the user has the ability to call [resetBindings](#resetbindings-function), removing the bound **Key Wallets** and resetting the security features. The **FKBTs** will now function as a traditional ERC-20 until [addBindings](#addbindings-function) is called again and a new set of **Key Wallets** are added. +[resetBindings](#resetbindings-function): This function was created in the event that the owner believes `_keyWallet1`[^15] or `_keyWallet2`[^16] has been compromised. It can also be used if the owner losses access to one of the **Key Wallets**[^1]. In this instance, the user has the ability to call [resetBindings](#resetbindings-function), removing the bound **Key Wallets** and resetting the security features. The **FKBT's** will now function as a traditional ERC-20 until [addBindings](#addbindings-function) is called again and a new set of **Key Wallets** are added. -The reason why `_keyWallet1`[^15] or `_keyWallet2`[^16] are required to call the [resetBindings](#resetbindings-function) function is because a **Holding Wallet**[^3] having the ability to call [resetBindings](#resetbindings-function) could result in an immediate loss of **FKBTs**. The attacker would only need to gain access to the **Holding Wallet** and call [resetBindings](#resetbindings-function). +The reason why `_keyWallet1`[^15] or `_keyWallet2`[^16] are required to call the [resetBindings](#resetbindings-function) function is because a **Holding Wallet**[^3] having the ability to call [resetBindings](#resetbindings-function) could result in an immediate loss of **FKBT's**. The attacker would only need to gain access to the **Holding Wallet** and call [resetBindings](#resetbindings-function). -In the scenario that 2 of the 3 wallets have been compromised, there is nothing the owner of the **FKBTs** can do if the attack is malicious. However, by allowing 1 wallet to be compromised, holders of fungible tokens built using the **FKBT** standard are given a second chance, unlike other current standards. +In the scenario that 2 of the 3 wallets have been compromised, there is nothing the owner of the **FKBT's** can do if the attack is malicious. However, by allowing 1 wallet to be compromised, holders of fungible tokens built using the **FKBT** standard are given a second chance, unlike other current standards. -The [allowTransfer](#allowtransfer-function) function is in place to guarantee a **Safe Transfer**[^2], but can also have **Default Values**[^7] set by a dApp to emulate **Default Behaviors**[^3] of a traditional ERC-20. It enables the user to highly specify the type of transfer they are about to conduct, whilst simultaneously allowing the user to unlock all the **FKBTs** to anyone for an unlimited amount of time. The desired security is completely up to the user. +The [allowTransfer](#allowtransfer-function) function is in place to guarantee a **Safe Transfer**[^2], but can also have **Default Values**[^7] set by a dApp to emulate **Default Behaviors**[^3] of a traditional ERC-20. It enables the user to highly specify the type of transfer they are about to conduct, whilst simultaneously allowing the user to unlock all the **FKBT's** to anyone for an unlimited amount of time. The desired security is completely up to the user. This function requires 4 parameters to be filled and different combinations of these result in different levels of security; -Parameter 1 `_amount`[^8]: This is the number of **FKBTs** that will be spent on a transfer. +Parameter 1 `_amount`[^8]: This is the number of **FKBT's** that will be spent on a transfer. -Parameter 2 `_time`[^9]: The number of blocks the **FKBTs** can be transferred starting from the current block timestamp. +Parameter 2 `_time`[^9]: The number of blocks the **FKBT's** can be transferred starting from the current block timestamp. -Parameter 3 `_address`[^10]: The destination the **FKBTs** will be sent to. +Parameter 3 `_address`[^10]: The destination the **FKBT's** will be sent to. Parameter 4 `_allFunds`[^11]: This is a boolean value. When false, the `transfer` function takes into consideration Parameters 1, 2 and 3. If the value is true, the `transfer` function will revert to a **Default Behavior**[^4], the same as a traditional ERC-20. The [allowTransfer](#allowtransfer-function) function requires `_keyWallet1`[^15] or `_keyWallet2`[^16] and enables the **Holding Wallet**[^3] to conduct a `transfer` within the previously specified parameters. These parameters were added in order to provide additional security by limiting the **Holding Wallet** in case it was compromised without the user's knowledge. -The [allowApproval](#allowapproval-function) function provides extra security when allowing on-chain third parties to use your **FKBTs** on your behalf. This is especially useful when a user is met with common malicious attacks e.g. draining dApp. +The [allowApproval](#allowapproval-function) function provides extra security when allowing on-chain third parties to use your **FKBT's** on your behalf. This is especially useful when a user is met with common malicious attacks e.g. draining dApp. This function requires 2 parameters to be filled and different combinations of these result in different levels of security; @@ -500,15 +500,15 @@ Copyright and related rights waived via [CC0](../LICENSE.md). [^1]: The **Key Wallet/s** refers to `_keyWallet1` or `_keyWallet2` which can call the `safeFallback`, `resetBindings`, `allowTransfer` and `allowApproval` functions. -[^2]: A **Safe Transfer** is when 1 of the **Key Wallets** safely approved the use of the **FKBTs**. -[^3]: The **Holding Wallet** refers to the wallet containing the **FKBTs**. +[^2]: A **Safe Transfer** is when 1 of the **Key Wallets** safely approved the use of the **FKBT's**. +[^3]: The **Holding Wallet** refers to the wallet containing the **FKBT's**. [^4]: A **Default Behavior/s** refers to behavior/s present in the preexisting non-fungible ERC-20 standard. [^5]: The number of crypto scam reports the United States Federal Trade Commission received, from January 2021 through March 2022. [^6]: The amount stolen via crypto scams according to the United States Federal Trade Commission, from January 2021 through March 2022. [^7]: A **Default Value/s** refer to a value/s that emulates the non-fungible ERC-20 **Default Behavior/s**. -[^8]: The `_amount` represents the amount of the **FKBTs** intended to be spent. +[^8]: The `_amount` represents the amount of the **FKBT's** intended to be spent. [^9]: The `_time` in `allowTransfer` represents the number of blocks a `transfer` can take place in. -[^10]: The `_address` represents the address that the **FKBTs** will be sent to. +[^10]: The `_address` represents the address that the **FKBT's** will be sent to. [^11]: The `_allFunds` is a bool that can be set to true or false. [^12]: The `_time` in `allowApproval` represents the number of blocks an `approve` can take place in. [^13]: The `_numberOfTransfers` is the number of transfers a third-party entity can conduct via `transfer` on the user's behalf. diff --git a/EIPS/eip-6809.md b/EIPS/eip-6809.md index b642cc4e8a7de..e0e5cea7361d6 100644 --- a/EIPS/eip-6809.md +++ b/EIPS/eip-6809.md @@ -1,10 +1,10 @@ --- eip: 6809 title: Non-Fungible Key Bound Token -description: An interface for Non-Fungible Key Bound Tokens, also known as an NFKBT. +description: An interface for Non-Fungible Key Bound Tokens, also known as a NFKBT. author: Mihai Onila (@MihaiORO), Nick Zeman (@NickZCZ), Narcis Cotaie (@NarcisCRO) discussions-to: https://ethereum-magicians.org/t/non-fungible-key-bound-token-kbt/13625 -status: Draft +status: Review type: Standards Track category: ERC created: 2023-03-31 @@ -15,11 +15,11 @@ requires: 721 A standard interface for Non-Fungible Key Bound Tokens (**NFKBT/s**), a subset of the more general Key Bound Tokens (**KBT/s**). -The following standardizes an API for tokens within smart contracts and provides basic functionality to the [addBindings](#addbindings-function) function. This function designates **Key Wallets**[^1], which are responsible for conducting a **Safe Transfer**[^2]. During this process, **NFKBTs** are safely approved so they can be spent by the user or an on-chain third-party entity. +The following standardizes an API for tokens within smart contracts and provides basic functionality to the [addBindings](#addbindings-function) function. This function designates **Key Wallets**[^1], which are responsible for conducting a **Safe Transfer**[^2]. During this process, **NFKBT's** are safely approved so they can be spent by the user or an on-chain third-party entity. -The premise of **NFKBTs** is to provide fully optional security features built directly into the non-fungible asset, via the concept of _allow_ found in the [allowTransfer](#allowtransfer-function) and [allowApproval](#allowapproval-function) functions. These functions are called by one of the **Key Wallets**[^1] and _allow_ the **Holding Wallet**[^3] to either call the already familiar `transferFrom` and `approve` function found in [ERC-721](./eip-721.md). Responsibility for the **NFKBT** is therefore split. The **Holding Wallet** contains the asset and **Key Wallets** have authority over how the assets can be spent or approved. **Default Behaviors**[^4] of a traditional non-fungible ERC-721 can be achieved by simply never using the [addBindings](#addbindings-function) function. +The premise of **NFKBT's** is to provide fully optional security features built directly into the non-fungible asset, via the concept of _allow_ found in the [allowTransfer](#allowtransfer-function) and [allowApproval](#allowapproval-function) functions. These functions are called by one of the **Key Wallets**[^1] and _allow_ the **Holding Wallet**[^3] to either call the already familiar `transferFrom` and `approve` function found in [ERC-721](./eip-721.md). Responsibility for the **NFKBT** is therefore split. The **Holding Wallet** contains the asset and **Key Wallets** have authority over how the assets can be spent or approved. **Default Behaviors**[^4] of a traditional non-fungible ERC-721 can be achieved by simply never using the [addBindings](#addbindings-function) function. -We considered **NFKBTs** being used by every individual who wishes to add additional security to their non-fungible assets, as well as consignment to third-party wallets/brokers/banks/insurers/museums. **NFKBTs** allow tokens to be more resilient to attacks/thefts, by providing additional protection to the asset itself on a self-custodial level. +We considered **NFKBTs** being used by every individual who wishes to add additional security to their non-fungible assets, as well as consignment to third-party wallets/brokers/banks/insurers/galleries. **NFKBTs** are resilient to attacks/thefts, by providing additional protection to the asset itself on a self-custodial level. ## Motivation @@ -27,31 +27,31 @@ In this fast-paced technologically advancing world, people learn and mature at d From January 2021 through March 2022, the United States Federal Trade Commission received more than 46,000[^5] crypto scam reports. This directly impacted crypto users and resulted in a net consumer loss exceeding $1 Billion[^6]. Theft and malicious scams are an issue in any financial sector and oftentimes lead to stricter regulation. However, government-imposed regulation goes against one of this space’s core values. Efforts have been made to increase security within the space through centralized and decentralized means. Up until now, no one has offered a solution that holds onto the advantages of both whilst eliminating their disadvantages. -We asked ourselves the same question as many have in the past, “How does one protect the wallet?”. After a while, realizing the question that should be asked is “How does one protect the asset?”. Creating the wallet is free, the asset is what has value and is worth protecting. This question led to the development of **KBTs**. A solution that is fully optional and can be tailored so far as the user is concerned. Individual assets remain protected even if the seed phrase or private key is publicly released, as long as the security feature was activated. +We asked ourselves the same question as many have in the past, “How does one protect the wallet?”. After a while, realizing the question that should be asked is “How does one protect the asset?”. Creating the wallet is free, the asset is what has value and is worth protecting. This question led to the development of **KBT's**. A solution that is fully optional and can be tailored so far as the user is concerned. Individual assets remain protected even if the seed phrase or private key is publicly released, as long as the security feature was activated. -**NFKBTs** saw the need to improve on the widely used non-fungible ERC-721 token standard. The security of non-fungible assets is a topic that concerns every entity in the crypto space, as their current and future use cases continue to be explored. **NFKBTs** provide a scalable decentralized security solution that takes security one step beyond wallet security, focusing on the token's ability to remain secure. The security is on the blockchain itself, which allows every demographic that has access to the internet to secure their assets without the need for current hardware or centralized solutions. Made to be a promising alternative, **NFKBTs** inherit all the characteristics of an ERC-721. This was done so **NFKBTs** could be used on every dApp that is configured to use traditional non-fungible tokens. +**NFKBTs** saw the need to improve on the widely used non-fungible ERC-721 token standard. The security of non-fungible assets is a topic that concerns every entity in the crypto space, as their current and future use cases are continuously explored. **NFKBTs** provide a scalable decentralized security solution that takes security one step beyond wallet security, focusing on the token's ability to remain secure. The security is on the blockchain itself, which allows every demographic that has access to the internet to secure their assets without the need for current hardware or centralized solutions. Made to be a promising alternative, **NFKBTs** inherit all the characteristics of an ERC-721. This was done so **NFKBTs** could be used on every dApp that is configured to use traditional non-fungible tokens. -During the development process, the potential advantages **KBTs** explored were the main motivation factors leading to their creation; +During the development process, the potential advantages **KBT's** explored were the main motivation factors leading to their creation; 1. **Completely Decentralized:** The security features are fully decentralized meaning no third-party will have access to user funds when activated. This was done to truly stay in line with the premise of self-custodial assets, responsibility and values. -2. **Limitless Scalability:** Centralized solutions require the creation of an account and their availability may be restricted based on location. **NFKBTs** do not face regional restrictions or account creation. Decentralized security solutions such as hardware options face scalability issues requiring transport logistics, secure shipping and vendor. **NFKBTs** can be used anywhere around the world by anyone who so wishes, provided they have access to the internet. +2. **Limitless Scalability:** Centralized solutions require the creation of an account and their availability may be restricted based on location. **NFKBT's** do not face regional restrictions or account creation. Decentralized security solutions such as hardware options face scalability issues requiring transport logistics, secure shipping and vendor. **NFKBT's** can be used anywhere around the world by anyone who so wishes, provided they have access to the internet. -3. **Fully Optional Security:** Security features are optional, customizable and removable. It’s completely up to the user to decide the level of security they would like when using **NFKBTs**. +3. **Fully Optional Security:** Security features are optional, customizable and removable. It’s completely up to the user to decide the level of security they would like when using **NFKBT's**. -4. **Default Functionality:** If the user would like to use **NFKBTs** as a traditional ERC-721, the security features do not have to be activated. As the token inherits all of the same characteristics, it results in the token acting with traditional non-fungible **Default Behaviors**[^4]. However, even when the security features are activated, the user will still have the ability to customize the functionality of the various features based on their desired outcome. The user can pass a set of custom and or **Default Values**[^7] manually or through a dApp. +4. **Default Functionality:** If the user would like to use **NFKBT's** as a traditional ERC-721, the security features do not have to be activated. As the token inherits all of the same characteristics, it results in the token acting with traditional non-fungible **Default Behaviors**[^4]. However, even when the security features are activated, the user will still have the ability to customize the functionality of the various features based on their desired outcome. The user can pass a set of custom and or **Default Values**[^7] manually or through a dApp. -5. **Unmatched Security:** By calling the [addBindings](#addbindings-function) function a **Key Wallet**[^1] is now required for the [allowTransfer](#allowtransfer-function) or [allowApproval](#allowapproval-function) function. The [allowTransfer](#allowtransfer-function) function requires 4 parameters, `_tokenId`[^8], `_time`[^9], `_address`[^10], and `_anyToken`[^11], where as the [allowApproval](#allowapproval-function) function has 2 parameters, `_time`[^12] and `_numberOfTransfers`[^13]. In addition to this, **NFKBTs** have a [safeFallback](#safefallback-function) and [resetBindings](#resetbindings-function) function. The combination of all these prevent and virtually cover every single point of failure that is present with a traditional ERC-721, when properly used. +5. **Unmatched Security:** By calling the [addBindings](#addbindings-function) function a **Key Wallet**[^1] is now required for the [allowTransfer](#allowtransfer-function) or [allowApproval](#allowapproval-function) function. The [allowTransfer](#allowtransfer-function) function requires 4 parameters, `_tokenId`[^8], `_time`[^9], `_address`[^10], and `_anyToken`[^11], where as the [allowApproval](#allowapproval-function) function has 2 parameters, `_time`[^12] and `_numberOfTransfers`[^13]. In addition to this, **NFKBT's** have a [safeFallback](#safefallback-function) and [resetBindings](#resetbindings-function) function. The combination of all these prevent and virtually cover every single point of failure that is present with a traditional ERC-721, when properly used. -6. **Security Fail-Safes:** With **NFKBTs**, users can be confident that their tokens are safe and secure, even if the **Holding Wallet**[^3] or one of the **Key Wallets**[^1] has been compromised. If the owner suspects that the **Holding Wallet** has been compromised or lost access, they can call the [safeFallback](#safefallback-function) function from one of the **Key Wallets**. This moves the assets to the other **Key Wallet** preventing a single point of failure. If the owner suspects that one of the **Key Wallets** has been comprised or lost access, the owner can call the [resetBindings](#resetbindings-function) function from `_keyWallet1`[^15] or `_keyWallet2`[^16]. This resets the **NFKBTs** security feature and allows the **Holding Wallet** to call the [addBindings](#addbindings-function) function again. New **Key Wallets** can therefore be added and a single point of failure can be prevented. +6. **Security Fail-Safes:** With **NFKBTs**, users can be confident that their tokens are safe and secure, even if the **Holding Wallet**[^3] or one of the **Key Wallets**[^1] has been compromised. If the owner suspects that the **Holding Wallet** has been compromised or lost access, they can call the [safeFallback](#safefallback-function) function from one of the **Key Wallets**. This moves the assets to the other **Key Wallet** preventing a single point of failure. If the owner suspects that one of the **Key Wallets** has been comprised or lost access, the owner can call the [resetBindings](#resetbindings-function) function from `_keyWallet1`[^15] or `_keyWallet2`[^16]. This resets the **NFKBT's** security feature and allows the **Holding Wallet** to call the [addBindings](#addbindings-function) function again. New **Key Wallets** can therefore be added and a single point of failure can be prevented. -7. **Anonymous Security:** Frequently, centralized solutions ask for personal information that is stored and subject to prying eyes. Purchasing decentralized hardware solutions are susceptible to the same issues e.g. a shipping address, payment information, or a camera recording during a physical cash pick-up. This may be considered by some as infringing on their privacy and asset anonymity. **NFKBTs** ensure user confidentially as everything can be done remotely under a pseudonym on the blockchain. +7. **Anonymous Security:** Frequently, centralized solutions ask for personal information that is stored and subject to prying eyes. Purchasing decentralized hardware solutions are susceptible to the same issues e.g. a shipping address, payment information, or a camera recording during a physical cash pick-up. This may be considered by some as infringing on their privacy and asset anonymity. **NFKBT's** ensure user confidentially as everything can be done remotely under a pseudonym on the blockchain. -8. **Low-Cost Security:** The cost of using **NFKBTs** security features correlate to on-chain fees, the current _GWEI_ at the given time. As a standalone solution, they are a viable cost-effective security measure feasible to the majority of the population. +8. **Low-Cost Security:** The cost of using **NFKBT's** security features correlate to on-chain fees, the current _GWEI_ at the given time. As a standalone solution, they are a viable cost-effective security measure feasible to the majority of the population. -9. **Environmentally Friendly:** Since the security features are coded into the **NFKBT**, there is no need for centralized servers, shipping, or the production of physical object/s. Thus leading to a minimal carbon footprint by the use of **NFKBTs**, working hand in hand with Ethereum’s change to a _PoS_[^14] network. +9. **Environmentally Friendly:** Since the security features are coded into the **NFKBT**, there is no need for centralized servers, shipping, or the production of physical object/s. Thus leading to a minimal carbon footprint by the use of **NFKBT's**, working hand in hand with Ethereum’s change to a _PoS_[^14] network. -10. **User Experience:** The security feature can be activated by a simple call to the [addBindings](#addbindings-function) function. The user will only need two other wallets, which will act as `_keyWallet1`[^15] and `_keyWallet2`[^16], to gain access to all of the benefits **NFKBTs** offer. The optional security features improve the overall user experience and Ethereum ecosystem by ensuring a safety net for those who decide to use it. Those that do not use the security features are not hindered in any way. This safety net can increase global adoption as people can remain confident in the security of their assets, even in the scenario of a compromised wallet. +10. **User Experience:** The security feature can be activated by a simple call to the [addBindings](#addbindings-function) function. The user will only need two other wallets, which will act as `_keyWallet1`[^15] and `_keyWallet2`[^16], to gain access to all of the benefits **NFKBT's** offer. The optional security features improve the overall user experience and Ethereum ecosystem by ensuring a safety net for those who decide to use it. Those that do not use the security features are not hindered in any way. This safety net can increase global adoption as people can remain confident in the security of their assets, even in the scenario of a compromised wallet. ## Specification @@ -425,13 +425,13 @@ function setApprovalForAll(address _operator, bool _approved) public virtual ove ## Rationale -The intent from individual technical decisions made during the development of **NFKBTs** focused on maintaining consistency and backward compatibility with ERC-721s, all the while offering self-custodial security features to the user. It was important that **NFKBTs** inherited all of ERC-721s characteristics to comply with requirements found in dApps which use non-fungible tokens on their platform. In doing so, it allowed for flawless backward compatibility to take place and gave the user the choice to decide if they want their **NFKBTs** to act with **Default Behaviors**[^4]. We wanted to ensure that wide-scale implementation and adoption of **NFKBTs** could take place immediately, without the greater collective needing to adapt and make changes to the already flourishing decentralized ecosystem. +The intent from individual technical decisions made during the development of **NFKBTs** focused on maintaining consistency and backward compatibility with ERC-721s, all the while offering self-custodial security features to the user. It was important that **NFKBT's** inherited all of ERC-721s characteristics to comply with requirements found in dApps which use non-fungible tokens on their platform. In doing so, it allowed for flawless backward compatibility to take place and gave the user the choice to decide if they want their **NFKBTs** to act with **Default Behaviors**[^4]. We wanted to ensure that wide-scale implementation and adoption of **NFKBTs** could take place immediately, without the greater collective needing to adapt and make changes to the already flourishing decentralized ecosystem. For developers and users alike, the [allowTransfer](#allowtransfer-function) and [allowApproval](#allowapproval-function) functions both return bools on success and revert on failures. This decision was done purposefully, to keep consistency with the already familiar ERC-721. Additional technical decisions related to self-custodial security features are broken down and located within the [Security Considerations](#security-considerations) section. ## Backwards Compatibility -**KBTs** are designed to be backward-compatible with existing token standards and wallets. Existing tokens and wallets will continue to function as normal, and will not be affected by the implementation of **NFKBTs**. +**KBT's** are designed to be backward-compatible with existing token standards and wallets. Existing tokens and wallets will continue to function as normal, and will not be affected by the implementation of **NFKBT's**. ## Test Cases @@ -451,27 +451,27 @@ The implementation is located in the [assets](../assets/eip-6809/README.md) dire ## Security Considerations -**NFKBTs** were designed with security in mind every step of the way. Below are some design decisions that were rigorously discussed and thought through during the development process. +**NFKBT's** were designed with security in mind every step of the way. Below are some design decisions that were rigorously discussed and thought through during the development process. -**Key Wallets**[^1]: When calling the [addBindings](#addbindings-function) function for an **NFKBT**, the user must input 2 wallets that will then act as `_keyWallet1`[^15] and `_keyWallet2`[^16]. They are added simultaneously to reduce user fees, minimize the chance of human error and prevent a pitfall scenario. If the user had the ability to add multiple wallets it would not only result in additional fees and avoidable confusion but would enable a potentially disastrous [safeFallback](#safefallback-function) situation to occur. For this reason, all **KBTs** work under a 3-wallet system when security features are activated. +**Key Wallets**[^1]: When calling the [addBindings](#addbindings-function) function for an **NFKBT**, the user must input 2 wallets that will then act as `_keyWallet1`[^15] and `_keyWallet2`[^16]. They are added simultaneously to reduce user fees, minimize the chance of human error and prevent a pitfall scenario. If the user had the ability to add multiple wallets it would not only result in additional fees and avoidable confusion but would enable a potentially disastrous [safeFallback](#safefallback-function) situation to occur. For this reason, all **KBT's** work under a 3-wallet system when security features are activated. -Typically if a wallet is compromised, the non-fungible assets within are at risk. With **NFKBTs** there are two different functions that can be called from a **Key Wallet**[^1] depending on which wallet has been compromised. +Typically if a wallet is compromised, the non-fungible assets within are at risk. With **NFKBT's** there are two different functions that can be called from a **Key Wallet**[^1] depending on which wallet has been compromised. Scenario: **Holding Wallet**[^3] has been compromised, call [safeFallback](#safefallback-function). -[safeFallback](#safefallback-function): This function was created in the event that the owner believes the **Holding Wallet**[^3] has been compromised. It can also be used if the owner losses access to the **Holding Wallet**. In this scenario, the user has the ability to call [safeFallback](#safefallback-function) from one of the **Key Wallets**[^1]. **NFKBTs** are then redirected from the **Holding Wallet** to the other **Key Wallet**. +[safeFallback](#safefallback-function): This function was created in the event that the owner believes the **Holding Wallet**[^3] has been compromised. It can also be used if the owner losses access to the **Holding Wallet**. In this scenario, the user has the ability to call [safeFallback](#safefallback-function) from one of the **Key Wallets**[^1]. **NFKBT's** are then redirected from the **Holding Wallet** to the other **Key Wallet**. -By redirecting the **NFKBTs** it prevents a single point of failure. If an attacker were to call [safeFallback](#safefallback-function) and the **NFKBTs** redirected to the **Key Wallet**[^1] that called the function, they would gain access to all the **NFKBTs**. +By redirecting the **NFKBT's** it prevents a single point of failure. If an attacker were to call [safeFallback](#safefallback-function) and the **NFKBT's** redirected to the **Key Wallet**[^1] that called the function, they would gain access to all the **NFKBT's**. Scenario: **Key Wallet**[^1] has been compromised, call [resetBindings](#resetbindings-function). -[resetBindings](#resetbindings-function): This function was created in the event that the owner believes `_keyWallet1`[^15] or `_keyWallet2`[^16] has been compromised. It can also be used if the owner losses access to one of the **Key Wallets**[^1]. In this instance, the user has the ability to call [resetBindings](#resetbindings-function), removing the bound **Key Wallets** and resetting the security features. The **NFKBTs** will now function as a traditional ERC-721 until [addBindings](#addbindings-function) is called again and a new set of **Key Wallets** are added. +[resetBindings](#resetbindings-function): This function was created in the event that the owner believes `_keyWallet1`[^15] or `_keyWallet2`[^16] has been compromised. It can also be used if the owner losses access to one of the **Key Wallets**[^1]. In this instance, the user has the ability to call [resetBindings](#resetbindings-function), removing the bound **Key Wallets** and resetting the security features. The **NFKBT's** will now function as a traditional ERC-721 until [addBindings](#addbindings-function) is called again and a new set of **Key Wallets** are added. -The reason why `_keyWallet1`[^15] or `_keyWallet2`[^16] are required to call the [resetBindings](#resetbindings-function) function is because a **Holding Wallet**[^3] having the ability to call [resetBindings](#resetbindings-function) could result in an immediate loss of **NFKBTs**. The attacker would only need to gain access to the **Holding Wallet** and call [resetBindings](#resetbindings-function). +The reason why `_keyWallet1`[^15] or `_keyWallet2`[^16] are required to call the [resetBindings](#resetbindings-function) function is because a **Holding Wallet**[^3] having the ability to call [resetBindings](#resetbindings-function) could result in an immediate loss of **NFKBT's**. The attacker would only need to gain access to the **Holding Wallet** and call [resetBindings](#resetbindings-function). -In the scenario that 2 of the 3 wallets have been compromised, there is nothing the owner of the **NFKBTs** can do if the attack is malicious. However, by allowing 1 wallet to be compromised, holders of non-fungible tokens built using the **NFKBT** standard are given a second chance, unlike other current standards. +In the scenario that 2 of the 3 wallets have been compromised, there is nothing the owner of the **NFKBT's** can do if the attack is malicious. However, by allowing 1 wallet to be compromised, holders of non-fungible tokens built using the **NFKBT** standard are given a second chance, unlike other current standards. -The [allowTransfer](#allowtransfer-function) function is in place to guarantee a **Safe Transfer**[^2], but can also have **Default Values**[^7] set by a dApp to emulate **Default Behaviors**[^3] of a traditional ERC-721. It enables the user to highly specify the type of transfer they are about to conduct, whilst simultaneously allowing the user to unlock all the **NFKBTs** to anyone for an unlimited amount of time. The desired security is completely up to the user. +The [allowTransfer](#allowtransfer-function) function is in place to guarantee a **Safe Transfer**[^2], but can also have **Default Values**[^7] set by a dApp to emulate **Default Behaviors**[^3] of a traditional ERC-721. It enables the user to highly specify the type of transfer they are about to conduct, whilst simultaneously allowing the user to unlock all the **NFKBT's** to anyone for an unlimited amount of time. The desired security is completely up to the user. This function requires 4 parameters to be filled and different combinations of these result in different levels of security; @@ -485,7 +485,7 @@ Parameter 4 `_anyToken`[^11]: This is a boolean value. When false, the `transfer The [allowTransfer](#allowtransfer-function) function requires `_keyWallet1`[^15] or `_keyWallet2`[^16] and enables the **Holding Wallet**[^3] to conduct a `transferFrom` within the previously specified parameters. These parameters were added in order to provide additional security by limiting the **Holding Wallet** in case it was compromised without the user's knowledge. -The [allowApproval](#allowapproval-function) function provides extra security when allowing on-chain third parties to use your **NFKBTs** on your behalf. This is especially useful when a user is met with common malicious attacks e.g. draining dApp. +The [allowApproval](#allowapproval-function) function provides extra security when allowing on-chain third parties to use your **NFKBT's** on your behalf. This is especially useful when a user is met with common malicious attacks e.g. draining dApp. This function requires 2 parameters to be filled and different combinations of these result in different levels of security; @@ -500,8 +500,8 @@ The [allowApproval](#allowapproval-function) function requires `_keyWallet1`[^15 Copyright and related rights waived via [CC0](../LICENSE.md). [^1]: The **Key Wallet/s** refers to `_keyWallet1` or `_keyWallet2` which can call the `safeFallback`, `resetBindings`, `allowTransfer` and `allowApproval` functions. -[^2]: A **Safe Transfer** is when 1 of the **Key Wallets** safely approved the use of the **NFKBTs**. -[^3]: The **Holding Wallet** refers to the wallet containing the **NFKBTs**. +[^2]: A **Safe Transfer** is when 1 of the **Key Wallets** safely approved the use of the **NFKBT's**. +[^3]: The **Holding Wallet** refers to the wallet containing the **NFKBT's**. [^4]: A **Default Behavior/s** refers to behavior/s present in the preexisting non-fungible ERC-721 standard. [^5]: The number of crypto scam reports the United States Federal Trade Commission received, from January 2021 through March 2022. [^6]: The amount stolen via crypto scams according to the United States Federal Trade Commission, from January 2021 through March 2022. diff --git a/EIPS/eip-6823.md b/EIPS/eip-6823.md new file mode 100644 index 0000000000000..2d01a52fec326 --- /dev/null +++ b/EIPS/eip-6823.md @@ -0,0 +1,115 @@ +--- +eip: 6823 +title: Token Mapping Slot Retrieval Extension +description: Approach to enhance precision of off-chain transaction simulations by accessing mapping storage slot in ERC-20/721/1155 contracts. +author: qdqd (@qd-qd) +discussions-to: https://ethereum-magicians.org/t/eip-6823-token-mapping-slot-retrieval-extension/13666 +status: Draft +type: Standards Track +category: ERC +created: 2023-03-29 +requires: 20, 721, 1155 +--- + +## Abstract + +The aim of this proposal is to enhance the precision of off-chain simulations for transactions that involve contracts complying with the [ERC-20](./eip-20.md), [ERC-721](./eip-721.md), or [ERC-1155](./eip-1155.md) standards. To achieve this, a method is proposed for obtaining the reserved storage slot of the mapping responsible to track ownership of compliant tokens. The proposed extension offers a standardized entry point that allows for identifying the reserved storage slot of a mapping in a compatible manner. This not only facilitates capturing state changes more precisely but also enables external tools and services to do so without requiring expertise in the particular implementation details. + +## Motivation + +To understand the rationale behind this proposal, it's important to remember how values and mapping are stored in the storage layout. This procedure is language-agnostic; it can be applied to multiple programming languages beyond Solidity, including Vyper. + +The storage layout is a way to persistently store data in Ethereum smart contracts. In the EVM, storage is organized as a key-value store, where each key is a 32-byte location, and each value is a 32-byte word. When you define a state variable in a contract, it is assigned to a storage location. The location is determined by the variable's position in the contract's storage structure. The first variable in the contract is assigned to location 0, the second to location 1, and so on. Multiple values less than 32 bytes can be grouped to fit in a single slot if possible. + +Due to their indeterminate size, mappings utilize a specialized storage arrangement. Instead of storing mappings "in between" state variables, they are allocated to occupy 32 bytes only, and their elements are stored in a distinct storage slot computed through a keccak-256 hash. The location of the value corresponding to a mapping key `k` is determined by concatenating `h(k)` and `p` and performing a keccak-256 hash. The value of `p` is the position of the mapping in the storage layout, which depends on the order and the nature of the variables initialized before the mapping. It can't be determined in a universal way as you have to know how the implementation of the contract is done. + +Due to the nature of the mapping type, it is challenging to simulate transactions that involve smart contracts because the storage layout for different contracts is unique to their specific implementation, etched by their variable requirements and the order of their declaration. Since the storage location of a value in a mapping variable depends on this implementation-sensitive storage slot, we cannot guarantee similarity on the off-chain simulation version that an on-chain attempted interaction will result in. + +This hurdle prevents external platforms and tools from capturing/validating changes made to the contract's state with certainty. + +That's why transaction simulation relies heavily on events. However, this approach has limitations, and events should only be informative and not relied upon as the single source of truth. The state is and must be the only source of truth. Furthermore, it is impossible to know the shape of the storage deterministically and universally, which prevents us from verifying the source of truth that is storage, forcing us to rely on information emitted from the application layer. + +## Specification + +The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. + +The proposal suggests an extension to the ERC-20/ERC-721/ERC-1155 standards that allows retrieving the reserved storage slot for the mapping type in any compliant smart-contract implementation in a deterministic manner. This method eliminates the reliance on events and enhances the precision of the data access from storage. The proposed extension therefore enables accurate off-chain simulations. The outcome is greater transparency and predictability at no extra cost for the caller, and a negigleable increase in the deployment cost of the contract. + +The proposed extension is a single function that returns the reserved storage slot for the mapping type in any ERC-20/ERC-721/ERC-1155 compliant smart-contract implementation. The function is named `getTokenLocationRoot` and is declared as follows: + +```solidity +abstract contract ERC20Extension is ERC20 { + function getTokenLocationRoot() external pure virtual returns (bytes32 slot) { + assembly { + slot := .slot + } + } +} + +abstract contract ERC721Extension is ERC721 { + function getTokenLocationRoot() external pure virtual returns (bytes32 slot) { + assembly { + slot := .slot + } + } +} + +abstract contract ERC1155Extension is ERC1155 { + function getTokenLocationRoot() external pure virtual returns (bytes32 slot) { + assembly { + slot := .slot + } + } +} +``` + +For these contracts, off-chain callers can use the `getTokenLocationRoot()` function to find the reserved storage slot for the mapping type. This function returns the reserved storage slot for the mapping type in the contract. This location is used to calculate where all the values of the mapping will be stored. Knowing this value makes it possible to determine precisely where each value of the mapping will be stored, regardless of the contract's implementation. The caller can use this slot to calculate the storage slot for a specific token ID and compare the value to the expected one to verify the action stated by the event. In the case of a ERC-721 mint, the caller can compare the value of the storage slot to the address of the token's owner. In the case of a ERC-20 transfer, the caller can compare the value of the storage slot to the address of the token's new owner. In the case of a ERC-1155 burn, the caller can compare the value of the storage slot to the zero address. The off-chain comparison can be performed with any of the many tools available. In addition, it could perhaps allow storage to be proven atomically by not proving the entire state but only a location -- to track ownership of a specific token, for example. + +The name of the function is intentionally generic to allow the same implementation for all the different token standards. Once implemented universally, the selector derived from the signature of this function will be a single, universal entry point that can be used to directly read the slots in the storage responsible of the ownership, of any token contract. This will make off-chain simulations significantly more accurate, and the events will be used for informational purposes only. + +Contract implementers MUST implement the `getTokenLocationRoot()` function in their contracts. The function MUST return the reserved storage slot for the mapping type in the contract. The function SHOULD be declared as `external pure`. + +## Rationale + +The idea behind the implementation was to find an elegant and concise way that avoided any breaking changes with the current standard. Moreover, since gas consumption is crucial, it was inconceivable to find an implementation that would cost gas to the final user. In this case, the addition of a function increases the deployment cost of the contract in a minimal way, but its use is totally free for the external actors. + +The implementation is minimalist in order to be as flexible as possible while being directly compatible with the main programming languages used today to develop smart-contracts for the EVM. + +## Backwards Compatibility + +No backward compatibility issues have been found. + +## Reference Implementation + +```solidity +abstract contract ERC20Extension is ERC20 { + function getTokenLocationRoot() external pure virtual returns (bytes32 slot) { + assembly { + slot := .slot + } + } +} + +abstract contract ERC721Extension is ERC721 { + function getTokenLocationRoot() external pure virtual returns (bytes32 slot) { + assembly { + slot := .slot + } + } +} + +abstract contract ERC1155Extension is ERC1155 { + function getTokenLocationRoot() external pure virtual returns (bytes32 slot) { + assembly { + slot := .slot + } + } +``` + +## Security Considerations + +No security issues are raised by the implementation of this extension. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-6865.md b/EIPS/eip-6865.md new file mode 100644 index 0000000000000..0bf78ab6806b7 --- /dev/null +++ b/EIPS/eip-6865.md @@ -0,0 +1,155 @@ +--- +eip: 6865 +title: On-Chain EIP-712 Visualization +description: Visualize structured data highlighting the potential consequences for users' assets +author: Abderrahmen Hanafi (@a6-dou) +discussions-to: https://ethereum-magicians.org/t/eip-6865-on-chain-eip-712-visualization/13800 +status: Draft +type: Standards Track +category: ERC +created: 2023-04-10 +requires: 712 +--- + +## Abstract + +Numerous protocols employ distinct [EIP-712](./eip-712.md) schemas, leading to unavoidable inconsistencies across the ecosystem. To address this issue, we propose a standardized approach for dApps to implement an on-chain view function called `visualizeEIP712Message`. This function takes an abi encoded EIP-712 payload message as input and returns a universally agreed-upon structured data format that emphasizes the potential impact on users' assets. Wallets can then display this structured data in a user-friendly manner, ensuring a consistent experience for end-users when interacting with various dApps and protocols. + +## Motivation + +The rapid expansion of the web3.0 ecosystem has unlocked numerous opportunities and innovations. However, this growth has also heightened users' vulnerability to security threats, such as phishing scams. Ensuring that users have a comprehensive understanding of the transactions they sign is crucial for mitigating these risks. + +In an attempt to address this issue, we developed an in-house, open-source off-chain SDK for wallets to visualize various protocols. However, we encountered several challenges along the way: + +- Scalability: Identifying and understanding all protocols that utilize EIP-712 and their respective business logic is a daunting task, particularly with limited resources. Crafting an off-chain solution for all these protocols is nearly impossible. +- Reliability: Grasping each protocol's business logic is difficult and may lead to misunderstandings of the actual implementation. This can result in inaccurate visualizations, which could be more detrimental than providing no visualization at all. +- Maintainability: Offering support for protocols with an off-chain solution is insufficient in a rapidly evolving ecosystem. Protocols frequently upgrade their implementations by extending features or fixing bugs, further complicating the maintenance process. + +To overcome these challenges, we propose a standardized, on-chain solution that can accommodate the diverse and ever-changing web3.0 ecosystem. This approach would enhance scalability, reliability, and maintainability by shifting the responsibility of visualizing EIP-712 payloads from the wallets to the protocols themselves. Consequently, wallets can use a consistent and effective approach to EIP-712 message visualization. + +The adoption of a universal solution will not only streamline the efforts and reduce the maintenance burden for wallet providers, but it will also allow for faster and more extensive coverage across the ecosystem. This will ultimately result in users gaining a clearer understanding of the transactions they're signing, leading to increased security and an improved overall user experience within the crypto space. + +Currently, most of the wallets display something similar to image below + +![](../assets/eip-6865/current-EIP-712-signature-wallet-interface.png) + +With visualization we can achieve something similar to image below where more insightful details are revealed to user thanks to the structured data returned from the EIP + +![](../assets/eip-6865/vision-EIP-712-signature-wallet-interface.png) + +## Specification + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. + +Contracts implementing this proposal MUST include the `visualizeEIP712Message` function in the `verifyingContract` implementation so that wallets upon receiving a request to sign an EIP-712 message(`eth_signTypedData`) MAY call the function `visualizeEIP712Message` at the smart contract and chain specified in the EIP-712 message domain separator `verifyingContract` and `chainId` fields, respectively. + +Wallets SHOULD ignore this proposal if the domain separator does not include the `verifyingContract` and `chainId` fields. + +```solidity +/** +* @notice This function processes an EIP-712 payload message and returns a structured data format emphasizing the potential impact on users' assets. +* @dev The function returns assetsOut (assets the user is offering), assetsIn (assets the user would receive), and liveness (validity duration of the EIP-712 message). +* @param encodedMessage The ABI-encoded EIP-712 message (abi.encode(types, params)). +* @param domainHash The hash of the EIP-712 domain separator as defined in the EIP-712 proposal; see https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator. +* @return Result struct containing the user's assets impact and message liveness. +*/ +function visualizeEIP712Message( + bytes memory encodedMessage, + bytes32 domainHash +) external view returns (Result memory); +``` + +### Params + +`encodedMessage` is bytes that represents the encoded EIP-712 message with `abi.encode` and it can be decoded using `abi.decode` + +`domainHash` is the bytes32 hash of the EIP-712 domain separator as defined in the EIP-712 proposal + +### Outputs + +The function MUST return `Result`, a struct that contains information's about user’s assets impact and the liveness of such a message if it gets signed. + +```solidity +struct Liveness { + uint256 from; + uint256 to; +} + +struct UserAssetMovement { + address assetTokenAddress; + uint256 id; + uint256[] amounts; +} + +struct Result { + UserAssetMovement[] assetsIn; + UserAssetMovement[] assetsOut; + Liveness liveness; +} +``` + +#### `Liveness` + +`Liveness` is a struct that defines the timestamps which the message is valid where: + +- `from` is the starting timestamp. +- `to` is the expiry timestamp +- `from` MUST be less than `to` + +#### `UserAssetMovement` + +`UserAssetMovement` defines the user’s asset where: + +- `assetTokenAddress` is the token ([ERC-20](./eip-20.md), [ERC-721](./eip-721.md), [ERC-1155](./eip-1155.md)) smart contract address where the zero address MUST represents the Native coin (Native ETH in the case of Ethereum network). +- `id` is the NFT ID, this item MUST ignored if the asset is not an NFT + - if token with `id` doesn’t exist in an NFT collection, this SHOULD be considered as any token within that collection +- `amounts` is an Array of `uint256` where items MUST define the amount per time curve, with time defined within liveness boundaries + - the first amount in `amounts` Array (amounts[0]) MUST be the amount of the asset at `liveness.from` timestamp + - the last amount in `amounts` Array (amounts[amounts.length-1]) MUST be the amount of the asset at `liveness.to` timestamp + - in most of the cases, `amounts` will be an Array with a single item which is MUST be the minimum amount of the asset. + +#### `assetsIn` + +`assetsIn` are the minimum assets which the user MUST get if the message is signed and fulfilled + +#### `assetsOut` + +`assetsOut` are the maximum assets which the user MUST offer if the message is signed and fulfilled + +## Rationale + +### on-chain + +One might argue that certain processes can be done off-chain, which is true, but our experience building an off-chain TypeScript SDK to solve this matter revealed some issues: + +- Reliability: Protocols developers are the ones responsible for developing the protocol itself, thus crafting the visualization is much more accurate when done by them. +- Scalability: Keeping up with the rapidly expanding ecosystem is hard. Wallets or 3rd party entities must keep an eye on each new protocol, understand it carefully (which poses the reliability issues mentioned above), and then only come up with an off-chain implementation. +- Maintainability: Many protocols implement smart contracts in an upgradable manner. This causes the off-chain visualization to differ from the real protocol behaviors (if updated), making the solution itself unreliable and lacking the scalability to handle various protocols. + +### `DomainHash` + +The `domainHash` is much needed by protocols to revert against unsupported versions of its EIP-712 implementation. It identifies the needed implementation in case the protocol implements various EIP-712 implementations (`name`) or to revert if the `domainHash` belongs to a different protocol. + +In the future, if there is a registry that reroutes this EIP implementation for already deployed protocols that can't upgrade the existing deployed smart contract, `domainHash` can be used to identify protocols. + +### Amounts Array + +We suggest using an array of amounts (uint256[]) instead of a single uint256 to cover auctions, which are common in NFT protocols. + +## Backwards Compatibility + +No backward compatibility issues found. + +## Reference Implementation + +openSea Seaport NFT marketplace implementation example is available [here](../assets/eip-6865/contracts/SeaPortEIP712Visualizer.sol) + +## Security Considerations + +`visualizeEIP712Message` function should be reliable and accurately represent the potential impact of the EIP-712 message on users' assets. Wallet providers and users must trust the protocol's implementation of this function to provide accurate and up-to-date information. + +`visualizeEIP712Message` function results should be treated based on the reputation of its `verifyingContract`, if the `verifyingContract` is trusted it means the `visualizeEIP712Message` function results are trusted as the this proposal implementation lives at the same address of `verifyingContract`. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-6900.md b/EIPS/eip-6900.md index 3d6dfa2066498..37dd66eef8fe0 100644 --- a/EIPS/eip-6900.md +++ b/EIPS/eip-6900.md @@ -1,7 +1,7 @@ --- eip: 6900 title: Modular Smart Contract Accounts and Plugins -description: Interfaces for composable account plugins optionally supporting upgradability and introspection +description: Interfaces for composable contract accounts optionally supporting upgradability and introspection author: Adam Egyed (@adamegyed), Fangting Liu (@trinity-0111) discussions-to: https://ethereum-magicians.org/t/eip-modular-smart-contract-accounts-and-plugins/13885 status: Draft @@ -13,25 +13,27 @@ requires: 4337 ## Abstract -This proposal standardizes smart contract accounts and account plugins, which are smart contract interfaces that allow for composable logic within smart contract accounts. This proposal is compliant with [ERC-4337](./eip-4337.md), and builds on the existing work from [ERC-2535](./eip-2535.md) when defining interfaces for updating and querying modular function implementations. +This proposal standardizes smart contract accounts and account plugins, which are smart contract interfaces that allow for composable logic within smart contract accounts. This proposal is compliant with [ERC-4337](./eip-4337.md), and takes inspiration from [ERC-2535](./eip-2535.md) when defining interfaces for updating and querying modular function implementations. -This modular approach splits account functionality into three categories, delegates them to external contracts, and defines an expected execution flow from accounts. +This modular approach splits account functionality into three categories, implements them in external contracts, and defines an expected execution flow from accounts. ## Motivation -One of the goals that ERC-4337 accomplishes is abstracting the logic for execution and validation to each smart contract wallet. +One of the goals that ERC-4337 accomplishes is abstracting the logic for execution and validation to each smart contract account. -Many new features of wallets can be built by customizing the logic that goes into the validation and execution steps. Examples of such features include session keys, subscriptions, spending limits, and role-based access control. Currently, some of these features are implemented natively by specific smart contract accounts, and others are able to be implemented by plugin systems. Examples of proprietary plugin systems include Safe modules and ZeroDev plugins. +Many new features of accounts can be built by customizing the logic that goes into the validation and execution steps. Examples of such features include session keys, subscriptions, spending limits, and role-based access control. Currently, some of these features are implemented natively by specific smart contract accounts, and others are able to be implemented by plugin systems. Examples of proprietary plugin systems include Safe modules and ZeroDev plugins. -However, managing multiple wallet instances provides a worse user experience, fragmenting accounts across supported features and security configurations. Additionally, it requires plugin developers to choose which platforms to support, causing either platform lock-in or duplicated development effort. +However, managing multiple account instances provides a worse user experience, fragmenting accounts across supported features and security configurations. Additionally, it requires plugin developers to choose which platforms to support, causing either platform lock-in or duplicated development effort. -We propose a standard that coordinates the implementation work between plugin developers and wallet developers. This standard defines a modular smart contract account capable of supporting all standard-conformant plugins. This allows users to have greater portability of their data, and for plugin developers to not have to choose specific wallet implementations to support. +We propose a standard that coordinates the implementation work between plugin developers and wallet developers. This standard defines a modular smart contract account capable of supporting all standard-conformant plugins. This allows users to have greater portability of their data, and for plugin developers to not have to choose specific account implementations to support. -![diagram showing relationship between accounts and plugins of each type](../assets/eip-modular-smart-contract-accounts-and-plugins/MSCA_Shared_Components_Diagram.svg) +![diagram showing relationship between accounts and plugins of each type](../assets/eip-6900/MSCA_Shared_Components_Diagram.svg) -We take inspiration from ERC-2535’s diamond pattern and adopt a similar composability by proposing three types of plugins. However, you are not required to implement the account with a multi-facet proxy pattern. These plugins contain execution logic. They also incorporate validation schemes and hooks. Validation schemes define the circumstances under which the smart contract account will approve actions taken on its behalf, while hooks allow for pre- and post-execution controls. Accounts adopting this ERC will support modular, upgradable execution and validation logic. +We take inspiration from ERC-2535’s diamond pattern for routing execution based on function selectors, and create a similarly composable account. However, the standard does not require the multi-facet proxy pattern. -Defining this as a standard for smart contract accounts will make plugins easier to develop securely and will allow for greater interoperability. +These plugins can contain execution logic, validation schemes, and hooks. Validation schemes define the circumstances under which the smart contract account will approve actions taken on its behalf, while hooks allow for pre- and post-execution controls. + +Accounts adopting this standard will support modular, upgradable execution and validation logic. Defining this as a standard for smart contract accounts will make plugins easier to develop securely and will allow for greater interoperability. Goals: @@ -50,44 +52,44 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S - **Execution functions** execute any custom logic allowed by the account. - **Hooks** execute custom logic and checks before and/or after an execution function. - A **validation function** is a function that validates authentication and authorization of a caller to the account. There are two types of validation functions: - - **User Operation Validator** functions handle calls to `validateUserOp` and check the validity of an ERC-4337 user operation. The function may have any function name, but MUST take in the parameters `(UserOperation calldata, bytes32, uint256)`, representing the user operation, user operation hash, and required prefund. It MUST return `(uint256)`, representing packed validation data for `authorizer`, `validUntil`, and `validAfter`. - - **Runtime Validator** functions run before an execution function, and enforce checks. Common checks include enforcing only calls from `EntryPoint` or an owner. -- An **execution function** is a smart contract function that defines the execution of a function for a **modular account**. -- A **hook** is a smart contract function executed before or after an **execution function**, with the ability to modify state or cause the entire call to revert. There are two types of **hooks**. - - **preHook** functions run before an **execution function;**. They map optionally return data to be consumed the **postHook**. - - **postHook** functions run after an **execution function**. They can optionally take returned data from **preHook**. + - **User Operation Validator** functions handle calls to `validateUserOp` and check the validity of an ERC-4337 user operation. The function may have any function name, and MUST take in the parameters `(UserOperation calldata, bytes32)`, representing the user operation and user operation hash. It MUST return `(uint256)`, representing packed validation data for `authorizer`, `validUntil`, and `validAfter`. + - **Runtime Validator** functions run before an execution function when not called via a user operation, and enforce checks. Common checks include allowing execution only by an owner. +- An **execution function** is a smart contract function that defines the main execution step of a function for a **modular account**. +- The **standard execute functions** are two specific execution functions that are implemented natively by the modular account, and not on a plugin. These allow for open-ended execution. +- A **hook** is a smart contract function executed before or after another function, with the ability to modify state or cause the entire call to revert. There are four types of **hooks**. + - **Pre User Operation Validation Hook** functions run before user operation validators. These can enforce permissions on what actions a validator may perform via user operations. + - **Pre Runtime Validation Hook** functions run before runtime validators. These can enforce permissions on what actions a validator may perform via direct calls. + - **Pre Execution Hook** functions run before an **execution function**. They may optionally return data to be consumed the **postHook**. + - **Post Execution Hook** functions run after an **execution function**. They may optionally take returned data from **preHook**. - **Associated function** refers to either a validation function or a hook. - A **plugin** is a deployed smart contract that hosts any amount of the above three kinds of modular functions: execution functions, validation functions, or hooks. ### Overview -A smart contract account handles two kinds of calls: one from `Entrypoint` through ERC-4337, the other are direct calls from EOA and other smart contracts. The proposal supports both use cases. +A modular account handles two kinds of calls: either from the `Entrypoint` through ERC-4337, or through direct calls from externally owned accounts (EOAs) and other smart contracts. This standard supports both use cases. -A call to the smart contract account can be decomposed into 4 steps as shown in the diagram below. The validation step (Step 1) validates if the caller is allowed to call. The pre execution hook step (Step 2) can be used to do any pre execution checks or updates. It can also be used with the post execution hook step (Step 4) to perform certain verifications. The execution step (Step 3) performs a performs a call-defined task or collection of tasks. +A call to the smart contract account can be decomposed into 5 steps as shown in the diagram below. The validation steps (Steps 1 and 2) validate if the caller is allowed to call. The pre execution hook step (Step 3) can be used to do any pre execution checks or updates. It can also be used with the post execution hook step (Step 5) to perform additional actions or verification. The execution step (Step 4) performs a defined task or collection of tasks. -![diagram showing execution flow within an account](../assets/eip-modular-smart-contract-accounts-and-plugins/MSCA_Two_Call_Paths_Diagram.svg) +![diagram showing execution flow within an account](../assets/eip-6900/MSCA_Two_Call_Paths_Diagram.svg) -Each step is modularized and can have different combinations and infinite functionalities. **The smart contract account SHOULD orchestrate the above 4 steps.** For example, a MSCA has a fallback functions that orchestrate the above 4 steps for the account. +Each step is modular, supporting different implementations for each execution function, and composable, supporting multiple steps through hooks. Combined, these allow for open-ended programmable accounts. ### Interfaces Modular Smart Contract Accounts MUST implement the `IAccount` interface from [ERC-4337](./eip-4337.md). -#### `IModularAccount.sol` +#### Common types -Modular Smart Contract Accounts MAY implement `IModularAccount` to support view functions without the need to add view functions selectors into storage through updatePlugins. +The following types are used by both of the following interfaces. Implementors MAY use the elementary value type instead of the type alias. ```solidity -interface IModularAccount { - /** - * view function calls to the account - * @param implAddress the address of the implmentation contract - * @param data params to pass to the view function - */ - function viewCall(address implAddress, bytes calldata data) external returns (bytes memory); -} +type FunctionReference is bytes24; + +type HookGroupId is uint32; ``` +Variables of the type `FunctionReference` MUST be interpreted as an address in the first 20 bytes and a function selector in the remaining 4 bytes. + #### `IPluginUpdate.sol` Plugin modification interface. Modular Smart Contract Accounts MAY implement this interface to support updates to plugins. @@ -100,103 +102,114 @@ interface IPluginUpdate { REMOVE } - enum AssociatedFunctionType { + enum ValidatorType { USER_OP_VALIDATOR, - RUNTIME_VALIDATOR, - PRE_HOOK, - POST_HOOK + RUNTIME_VALIDATOR } - struct PluginUpdate { - address executionPluginAddress; + enum HookType { + PRE_EXEC_HOOK, + POST_EXEC_HOOK, + PRE_USER_OP_VALIDATION_HOOK, + PRE_RUNTIME_VALIDATION_HOOK + } + + struct ExecutionUpdate { PluginAction action; - ExecutionUpdate[] executionUpdates; + address pluginAddress; + bytes4[] executionSelectors; + ValidatorUpdate[] validatorUpdates; } - struct GlobalPluginUpdate { + struct ValidatorUpdate { PluginAction action; - AssociatedFunction globalPlugin; + ValidatorType validatorType; + FunctionReference functionReference; } - struct ExecutionUpdate { - bytes4 executionSelector; - AssociatedFunction[] associatedFunctions; + struct HookGroupUpdate { + PluginAction action; + HookGroupId hookGroupId; + bytes4[] executionSelectors; } - struct AssociatedFunction { - AssociatedFunctionType functionType; - address implAddress; - bytes4 implSelector; + struct HookUpdate { + PluginAction action; + HookGroupId hookGroupId; + HookType hookType; + FunctionReference functionReference; } - event PluginsUpdated(PluginUpdate[] pluginUpdates, address init, bytes callData); - - event GlobalPluginsUpdated(AssociatedFunction[] globalPluginUpdates, address init, bytes callData); - - /** - * @notice Add/replace/remove any number of plugins and optionally execute a function - * @param pluginUpdates Contains the plugin addresses and function selectors. - * executionPluginAddress specifies the plugin containing the execution functions defined within - * pluginAction denotes what operation to perform - * executionUpdates denote which execution function and associated function to perform the opeartion on. - * @param init The address of the contract or facet to execute calldata - * @param callData A function call, including function selector and arguments - */ - function updatePlugins(PluginUpdate[] memory pluginUpdates, address init, bytes calldata callData) external; - - /** - * @notice Add/replace/remove any number of global plugins and optionally execute a function - * @param globalPluginUpdates Contains the plugin addresses and function selectors. - * @param init The address of the contract or facet to execute calldata - * @param callData A function call, including function selector and arguments - */ - function updateGlobalPlugins(GlobalPluginUpdate[] memory globalPluginUpdates, address init, bytes calldata callData) - external; + event ExecutionPluginUpdate(ExecutionUpdate[] executionUpdates); + + function updatePlugins( + ExecutionUpdate[] calldata executionUpdates, + HookUpdate[] calldata hookUpdates, + HookGroupUpdate[] calldata hookGroupUpdates, + address init, + bytes calldata callData + ) external; } ``` #### `IPluginLoupe.sol` -Plugin inspection interface. Modular Smart Contract Accounts MAY implement this interface to support visibility in plugin configuration on-chain. Note this will require extra storage. +Plugin inspection interface. Modular Smart Contract Accounts MAY implement this interface to support visibility in plugin configuration on-chain. ```solidity interface IPluginLoupe { - struct PluginInfo { + struct ExecutionPluginConfig { address executionPluginAddress; - FunctionConfig[] configs; - } - - struct FunctionConfig { - bytes4 executionSelector; + HookGroupId[] hookGroupIds; + HookGroup[] hookGroups; FunctionReference userOpValidator; FunctionReference runtimeValidator; - FunctionReference preHook; - FunctionReference postHook; } - struct FunctionReference { - address implAddress; - bytes4 implSelector; + struct HookGroup { + FunctionReference preUserOpValidation; + FunctionReference preRuntimeValidation; + FunctionReference preExec; + FunctionReference postExec; } - function getPlugins() external view returns (PluginInfo[] memory); + function getExecutionFunctionConfig(bytes4 executionSelector) + external + view + returns (ExecutionPluginConfig memory); - function getPlugin(address executionPluginAddress) external view returns (FunctionConfig[] memory functions); - - function getFunctionConfig(bytes4 executionSelector) external view returns (FunctionConfig memory); + function getStandardExecutionValidators() + external + view + returns (FunctionReference[] memory userOpValidators, FunctionReference[] memory runtimeValidators); } ``` -#### `IPlugin.sol` +#### `IStandardExecutor.sol` -Plugin interface. Plugins MUST implement the following interface. +Standard execution interface. Modular Smart Contract Accounts MUST implement this interface to support open-ended execution. ```solidity -interface IPlugin { - // Returns the starting storage slot owned by the plugin. - // Storage may extend past this slot, or to other locations - // when used through mappings or dynamically-sized arrays - function pluginStorageRoot() external view returns (bytes32 slot); +interface IStandardExecutor { + + enum ExecutionMode { + CALL, + DELEGATECALL, + STATICCALL + } + + struct Execution { + address target; + uint256 value; + bytes data; + ExecutionMode mode; + } + + function execute(address dest, uint256 value, bytes calldata func, ExecutionMode mode, FunctionReference validator) + external + payable; + + function executeBatch(Execution[] calldata executions, FunctionReference validator) external payable; } ``` @@ -204,99 +217,69 @@ interface IPlugin { #### Calls to `updatePlugins` -The function `updatePlugins` takes in an array of updates to perform, and an optional initialization function. The function MUST perform the update operation sequentially, then, if the address provided in `init` is not `address(0)`, MUST execute `init` with the calldata `callData`. +The function `updatePlugins` takes in arrays of execution updates, hook updates, and hook group updates to perform. It also takes in an optional initialization function. The function MUST perform the update operation sequentially, then, if the address provided in `init` is not `address(0)`, MUST execute `init` with the calldata `callData` through a `delegatecall`. -> **⚠️ The ability to update a plugin is very powerful. The security of the updatePlugins determines the security of the account. It is critical for Account builders to make sure updatePlugins has the proper security consideration and access control in place.** +> **⚠️ The ability to update a plugin is very powerful. The security of the updatePlugins determines the security of the account. It is critical for modular account implementers to make sure updatePlugins has the proper security consideration and access control in place.** #### Calls to `validateUserOp` -When the function `validateUserOp` is called on an MSCA by the `EntryPoint`, it MUST find the user operation validator defined for the selector in `userOp.callData`, which is in the first four bytes. If there is no function defined for the selector, or if `userOp.callData.length < 4`, then execution MUST revert. Otherwise, the MSCA MUST execute the validator function with the user operation, its hash, and the required prefund as parameters. The returned validation data from the user operation validator MUST be returned by `validateUserOp`. +When the function `validateUserOp` is called on modular account by the `EntryPoint`, it MUST find the user operation validator defined for the selector in `userOp.callData`, which is in the first four bytes. If there is no function defined for the selector, or if `userOp.callData.length < 4`, then execution MUST revert. Otherwise, the MSCA MUST execute the validator function with the user operation and its hash as parameters using the `call` opcode. The returned validation data from the user operation validator MUST be returned by `validateUserOp`. + +If the execution selector has associated hook groups with pre user operation validation hooks, then those hooks MUST be run sequentially. If any revert or return false, the outer call MUST revert. + +If the call is to a standard execution function, then the modular account must verify that the provided `validator` in calldata has previously been associated with either of the standard execution functions. If it was previously added, the specified user operation validator MUST be run. #### Calls to execution functions -When a function other than `validateUserOp` is called on an MSCA, it MUST find the plugin configuration for the corresponding selector added via `updatePlugins`. If no corresponding plugin is found, the MSCA MUST revert. Otherwise, the MSCA MUST perform the following steps: +When a function other than a natively defined function is called on an MSCA, it MUST find the plugin configuration for the corresponding selector added via `updatePlugins`. If no corresponding plugin is found, the MSCA MUST revert. Otherwise, the MSCA MUST perform the following steps: -- If a `runtimeValidator` function is defined, execute the function with the execution function’s calldata as parameter. -- If there are global `preHook`s, execute each with the execution function’s calldata. -- If an associated `preHook` is defined, execute the associated function with the execution function’s calldata. If the `preHook` returns data, it MUST be preserved until the call to `postHook`. -- execute the execution function. -- If an associated `postHook` is defined, execute the associated function with the execution function’s calldata. If the `preHook` function returned data, the MSCA MUST pass that data in to `postHook`. -- If there are global `postHook`s, execute each with the execution function’s calldata. +- If the call is not from the `EntryPoint`, then find an associated `runtimeValidator` function. If one does not exist, execution MUST revert. The modular account MUST execute all pre runtime validation hooks, then the runtime validator function, with the `call` opcode. All of these functions MUST receive the caller, value, and execution function’s calldata as parameters. If any of these functions revert, or return a boolean false, execution MUST revert. +- If there are pre execution hooks defined in the associated hook groups of the execution function, execute those hooks with the caller, value, and execution function’s calldata as parameters. If any of thee hooks returns data, it MUST be preserved until the call to the post execution hook. The operation must be done with the `call` opcode. +- Run the execution function. +- If any associated post execution hooks are defined, run the functions. If a pre execution hook in the same hook group returned data to the account, that data MUST be passed as a parameter to the post execution hook. The operation must be done with the `call` opcode. -> **⚠️ If the execution function does not have a definition for either `runtimeValidator`, `preHook`, or `postHook`, the undefined functions will be skipped. The execution function will be executed and it may change account state.** -> -> **💡 If, during the execution of `runtimeValidator`, the caller can be established as the EntryPoint contract, it is guaranteed the associated user operation validator has returned a valid signature. Validation MAY be skipped.** +> **⚠️ If the execution function does not have a definition for either pre runtime validation hooks, pre execution hooks or post execution hooks, the undefined functions will be skipped. The execution function will be run and it may change account state.** #### Plugin update operations When `updatePlugins` is called with `PluginAction.ADD`, the following MUST occur: -- Each `executionSelector` must be added their parent `executionPluginAddress` as a valid implementation contract to forward calls to. -- Each `AssociatedFunction` must be added to their parent execution function in the role specified by `associatedFunctionType`. +- Each execution selector must be added as a valid execution function, with the contract specified in `pluginAddress` as implementation contract to call to. +- Each validator function reference must be added to their parent execution function in the role specified by `validatorType`. +- Each hook update must add the hook type specified by `hookType` to the group specified by `hookGroupId`. If that hook type is already defined, the update MUST revert. +- Each hook group update must add that hook group to the execution selectors specified by `executionSelectors`. Execution function selectors MUST be unique when added. -When `updatePlugins` is called with `PluginAction.REPLACE`, each `executionSelector` MUST override any previous execution definition for said function selector. Any associated function defined MUST override previously defined function selectors. Existing associated functions not specified in this operation MUST NOT be modified. - -When `updatePlugins` is called with `PluginAction.REMOVE`, both execution function definitions and associated function definitions MUST be removed. The contents of the `associatedFunctions` array MUST be ignored. +When `updatePlugins` is called with `PluginAction.REPLACE`, each each execution selector or function reference MUST override any previous definition for said function. Existing associated functions not specified in this operation MUST NOT be modified. -When adding a plugin function of any type, the MSCA MAY call `pluginStorageRoot()` on the plugin. If the returned `bytes32` value has ever been returned by a previously added plugin, the MSCA MAY revert and reject the operation. +When `updatePlugins` is called with `PluginAction.REMOVE`, execution function definitions and associated function definitions MUST be removed. -#### Plugins Storage Management - -Plugins MAY access the storage of other plugins. If a plugin does not have any plugin-specific storage, it MUST return `0` for the method `pluginStorageRoot()`. +#### Plugin Functions -Plugin contracts MUST NOT define or access storage structs growing from slot 0. +Execution functions may have any function signature, but must be unique for the account. When added to an MSCA via `updatePlugins`, the function selector of the execution function will be mapped from the modular account to the plugin. -Plugin storage management is managed by plugin implementations. Here is an example where storage management is done through statically linked Solidity libraries. +User Operation Validation functions may have any function name, and MUST take in the parameters `(UserOperation calldata, bytes32)`, representing the user operation and the user operation hash. The functions MUST return `(uint256)`, representing packed validation data for `authorizer`, `validUntil`, and `validAfter`. -`LibMyPlugin.sol` +Here is an example function signature of a conformant user operation validator function: ```solidity -library LibMyPlugin { - bytes32 constant MY_PLUGIN_POSITION = keccak256("plugin.standard.my.plugin"); - - struct MyPluginStorage { - // Any storage fields you need - } - - // Return my plugin storage struct for reading and writing - function getStorage() internal pure returns (MyPluginStorage storage storageStruct) { - bytes32 position = MY_PLUGIN_POSITION; - assembly { - storageStruct.slot := position - } - } -} +function validateSignature(UserOperation calldata userOp, bytes32 userOpHash) external returns (uint256 validationData); ``` -#### Plugin Functions - -Execution functions may have any function signature, but must be unique for the account. When added to an MSCA via `updatePlugins`, the function selector of the execution function will be mapped from the modular account to the plugin. - -User Operation Validation functions may have any function name, and MUST take in the parameters `(UserOperation calldata, bytes32)`, representing the user operation and the user operation hash. The functions MUST return `(uint256)`, representing packed validation data for `authorizer`, `validUntil`, and `validAfter`. - -> Here is an example function signature of a conformant user operation validator function: -> -> ```solidity -> function validateSignature(UserOperation calldata userOp, bytes32 userOpHash) external returns (uint256 validationData); -> ``` +Runtime Validation Functions may have any function name, and MUST take in the parameters `(address, uint256, bytes calldata)`. -Runtime Validation Functions may have any function name, and MUST take in the parameters `(bytes calldata)`. +Here is an example function signature of a conformant runtime validator function: -> Here is an example function signature of a conformant runtime validator function: -> -> ```solidity -> function validateOwnership(bytes calldata) external; -> ``` +```solidity +function validateOwnership(address caller, uint256 value, bytes calldata) external; +``` Hooks MAY have any function name. -Global hooks MUST be executed for every incoming call. -The global preHook function MUST take in the parameters `(bytes calldata data)`. -The global postHook function MUST take in the parameters `(bytes calldata data)`. -For sets of hooks that are used specifically with execution funtions, they MAY be paired and share information through returned value. -The preHook function MUST take in the parameters `(bytes calldata data)` and return `(bytes calldata preHookReturnedData)`. -The postHook function MUST take in the parameters `(bytes calldata data, bytes calldata preHookReturnedData)`. +The pre user operation validation hook functions MUST take in the parameters `(bytes calldata callData, bytes calldata paymasterAndData)` and return `(bool)`. +The pre runtime validation hook functions MUST take in the parameters `(bytes calldata)` and return `(bool)`. +The pre execution hook functions MUST take in the parameters `(address, uint256, bytes calldata)` and return `(bytes calldata)`. +The post execution hook functions MUST take in the parameters `(bytes calldata)`. ## Rationale diff --git a/EIPS/eip-6909.md b/EIPS/eip-6909.md new file mode 100644 index 0000000000000..b265e4b5b746c --- /dev/null +++ b/EIPS/eip-6909.md @@ -0,0 +1,606 @@ +--- +eip: 6909 +title: Minimal Multi-Token Interface +description: A minimal specification for managing multiple tokens by their id in a single contract. +author: Joshua Trujillo (@jtriley) +discussions-to: https://ethereum-magicians.org/t/eip-6909-multi-token-standard/13891 +status: Draft +type: Standards Track +category: ERC +created: 2023-04-19 +requires: 165 +--- + +## Abstract + +The following standard specifies a multi-token contract as a simplified alternative to the [ERC-1155](./eip-1155.md) Multi-Token Standard. + +## Motivation + +The ERC-1155 standard includes unnecessary features such as requiring recipient accounts with code to implement callbacks returning specific values and batch-calls in the specification. In addition, the single operator permission scheme grants unlimited allowance on every token ID in the contract. Backwards compatibility is deliberately removed only where necessary. Additional features such as batch calls, increase and decrease allowance methods, and other user experience improvements are deliberately omitted in the specification to minimize the required external interface. + +According to ERC-1155, callbacks are required for each transfer and batch transfer to contract accounts. This requires potentially unnecessary external calls to the recipient when the recipient account is a contract account. While this behavior may be desirable in some cases, there is no option to opt-out of this behavior, as is the case for [ERC-721](./eip-721.md) having both `transferFrom` and `safeTransferFrom`. In addition to runtime performance of the token contract itself, it also impacts the runtime performance and codesize of recipient contract accounts, requiring multiple callback functions and return values to recieve the tokens. + +Batching transfers, while useful, are excluded from this standard to allow for opinionated batch transfer operations on different implementations. For example, a different ABI encoding may provide different benefits in different environments such as calldata size optimization for rollups with calldata storage commitments or runtime performance for environments with expensive gas fees. + +A hybrid allowance-operator permission scheme enables granular yet scalable controls on token approvals. Allowances enable an external account to transfer tokens of a single token ID on a user's behalf w by their ID while operators are granted full transfer permission for all token IDs for the user. + +## Specification + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. + +### Definitions + +- infinite: The maximum value for a uint256 (`2 ** 256 - 1`). +- caller: The caller of the current context (`msg.sender`). +- spender: An account that transfers tokens on behalf of another account. +- operator: An account that has unlimited transfer permissions on all token ids for another account. +- mint: The creation of an amount of tokens. This MAY happen in a mint method or as a transfer from the zero address. +- burn: The removal an amount of tokens. This MAY happen in a burn method or as a transfer to the zero address. + +### Methods + +#### `totalSupply` + +The total `amount` of a token `id` that exists. + +MUST be equal to the sum of the `balanceOf` of all accounts of the token `id`. + +```yaml +- name: totalSupply + type: function + stateMutability: view + + inputs: + - name: id + type: uint256 + + outputs: + - name: amount + type: uint256 +``` + +#### `balanceOf` + +The total `amount` of a token `id` that an `owner` owns. + +```yaml +- name: balanceOf + type: function + stateMutability: view + + inputs: + - name: owner + type: address + - name: id + type: uint256 + + outputs: + - name: amount + type: uint256 +``` + +#### `allowance` + +The total `amount` of a token id that a spender is permitted to transfer on behalf of an owner. + +```yaml +- name: allowance + type: function + stateMutability: view + + inputs: + - name: owner + type: address + - name: spender + type: address + - name: id + type: uint256 + + outputs: + - name: amount + type: uint256 +``` + +#### `isOperator` + +Returns `true` if the `spender` is approved as an operator for an `owner`. + +```yaml +- name: isOperator + type: function + stateMutability: view + + inputs: + - name: owner + type: address + - name: spender + type: address + + outputs: + - name: status + type: bool +``` + +#### `transfer` + +Transfers an `amount` of a token `id` from the caller to the `receiver`. + +MUST revert when the caller's balance for the token `id` is insufficient. + +MUST log the `Transfer` event. + +```yaml +- name: transfer + type: function + stateMutability: nonpayable + + inputs: + - name: receiver + type: address + - name: id + type: uint256 + - name: amount + type: uint256 + + outputs: [] +``` + +#### `transferFrom` + +Transfers an `amount` of a token `id` from a `sender` to a `receiver` by the caller. + +MUST revert when the caller is not an operator for the `sender` and the caller's allowance for the token `id` for the `sender` is insufficient. + +MUST revert when the `sender`'s balance for the token id is insufficient. + +MUST log the `Transfer` event. + +MUST decrease the caller's `allowance` by the same `amount` of the `sender`'s balance decrease if the caller is not an operator for the `sender` and the caller's `allowance` is not infinite. + +SHOULD NOT decrease the caller's `allowance` for the token `id` for the `sender` if the `allowance` is infinite. + +SHOULD NOT decrease the caller's `allowance` for the token `id` for the `sender` if the caller is an operator. + +```yaml +- name: transferFrom + type: function + stateMutability: nonpayable + + inputs: + - name: sender + type: address + - name: receiver + type: address + - name: id + type: uint256 + - name: amount + type: uint256 + + outputs: [] +``` + +#### `approve` + +Approves an `amount` of a token `id` that a `spender` is permitted to transfer on behalf of the caller. + +MUST set the `allowance` of the `spender` of the token `id` for the caller to the `amount`. + +MUST log the `Approval` event. + +```yaml +- name: approve + type: function + stateMutability: nonpayable + + inputs: + - name: spender + type: address + - name: id + type: uint256 + - name: amount + type: uint256 + + outputs: [] +``` + +#### `setOperator` + +Grants or revokes unlimited transfer permissions for a `spender` for any token `id` on behalf of the caller. + +MUST set the operator status to the `approved` value. + +MUST log the `OperatorSet` event. + +```yaml +- name: setOperator + type: function + stateMutability: nonpayable + + inputs: + - name: spender + type: address + - name: approved + type: bool +``` + +### Events + +#### `Transfer` + +The `sender` has transferred an `amount` of a token `id` to a `receiver`. + +MUST be logged when an `amount` of a token `id` is transferred from one account to another. + +SHOULD be logged with the `sender` address as the zero address when an `amount` of a token `id` is minted. + +SHOULD be logged with the `receiver` address as the zero address when an `amount` of a token `id` is burned. + +```yaml +- name: Transfer + type: event + + inputs: + - name: sender + indexed: true + type: address + - name: receiver + indexed: true + type: address + - name: id + indexed: true + type: address + - name: amount + indexed: false + type: address +``` + +#### `OperatorSet` + +The `owner` has set the `approved` status to a `spender`. + +MUST be logged when the operator status is set. + +MAY be logged when the operator status is set to the same status it was before the current call. + +```yaml +- name: OperatorSet + type: event + + inputs: + - name: owner + indexed: true + type: address + - name: spender + indexed: true + type: address + - name: approved + indexed: false + type: bool +``` + +#### `Approval` + +The `owner` has approved a `spender` to transfer an `amount` of a token `id` to be transferred on the owner's behalf. + +MUST be logged when the `allowance` is set by an `owner`. + +```yaml +- name: Approval + type: event + + inputs: + - name: owner + indexed: true + type: address + - name: spender + indexed: true + type: address + - name: id + indexed: true + type: uint256 + - name: amount + indexed: false + type: uint256 +``` + +## Rationale + +### Granular Approvals + +While the "operator model" from the ERC-1155 standard allows an account to set another account as an operator, giving full permissions to transfer any amount of any token id on behalf of the owner, this may not always be the desired permission scheme. The "allowance model" from [ERC-20](./eip-20.md) allows an account to set an explicit amount of the token that another account can spend on the owner's behalf. This standard requires both be implemented, with the only modification being to the "allowance model" where the token id must be specified as well. This allows an account to grant specific approvals to specific token ids, infinite approvals to specific token ids, or infinite approvals to all token ids. If an account is set as an operator, the allowance SHOULD NOT be decreased when tokens are transferred on behalf of the owner. + +### Removal of Batching + +While batching operations is useful, its place should not be in the standard itself, but rather on a case-by-case basis. This allows for different tradeoffs to be made in terms of calldata layout, which may be especially useful for specific applications such as roll-ups that commit calldata to global storage. + +### Removal of Required Callbacks + +Callbacks MAY be used within a multi-token compliant contract, but it is not required. This allows for more gas efficient methods by reducing external calls and additional checks. + +### Removal of "Safe" Naming + +The `safeTransfer` and `safeTransferFrom` naming conventions are misleading, especially in the context of the ERC-1155 and ERC-721 standards, as they require external calls to receiver accounts with code, passing the execution flow to an arbitrary contract, provided the receiver contract returns a specific value. The combination of removing mandatory callbacks and removing the word "safe" from all method names improves the safety of the control flow by default. + +### Interface ID + +The interface ID is `0xb2e69f8a`. + +### Metadata Extension + +#### Methods + +##### name + +The `name` of the contract. + +```yaml +- name: name + type: function + stateMutability: view + + inputs: [] + + outputs: + - name: name + type: string +``` + +##### symbol + +The ticker `symbol` of the contract. + +```yaml +- name: symbol + type: function + stateMutability: view + + inputs: [] + + outputs: + - name: symbol + type: string +``` + +##### decimals + +The `amount` of decimals for a token `id`. + +```yaml +- name: decimals + type: function + stateMutability: view + + inputs: + - name: id + type: uint256 + + outputs: + - name: amount + type: uint8 +``` + +### Metadata URI Extension + +#### Methods + +##### tokenURI + +The `URI` for a token `id`. + +MAY revert if the token `id` does not exist. + +MUST replace occurrences of `{id}` in the returned URI string by the client. + +```yaml +- name: tokenURI + type: function + stateMutability: view + + inputs: + - name: id + type: uint256 + + outputs: + - name: uri + type: string +``` + +#### Metadata Structure + +The metadata specification closely follows that of the ERC-721 JSON schema. + +MUST replace occurrences of `{id}` in the returned URI string by the client. + +```json +{ + "title": "Asset Metadata", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Identifies the token" + }, + "description": { + "type": "string", + "description": "Describes the token" + }, + "image": { + "type": "string", + "description": "A URI pointing to an image resource." + } + } +} +``` + +## Backwards Compatibility + +This is not backwards compatible with ERC-1155 as some methods are removed. However, wrappers can be implemented for the ERC-20, ERC-721, and ERC-1155 standards. + +## Reference Implementation + +```solidity +// SPDX-License-Identifier: CC0-1.0 +pragma solidity 0.8.19; + +/// @title ERC6909 Multi-Token Reference Implementation +/// @author jtriley.eth +contract ERC6909 { + /// @dev Thrown when owner balance for id is insufficient. + /// @param owner The address of the owner. + /// @param id The id of the token. + error InsufficientBalance(address owner, uint256 id); + + /// @dev Thrown when spender allowance for id is insufficient. + /// @param spender The address of the spender. + /// @param id The id of the token. + error InsufficientPermission(address spender, uint256 id); + + /// @notice The event emitted when a transfer occurs. + /// @param sender The address of the sender. + /// @param receiver The address of the receiver. + /// @param id The id of the token. + /// @param amount The amount of the token. + event Transfer(address indexed sender, address indexed receiver, uint256 indexed id, uint256 amount); + + /// @notice The event emitted when an operator is set. + /// @param owner The address of the owner. + /// @param spender The address of the spender. + /// @param approved The approval status. + event OperatorSet(address indexed owner, address indexed spender, bool approved); + + /// @notice The event emitted when an approval occurs. + /// @param owner The address of the owner. + /// @param spender The address of the spender. + /// @param id The id of the token. + /// @param amount The amount of the token. + event Approval(address indexed owner, address indexed spender, uint256 indexed id, uint256 amount); + + /// @notice The total supply of each id. + mapping(uint256 id => uint256 amount) public totalSupply; + + /// @notice Owner balance of an id. + mapping(address owner => mapping(uint256 id => uint256 amount)) public balanceOf; + + /// @notice Spender allowance of an id. + mapping(address owner => mapping(address spender => mapping(uint256 id => uint256 amount))) public allowance; + + /// @notice Checks if a spender is approved by an owner as an operator. + mapping(address owner => mapping(address spender => bool)) public isOperator; + + /// @notice Transfers an amount of an id from the caller to a receiver. + /// @param receiver The address of the receiver. + /// @param id The id of the token. + /// @param amount The amount of the token. + function transfer(address receiver, uint256 id, uint256 amount) public { + if (balanceOf[msg.sender][id] < amount) revert InsufficientBalance(msg.sender, id); + balanceOf[msg.sender][id] -= amount; + balanceOf[receiver][id] += amount; + emit Transfer(msg.sender, receiver, id, amount); + } + + /// @notice Transfers an amount of an id from a sender to a receiver. + /// @param sender The address of the sender. + /// @param receiver The address of the receiver. + /// @param id The id of the token. + /// @param amount The amount of the token. + function transferFrom(address sender, address receiver, uint256 id, uint256 amount) public { + if (sender != msg.sender && !isOperator[sender][msg.sender]) { + if (allowance[sender][msg.sender][id] < amount) { + revert InsufficientPermission(msg.sender, id); + } + allowance[sender][msg.sender][id] -= amount; + } + if (balanceOf[sender][id] < amount) revert InsufficientBalance(sender, id); + balanceOf[sender][id] -= amount; + balanceOf[receiver][id] += amount; + emit Transfer(sender, receiver, id, amount); + } + + /// @notice Approves an amount of an id to a spender. + /// @param spender The address of the spender. + /// @param id The id of the token. + /// @param amount The amount of the token. + function approve(address spender, uint256 id, uint256 amount) public { + allowance[msg.sender][spender][id] = amount; + emit Approval(msg.sender, spender, id, amount); + } + + /// @notice Sets or removes a spender as an operator for the caller. + /// @param spender The address of the spender. + /// @param approved The approval status. + function setOperator(address spender, bool approved) public { + isOperator[msg.sender][spender] = approved; + emit OperatorSet(msg.sender, spender, approved); + } + + /// @notice Checks if a contract implements an interface. + /// @param interfaceId The interface identifier, as specified in ERC-165. + /// @return supported True if the contract implements `interfaceId` and + function supportsInterface(bytes4 interfaceId) public pure returns (bool supported) { + return interfaceId == 0xb2e69f8a || interfaceId == 0x01ffc9a7; + } + + function _mint(address receiver, uint256 id, uint256 amount) internal { + // WARNING: important safety checks should preceed calls to this method. + balanceOf[receiver][id] += amount; + totalSupply[id] += amount; + emit Transfer(address(0), receiver, id, amount); + } + + function _burn(address sender, uint256 id, uint256 amount) internal { + // WARNING: important safety checks should preceed calls to this method. + balanceOf[sender][id] -= amount; + totalSupply[id] -= amount; + emit Transfer(sender, address(0), id, amount); + } +} +``` + +## Security Considerations + +### Approvals and Operators + +The specification includes two token transfer permission systems, the "allowance" and "operator" +models. There are two security considerations in regards to delegating permission to transfer. + +The first consideration is consistent with all delegated permission models. Any account with an allowance may transfer the full allowance for any reason at any time until the allowance is revoked. Any account with operator permissions may transfer any amount of any token id on behalf of the owner until the operator permission is revoked. + +The second consideration is unique to systems with both delegated permission models. In accordance with the `transferFrom` method, spenders with operator permission are not subject to allowance restrictions, spenders with infinite approvals SHOULD NOT have their allowance deducted on delegated transfers, but spenders with non-infinite approvals MUST have their balance deducted on delegated transfers. A spender with both operator permission and a non-infinite approval may introduce functional ambiguity. If the operator permission takes precedence, that is, the allowance is never deducted when a spender has operator permissions, there is no ambiguity. However, in the event the allowance takes precedence over the operator permissions, an additional branch may be necessary to ensure an allowance underflow does not occur. The following is an example of such an issue. + +```solidity +contract ERC6909OperatorPrecedence { + // -- snip -- + + function transferFrom(address sender, address receiver, uint256 id, uint256 amount) public { + // check if `isOperator` first + if (msg.sender != sender && !isOperator[sender][msg.sender]) { + require(allowance[sender][msg.sender][id] >= amount, "insufficient allowance"); + allowance[sender][msg.sender][id] -= amount; + } + + // -- snip -- + } +} + +contract ERC6909AllowancePrecedence { + // -- snip -- + + function transferFrom(address sender, address receiver, uint256 id, uint256 amount) public { + // check if allowance is sufficient first + if (msg.sender != sender && allowance[sender][msg.sender][id] < amount) { + require(isOperator[sender][msg.sender], "insufficient allowance"); + } + + // ERROR: when allowance is insufficient, this panics due to arithmetic underflow, regardless of + // whether the caller has operator permissions. + allowance[sender][msg.sender][id] -= amount; + + // -- snip + } +} +``` + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-6913.md b/EIPS/eip-6913.md index e2309078e22e3..4ecb82d3b3de8 100644 --- a/EIPS/eip-6913.md +++ b/EIPS/eip-6913.md @@ -12,8 +12,7 @@ created: 2023-04-20 ## Abstract -Introduce the `SETCODE` (`0x49`) instruction, which replaces the code of the current executing address from memory. -Future calls to the modified contract use the new code. +Introduce the `SETCODE` (`0xfc`) instruction, which replaces the code of the executing account from memory. ## Motivation @@ -21,7 +20,7 @@ Many contracts are upgradeable in order to facilitate improvement or defer decis Contracts presently do this in several ways: The oldest method uses `CALL`. -The limitation of this method is that owned state must be modifiable by all future implementations. +The limitation of this method is that internal state must be modifiable by all future implementations. Second, `DELEGATECALL` can proxy the implementation. Some proxies are minimal while others branch to many separate implementation accounts. @@ -36,18 +35,20 @@ Given the upcoming deprecation of `SELFDESTRUCT`, `SETCODE` introduces a better ## Specification +When within a read-only execution scope like the recursive kind created by `STATICCALL`, `SETCODE` causes an exceptional abort. When inside of a `CREATE`-like execution scope that returns new code for the executing address (the account returned by `ADDRESS`), `SETCODE` causes an exceptional abort. +When inside of a `DELEGATECALL`-like execution scope where the currently executing code does not belong to the executing account, `SETCODE` causes an exceptional abort. + Otherwise, `SETCODE` consumes two words from the stack: offset and length. These specify a range of memory containing the new code. Any validations that would be performed on the result of `CREATE` or `CREATE2` occur immediately, potentially causing failure with exceptional abort. -Code replacement is deferred; the current execution scope and its children proceed before code replacement. -After the current execution scope exits successfully (neither reverting nor aborting), the code in the executing account is replaced. -Like `SSTORE`, this account modification will be reverted if a parent scope reverts or aborts. -Unlike `SELFDESTRUCT`, `SETCODE` does not clear account balance or storage. +The operations `EXTCODESIZE` and `EXTCODECOPY` now query the updated code, and message-calls such as `DELEGATECALL`, `CALLCODE`, `CALL`, and `STATICCALL` now execute the updated code. +Any execution scopes already executing replaced code, including the one that `SETCODE`, will continue executing the prior code. +Inside such scopes, `CODESIZE` and `CODECOPY` continue to query the executing code. -Multiple `SETCODE` operations inside the same execution scope are allowed and replace the pending replacement. +Like `SSTORE`, this account modification will be reverted if the current scope or any parent scope reverts or aborts. -A `SELFDESTRUCT` operation discards the pending code. +Unlike `SELFDESTRUCT`, `SETCODE` does not clear account balance, nonce, or storage. ### Gas @@ -55,29 +56,35 @@ The gas cost of this operation is the sum of Gselfdestruct and the product of Gc ## Rationale +The behavior of `CODECOPY`, `CODESIZE`, `EXTCODESIZE`, and `EXTCODECOPY` match the behavior of `DELEGATECALL` and `CREATE`, where it is also possible for executing code to differ from the code of the executing account. + The gas cost of `SETCODE` is comparable to `CREATE` but excludes Gcreate because no execution context is created, nor any new account. Other account modification costs are accounted for outside of execution gas. -Unlike `SELFDESTRUCT`, execution proceeds normally after `SETCODE` in order to allow return data. +Unlike `SELFDESTRUCT`, execution proceeds normally after `SETCODE` in order to allow validation and return data. +Post-update validation can undo a `SETCODE` operation with `REVERT` or with a subesequent `SETCODE`, but `REVERT` uses less-gas. + +Preventing `SETCODE` within `DELEGATECALL` allows static analysis to easily identify mutable code. +Account code not containing the `SETCODE` operation can be safely assumed to be immutable. ## Backwards Compatibility The only prior operation changing code is `SELFDESTRUCT`. -`SELFDESTRUCT` remains compatible by discarding any pending replacement code. +As code modification via `SELFDESTRUCT` is deferred until the end of the transaction, its interactions with `SETCODE` are well-defined. ## Test Cases | CodeStart | CallData | CodeResult | Gas | |----------------------|------------------|----------------------|------| -| 365f5f37365f4900 | 365f5f37365f4900 | 365f5f37365f4900 | 6613 | -| 365f5f37365f4900 | 00 | 00 | 5213 | -| 365f5f37365f4900 | | | 5013 | -| 365f5f37365f49595ffd | 365f5f37365f4900 | 365f5f37365f49595ffd | 6617 | -| 365f5f37365f49fe | 365f5f37365f4900 | 365f5f37365f49fe | all | +| 365f5f37365ffc00 | 365f5f37365ffc00 | 365f5f37365ffc00 | 6613 | +| 365f5f37365ffc00 | 00 | 00 | 5213 | +| 365f5f37365ffc00 | | | 5013 | +| 365f5f37365ffc595ffd | 365f5f37365ffc00 | 365f5f37365ffc595ffd | 6617 | +| 365f5f37365ffcfe | 365f5f37365ffc00 | 365f5f37365ffcfe | all | ## Security Considerations -Risks related to SETCODE similarly apply to other upgrade patterns. +Risks related to `SETCODE` similarly apply to other upgrade patterns. Most contracts should never be replaced and should not be upgradeable. Any upgrade mechanism can risk permanent failure. diff --git a/EIPS/eip-6944.md b/EIPS/eip-6944.md new file mode 100644 index 0000000000000..ed934544f9e9a --- /dev/null +++ b/EIPS/eip-6944.md @@ -0,0 +1,59 @@ +--- +eip: 6944 +title: ERC-5219 Resolve Mode +description: Adds an ERC-4804 resolveMode to support ERC-5219 requests +author: Gavin John (@Pandapip1), Qi Zhou (@qizhou) +discussions-to: https://ethereum-magicians.org/t/erc-5219-resolve-mode/14088 +status: Draft +type: Standards Track +category: ERC +created: 2023-04-27 +requires: 4804, 5219 +--- + +## Abstract + +This EIP adds a new [ERC-4804](./eip-4804.md) `resolveMode` to resolve [ERC-5219](./eip-5219.md) contract resource requests. + +## Specification + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. + +Contracts wishing to use ERC-5219 as their ERC-4804 resolve mode must implement the following interface: + +```solidity +/// @dev IDecentralizedApp is the ERC-5219 interface +interface IERC5219Resolver is IDecentralizedApp { + // @notice The ERC-4804 resolve mode + // @dev This MUST return "5219" (0x3532313900000000000000000000000000000000000000000000000000000000) for ERC-5219 resolution (case-insensitive). The other options, as of writing this, are "auto" for automatic resolution, or "manual" for manual resolution. + function resolveMode() external pure returns (bytes32 mode); +} +``` + +## Rationale + +[ERC-165](./eip-165.md) was not used because interoperability can be checked by calling `resolveMode`. + +## Backwards Compatibility + +No backward compatibility issues found. + + +## Reference Implementation + +```solidity +abstract contract ERC5219Resolver is IDecentralizedApp { + function resolveMode() public pure returns (bytes32 mode) { + return "5219"; + } +} +``` + + +## Security Considerations + +The security considerations of [ERC-4804](./eip-4804.md#security-considerations) and [ERC-5219](./eip-5219.md#security-considerations) apply. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-6953.md b/EIPS/eip-6953.md index f0af144d603aa..6e963f7a9fc4d 100644 --- a/EIPS/eip-6953.md +++ b/EIPS/eip-6953.md @@ -4,7 +4,7 @@ title: Network Upgrade Activation Triggers description: Exhaustive list of network upgrade activation mechanisms author: Tim Beiko (@timbeiko) discussions-to: https://ethereum-magicians.org/t/eip-6666-network-upgrade-activation-triggers/14047 -status: Draft +status: Review type: Informational created: 2023-04-28 requires: 2982, 3675, 6122 @@ -16,7 +16,7 @@ This EIP outlines the various network upgrade activation triggers used on Ethere ## Motivation -This EIP aims to provide users and developers with a single source of truth for understanding the various upgrade activation patterns used throughout Ethereum's history. +This EIP aims to provide users and developers with a single source of truth for understanding the various upgrade activation patterns used throughout Ethereum's history. It does not aim to be a comprehensive, ongoing record, of upgrades and their activations mechanism. Readers should assume that future upgrades use the mechanism described in the [Post Merge Upgrades](#post-merge-upgrades) section, unless this EIP is superceded by another one. ## Specification diff --git a/EIPS/eip-6956.md b/EIPS/eip-6956.md new file mode 100644 index 0000000000000..21005fd96a0d9 --- /dev/null +++ b/EIPS/eip-6956.md @@ -0,0 +1,652 @@ +--- +eip: 6956 +title: Asset-bound Non-Fungible Tokens +description: Asset-bound NFTs anchor a token 1-1 to an asset and operations are authorized through oracle-attestation of control over the asset +author: Thomas Bergmueller (@tbergmueller), Lukas Meyer (@ibex-technology) +discussions-to: https://ethereum-magicians.org/t/erc-6956-asset-bound-non-fungible-tokens/14056 +status: Draft +type: Standards Track +category: ERC +created: 2023-04-29 +requires: 165, 721 +--- + +## Abstract + +This standard allows integrating physical and digital ASSETS without signing capabilities into dApps/web3 by extending [ERC-721](eip-721.md). + +An ASSET, for example a physical object, is marked with a uniquely identifiable ANCHOR. The ANCHOR is bound in a secure and inseperable manner 1:1 to an NFT on-chain - over the complete life cylce of the ASSET. + +Through an ATTESTATION, an ORACLE testifies that a particular ASSET associated with an ANCHOR has been CONTROLLED when defining the `to`-address for certain operations (mint, transfer, burn, approve, ...). The ORACLE signs the ATTESTATION off-chain. The operations are authorized through verifying on-chain that ATTESTATION has been signed by a trusted ORACLE. Note that authorization is solely provided through the ATTESTATION, or in other words, through PROOF-OF-CONTROL over the ASSET. The controller of the ASSET is guaranteed to be the controller of the Asset-Bound NFT. + +The proposed ATTESTATION-authorized operations such as `transferAnchor(attestation)` are permissionless, meaning neither the current owner (`from`-address) nor the receiver (`to`-address) need to sign. + +Figure 1 shows the data flow of an ASSET-BOUND NFT transfer. The simplified system is utilizing a smartphone as user-device to interact with a physical ASSET and specify the `to`-address. + +![Figure 1: Sample system](../assets/eip-6956/img/erc6956_concept.svg) + +## Motivation + +The well-known [ERC-721](eip-721.md) establishes that NFTs may represent "ownership over physical properties [...] as well as digital collectables and even more abstract things such as responsibilities" - in a broader sense, we will refer to all those things as ASSETS, which typically have value to people. + +### The Problem + +ERC-721 outlines that "NFTs can represent ownership over digital or physical assets". ERC-721 excels in this task when used to represent ownership over digital, on-chain assets, that is when the asset is "holding a token of a specific contract" or the asset is an NFT's metadata. Today, people commonly treat an NFT's metadata (images, traits, ...) as asset-class, with their rarity often directly defining the value of an invididual NFT. + +However, we see integrity issues not solveable with ERC-721, primarily when NFTS are used to represent off-chain ASSETS ("ownership over physical products", "digital collectables", "in-game assets", "responsibilities", ...). Over an ASSET's lifecycle, the ASSET's ownership and posession state changes multiple, sometimes thousands, of times. Each of those state changes may result in shifting obligations and privileges for the involved parties. Therefore tokenization of an ASSET *without* enforcably anchoring the ASSET's associated obligation and properties to the token is not complete. Nowadays, off-chain ASSETs are often "anchored" through adding an ASSET-identifier to a NFT's metadata. + +**NFT-ASSET integrity:** Contrary to a popular belief among NFT-investors, metadata is data that is, more often than not, mutable and off-chain. Therefore the link between an ASSET through an asset-identifier stored in mutable metadata, which is only linked to the NFT through tokenURI, can be considered weak at best. + +Approaches to ensure integrity between metadata (=reference to ASSET) and a token exist. This is most commonly achieved by storing metadata-hashes onchain. Additional problems arise through hashing; For many applications, metadata (besides the asset-identifier) should be update-able. Therefore making metadata immutable through storing a hash is problematic. Further the offchain metadata-resource specified via tokenURI must be made available until eternity, which has historically been subject to failure (IPFS bucket disappears, central tokenURI-provider has downtimes, ...) + +**Off-chain-on-chain-integrity:** There are approaches where off-chain ASSET ownership is enforced or conditioned through having ownership over the on-chain representation. A common approach is to burn tokens in order to get the (physical) ASSET, as the integrity cannot be maintained. However, there are no approaches known, where on-chain ownership is enforced through having off-chain ownership of the ASSET. Especially when the current owner of an NFT is incooperative or incapacitated, integrity typically fail due to lack of signing-power from the current NFT owner. + +Metadata is off-chain. The majority of implementations completely neglect that metadata is mutable. More serious implementations strive to preserve integrity by for example hashing metadata and storing the hash mapped to the tokenId on-chain. However, this approach does not allow for use-case, where metadata besides the asset-identifier, for example traits, "hours played", ... shall be mutable or evolvable. + +### ASSET-BOUND NON-FUNGIBLE TOKENS + +In this standard we propose to + +1. Elevate the concept of representing physical or digital off-chain ASSETS by on-chain ANCHORING the ASSET inseperably into an NFT. +1. Being off-chain in control over the ASSET must mean being on-chain in control over the anchored NFT. +1. (Related) A change in off-chain ownership over the ASSET inevitably should be reflected by a change in on-chain ownership over the anchored NFT, even if the current owner is uncooperative or incapacitated. + +As 2. and 3. indicate, the control/ownership/posession of the ASSET should be the single source of truth, *not* the posession of an NFT. Hence, we propose an ASSET-BOUND NFT, where off-chain CONTROL over the ASSET enforces on-chain CONTROL over the anchored NFT. +Also the proposed ASSET-BOUND NFTs allow to anchor digital metadata inseperably to the ASSET. When the ASSET is a physical asset, this allows to design "phygitals" in their purest form, namely creating a "phygital" asset with a physical and digital component that are inseperable. Note that metadata itself can still change, for instance for "Evolvable NFT". + +We propose to complement the existing transfer control mechanisms of a token according to ERC-721, `Approval` according to [ERC-721](eip-721.md) and `Permit` according to [ERC-4494](eip-4494.md), by another mechanism; ATTESTATION. An ATTESTATION is signed off-chain by the ORACLE and must only be issued when the ORACLE verified that whoever specifies the `to` address or beneficiary address has simultanously been in control over the ASSET. The `to` address of an attestation may be used for Transfers as well as for approvals and other authorizations. + +Transactions authorized via ATTESTATION shall not require signature or approval from neither the `from` (donor, owner, sender) nor `to` (beneficiary, receiver) account, namely making transfers permissionless. Ideally, transaction are signed independent from the ORACLE as well, allowing different scenarios in terms of gas-fees. + +Lastly we want to mention two major side-benefits of using the proposed standard, which drastically lowers hurdles in onboarding web2 users and increase their security; + +- New users, e.g `0xaa...aa` (Fig.1), can use gasless wallets, hence participate in Web3/dApps/DeFi and mint+transfer tokens without ever owning crypto currency. Gas-fees may be paid through a third-party account `0x..gasPayer` (Fig.1). The gas is typically covered by the ASSET issuer, who signs `transferAnchor()` transactions +- Users cannot get scammed. Common attacks (for example wallet-drainer scams) are no longer possible or easily reverted, since only the anchored NFT can be stolen, not the ASSET itself. Also mishaps like transferring the NFT to the wrong account, losing access to an account etc can be mitigated by executing another `transferAnchor()` transaction based on proofing control over the ASSET, namely the physical object. + +### Related work + +We primarily aim to onboard physical or digital ASSETS into dApps, which do not signing-capabilities of their own (contrary to [ERC-5791](eip-5791.md) approach using crypto-chip based solutions). Note that we do not see any restrictions preventing to use ERC-5791 in combination with this standard, as the address of the crypto-chip qualifies as an ANCHOR. + + + +## Specification + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. + +### Definitions (alphabetical) + +- **ANCHOR** uniquely identifies the off-chain ASSET, whether it is physical or digital. +- **ANCHOR-TECHNOLOGY** MUST ensure that + - the ANCHOR is inseperable from the ASSET (physically or otherwise) + - an ORACLE can establish PROOF-OF-CONTROL over the ASSET beyond reasonable doubt + - For physical ASSETS, additional [Security considerations for Physical Assets](#security-considerations-for-physical-assets) MUST be taken into account + +- **ASSET** refers to the "thing", being it physical or digital, which is represented through NFTs according to the proposed standard. Typically, an ASSET does not have signing capabilities. + +- **ATTESTATION** is the confirmation that PROOF OF CONTROL was established when specifying the `to` (receiver, beneficiary) address. + +- **PROOF-OF-CONTROL** over the ASSET means owning or otherwise controlling an ASSET. How Proof of Control is established depends on the ASSET and may be implemented using technical, legal or other means. For physical ASSETS, CONTROL is typically verified by proofing physical proximity between a physical ASSET and an input device (for example a smartphone) used to specify the `to` address. + +- An **ORACLE** has signing capabilities. MUST be able to sign ATTESTATIONS off-chain in a way such that signatures can be verified on-chain. + + +### Base Interface + +Every contract compliant to this standard MUST implement the [the proposed standard interface](../assets/eip-6956/contracts/IERC6956.sol), [ERC-721](eip-721.md) and [ERC-165](eip-165.md) interfaces and is subject to [Caveats](#caveats-for-base-interface) below: + +```solidity +// SPDX-License-Identifier: MIT OR CC0-1.0 +pragma solidity ^0.8.18; + +/** + * @title IERC6956 Asset-Bound Non-Fungible Tokens + * @notice Asset-bound Non-Fungible Tokens anchor a token 1:1 to a (physical or digital) asset and token transfers are authorized through attestation of control over the asset + * @dev See https://eips.ethereum.org/EIPS/eip-6956 + * Note: The ERC-165 identifier for this interface is 0xa9cf7635 + */ +interface IERC6956 { + + /** @dev Authorization, typically mapped to authorizationMaps, where each bit indicates whether a particular ERC6956Role is authorized + * Typically used in constructor (hardcoded or params) to set burnAuthorization and approveAuthorization + * Also used in optional updateBurnAuthorization, updateApproveAuthorization, I + */ + enum Authorization { + NONE, // = 0, // None of the above + OWNER, // = (1<0) of the anchored token + */ + event AnchorApproval(address indexed owner, address approved, bytes32 indexed anchor, uint256 tokenId); + + /** + * @notice This emits when the ownership of any anchored NFT changes by any mechanism + * @dev This emits together with tokenId-based ERC-721.Transfer and provides an anchor-perspective on transfers + * @param from The previous owner, address(0) indicate there was none. + * @param to The new owner, address(0) indicates the token is burned + * @param anchor The anchor which is bound to tokenId + * @param tokenId ID (>0) of the anchored token + */ + event AnchorTransfer(address indexed from, address indexed to, bytes32 indexed anchor, uint256 tokenId); + /** + * @notice This emits when an attestation has been used indicating no second attestation with the same attestationHash will be accepted + * @param to The to address specified in the attestation + * @param anchor The anchor specificed in the attestation + * @param attestationHash The hash of the attestation, see ERC-6956 for details + * @param totalUsedAttestationsForAnchor The total number of attestations already used for the particular anchor + */ + event AttestationUse(address indexed to, bytes32 indexed anchor, bytes32 indexed attestationHash, uint256 totalUsedAttestationsForAnchor); + + /** + * @notice This emits when the trust-status of an oracle changes. + * @dev Trusted oracles must explicitely be specified. + * If the last event for a particular oracle-address indicates it's trusted, attestations from this oracle are valid. + * @param oracle Address of the oracle signing attestations + * @param trusted indicating whether this address is trusted (true). Use (false) to no longer trust from an oracle. + */ + event OracleUpdate(address indexed oracle, bool indexed trusted); + + /** + * @notice Returns the 1:1 mapped anchor for a tokenId + * @param tokenId ID (>0) of the anchored token + * @return anchor The anchor bound to tokenId, 0x0 if tokenId does not represent an anchor + */ + function anchorByToken(uint256 tokenId) external view returns (bytes32 anchor); + /** + * @notice Returns the ID of the 1:1 mapped token of an anchor. + * @param anchor The anchor (>0x0) + * @return tokenId ID of the anchored token, 0 if no anchored token exists + */ + function tokenByAnchor(bytes32 anchor) external view returns (uint256 tokenId); + + /** + * @notice The number of attestations already used to modify the state of an anchor or its bound tokens + * @param anchor The anchor(>0) + * @return attestationUses The number of attestation uses for a particular anchor, 0 if anchor is invalid. + */ + function attestationsUsedByAnchor(bytes32 anchor) view external returns (uint256 attestationUses); + /** + * @notice Decodes and returns to-address, anchor and the attestation hash, if the attestation is valid + * @dev MUST throw when + * - Attestation has already been used (an AttestationUse-Event with matching attestationHash was emitted) + * - Attestation is not signed by trusted oracle (the last OracleUpdate-Event for the signer-address does not indicate trust) + * - Attestation is not valid yet or expired + * - [if IERC6956AttestationLimited is implemented] attestationUsagesLeft(attestation.anchor) <= 0 + * - [if IERC6956ValidAnchors is implemented] validAnchors(data) does not return true. + * @param attestation The attestation subject to the format specified in ERC-6956 + * @param data Optional additional data, may contain proof as the first abi-encoded argument when IERC6956ValidAnchors is implemented + * @return to Address where the ownership of an anchored token or approval shall be changed to + * @return anchor The anchor (>0) + * @return attestationHash The attestation hash computed on-chain as `keccak256(attestation)` + */ + function decodeAttestationIfValid(bytes memory attestation, bytes memory data) external view returns (address to, bytes32 anchor, bytes32 attestationHash); + + /** + * @notice Indicates whether any of ASSET, OWNER, ISSUER is authorized to burn + */ + function burnAuthorization() external view returns(Authorization burnAuth); + + /** + * @notice Indicates whether any of ASSET, OWNER, ISSUER is authorized to approve + */ + function approveAuthorization() external view returns(Authorization approveAuth); + + /** + * @notice Corresponds to transferAnchor(bytes,bytes) without additional data + * @param attestation Attestation, refer ERC-6956 for details + */ + function transferAnchor(bytes memory attestation) external; + + /** + * @notice Changes the ownership of an NFT mapped to attestation.anchor to attestation.to address. + * @dev Permissionless, i.e. anybody invoke and sign a transaction. The transfer is authorized through the oracle-signed attestation. + * - Uses decodeAttestationIfValid() + * - When using a centralized "gas-payer" recommended to implement IERC6956AttestationLimited. + * - Matches the behavior of ERC-721.safeTransferFrom(ownerOf[tokenByAnchor(attestation.anchor)], attestation.to, tokenByAnchor(attestation.anchor), ..) and mint an NFT if `tokenByAnchor(anchor)==0`. + * - Throws when attestation.to == ownerOf(tokenByAnchor(attestation.anchor)) + * - Emits AnchorTransfer + * + * @param attestation Attestation, refer EIP-6956 for details + * @param data Additional data, may be used for additional transfer-conditions, may be sent partly or in full in a call to safeTransferFrom + * + */ + function transferAnchor(bytes memory attestation, bytes memory data) external; + + /** + * @notice Corresponds to approveAnchor(bytes,bytes) without additional data + * @param attestation Attestation, refer ERC-6956 for details + */ + function approveAnchor(bytes memory attestation) external; + + /** + * @notice Approves attestation.to the token bound to attestation.anchor. . + * @dev Permissionless, i.e. anybody invoke and sign a transaction. The transfer is authorized through the oracle-signed attestation. + * - Uses decodeAttestationIfValid() + * - When using a centralized "gas-payer" recommended to implement IERC6956AttestationLimited. + * - Matches the behavior of ERC-721.approve(attestation.to, tokenByAnchor(attestation.anchor)). + * - Throws when ASSET is not authorized to approve. + * + * @param attestation Attestation, refer EIP-6956 for details + */ + function approveAnchor(bytes memory attestation, bytes memory data) external; + + /** + * @notice Corresponds to burnAnchor(bytes,bytes) without additional data + * @param attestation Attestation, refer ERC-6956 for details + */ + function burnAnchor(bytes memory attestation) external; + + /** + * @notice Burns the token mapped to attestation.anchor. Uses ERC-721._burn. + * @dev Permissionless, i.e. anybody invoke and sign a transaction. The transfer is authorized through the oracle-signed attestation. + * - Uses decodeAttestationIfValid() + * - When using a centralized "gas-payer" recommended to implement IERC6956AttestationLimited. + * - Throws when ASSET is not authorized to burn + * + * @param attestation Attestation, refer EIP-6956 for details + */ + function burnAnchor(bytes memory attestation, bytes memory data) external; +} +``` + +#### Caveats for Base Interface + +- MUST implement ERC-721 and ERC-165 +- MUST have bidirectional mapping `tokenByAnchor(anchor)` and `anchorByToken(tokenId)`. This implies that a maximum of one token per ANCHOR exists. +- MUST have a mechnism to determine whether an ANCHOR is valid for the contract. RECOMMENDED to implement the proposed [ValidAnchors-Interface](#validanchors-interface) +- MUST implement `decodeAttestationIfValid(attestation, data)` to validate and decode ATTESTATIONS as specified in the [ORACLE-Section](#oracle) + - MUST return `attestation.to`, `attestation.anchor`, `attestation.attestationHash`. + - MUST not modify state, as this function can be used to check an ATTESTATION's validity without redeeming it. + - MUST throw when + - ATTESTATION is not signed from a trusted ORACLE. + - ATTESTATION has expired or is not valid yet + - ATTESTATION has not been reedemed. "Redeemed" being defined in at least one state-changing operation has been authorized through a particular ATTESTATION. + - If [AttestationLimited-Interface](#attestationlimited-interface) implemented: When `attestationUsagesLeft(attestation.to) <= 0` + - If [ValidAnchors-Interface](#validanchors-interface) implemented: When `validAnchor() != true`. + - If [ValidAnchors-Interface](#validanchors-interface) implemented: MUST call `validAnchor(attestation.to, abi.decode('bytes32[]',data))`, meaning the first abi-encoded value in the `data` parameter corresponds to `proof`. +- MUST have a ANCHOR-RELEASED mechanism, indicating whether the anchored NFT is released/transferable. + - Any ANCHOR MUST NOT be released by default. +- MUST extend any ERC-721 token transfer mechanism by: + - MUST throw when `ANCHOR` is not released. + - MUST throw when batchSize > 1, namely no batch transfers are supported with this contract. + - MUST emit `AnchorTransfer(from, to, anchorByToken[tokenId], tokenId)` + +- MUST implement `attestationsUsedByAnchor(anchor)`, returning how many attestations have already been used for a specific anchor. + +- MUST implement the state-changing `transferAnchor(..)`, `burnAnchor(..)`, `approveAnchor(..)` and OPTIONAL MAY implement additional state-changing operations which + - MUST use the `decodeAttestationIfValid()` to determine `to`, `anchor` and `attestationHash` + - MUST redeem each ATTESTATION in the same transaction as any authorized state-changing operation. RECOMMENDED by storing each used `attestationHash` + - MUST increment `attestationsUsedByAnchor[anchor]` + - MUST emit `AttestationUsed` + - `transferAnchor(attestation)` MUST behave and emit events like `ERC-721.safeTransferFrom(ownerOf[tokenByAnchor(attestation.anchor)], attestation.to, tokenByAnchor(attestation.anchor), ..)` and mint an NFT if `tokenByAnchor(anchor)==0`. + +- RECOMMENDED to implement `tokenURI(tokenId)` to return an anchorBased-URI, namely `baseURI/anchor`. This anchoring metadata to ASSET. Before an anchor is not used for the first time, the ANCHOR's mapping to tokenId is unknown. Hence, using the anchor in instead of the tokenId is preferred. + + +### ORACLE + +- MUST provide an ATTESTATION. Below we define the format how an ORACLE testifies that the `to` address of a transfer has been specified under the pre-condition of PROOF-OF-CONTROL associated with the particular ANCHOR being transferred to `to`. +- The ATTESTATION MUST abi-encode the following: + - `to`, MUST be address, specifying the beneficiary, for example the to-address, approved account etc. + - ANCHOR, aka the ASSET identifier, MUST have a 1:1 relation to the ASSET + - `attestationTime`, UTC seconds, time when attestation was signed by ORACLE, + - `validStartTime` UTC seconds, start time of the ATTESTATION's validity timespan + - `validEndTime`, UTC seconds, end time of the ATTESTATION's validity timespan + - `signature`, ETH-signature (65 bytes). Output of an ORACLE signing the `attestationHash = keccak256([to, anchor, attestationTime, validStartTime, validEndTime])`. +- How PROOF-OF-CONTROL is establish in detail through an ANCHOR-TECHNOLOGY is not subject to this standard. Some ORACLE requirements and ANCHOR-TECHNOLOGY requirements when using PHYSICAL ASSETS are outlined in [Security considerations for Physical Assets](#security-considerations-for-physical-assets). + +Minimal Typescript sample to generate an ATTESTATION using ethers library: + +```typescript +export async function minimalAttestationSample() { + // #################################### ACCOUNTS + // Alice shall get the NFT, oracle signs the attestation off-chain + // Oracle needs to be a trusted Oracle of the smart-contract that shall accept the generated attestation + const [alice, oracle] = await ethers.getSigners(); + + // #################################### CREATE AN ATTESTATION + const to = alice.address; + const anchor = '0x4cc52563699fb1e3333b8aab3ecf016f8fd084e6fc48edf8603d83d4c5b97536' + + const attestationTime = Math.floor(Date.now() / 1000.0); // Now in seconds UTC + const validStartTime = 0; + const validEndTime = attestationTime + 15 * 60; // 15 minutes valid from attestation + + const messageHash = ethers.utils.solidityKeccak256( + ["address", "bytes32", "uint256", 'uint256', "uint256"], + [to, anchor, attestationTime, validStartTime, validEndTime] + ); + const sig = await signer.signMessage(ethers.utils.arrayify(messageHash)); + + return ethers.utils.defaultAbiCoder.encode( + ['address', 'bytes32', 'uint256', 'uint256', 'uint256', 'bytes'], + [to, anchor, attestationTime, validStartTime, validEndTime, sig] + ); +} +``` + +### AttestationLimited-Interface + +Every contract compliant to this standard MAY implement the [proposed AttestationLimited interface](../assets/eip-6956/contracts/IERC6956AttestationLimited.sol) and is subject to [Caveats](#caveats-for-attestationlimited-interface) below: + +```solidity +// SPDX-License-Identifier: MIT OR CC0-1.0 +pragma solidity ^0.8.18; +import "./IERC6956.sol"; + +/** + * @title Attestation-limited Asset-Bound NFT + * @dev See https://eips.ethereum.org/EIPS/eip-6956 + * Note: The ERC-165 identifier for this interface is 0x75a2e933 + */ +interface IERC6956AttestationLimited is IERC6956 { + enum AttestationLimitPolicy { + IMMUTABLE, + INCREASE_ONLY, + DECREASE_ONLY, + FLEXIBLE + } + + /// @notice Returns the attestation limit for a particular anchor + /// @dev MUST return the global attestation limit per default + /// and override the global attestation limit in case an anchor-based limit is set + function attestationLimit(bytes32 anchor) external view returns (uint256 limit); + + /// @notice Returns number of attestations left for a particular anchor + /// @dev Is computed by comparing the attestationsUsedByAnchor(anchor) and the current attestation limit + /// (current limited emitted via GlobalAttestationLimitUpdate or AttestationLimt events) + function attestationUsagesLeft(bytes32 anchor) external view returns (uint256 nrTransfersLeft); + + /// @notice Indicates the policy, in which direction attestation limits can be updated (globally or per anchor) + function attestationLimitPolicy() external view returns (AttestationLimitPolicy policy); + + /// @notice This emits when the global attestation limt is updated + event GlobalAttestationLimitUpdate(uint256 indexed transferLimit, address updatedBy); + + /// @notice This emits when an anchor-specific attestation limit is updated + event AttestationLimitUpdate(bytes32 indexed anchor, uint256 indexed tokenId, uint256 indexed transferLimit, address updatedBy); + + /// @dev This emits in the transaction, where attestationUsagesLeft becomes 0 + event AttestationLimitReached(bytes32 indexed anchor, uint256 indexed tokenId, uint256 indexed transferLimit); +} +``` + +#### Caveats for AttestationLimited-Interface + +- MUST extend the proposed standard interface +- MUST define one of the above listed AttestationLimit update policies and expose it via `attestationLimitPolicy()` + - MUST support different update modes, namely FIXED, INCREASE_ONLY, DECREASE_ONLY, FLEXIBLE (= INCREASABLE and DECREASABLE) + - RECOMMENDED to have a global transfer limit, which can be overwritten on a token-basis (when `attestationLimitPolicy() != FIXED`) +- MUST implement `attestationLimit(anchor)`, specifying how often an ANCHOR can be transferred in total. Changes in the return value MUST reflect the AttestationLimit-Policy. +- MUST implement `attestationUsagesLeft(anchor)`, returning the number of usages left (namely `attestationLimit(anchor)-attestationsUsedByAnchor[anchor]`) for a particular anchor + + +### Floatable-Interface + +Every contract compliant to this extension MAY implement the proposed [Floatable interface](../assets/eip-6956/contracts/IERC6956Floatable.sol) and is subject to [Caveats](#caveats-for-floatable-interface) below: + +```solidity +// SPDX-License-Identifier: MIT OR CC0-1.0 +pragma solidity ^0.8.18; +import "./IERC6956.sol"; + +/** + * @title Floatable Asset-Bound NFT + * @notice A floatable Asset-Bound NFT can (temporarily) be transferred without attestation + * @dev See https://eips.ethereum.org/EIPS/eip-6956 + * Note: The ERC-165 identifier for this interface is 0xf82773f7 + */ +interface IERC6956Floatable is IERC6956 { + enum FloatState { + Default, // 0, inherits from floatAll + Floating, // 1 + Anchored // 2 + } + + /// @notice Indicates that an anchor-specific floating state changed + event FloatingStateChange(bytes32 indexed anchor, uint256 indexed tokenId, FloatState isFloating, address operator); + /// @notice Emits when FloatingAuthorization is changed. + event FloatingAuthorizationChange(Authorization startAuthorization, Authorization stopAuthorization, address maintainer); + /// @notice Emits, when the default floating state is changed + event FloatingAllStateChange(bool areFloating, address operator); + + /// @notice Indicates whether an anchored token is floating, namely can be transferred without attestation + function floating(bytes32 anchor) external view returns (bool); + + /// @notice Indicates whether any of OWNER, ISSUER, (ASSET) is allowed to start floating + function floatStartAuthorization() external view returns (Authorization canStartFloating); + + /// @notice Indicates whether any of OWNER, ISSUER, (ASSET) is allowed to stop floating + function floatStopAuthorization() external view returns (Authorization canStartFloating); + + /** + * @notice Allows to override or reset to floatAll-behavior per anchor + * @dev Must throw when newState == Floating and floatStartAuthorization does not authorize msg.sender + * @dev Must throw when newState == Anchored and floatStopAuthorization does not authorize msg.sender + * @param anchor The anchor, whose anchored token shall override default behavior + * @param newState Override-State. If set to Default, the anchor will behave like floatAll + */ + function float(bytes32 anchor, FloatState newState) external; +} +``` + + +#### Caveats for Floatable-Interface + +If `floating(anchor)` returns true, the token identified by `tokenByAnchor(anchor)` MUST be transferable without attestation, typically authorized via `ERC721.isApprovedOrOwner(msg.sender, tokenId)` + +### ValidAnchors-Interface + +Every contract compliant to this extension MAY implement the proposed [ValidAnchors interface](../assets/eip-6956/contracts/IERC6956ValidAnchors.sol) and is subject to [Caveats](#caveats-for-validanchors-interface) below: + +```solidity +// SPDX-License-Identifier: MIT OR CC0-1.0 +pragma solidity ^0.8.18; +import "./IERC6956.sol"; + +/** + * @title Anchor-validating Asset-Bound NFT + * @dev See https://eips.ethereum.org/EIPS/eip-6956 + * Note: The ERC-165 identifier for this interface is 0x051c9bd8 + */ +interface IERC6956ValidAnchors is IERC6956 { + /** + * @notice Emits when the valid anchors for the contract are updated. + * @param validAnchorHash Hash representing all valid anchors. Typically Root of Merkle-Tree + * @param maintainer msg.sender when updating the hash + */ + event ValidAnchorsUpdate(bytes32 indexed validAnchorHash, address indexed maintainer); + + /** + * @notice Indicates whether an anchor is valid in the present contract + * @dev Typically implemented via MerkleTrees, where proof is used to verify anchor is part of the MerkleTree + * MUST return false when no ValidAnchorsUpdate-event has been emitted yet + * @param anchor The anchor in question + * @param proof Proof that the anchor is valid, typically MerkleProof + * @return isValid True, when anchor and proof can be verified against validAnchorHash (emitted via ValidAnchorsUpdate-event) + */ + function anchorValid(bytes32 anchor, bytes32[] memory proof) external view returns (bool isValid); +} +``` + +#### Caveats for ValidAnchors-Interface + +- MUST implement `validAnchor(anchor, proof)` which returns true when anchor is valid, namely MerkleProof is correct, false otherwise. + + +## Rationale + +**Why do you use an anchor<>tokenId mapping and not simply use tokenIds directly?** +Especially for collectable use-cases, special or sequential tokenIds (for example low numbers), have value. Holders may be proud to have claimed tokenId=1 respectively the off-chain ASSET with tokenId=1 may increase in value, because it was the first ever claimed. Or an Issuer may want to address the first 100 owners who claimed their ASSET-BOUND NFT. While these use-cases technically can certainly be covered by observing the blockchain state-changes, we consider reflecting the order in the tokenIds to be the user-friendly way. Please refer [Security considerations](#security-considerations) on why sequential anchors shall be avoided. + +**Why is tokenId=0 and anchor=0x0 invalid?** +For gas efficiency. This allows to omit checks and state-variables for the existence of a token or anchor, since mappings of a non-existent key return 0 and cannot be easily distinguised from anchor=0 or tokenId=0. + +**ASSETS are often batch-produced with the goal of identical properties, for example a batch of automotive spare parts. Why should do you extend ERC-721 and not Multi-Token standards?** +Even if a (physical) ASSET is mass produced with fungible characteristics, each ASSET has an individual property/ownership graph and thus shall be represented in a non-fungible way. Hence this EIP follows the design decision that ASSET (represented via a unique asset identifier called ANCHOR) and token are always mapped 1-1 and not 1-N, so that a token represents the individual property graph of the ASSET. + +**Why is there a burnAnchor() and approveAnchor()?** +Due to the permissionless nature ASSET-BOUND NFTs can even be transferred to or from any address. This includes arbitrary and randomly generated accounts (where the private key is unknown) and smart-contracts which would traditionally not support ERC-721 NFTs. Following that owning the ASSET must be equivalent to owning the NFT, this means that we also need to support ERC-721 operations like approval and burning in such instances through authorizing the operations with an attestation. + +**Implementation alternatives considered** Soulbound burn+mint combination, for example through Consensual Soulbound Tokens ([ERC-5484](eip-5484.md)). Disregarded because appearance is highly dubious, when the same asset is represented through multiple tokens over time. An predecessor of this EIP has used this approach and can be found deployed to Mumbai Testnet under address `0xd04c443913f9ddcfea72c38fed2d128a3ecd719e`. + +**When should I implement AttestationLimited-Interface** +Naturally, when your use-case requires each ASSET being transferable only a limited number of times. But also for security reasons, see [Security Considerations](#security-considerations) + +**Why is there the `IERC6956Floatable.FloatState` enum?** In order to allow gas-efficient implementation of floatAll(), which can be overruled by anchor-based floatability in all combinations. (See rationale for tokenId=0 above). + +**Why is there no `floating(tokenId)` function?** +This would behave identically to an `isTransferable(tokenId,...)` mechanism proposed in many other EIPs (refer e.g. [ERC-6454](eip-6454.md)). Further, the proposed `floating(anchorByToken(tokenId))` can be used. + +**Why are there different FloatingAuthorizations for start and stop?** +Depending on the use-case, different roles should be able to start or stop floating. Note that for many applications the ISSUER may want to have control over the floatability of the collection. + + +### Example Use Cases and recommended combination of interfaces + +Posession based use cases are covered by the standard interface `IERC6956`: The holder of ASSET is in posession of ASSET. Possession is an important social and economical tool: In many sports games posession of ASSET, commonly referred to as "the ball", is of essence. Posession can come with certain obligations and privileges. Ownership over an ASSET can come with rights and benefits as well as being burdened with liens and obligations. For example, an owned ASSET can be used for collateral, can be rented or can even yield a return. Example use-cases are + +- **Posession based token gating:** Club guest in posession of limited T-Shirt (ASSET) gets a token which allows him to open the door to the VIP lounge. + +- **Posession based digital twin:** A gamer is in posession of a pair of physical sneakers (ASSET), and gets a digital twin (NFT) to wear them in metaverse. + +- **Scarce posession based digital twin:** The producer of the sneakers (ASSET) decided that the product includes a limit of 5 digital twins (NFTs), to create scarcity. + +- **Lendable digital twin:** The gamer can lend his sneaker-tokens (NFT) to a friend in the metaverse, so that the friend can run faster. + +- **Securing ownership from theft:** If ASSET is owned off-chain, the owner wants to secure the anchored NFT, namely not allow transfers to prevent theft or recover the NFT easily through the ASSET. + +- **Selling a house with a mortage:** The owner holds NFT as proof of ownership. The DeFi-Bank finances the house and puts a lock on the transfer of NFT. Allow Transfers of the NFT require the mortage to be paid off. Selling the ASSET (house) off-chain will be impossible, as it's no longer possible to finance the house. + +- **Selling a house with a lease:** A lease contract puts a lien on an ASSET's anchored NFT. The old owner removes the lock, the new owner buys and refinances the house. Transfer of NFT will also transfer the obligations and benefits of the lien to the new owner. As a lien-interface, the proposed EIP can for example be extended with [ERC-5604](eip-5604.md) + +- **Buying a brand new car with downpayment:** A buyer configures a car and provides a downpayment, for a car that will have an ANCHOR. As long as the car is not produced, the NFT can float and be traded on NFT market places. The owner of the NFT at time of delivery of the ASSET has the the permission to pick up the car and the obligation to pay full price. + +- **Buying a barrel of oil by forward transaction:** A buyer buys an oil option on a forward contract for one barrel of oil (ASSET). On maturity date the buyer has the obligation to pick up the oil. + +The use case matrix below shows which extensions and settings must (additionally to `IERC6956`!) be implemented for the example use-cases together with relevant configurations. + +Note that for `Lockable` listed in the table below, the proposed EIP can be extended with any Lock- or Lien-Mechanism known to extend for ERC-721. Suitable extensions to achieve `Lockable` are for example [ERC-5058](eip-5058.md) or [ERC-5753](eip-5753.md). We recommend to verify whether a token is locked in the `_beforeTokenTransfer()`-hook, as this is called from `safeTransferFrom()` as well as `transferAnchor()`, hence suitable to block "standard" ERC-721 transfers as well as the proposed attestation-based transfers. + +| Use Case | approveAuthorization | burnAuthorization | `IERC6956Floatable` | `IERC6956AttestationLimited` | Lockable | +|---------------|---|---|---|---|---| +| **Managing Posession** | +| Token gating | ASSET | ANY | incompatible | - | - | +| Digital twin | ASSET | ANY | incompatible | - | - | +| Scarce digital twin | ASSET | ANY | incompatible | required | - | +| Lendable digital twin | OWNER_AND_ASSET | ASSET | required | - | - | +| **Managing Ownership** | +| Securing ownership from theft | OWNER or OWNER_AND_ASSET | ANY | optional | - | required | +| Selling an house with a mortage | ASSET or OWNER_AND_ASSET | ANY | optional | optional | required | +| Selling a house with a lease | ASSET or OWNER_AND_ASSET | ANY | optional | optional | required | +| Buying a brand new car with downpayment | ASSET or OWNER_AND_ASSET | ANY | optional | optional | required | +| Buying a barrel of oil by forward transaction | ASSET or OWNER_AND_ASSET | ANY | optional | optional | required | + +Legend: + +- required ... we don't see a way how to implement the use-case without it +- incompatible ... this MUSTN'T be implemented, as it is a security risk for the use-case +- optional ... this MAY optionally be implemented + +## Backwards Compatibility + + + +No backward compatibility issues found. + +This EIP is fully compatible with ERC-721 and (when extended with the `IERC6956Floatable`-interface) corresponds to the well-known ERC-721 behavior with an additional authorization-mechanism via attestations. Therefore we recommend - especially for physical assets - to use the present EIP instead of ERC-721 and amend it with extensions designed for ERC-721. + +However, it is RECOMMENDED to extend implementations of the proposed standard with an interface indicating transferability of NFTs for market places. Examples include [ERC-6454](eip-6454.md) and [ERC-5484](eip-5484.md). + +Many ERC-721 extensions suggest to add additional throw-conditions to transfer methods. This standard is fully compatible, as + +- The often-used ERC-721 `_beforeTokenTransfer()` hook must be called for all transfers including attestation-authorized transfers. +- A `_beforeAnchorUse()` hook is suggested in the reference implementation, which only is called when using attestation as authorization. + +## Test Cases + +Test cases are available: + +- For only implementing [the proposed standard interface](../assets/eip-6956/contracts/IERC6956.sol) can be found [here](../assets/eip-6956/test/ERC6956.ts) +- For implementing [the proposed standard interface](../assets/eip-6956/contracts/IERC6956.sol), [the Floatable extension](../assets/eip-6956/contracts/IERC6956Floatable.sol), [the ValidAnchors extension](../assets/eip-6956/contracts/IERC6956ValidAnchors.sol) and [the AttestationLimited extension](../assets/eip-6956/contracts/IERC6956AttestationLimited.sol) can be found [here](../assets/eip-6956/test/ERC6956Full.ts) + +## Reference Implementation + +- Minimal implementation, only supporting [the proposed standard interface](../assets/eip-6956/contracts/IERC6956.sol) can be found [here](../assets/eip-6956/contracts/ERC6956.sol) +- Full implementation, with support for [the proposed standard interface](../assets/eip-6956/contracts/IERC6956.sol), [the Floatable extension](../assets/eip-6956/contracts/IERC6956Floatable.sol), [the ValidAnchors extension](../assets/eip-6956/contracts/IERC6956ValidAnchors.sol) and [the AttestationLimited extension](../assets/eip-6956/contracts/IERC6956AttestationLimited.sol) can be found [here](../assets/eip-6956/contracts/ERC6956Full.sol) + +## Security Considerations + + + +**If the asset is stolen, does this mean the thief has control over the NFT?** +Yes.The standard aims to anchor an NFT to the asset inseperably and unconditionally. This includes reflecting theft, as the ORACLE will testify that PROOF-OF-CONTROL over the ASSET is established. The ORACLE does not testify whether the controller is the legitimate owner, +Note that this may even be a benefit. If the thief (or somebody receiving the asset from the thief) should interact with the anchor, an on-chain address of somebody connected to the crime (directly or another victim) becomes known. This can be a valuable starting point for investigation. +Also note that the proposed standard can be combined with any lock-mechanism, which could lock attestation-based action temporarily or permamently (after mint). + +**How to use AttestationLimits to avoid fund-draining** +A central security mechanism in blockchain applications are gas fees. Gas fees ensure that executing a high number of transactions get penalized, hence all DoS or other large-scale attacks are discouraged. Due to the permissionless nature of attestation-authorized operations, many use-cases will arise, where the issuer of the ASSET (which normally is also the issuer of the ASSET-BOUND NFT) will pay for all transactions - contrary to the well-known ERC-721 behavior, where either from- or to-address are paying. So a user with malicious intent may just let the ORACLE approve PROOF-OF-CONTROL multiple times with specifying alternating account addresses. These ATTESTATIONS will be handed to the central gas-payer, who will execute them in a permissionless way, paying gas-fees for each transactions. This effectively drains the funds from the gas-payer, making the system unusable as soon as the gas-payer can no longer pay for transactions. + +**Why do you recommend hashing serial numbers over using them plain?** +Using any sequential identifier allows to at least conclude of the number between the lowest and highest ever used serial number. This therefore provides good indication over the total number of assets on the market. While a limited number of assets is often desireable for collectables, publishing exact production numbers of assets is undesireable for most industries, as it equals to publishing sales/revenue numbers per product group, which is often considered confidential. Within supply chains, serial numbers are often mandatory due to their range-based processing capability. The simplest approach to allow using physical serial numbers and still obfuscating the actual number of assets is through hashing/encryption of the serial number. + +**Why is anchor-validation needed, why not simply trust the oracle to attest only valid anchors?** +The oracle testifies PROOF-OF-CONTROL. As the ORACLE has to know the merkle-tree of valid anchors, it could also modify the merkle-tree with malicious intent. Therefore, having an on-chain verification, whether the original merkle-tree has been used, is needed. Even if the oracle gets compromised, it should not have the power to introduce new anchors. This is achieved by requiring that the oracle knows the merkle-tree, but updateValidAnchors() can only be called by a maintainer. Note that the oracle must not be the maintainer. As a consequence, care shall be taken off-chain, in order to ensure that compromising one system-part not automatically compromises oracle and maintainer accounts. + +**Why do you use merkle-trees for anchor-validation?** +For security- and gas-reasons. Except for limited collections, anchors will typically be added over time, e.g. when a new batch of the asset is produced or issued. While it is already ineffective to store all available anchors on-chain gas-wise, publishing all anchors would also expose the total number of assets. When using the data from anchor-updates one could even deduce the production capabilities of that asset, which is usually considered confidential information. + +**Assume you have N anchors. If all anchored NFTs are minted, what use is a merkle-tree?** +If all anchored NFTs are minted this implies that all anchors have been published and could be gathered on-chain. Consequently, the merkle-tree can be reconstructed. While this may not be an issue for many use cases (all supported anchors are minted anyway), we still recommend to add one "salt-leave" to the merkle-tree, characterized in that the ORACLE will never issue an attestation for an ANCHOR matching that salt-leave. Therefore, even if all N anchors are + +### Security Considerations for PHYSICAL ASSETS + +In case the ASSET is a physical object, good or property, the following ADDITIONAL specifications MUST be satisifed: + +#### ORACLE for Physical Anchors + +- Issuing an ATTESTATION requires that the ORACLE + - MUST proof physical proximity between an input device (for example smartphone) specifying the `to` address and a particular physical ANCHOR and it's associated physical object. Typical acceptable proximity is ranges between some millimeters to several meters. + - The physical presence MUST be verified beyond reasonable doubt, in particular the employed method + - MUST be robust against duplication or reproduction attempts of the physical ANCHOR, + - MUST be robust against spoofing (for example presentation attacks) etc. + - MUST be implemented under the assumption that the party defining the `to` address has malicious intent and to acquire false ATTESTATION, without currently or ever having access to the physical object comprising the physical ANCHOR. + +#### Physical ASSET + +- MUST comprise an ANCHOR, acting as the unique physical object identifier, typically a serial number (plain (NOT RECOMMENDED) or hashed (RECOMMENDED)) +- MUST comprise a physical security device, marking or any other feature that enables proofing physical presence for ATTESTATION through the ORACLE +- Is RECOMMENDED to employ ANCHOR-TECHNOLOGIES featuring irreproducible security features. +- In general it is NOT RECOMMENDED to employ ANCHOR-TECHNOLOGIES that can easily be replicated (for example barcodes, "ordinary" NFC chips, .. ). Replication includes physical and digital replication. + + + +### Security Considerations for DIGITAL ASSETS + + + + + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-6960.md b/EIPS/eip-6960.md new file mode 100644 index 0000000000000..7d1214061f434 --- /dev/null +++ b/EIPS/eip-6960.md @@ -0,0 +1,325 @@ +--- +eip: 6960 +title: Dual Layer Token +description: Token with a two-level classification system using mainId and subId +author: Adam Boudjemaa (@aboudjem), Mohamad Hammoud (@mohamadhammoud), Nawar Hisso (@nawar-hisso), Khawla Hassan (@khawlahssn), Mohammad Zakeri Rad (@zakrad), Ashish Sood +discussions-to: https://ethereum-magicians.org/t/eip-6960-dual-layer-token/14070 +status: Draft +type: Standards Track +category: ERC +created: 2023-04-30 +--- + +## Abstract + +The dual-layer token combines the functionalities of [ERC-20](./eip-20.md), [ERC-721](./eip-721.md), and [ERC-1155](./eip-1155.md) while adding a classification layer that uses `mainId` as the main asset type identifier and `subId` as the unique attributes or variations of the main asset. +![Dual Layer Token](../assets/eip-6960/eip-6960-dual-layer-token-dlt.png) + +The proposed token aims to offer more granularity in token management, facilitating a well-organized token ecosystem and simplifying the process of tracking tokens within a contract. This standard is particularly useful for tokenizing and enabling the fractional ownership of Real World Assets (RWAs). It also allows for efficient and flexible management of both fungible and non-fungible assets. + +The following are examples of assets that the DLT standard can represent fractional ownership of: + +- Invoices +- Company stocks +- Digital collectibles +- Real estate + +## Motivation + +The [ERC-1155](./eip-1155.md) standard has experienced considerable adoption within the Ethereum ecosystem; however, its design exhibits constraints when handling tokens with multiple classifications, particularly in relation to Real World Assets (RWAs) and fractionalization of assets. + +This EIP strives to overcome this limitation by proposing a token standard incorporating a dual-layer classification system, allowing for enhanced organization and management of tokens, especially in situations where additional sub-categorization of token types is necessary. + +## Specification + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. + +### DLT Interface + +```solidity +// SPDX-License-Identifier: CC0-1.0 +pragma solidity 0.8.17; + +/** + * @title DLT token standard interface + * @dev Interface for any contract that wants to implement the DLT standard + */ +interface IDLT { + + /** + * @dev MUST emit when `subId` token is transferred from `sender` to `recipient` + * @param sender is the address of the previous holder whose balance is decreased + * @param recipient is the address of the new holder whose balance is increased + * @param mainId is the main token type ID to be transferred + * @param subId is the token subtype ID to be transferred + * @param amount is the amount to be transferred of the token subtype + */ + event Transfer( + address indexed sender, + address indexed recipient, + uint256 indexed mainId, + uint256 subId, + uint256 amount + ); + + /** + * @dev MUST emit when `subIds` token array is transferred from `sender` to `recipient` + * @param sender is the address of the previous holder whose balance is decreased + * @param recipient is the address of the new holder whose balance is increased + * @param mainIds is the main token type ID array to be transferred + * @param subIds is the token subtype ID array to be transferred + * @param amounts is the amount array to be transferred of the token subtype + */ + event TransferBatch( + address indexed sender, + address indexed recipient, + uint256[] mainIds, + uint256[] subIds, + uint256[] amounts + ); + + /** + * @dev MUST emit when `owner` enables `operator` to manage the `subId` token + * @param owner is the address of the token owner + * @param operator is the authorized address to manage the allocated amount for an owner address + * @param mainId is the main token type ID to be approved + * @param subId is the token subtype ID to be approved + * @param amount is the amount to be approved of the token subtype + */ + event Approval( + address indexed owner, + address indexed operator, + uint256 mainId, + uint256 subId, + uint256 amount + ); + + /** + * @dev MUST emit when `owner` enables or disables (`approved`) `operator` to manage all of its assets + * @param owner is the address of the token owner + * @param operator is the authorized address to manage all tokens for an owner address + * @param approved true if the operator is approved, false to revoke approval + */ + event ApprovalForAll( + address indexed owner, + address indexed operator, + bool approved + ); + + /** + * @dev MUST emit when the URI is updated for a main token type ID. + * URIs are defined in RFC 3986. + * The URI MUST point to a JSON file that conforms to the "DLT Metadata URI JSON Schema". + * @param oldValue is the old URI value + * @param newValue is the new URI value + * @param mainId is the main token type ID + */ + event URI(string oldValue, string newValue, uint256 indexed mainId); + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any subId owned by the caller. + * The `operator` MUST NOT be the caller. + * MUST emit an {ApprovalForAll} event. + * @param operator is the authorized address to manage all tokens for an owner address + * @param approved true if the operator is approved, false to revoke approval + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * MUST revert if `sender` or `recipient` is the zero address. + * MUST revert if balance of holder for token `subId` is lower than the `amount` sent. + * MUST emit a {Transfer} event. + * @param sender is the address of the previous holder whose balance is decreased + * @param recipient is the address of the new holder whose balance is increased + * @param mainId is the main token type ID to be transferred + * @param subId is the token subtype ID to be transferred + * @param amount is the amount to be transferred of the token subtype + * @param data is additional data with no specified format + * @return True if the operation succeeded, false if operation failed + */ + function safeTransferFrom( + address sender, + address recipient, + uint256 mainId, + uint256 subId, + uint256 amount, + bytes calldata data + ) external returns (bool); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * The `operator` MUST NOT be the caller. + * MUST revert if `operator` is the zero address. + * MUST emit an {Approval} event. + * @param operator is the authorized address to manage tokens for an owner address + * @param mainId is the main token type ID to be approved + * @param subId is the token subtype ID to be approved + * @param amount is the amount to be approved of the token subtype + * @return True if the operation succeeded, false if operation failed + */ + function approve( + address operator, + uint256 mainId, + uint256 subId, + uint256 amount + ) external returns (bool); + + /** + * @notice Get the token with a particular subId balance of an `account` + * @param account is the address of the token holder + * @param mainId is the main token type ID + * @param subId is the token subtype ID + * @return The amount of tokens owned by `account` in subId + */ + function subBalanceOf( + address account, + uint256 mainId, + uint256 subId + ) external view returns (uint256); + + /** + * @notice Get the tokens with a particular subIds balance of an `accounts` array + * @param accounts is the address array of the token holder + * @param mainIds is the main token type ID array + * @param subIds is the token subtype ID array + * @return The amount of tokens owned by `accounts` in subIds + */ + function balanceOfBatch( + address[] calldata accounts, + uint256[] calldata mainIds, + uint256[] calldata subIds + ) external view returns (uint256[] calldata); + + /** + * @notice Get the allowance allocated to an `operator` + * @dev This value changes when {approve} or {transferFrom} are called + * @param owner is the address of the token owner + * @param operator is the authorized address to manage assets for an owner address + * @param mainId is the main token type ID + * @param subId is the token subtype ID + * @return The remaining number of tokens that `operator` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + */ + function allowance( + address owner, + address operator, + uint256 mainId, + uint256 subId + ) external view returns (uint256); + + /** + * @notice Get the approval status of an `operator` to manage assets + * @param owner is the address of the token owner + * @param operator is the authorized address to manage assets for an owner address + * @return True if the `operator` is allowed to manage all of the assets of `owner`, false if approval is revoked + * See {setApprovalForAll} + */ + function isApprovedForAll( + address owner, + address operator + ) external view returns (bool); +} +``` + +### `DLTReceiver` Interface + +Smart contracts MUST implement all the functions in the `DLTReceiver` interface to accept transfers. + +```solidity +// SPDX-License-Identifier: CC0-1.0 +pragma solidity 0.8.17; + +/** + * @title DLT token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from DLT asset contracts. + */ +interface IDLTReceiver { + /** + * @notice Handle the receipt of a single DLT token type. + * @dev Whenever an {DLT} `subId` token is transferred to this contract via {IDLT-safeTransferFrom} + * by `operator` from `sender`, this function is called. + * MUST return its Solidity selector to confirm the token transfer. + * MUST revert if any other value is returned or the interface is not implemented by the recipient. + * The selector can be obtained in Solidity with `IDLTReceiver.onDLTReceived.selector`. + * @param operator is the address which initiated the transfer + * @param from is the address which previously owned the token + * @param mainId is the main token type ID being transferred + * @param subId subId is the token subtype ID being transferred + * @param amount is the amount of tokens being transferred + * @param data is additional data with no specified format + * @return `IDLTReceiver.onDLTReceived.selector` + */ + function onDLTReceived( + address operator, + address from, + uint256 mainId, + uint256 subId, + uint256 amount, + bytes calldata data + ) external returns (bytes4); + + /** + * @notice Handle the receipts of a DLT token type array. + * @dev Whenever an {DLT} `subIds` token is transferred to this contract via {IDLT-safeTransferFrom} + * by `operator` from `sender`, this function is called. + * MUST return its Solidity selector to confirm the token transfers. + * MUST revert if any other value is returned or the interface is not implemented by the recipient. + * The selector can be obtained in Solidity with `IDLTReceiver.onDLTReceived.selector`. + * @param operator is the address which initiated the transfer + * @param from is the address which previously owned the token + * @param mainIds is the main token type ID being transferred + * @param subIds subId is the token subtype ID being transferred + * @param amounts is the amount of tokens being transferred + * @param data is additional data with no specified format + * @return `IDLTReceiver.onDLTReceived.selector` + */ + function onDLTBatchReceived( + address operator, + address from, + uint256[] calldata mainIds, + uint256[] calldata subIds, + uint256[] calldata amounts, + bytes calldata data + ) external returns (bytes4); +} +``` + +## Rationale + +The two-level classification system introduced in this EIP allows for a more organized token ecosystem, enabling users to manage and track tokens with greater granularity. It is particularly useful for projects that require token classifications beyond the capabilities of the current ERC-1155 standard. + +As assets can have various properties or variations, our smart contract design reflects this by assigning a mainId to each asset category and a unique subId to each derivative or sub-category. This approach expands the capabilities of ERC-1155 to support a broader range of assets with complex requirements. Additionally, it enables tracking of mainBalance for the main asset and subBalance for its sub-assets individual accounts. + +The contract can be extended to support the use of subIds in two ways: + +- Shared SubIds: where all mainIds share the same set of subIds. +- Mixed SubIds: where mainIds have unique sets of subIds. + +DLT provides a more versatile solution compared to other token standards such as ERC-20, ERC-721, and ERC-1155 by effectively managing both fungible and non-fungible assets within the same contract. + +The following are questions that we considered during the design process: + +- How to name the proposal? +The standard introduces a two-level classification to tokens where one main asset (layer 1) can be further sub-divided into several sub-assets (layer 2) hence we decided to name it as "Dual-layer" token to reflect the hierarchical structure of the token classification. +- Should we limit the classification to two levels? +The standard’s implementation maintains a mapping to track the total supply of each sub-asset. If we allow sub-assets to have their own children, it would be necessary to introduce additional methods to track each sub-asset, which would be impractical and increases the complexity of the contract. +- Should we extend the ERC-1155 standard? +As the ERC-1155 standard is not designed to support a layered classification and requires significant modifications to do so, we concluded that it would not be appropriate to extend it for the dual-layer token standard. Hence, a standalone implementation would be a more suitable approach. + +## Backwards Compatibility + +No backward compatibility issues found. + +## Security Considerations + +Needs discussion. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-6963.md b/EIPS/eip-6963.md index 999ea33339b1d..eac9cc73c2ec6 100644 --- a/EIPS/eip-6963.md +++ b/EIPS/eip-6963.md @@ -2,7 +2,7 @@ eip: 6963 title: Multi Injected Provider Discovery description: Using window events to announce injected wallet providers -author: Pedro Gomes (@pedrouid), Kosala Hemachandra (@kvhnuke), Richard Moore (@ricmoo), Gregory Markou (@GregTheGreek), Kyle Den Hartog (@kdenhartog), Glitch (@glitch-txs), Micah Zoltu (@MicahZoltu), Jake Moxey (@jxom), Pierre Bertet (@bpierre), Darryl Yeo (@darrylyeo) +author: Pedro Gomes (@pedrouid), Kosala Hemachandra (@kvhnuke), Richard Moore (@ricmoo), Gregory Markou (@GregTheGreek), Kyle Den Hartog (@kdenhartog), Glitch (@glitch-txs), Jake Moxey (@jxom), Pierre Bertet (@bpierre), Darryl Yeo (@darrylyeo), Yaroslav Sergievsky (@everdimension) discussions-to: https://ethereum-magicians.org/t/eip-6963-multi-injected-provider-interface-aka-mipi/14076 status: Draft type: Standards Track @@ -33,100 +33,55 @@ This is achieved by introducing a set of window events to provide a two-way comm The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119. +### Definitions + +Wallet: A user agent that manages keys and facilitates transactions with Ethereum. + +Decentralized Application (DApp): A web page that relies upon one or many Web3 platform APIs which are exposed to the web page via the Wallet. + +Provider Discovery Library: A library or piece of software that assists a DApp to interact with the Wallet. + ### Provider Info -Each wallet provider will be announced with the following interface `EIP6963ProviderInfo` that will be used to display to the user: +Each wallet provider will be announced with the following interface `EIP6963ProviderInfo`. The values in the `EIP6963ProviderInfo` MUST be used as follows: + +- **`uuid`** - a globally unique of the wallet provider that MUST be (UUIDv4[^rfc4122] compliant) to uniquely distinguish different [EIP-1193](./eip-1193.md) provider sessions. The cryptographic uniqueness provided by UUIDv4[^rfc4122] guarantees that two independent `EIP6963ProviderInfo` objects can be separately identified. +- **`name`** - A human-readable local alias of the wallet provider to be displayed to the user on the DApp. (e.g. `DopeWalletExtension` or `AwesomeWallet`) +- **`icon`** - A URI[^rfc3986] pointing to an image. Icon images MUST be square with 96x96px minimum resolution ```typescript /** * Represents the assets needed to display a wallet */ interface EIP6963ProviderInfo { - walletId: string; uuid: string; name: string; icon: string; } ``` -The values in the `EIP6963ProviderInfo` MUST be used as follows: +#### Images/Icons -- **`walletId`** - globally unique identifier of the wallet provider (eg. `io.dopewallet.extension` or `awesomewallet`) -- **`uuid`** - locally unique of the wallet provider (UUIDv4[^rfc4122] compliant) -- **`name`** - human-readable name of the wallet provider (e.g. `DopeWalletExtension` or `AwesomeWallet`) -- **`icon`** - A URI[^rfc3986] pointing to an image. Icon images MUST be square with 96x96px minimum resolution +// TODO for @kdenhartog: This section should be updated to require support of SVGs instead of arbitrary data URIs or URLs that point to images. -[^rfc4122]: - ```csl-json - { - "author": [ - { - "given": "Paul J.", - "family": "Leach" - }, - { - "given": "Rich", - "family": "Salz" - }, - { - "given": "Michael H.", - "family": "Mealling" - } - ], - "collection-title": "Request for Comments", - "DOI": "10.17487/RFC4122", - "type": "book", - "id": "rfc4122", - "citation-label": "rfc4122", - "issued": { - "date-parts": [ - [2005, 7] - ] - }, - "number-of-pages": "32", - "publisher": "RFC Editor", - "title": "A Universally Unique IDentifier (UUID) URN Namespace", - "URL": "https://www.rfc-editor.org/info/rfc4122" - } - ``` +A uri encoded image was chosen to enable flexibility for multiple protocols for fetching and rendering icons, for example: -[^rfc3986]: - ```csl-json - { - "author": [ - { - "given": "Tim", - "family": "Berners-Lee" - }, - { - "given": "Roy T.", - "family": "Fielding" - }, - { - "given": "Larry M", - "family": "Masinter" - } - ], - "collection-title": "Request for Comments", - "DOI": "10.17487/RFC3986", - "type": "book", - "id": "rfc3986", - "citation-label": "rfc3986", - "issued": { - "date-parts": [ - [2005, 1] - ] - }, - "number-of-pages": "61", - "publisher": "RFC Editor", - "title": "Uniform Resource Identifier (URI): Generic Syntax", - "URL": "https://www.rfc-editor.org/info/rfc3986" - } - ``` +```sh +# svg (data uri) +data:image/svg+xml, +# png (data uri) +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg== +# png (ipfs uri) +ipfs://QmZo7gsostaUdrV1peFz4cX6Z2TgriFJJP4VahG5knVm29 +# webp (http uri) +https://ethereum.org/static/f541df14fca86543040c113725b5bd1a/99bcf/metamask.webp +``` + +Additionally the image must be squared with 96x96px minimum resolution. Image format is recommended to be lossless like PNG and WebP or alternatively vectorial like SVG. We strongly discourage lossy formats like JPG/JPEG. ### Provider Detail -The wallet provider will also announce their own [EIP-1193](./eip-1193.md) provider interface in parallel with the provider info defined above in the following interface `EIP6963ProviderDetail` +The `EIP6963ProviderDetail` is used as a composition interface to announce a wallet provider and and related metadata about the wallet provider. The `EIP6963ProviderDetail` MUST contain an `info` property of type `EIP6963ProviderInfo` and a `provider` property of type `EIP1193Provider` defined by [EIP-1193](./eip-1193.md). ```typescript interface EIP6963ProviderDetail { @@ -135,101 +90,93 @@ interface EIP6963ProviderDetail { } ``` -The `EIP1193Provider` interface is documented at [EIP-1193](./eip-1193.md) and can be used to override the `window.ethereum` object once the user has explicitly selected it. +### Window Events -### Window Event +In order to prevent provider collisions, the DApp and the Wallet are expected to emit an event and instantiate an eventListener to discover the various Wallets. This forms an Event concurrency loop. -Different wallet providers might inject their scripts at different times, plus there is no guarantees that the Ethereum library in the web page will be loaded before all injected scripts are present in the page. +Since the DApp code and Wallet code aren't guaranteed to run in a particular order, the events are designed to handle such race conditions. -To emit events both Ethereum libraries and Wallet providers must use `window.dispatchEvent` to emit events and `window.addEventListener` to observe events. There will be two event interfaces: +To emit events both DApps and Wallets MUST use the `window.dispatchEvent` function to emit events and MUST use the `window.addEventListener` function to observe events. There are two Event interfaces used for the DApp and Wallet to discover each other. -```typescript -// Requesting an EVM provider -interface EIP6963RequestProviderEvent extends Event { - type: "eip6963:requestProvider"; -} +#### Announce and Request Events -// Annoucing an EVM provider +The `EIP6963AnnounceProviderEvent` interface MUST be a `CustomEvent` object with a `type` property containing a string value of `eip6963:announceProvider` and a `detail` property with an object as it's value of type `EIP6963ProviderDetail`. The `EIP6963ProviderDetail` object MUST be frozen by calling `Object.freeze()` on the value of the `detail` property. + +```typescript +// Announce Event dispatched by a Wallet interface EIP6963AnnounceProviderEvent extends CustomEvent { type: "eip6963:announceProvider"; detail: EIP6963ProviderDetail; } ``` -Therefore both wallet providers and the Ethereum library must emit events when they initialize. - -```typescript -// Ethereum library initializes -window.dispatchEvent(new Event("eip6963:requestProvider")); - -// Wallet provider initializes -window.dispatchEvent(new CustomEvent("eip6963:announceProvider", { detail })); -``` - -Additionally the Wallet providers will react to the event emitted by the Ethereum library. +The `EIP6963RequestProviderEvent` interface MUST be an `Event` object with a `type` property containing a string value of `eip6963:requestProvider`. ```typescript -window.addEventListener( - "eip6963:requestProvider", - (event: EIP6963RequestProviderEvent) => { - announceProvider(); - } -); +// Request Event dispatched by a DApp +interface EIP6963RequestProviderEvent extends Event { + type: "eip6963:requestProvider"; +} ``` -## Rationale +The Wallet MUST announce to the DApp the `EIP6963AnnounceProviderEvent` via a `window.dispatchEvent()` function call. The Wallet MUST add an EventListener to catch an `EIP6963RequestProviderEvent` dispatched from the DApp. This EventListener MUST use a handler that will re-dispatch an `EIP6963AnnounceProviderEvent`. This re-announcement by the Wallet is useful for when a Wallet's initial Event announcement may have been delayed or fired before the DApp had initialized its EventListener. This allows the various Wallet Providers to react to the DApp without the need to pollute the `window.ethereum` namespace which can produce non-deterministic wallet behavior such as different wallets connecting each time. -### Interfaces +The Wallet listens dispatches the `"eip6963:announceProvider"` event and listens to the `"eip6963:requestProvider"` event: -Standardizing a provider info interface (`EIP6963ProviderInfo`) allows determining the necessary information to populate a wallet selection popup. This is particularly useful for Ethereum libraries such as Web3Modal, RainbowKit, Web3-Onboard, ConnectKit, etc. - -Regarding the announced provider interface (`EIP6963ProviderDetail`) it was important to leave the [EIP-1193](./eip-1193.md) provider interface untouched for backwards-compatiblity therefore it's exposed in parallel. +```typescript +let info: EIP6963ProviderInfo; +let provider: EIP1193Provider; -### Identifiers +const announceEvent: EIP6963AnnounceProviderEvent = new CustomEvent( + "eip6963:announceProvider", + { detail: Object.freeze({ info, provider }) } +); -A locally unique identifier prevents from conflicts using the same globally unique identifier by using UUID v4.0 +// The Wallet dispatches an announce event which is heard by +// the DApp code that had run earlier +window.dispatchEvent(announceEvent); -A globally unique identifier is used for machine-readable detection of the currently active wallet and it can take different formats, for example: +// The Wallet listens to the request events which may be +// dispatched later and re-dispatches the `EIP6963AnnounceProviderEvent` +window.addEventListener("eip6963:requestProvider", () => { + window.dispatchEvent(announceEvent); +}); +``` -```text -# lowercase name -awesomewallet +The DApp MUST listen for the `EIP6963AnnounceProviderEvent` dispatched by the Wallet via a `window.addEventListener()` method. The DApp MUST dispatch the `EIP6963RequestProviderEvent` via a `window.dispatchEvent()` function call. -# legacy JS variable -isCoolWallet +```typescript +// The DApp listens to announced providers +window.addEventListener( + "eip6963:announceProvider", + (event: EIP6963AnnounceProviderEvent) => {} +); -# reversed domain -io.dopewallet.app +// The DApp dispatches a request event which will be heard by +// Wallets' code that had run earlier +window.dispatchEvent(new Event("eip6963:requestProvider")); ``` -### Images/Icons +The DApp MAY also keep track of the various `EIP6963ProviderDetail` announced by the various wallets so that if the user wishes to utilize a different Wallet the DApp can immediately send transactions to the new Wallet. Otherwise, the DApp MAY re-initiate the wallet discovery flow via dispatching a new `EIP6963RequestProviderEvent` Event. -A uri encoded image was chosen to enable flexibility for multiple protocols for fetching and rendering icons, for example: +The described orchestration of events guarantees that the DApp is able to discover the Wallet, regardless of which code executes first, the Wallet code or the DApp code. -```sh -# svg (data uri) -data:image/svg+xml, -# png (data uri) -data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg== -# png (ipfs uri) -ipfs://QmZo7gsostaUdrV1peFz4cX6Z2TgriFJJP4VahG5knVm29 -# webp (http uri) -https://ethereum.org/static/f541df14fca86543040c113725b5bd1a/99bcf/metamask.webp -``` +## Rationale -Additionally the image must be squared with 96x96px minimum resolution. Image format is recommended to be lossless like PNG and WebP or alternatively vectorial like SVG. We strongly discourage lossy formats like JPG/JPEG. +Previous proposal introduced mechanisms that relied on a single window object that could be overridden by multiple parties. Therefore using an event-based approach we avoid the race conditions and potential attacks by making the communication available both ways in a way that doesn't have potential namespace collisions. -### Events +To follow the Javascript event name conventions, the names are written in present tense and are prefixed with the standard number (`eip6963`). -Previous proposal introduced mechanisms that relied on a single window object that could be overriden by multiple parties. +### Interfaces -Therefore using an event-based approach we avoid these race conditions and potential attacks by making the communication available both ways. +Standardizing a provider info interface (`EIP6963ProviderInfo`) allows determining the necessary information to populate a wallet selection popup. This is particularly useful for DApps and Ethereum libraries they might depend on such as Web3Modal, RainbowKit, Web3-Onboard, ConnectKit, etc. + +Regarding the announced provider interface (`EIP6963ProviderDetail`) it was important to leave the [EIP-1193](./eip-1193.md) provider interface untouched for backwards compatibility therefore it's exposed in parallel. However, just as it is today there is no guarantee that this backwards compatible method will result in the user selected wallet being chosen. -To follow the Javascript event name conventions, the names are written in present tense and are prefixed with the standard number (`eip6963`). ## Backwards Compatibility -This EIP doesn't require supplanting `window.ethereum`, so it doesn't directly break existing applications. However, the recommended behavior of eventually supplanting `window.ethereum` would break existing applications that rely on it. +This EIP doesn't require supplanting `window.ethereum`, so it doesn't directly break existing applications that cannot update to this method of Wallet discovery. However, it is RECOMMENDED DApps implement this EIP and SHOULD disable `window.ethereum` usage to ensure discovery of multiple Wallet Providers. Similarly, Wallets SHOULD keep compatibility of `window.ethereum` to ensure backwards compatibility for DApps that have not implemented this EIP. ## Reference Implementation @@ -245,14 +192,13 @@ function onPageLoad() { function announceProvider() { const info: EIP6963ProviderInfo = { - walletId: "org.example.wallet", uuid: "350670db-19fa-4704-a166-e52e178b59d2", name: "Example Wallet", icon: "https://wallet.example.org/icon.png", }; window.dispatchEvent( new CustomEvent("eip6963:announceProvider", { - detail: { info, provider }, + detail: Object.freeze({ info, provider }), }) ); } @@ -268,13 +214,12 @@ function onPageLoad() { } ``` -### Ethereum library +### DApp implementation -Here is a reference implementation for a Ethereum library to display and track multiple wallet providers that are injected by browser extensions. +Here is a reference implementation for a DApp to display and track multiple wallet providers that are injected by browser extensions. ```typescript -function onPageLoad() { - const providers: EIP6963ProviderDetail[] = []; +function onPageLoad(): EIP6963ProviderDetail[] => { window.addEventListener( "eip6963:announceProvider", @@ -293,6 +238,105 @@ The security considerations of [EIP-1193](./eip-1193.md) apply to this EIP. The use of SVG images introduces a cross-site scripting risk as they can include JavaScript code. Applications and libraries must render SVG images using the `` tag to ensure no JS executions can happen. +// TODO for @kdenhartog: Add a privacy section about Wallet fingerprinting and how Wallets should not announce themselves until the DApp has dispatched the request provider Event and gathered consent from the user that they wish to announce themselves to the DApp. + ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md). + + +[^rfc4122]: + ```csl-json + { + "author": [ + { + "given": "Paul J.", + "family": "Leach" + }, + { + "given": "Rich", + "family": "Salz" + }, + { + "given": "Michael H.", + "family": "Mealling" + } + ], + "collection-title": "Request for Comments", + "DOI": "10.17487/RFC4122", + "type": "book", + "id": "rfc4122", + "citation-label": "rfc4122", + "issued": { + "date-parts": [ + [2005, 7] + ] + }, + "number-of-pages": "32", + "publisher": "RFC Editor", + "title": "A Universally Unique IDentifier (UUID) URN Namespace", + "URL": "https://www.rfc-editor.org/info/rfc4122" + } + ``` + +[^rfc3986]: + ```csl-json + { + "author": [ + { + "given": "Tim", + "family": "Berners-Lee" + }, + { + "given": "Roy T.", + "family": "Fielding" + }, + { + "given": "Larry M", + "family": "Masinter" + } + ], + "collection-title": "Request for Comments", + "DOI": "10.17487/RFC3986", + "type": "book", + "id": "rfc3986", + "citation-label": "rfc3986", + "issued": { + "date-parts": [ + [2005, 1] + ] + }, + "number-of-pages": "61", + "publisher": "RFC Editor", + "title": "Uniform Resource Identifier (URI): Generic Syntax", + "URL": "https://www.rfc-editor.org/info/rfc3986" + } + ``` + + [^rfc2397]: + ```csl-json + { + "type": "book", + "id": "RFC2397", + "author": [ + { + "family": "Hoffman", + "given": "Paul" + } + ], + "collection-title": "Request for Comments", + "DOI": "10.17487/RFC2397", // TODO determine proper DOI number + "type": "book", + "id": "rfc2397", + "citation-label": "rfc2397", + "issued": { + "date-parts": [ + [1998, 08] + ] + }, + "number-of-pages": "5", + "publisher": "RFC Editor", + "title": "The 'data' URL scheme", + "URL": "https://www.rfc-editor.org/info/rfc3986" + } + ``` diff --git a/EIPS/eip-6968.md b/EIPS/eip-6968.md new file mode 100644 index 0000000000000..bdb1e0966732a --- /dev/null +++ b/EIPS/eip-6968.md @@ -0,0 +1,94 @@ +--- +eip: 6968 +title: Contract Secured Revenue on an EVM based L2 +description: Contract Secured Revenue on an EVM based L2 +author: Zak Cole , Zak Cole (@zscole), Kevin Owocki , Lightclient +discussions-to: https://ethereum-magicians.org/t/eip-6968-generalized-csr-protocol/14178 +status: Draft +type: Standards Track +category: Core +created: 2023-05-01 +--- + +## Abstract + +Contract Secured Revenue (CSR) allows smart contract developers to claim a percentage of all transaction fees paid by users when interacting with their smart contracts. + +This EIP proposes the introduction of CSR on EVM-based L2s which would provide smart contract developers who deploy on L2s access to revenue streams and/or public goods. + +## Motivation + +Using protocol rewards of an L1 to fund smart contract development would be a big change to the way the current market works. This EIP *does not* advocate for any changes to the existing Ethereum L1. + +This EIP does advocate that L2s could begin to experiment with Contract Secured Revenue as a means of: + +1. creating a new revenue stream for smart contract developers +2. creating a new way of funding public goods +3. creating incentives for developers to deploy their dapps on your network + +## Specification + +### Parameters + +| Constant | Value | +|---|---| +| REVENUE_SHARE_QUOTIENT | 5 | + +### Fee Mechanism + +The current [EIP-1559](./eip-1559.md) fee behavior is modified so that `header.base_fee_per_gas * REVENUE_SHARE_QUOTIENT` per gas is reallocated proportionally, based on gas used, to each contract executed during the transaction. + +Implicitly, this means that no fees are redistributed to externally owned accounts (EOA). + +#### Gas Tracking + +In order to fairly distribute the fee revenue, a new transaction-wide gas tracker is defined. + +When executing a block, maintain a mapping `gas_used_by_address` of `address` to `uint64`. This will track the amount of gas used by each address. For every EVM instruction that does not instantiate a new execution frame (e.g. `CALL`, `CALLCODE`, `DELEGATECALL`, `STATICCALL`, `CREATE`, and `CREATE2`), add the cost of the instruction to the address' current sum in the mapping. + +For EVM instructions which do instantiate new frames, greater care must be taken to determine the cost of the instruction to the calling frame. For simplicity, this cost is defined to be the total cost of the operation minus the amount of gas passed to the child frame. The gas passed to the child frame is determined via [EIP-150](./eip-150.md). The computed cost is added to the address' current sum in the mapping. + +Additionally: + +- If the address does not exist in the mapping, it's total gas used is `0`. +- If the instructions throws an out-of-gas (OOG) error, all remaining gas allocated to execution frame is added to the current total gas used by the address. +- No other exceptional halt adds remaining gas to the counter for the address where the halt occurred. + +#### Setting Revenue Recipient + +Revenue recipients are tracked via a new transaction wide mapping `revenue_recipient` of `address` to `address`. The default value for every key is the key itself. For example, unless set otherwise, the key `0xdead...beef` maps to the value `0xdead...beef`. + +To set a different revenue recipient, a new instruction `SETREVENUERECIPIENT` is introduced with the opcode `0x49`. The operation takes `1` stack element as input and outputs `0` stack elements. + +The `20` least significant bytes of the input stack element is the address of the new revenue recipient for the instruction's caller. The `revenue_recipient` entry is updated to reflect this. + +The instruction costs `3` gas. + +#### Dispersing Revenue + +After a transaction completes, for every element (`addr`, `gas_used`) in `gas_used_by_address`, increase the balance of `revenue_recipient[addr]` by `gas_used * (header.base_fee_per_gas // REVENUE_SHARE_QUOTIENT)` + +## Rationale + +### Tracking Gas Proportionally + +A simpler mechanism would be to send the full transaction revenue to the `to` value of the transaction. This, however, does not accurately reward the composition of many different smart contracts and applications. Additionally, it is not compatible with smart contract wallets which, by definition, are often the first destination of a transaction. + +Maintaining a transaction wide tracker of gas uses makes it possible to distribute revenue to contracts which are genuinely the most utilized. + +### Ephemeral Revenue Recipient Mapping + +Constructing the revenue recipient mapping ephemerally during each transaction appears inefficient on the surface. This value is expected to be relatively static and even if it did need to change, the change could be facilitated by the recipient contract. + +Unfortunately such a change is much more invasive for the EVM. The recipient value would need to be stored somewhere. This would require a modification to the account structure in the state trie. Also, the recipient value would need to be set at some point. This would necessitate either a modification to the `CREATE*` opcodes or a new opcode, similar to `SETREVENUERECIPIENT`, that would be called by initcode to "initialize" the recipient value. + +## Security Considerations + +### Increased Max Block Size/Complexity + +Similar to EIP-1559, we must consider the effects this will have on block size. Depending on the method by which this is implemented, it could increase maximum block size in the event that a significant number of contracts opt-in to CSR. + + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-6981.md b/EIPS/eip-6981.md new file mode 100644 index 0000000000000..4ac21cdf2710e --- /dev/null +++ b/EIPS/eip-6981.md @@ -0,0 +1,532 @@ +--- +eip: 6981 +title: Reserved Ownership Accounts +description: A registry for generating future-deployed smart contract accounts owned by users on external services +author: Paul Sullivan (@sullivph) , Wilkins Chung (@wwchung) , Kartik Patel (@Slokh) +discussions-to: https://ethereum-magicians.org/t/erc-6981-reserved-ownership-accounts/14118 +status: Draft +type: Standards Track +category: ERC +created: 2023-04-25 +requires: 1167, 1271, 6492 +--- + +## Abstract + +The following specifies a system for services to link their users to a claimable Ethereum address. Services can provide a signed message and unique salt to their users which can be used to deploy a smart contract wallet to the deterministic address through a registry contract using the `create2` opcode. + +## Motivation + +It is common for web services to allow their users to hold on-chain assets via custodial wallets. These wallets are typically EOAs, deployed smart contract wallets or omnibus contracts, with private keys or asset ownership information stored on a traditional database. This proposal outlines a solution that avoids the security concerns associated with historical approaches, and rids the need and implications of services controlling user assets + +Users on external services that choose to leverage the following specification can be given an Ethereum address to receive assets without the need to do any on-chain transaction. These users can choose to attain control of said addresses at a future point in time. Thus, on-chain assets can be sent to and owned by a user beforehand, therefore enabling the formation of an on-chain identity without requiring the user to interact with the underlying blockchain. + +## Specification + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. + +### Overview + +The system for creating reserved ownership accounts consists of: + +1. An Account Registry which provides deterministic addresses based on the service users' identifying salts, and implements a signature verified function that enables claiming of Account Instances by the service's end users. +2. Account Instances created through the Account Registry by end users which allow access to the assets received at the deterministic address prior to Account Instance deployment. + +External services wishing to provide their users with reserved ownership accounts MUST maintain a relationship between a user's identifying credentials and a salt. The external service SHALL refer to an Account Registry Instance to retrieve the deterministic account address for a given salt. Users of a given service MUST be able to create an Account Instance by validating their identifying credentials via the external service, which SHOULD give the user a signed message for their salt. Signatures SHOULD be generated by the external service using an signing address known to the Account Registry Instance. Users SHALL pass this message and signature to the service's Account Registry Instance in a call to `claimAccount` to deploy and claim an Account Instance at the deterministic address. + +### Account Registry + +The Account Registry MUST implement the following interface: + +```solidity +interface IAccountRegistry { + /** + * @dev Registry instances emit the AccountCreated event upon successful account creation + */ + event AccountCreated(address account, address accountImplementation, uint256 salt); + + /** + * @dev Registry instances emit the AccountClaimed event upon successful claim of account by owner + */ + event AccountClaimed(address account, address owner); + + /** + * @dev Creates a smart contract account. + * + * If account has already been created, returns the account address without calling create2. + * + * @param salt - The identifying salt for which the user wishes to deploy an Account Instance + * + * Emits AccountCreated event + * @return the address for which the Account Instance was created + */ + function createAccount(uint256 salt) external returns (address); + + /** + * @dev Allows an owner to claim a smart contract account created by this registry. + * + * If the account has not already been created, the account will be created first using `createAccount` + * + * @param owner - The initial owner of the new Account Instance + * @param salt - The identifying salt for which the user wishes to deploy an Account Instance + * @param expiration - If expiration > 0, represents expiration time for the signature. Otherwise + * signature does not expire. + * @param message - The keccak256 message which validates the owner, salt, expiration + * @param signature - The signature which validates the owner, salt, expiration + * + * Emits AccountClaimed event + * @return the address of the claimed Account Instance + */ + function claimAccount( + address owner, + uint256 salt, + uint256 expiration, + bytes32 message, + bytes calldata signature + ) external returns (address); + + /** + * @dev Returns the computed address of a smart contract account for a given identifying salt + * + * @return the computed address of the account + */ + function account(uint256 salt) external view returns (address); + + /** + * @dev Fallback signature verification for unclaimed accounts + */ + function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4); +} +``` + +#### createAccount + +`createAccount` is used to deploy the Account Instance for a given salt. + +- This function MUST deploy a new Account Instance as a [ERC-1167](./eip-1167.md) proxy pointing to the account implementation. +- This function SHOULD set the initial owner of the Account Instance to the Account Registry Instance. +- The account implementation address MUST be immutable, as it is used to compute the deterministic address for the Account Instance. +- Upon successful deployment of the Account Instance, the registry SHOULD emit an `AccountCreated` event. + +#### claimAccount + +`claimAccount` is used to claim ownership of the Account Instance for a given salt. + +- This function MUST create a new Account Instance if one does not already exist for the given salt. +- This function SHOULD verify that the msg.sender has permission to claim ownership over the Account Instance for the identifying salt and initial owner. Verification SHOULD be done by validating the message and signature against the owner, salt and expiration using ECDSA for EOA signers, or [ERC-1271](./eip-1271.md) for smart contract signers. +- This function SHOULD verify that the block.timestamp < expiration or that expiration == 0. +- Upon successful signature verification on calls to `claimAccount`, the registry MUST completely relinquish control over the Account Instance, and assign ownership to the initial owner by calling `setOwner` on the Account Instance. +- Upon successful claim of the Account Instance, the registry SHOULD emit an `AccountClaimed` event. + +#### isValidSignature + +`isValidSignature` is a fallback signature verification function used by unclaimed accounts. Valid signatures SHALL be generated by the registry signer by signing a composite hash of the original message hash, and the Account Instance address (e.g. `bytes32 compositeHash = keccak256(abi.encodePacked(originalHash, accountAddress))`). The function MUST reconstruct the composite hash, where `originalHash` is the hash passed to the function, and `accountAddress` is `msg.sender` (the unclaimed Account Instance). The function MUST verify the signature against the composite hash and registry signer. + +### Account Instance + +The Account Instance MUST implement the following interface: + +```solidity +interface IAccount is IERC1271 { + /** + * @dev Sets the owner of the Account Instance. + * + * Only callable by the current owner of the instance, or by the registry if the Account + * Instance has not yet been claimed. + * + * @param owner - The new owner of the Account Instance + */ + function setOwner(address owner) external; +} +``` + +- All Account Instances MUST be created using an Account Registry Instance. +- Account Instances SHOULD provide access to assets previously sent to the address at which the Account Instance is deployed to. +- `setOwner` SHOULD update the owner and SHOULD be callable by the current owner of the Account Instance. +- If an Account Instance is deployed, but not claimed, the owner of the Account Instance MUST be initialized to the Account Registry Instance. +- An Account Instance SHALL determine if it has been claimed by checking if the owner is the Account Registry Instance. + +#### Account Instance Signatures + +Account Instances MUST support [ERC-1271](./eip-1271.md) by implementing an `isValidSignature` function. When the owner of an Account Instance wants to sign a message (e.g. to log in to a dApp), the signature MUST be generated in one of the following ways, depending the state of the Account Instance: + +1. If the Account instance is deployed and claimed, the owner should generate the signature, and `isValidSignature` SHOULD verify that the message hash and signature are valid for the current owner of the Account Instance. +2. If the Account Instance is deployed, but unclaimed, the registry signer should generate the signature using a composite hash of the original message and address of the Account Instance described [above](#isvalidsignature), and `isValidSignature` SHOULD forward the message hash and signature to the Account Registry Instance's `isValidSignature` function. +3. If the Account Instance is not deployed, the registry signer should generate a signature on the composite hash as done in situation 2, and wrap the signature according to [ERC-6492](./eip-6492.md#signer-side) (e.g. `concat(abi.encode((registryAddress, createAccountCalldata, compositeHashSignature), (address, bytes, bytes)), magicBytes)`). + +Signature validation for Account Instances should be done according to [ERC-6492](./eip-6492.md#verifier-side). + +## Rationale + +### Service-Owned Registry Instances + +While it might seem more user-friendly to implement and deploy a universal registry for reserved ownership accounts, we believe that it is important for external service providers to have the option to own and control their own Account Registry. This provides the flexibility of implementing their own permission controls and account deployment authorization frameworks. + +We are providing a reference Registry Factory which can deploy Account Registries for an external service, which comes with: + +- Immutable Account Instance implementation +- Validation for the `claimAccount` method via ECDSA for EOA signers, or [ERC-1271](./eip-1271.md) validation for smart contract signers +- Ability for the Account Registry deployer to change the signing addressed used for `claimAccount` validation + +### Account Registry and Account Implementation Coupling + +Since Account Instances are deployed as [ERC-1167](./eip-1167.md) proxies, the account implementation address affects the addresses of accounts deployed from a given Account Registry. Requiring that registry instances be linked to a single, immutable account implementation ensures consistency between a user's salt and linked address on a given Account Registry Instance. + +This also allows services to gain the the trust of users by deploying their registries with a reference to a trusted account implementation address. + +Furthermore, account implementations can be designed as upgradeable, so users are not necessarily bound to the implementation specified by the Account Registry Instance used to create their account. + +### Separate `createAccount` and `claimAccount` Operations + +Operations to create and claim Account Instances are intentionally separate. This allows services to provide users with valid [ERC-6492](./eip-6492.md) signatures before their Account Instance has been deployed. + +## Reference Implementation + +The following is an example of an Account Registry Factory which can be used by external service providers to deploy their own Account Registry Instance. + +### Account Registry Factory + +```solidity +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.13; + +/// @author: manifold.xyz + +import {Create2} from "openzeppelin/utils/Create2.sol"; + +import {Address} from "../../lib/Address.sol"; +import {ERC1167ProxyBytecode} from "../../lib/ERC1167ProxyBytecode.sol"; +import {IAccountRegistryFactory} from "./IAccountRegistryFactory.sol"; + +contract AccountRegistryFactory is IAccountRegistryFactory { + using Address for address; + + error InitializationFailed(); + + address private immutable registryImplementation = 0x076B08EDE2B28fab0c1886F029cD6d02C8fF0E94; + + function createRegistry( + uint96 index, + address accountImplementation, + bytes calldata accountInitData + ) external returns (address) { + bytes32 salt = _getSalt(msg.sender, index); + bytes memory code = ERC1167ProxyBytecode.createCode(registryImplementation); + address _registry = Create2.computeAddress(salt, keccak256(code)); + + if (_registry.isDeployed()) return _registry; + + _registry = Create2.deploy(0, salt, code); + + (bool success, ) = _registry.call( + abi.encodeWithSignature( + "initialize(address,address,bytes)", + msg.sender, + accountImplementation, + accountInitData + ) + ); + if (!success) revert InitializationFailed(); + + emit AccountRegistryCreated(_registry, accountImplementation, index); + + return _registry; + } + + function registry(address deployer, uint96 index) external view override returns (address) { + bytes32 salt = _getSalt(deployer, index); + bytes memory code = ERC1167ProxyBytecode.createCode(registryImplementation); + return Create2.computeAddress(salt, keccak256(code)); + } + + function _getSalt(address deployer, uint96 index) private pure returns (bytes32) { + return bytes32(abi.encodePacked(deployer, index)); + } +} +``` + +### Account Registry + +```solidity +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.13; + +/// @author: manifold.xyz + +import {Create2} from "openzeppelin/utils/Create2.sol"; +import {ECDSA} from "openzeppelin/utils/cryptography/ECDSA.sol"; +import {Ownable} from "openzeppelin/access/Ownable.sol"; +import {Initializable} from "openzeppelin/proxy/utils/Initializable.sol"; +import {IERC1271} from "openzeppelin/interfaces/IERC1271.sol"; +import {SignatureChecker} from "openzeppelin/utils/cryptography/SignatureChecker.sol"; + +import {Address} from "../../lib/Address.sol"; +import {IAccountRegistry} from "../../interfaces/IAccountRegistry.sol"; +import {ERC1167ProxyBytecode} from "../../lib/ERC1167ProxyBytecode.sol"; + +contract AccountRegistryImplementation is Ownable, Initializable, IAccountRegistry { + using Address for address; + using ECDSA for bytes32; + + struct Signer { + address account; + bool isContract; + } + + error InitializationFailed(); + error ClaimFailed(); + error Unauthorized(); + + address public accountImplementation; + bytes public accountInitData; + Signer public signer; + + constructor() { + _disableInitializers(); + } + + function initialize( + address owner, + address accountImplementation_, + bytes calldata accountInitData_ + ) external initializer { + _transferOwnership(owner); + accountImplementation = accountImplementation_; + accountInitData = accountInitData_; + } + + /** + * @dev See {IAccountRegistry-createAccount} + */ + function createAccount(uint256 salt) external override returns (address) { + bytes memory code = ERC1167ProxyBytecode.createCode(accountImplementation); + address _account = Create2.computeAddress(bytes32(salt), keccak256(code)); + + if (_account.isDeployed()) return _account; + + _account = Create2.deploy(0, bytes32(salt), code); + + (bool success, ) = _account.call(accountInitData); + if (!success) revert InitializationFailed(); + + emit AccountCreated(_account, accountImplementation, salt); + + return _account; + } + + /** + * @dev See {IAccountRegistry-claimAccount} + */ + function claimAccount( + address owner, + uint256 salt, + uint256 expiration, + bytes32 message, + bytes calldata signature + ) external override returns (address) { + _verify(owner, salt, expiration, message, signature); + address _account = this.createAccount(salt); + + (bool success, ) = _account.call( + abi.encodeWithSignature("transferOwnership(address)", owner) + ); + if (!success) revert ClaimFailed(); + + emit AccountClaimed(_account, owner); + return _account; + } + + /** + * @dev See {IAccountRegistry-account} + */ + function account(uint256 salt) external view override returns (address) { + bytes memory code = ERC1167ProxyBytecode.createCode(accountImplementation); + return Create2.computeAddress(bytes32(salt), keccak256(code)); + } + + /** + * @dev See {IAccountRegistry-isValidSignature} + */ + function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4) { + bytes32 expectedHash = keccak256(abi.encodePacked(hash, msg.sender)); + bool isValid = SignatureChecker.isValidSignatureNow( + signer.account, + expectedHash, + signature + ); + if (isValid) { + return IERC1271.isValidSignature.selector; + } + + return ""; + } + + function updateSigner(address newSigner) external onlyOwner { + uint32 signerSize; + assembly { + signerSize := extcodesize(newSigner) + } + signer.account = newSigner; + signer.isContract = signerSize > 0; + } + + function _verify( + address owner, + uint256 salt, + uint256 expiration, + bytes32 message, + bytes calldata signature + ) internal view { + address signatureAccount; + + if (signer.isContract) { + if (!SignatureChecker.isValidSignatureNow(signer.account, message, signature)) + revert Unauthorized(); + } else { + signatureAccount = message.recover(signature); + } + + bytes32 expectedMessage = keccak256( + abi.encodePacked("\x19Ethereum Signed Message:\n84", owner, salt, expiration) + ); + + if ( + message != expectedMessage || + (!signer.isContract && signatureAccount != signer.account) || + (expiration != 0 && expiration < block.timestamp) + ) revert Unauthorized(); + } +} +``` + +### Example Account Implementation + +```solidity +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.13; + +/// @author: manifold.xyz + +import {IERC1271} from "openzeppelin/interfaces/IERC1271.sol"; +import {SignatureChecker} from "openzeppelin/utils/cryptography/SignatureChecker.sol"; +import {IERC165} from "openzeppelin/utils/introspection/IERC165.sol"; +import {ERC165Checker} from "openzeppelin/utils/introspection/ERC165Checker.sol"; +import {IERC721} from "openzeppelin/token/ERC721/IERC721.sol"; +import {IERC721Receiver} from "openzeppelin/token/ERC721/IERC721Receiver.sol"; +import {IERC1155Receiver} from "openzeppelin/token/ERC1155/IERC1155Receiver.sol"; +import {Initializable} from "openzeppelin/proxy/utils/Initializable.sol"; +import {Ownable} from "openzeppelin/access/Ownable.sol"; +import {IERC1967Account} from "./IERC1967Account.sol"; + +import {IAccount} from "../../interfaces/IAccount.sol"; + +/** + * @title ERC1967AccountImplementation + * @notice A lightweight, upgradeable smart contract wallet implementation + */ +contract ERC1967AccountImplementation is + IAccount, + IERC165, + IERC721Receiver, + IERC1155Receiver, + IERC1967Account, + Initializable, + Ownable +{ + address public registry; + + constructor() { + _disableInitializers(); + } + + function initialize() external initializer { + registry = msg.sender; + _transferOwnership(registry); + } + + function supportsInterface(bytes4 interfaceId) external pure returns (bool) { + return (interfaceId == type(IAccount).interfaceId || + interfaceId == type(IERC1967Account).interfaceId || + interfaceId == type(IERC1155Receiver).interfaceId || + interfaceId == type(IERC721Receiver).interfaceId || + interfaceId == type(IERC165).interfaceId); + } + + function onERC721Received( + address, + address, + uint256, + bytes memory + ) public pure returns (bytes4) { + return this.onERC721Received.selector; + } + + function onERC1155Received( + address, + address, + uint256, + uint256, + bytes memory + ) public pure returns (bytes4) { + return this.onERC1155Received.selector; + } + + function onERC1155BatchReceived( + address, + address, + uint256[] memory, + uint256[] memory, + bytes memory + ) public pure returns (bytes4) { + return this.onERC1155BatchReceived.selector; + } + + /** + * @dev {See IERC1967Account-executeCall} + */ + function executeCall( + address _target, + uint256 _value, + bytes calldata _data + ) external payable override onlyOwner returns (bytes memory _result) { + bool success; + // solhint-disable-next-line avoid-low-level-calls + (success, _result) = _target.call{value: _value}(_data); + require(success, string(_result)); + emit TransactionExecuted(_target, _value, _data); + return _result; + } + + /** + * @dev {See IAccount-setOwner} + */ + function setOwner(address _owner) external override onlyOwner { + _transferOwnership(_owner); + } + + receive() external payable {} + + function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4) { + if (owner() == registry) { + return IERC1271(registry).isValidSignature(hash, signature); + } + + bool isValid = SignatureChecker.isValidSignatureNow(owner(), hash, signature); + if (isValid) { + return IERC1271.isValidSignature.selector; + } + + return ""; + } +} +``` + +## Security Considerations + +### Front-running + +Deployment of reserved ownership accounts through an Account Registry Instance through calls to `createAccount` could be front-run by a malicious actor. However, if the malicious actor attempted to alter the `owner` parameter in the calldata, the Account Registry Instance would find the signature to be invalid, and revert the transaction. Thus, any successful front-running transaction would deploy an identical Account Instance to the original transaction, and the original owner would still gain control over the address. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-6982.md b/EIPS/eip-6982.md new file mode 100644 index 0000000000000..a307da5ad4034 --- /dev/null +++ b/EIPS/eip-6982.md @@ -0,0 +1,90 @@ +--- +eip: 6982 +title: Efficient Default Lockable Tokens +description: A gas-efficient approach to lockable ERC-721 tokens +author: Francesco Sullo (@sullof), Alexe Spataru (@urataps) +discussions-to: https://ethereum-magicians.org/t/erc721-default-lockable-proposal/13366 +status: Draft +type: Standards Track +category: ERC +created: 2023-05-02 +requires: 165, 721 +--- + +## Abstract + +This proposal introduces a lockable interface for [ERC-721](./eip-721.md) tokens that optimizes gas usage by eliminating unnecessary events. This interface forms the foundation for the creation and management of lockable [ERC-721](./eip-721.md) tokens. It provides a gas-efficient approach by emitting a `DefaultLocked(bool locked)` event upon deployment, setting the initial lock status for all tokens, while individual `Locked(uint256 indexed tokenId, bool locked)` events handle subsequent status changes for specific tokens. The interface also includes a view function `locked(uint256 tokenId)` to return the current lock status of a token. + +## Motivation + +Existing lockable token proposals often mandate the emission of an event each time a token is minted. This results in unnecessary gas consumption, especially in cases where tokens are permanently locked from inception to destruction (e.g., soulbounds or non-transferable badges). This proposal offers a more gas-efficient solution that only emits events upon contract deployment and status changes of individual tokens. + +## Specification + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. + +The interface is defined as follows: + +```solidity +// ERC165 interfaceId 0x6b61a747 +interface IERC6982 { + // This event MUST be emitted upon deployment of the contract, establishing + // the default lock status for any tokens that will be minted in the future. + // If the default lock status changes for any reason, this event + // MUST be re-emitted to update the default status for all tokens. + // Note that emitting a new DefaultLocked event does not affect the lock + // status of any tokens for which a Locked event has previously been emitted. + event DefaultLocked(bool locked); + + // This event MUST be emitted whenever the lock status of a specific token + // changes, effectively overriding the default lock status for this token. + event Locked(uint256 indexed tokenId, bool locked); + + // This function returns the current default lock status for tokens. + // It reflects the value set by the latest DefaultLocked event. + function defaultLocked() external view returns (bool); + + // This function returns the lock status of a specific token. + // If no Locked event has been emitted for a given tokenId, it MUST return + // the value that defaultLocked() returns, which represents the default + // lock status. + // This function MUST revert if the token does not exist. + function locked(uint256 tokenId) external view returns (bool); +} +``` + +The [ERC-165](./eip-165.md) interfaceId is `0x6b61a747`. + +## Rationale + +This standard seeks to optimize gas consumption by minimizing the frequency of event emission. The DefaultLocked event is designed to establish the lock status for all tokens, thereby circumventing the need to emit an event each time a new token is minted. It's crucial to note that the DefaultLocked event can be emitted at any point in time, and is not restricted to only before the Locked events are emitted. + +Tokens may alter their behavior under certain circumstances (such as after a reveal), prompting the re-emission of the DefaultLocked event to reflect the new default status. The primary objective here is to economize on gas usage by avoiding the need to emit a Locked event for each token when the default status changes. + +The Locked event is utilized to document changes in the lock status of individual tokens. + +The defaultLocked function returns the prevailing default lock status of a token. This function is beneficial as it fosters interaction with other contracts and averts potential conflicts with [ERC-5192](./eip-5192), which is in its final stage. + +The locked function gives the current lock status of a particular token, further facilitating interaction with other contracts. If no changes have been made to a specific token ID, this function should return the value provided by the defaultLocked function. + +Bear in mind that a token being designated as "locked" doesn't necessarily imply that it is entirely non-transferable. There might be certain conditions under which a token can still be transferred despite its locked status. Primarily, the locked status relates to a token's transferability on marketplaces and external exchanges. + +To illustrate, let's consider the Cruna protocol. In this system, an NFT owner has the ability to activate what is termed an 'initiator'. This is essentially a secondary wallet with the unique privilege of initiating key transactions. Upon setting an initiator, the token's status is rendered 'locked'. However, this does not impede the token's transferability if the initiation for the transfer comes from the designated initiator. + +## Backwards Compatibility + +This standard is fully backwards compatible with existing [ERC-721](./eip-721.md) contracts. It can be easily integrated into existing contracts and will not cause any conflicts or disruptions. + +## Reference Implementation + +An example implementation is located in the [assets](../assets/eip-6982) directory. + +It solves a specific use case: token's owners losing the ownership when staking the asset in a pool. The implementation allow the pool to lock the asset, leaving the ownership to the owner. In the [README](../assets/eip-6982/README.md) you can find more details about how to compile and test the contracts. + +## Security Considerations + +This EIP does not introduce any known security considerations. However, as with any smart contract standard, it is crucial to employ rigorous security measures in the implementation of this interface. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-6988.md b/EIPS/eip-6988.md new file mode 100644 index 0000000000000..f7816ad40f61c --- /dev/null +++ b/EIPS/eip-6988.md @@ -0,0 +1,60 @@ +--- +eip: 6988 +title: Elected block proposer has not been slashed +description: Prevents a slashed validator from being elected as a block proposer +author: Mikhail Kalinin (@mkalinin) +discussions-to: https://ethereum-magicians.org/t/eip-6988-elected-block-proposer-has-not-been-slashed/14349 +status: Draft +type: Standards Track +category: Core +created: 2023-05-04 +--- + +## Abstract + +Introduces a modification to the consensus layer specification which ensures that slashed validator cannot be elected as block proposer. + +## Motivation + +A block proposed by a slashed validator is rejected by the corresponding validity check in the [`phase0/process_block_header`](https://github.com/ethereum/consensus-specs/blob/3115d1140b23dd4c9c23fbd9e2428186cf816bde/specs/phase0/beacon-chain.md#block-header) function as defined in the consensus layer specification. + +At the same time the definition of the [`phase0/compute_proposer_index`](https://github.com/ethereum/consensus-specs/blob/3115d1140b23dd4c9c23fbd9e2428186cf816bde/specs/phase0/beacon-chain.md#compute_proposer_index) allows for a slashed validator to be elected as a proposer. This contradiction effectively leads to a missed proposal if it is supposed to be made by a slashed validator. + +The impact of the proposed fix in the case of a single slashing on Ethereum Mainnet is negligible but it becomes significant in the case of correlated slashings. For instance, a correlated slashing of `1/10th` of a validator set can lead to `1/10th` of missed proposals in a number of epochs after the slashing. + +## Specification + +Specification of the proposed change can be found in [`/_features/eip6988/beacon-chain.md`](https://github.com/ethereum/consensus-specs/blob/0ad3972725e7c22e8edf3bab2dd7730acbe3c272/specs/_features/eip6988/beacon-chain.md). + +## Rationale + +### Modifying `get_beacon_proposer_index` + +This function is modified to read a proposer index from a beacon state if a slot of a latest block header is the same as the `state.slot`. + +This modification is done to make the function return correct proposer index in the case when the proposer of a given block is being slashed during processing of the block. + +## Backwards Compatibility + +This fix changes proposer election mechanism in a backwards incompatible way and requires a hard fork to be deployed. + +## Test Cases + +The following test cases were added to cover this change: + +* [`test_slashed_proposer_rewarded_for_sync_aggregate_inclusion`](https://github.com/ethereum/consensus-specs/blob/0ad3972725e7c22e8edf3bab2dd7730acbe3c272/tests/core/pyspec/eth2spec/test/altair/block_processing/sync_aggregate/test_process_sync_aggregate.py#L712) +* [`test_slashed_proposer_rewarded_for_attestation_inclusion`](https://github.com/ethereum/consensus-specs/blob/0ad3972725e7c22e8edf3bab2dd7730acbe3c272/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_attestation.py#L17) +* [`test_slashed_validator_not_elected_for_proposal`](https://github.com/ethereum/consensus-specs/blob/0ad3972725e7c22e8edf3bab2dd7730acbe3c272/tests/core/pyspec/eth2spec/test/eip6988/unittests/validator/test_validator.py#L9) +* [`test_slashed_validator_elected_for_proposal`](https://github.com/ethereum/consensus-specs/blob/0ad3972725e7c22e8edf3bab2dd7730acbe3c272/tests/core/pyspec/eth2spec/test/phase0/unittests/validator/test_validator_unittest.py#L520) + +## Reference Implementation + +Reference implementation is in the same place as [Specification](#specification). + +## Security Considerations + +There are no observed security issues introduced by the proposed change. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-6997.md b/EIPS/eip-6997.md new file mode 100644 index 0000000000000..3c66b382e7062 --- /dev/null +++ b/EIPS/eip-6997.md @@ -0,0 +1,381 @@ +--- +eip: 6997 +title: ERC-721 with transaction validation step. +description: A new validation step for transfer and approve calls, achieving a security step in case of stolen wallet. +author: Eduard López i Fina (@eduardfina) +discussions-to: https://ethereum-magicians.org/t/erc721-with-a-validation-step/14071 +status: Review +type: Standards Track +category: ERC +created: 2023-05-07 +requires: 721 +--- + +## Abstract + +This standard is an extension of [ERC-721](./eip-721.md). It defines new validation functionality to avoid wallet draining: every `transfer` or `approve` will be locked waiting for validation. + +## Motivation + +The power of the blockchain is at the same time its weakness: giving the user full responsibility for their data. + +Many cases of NFT theft currently exist, and current NFT anti-theft schemes, such as transferring NFTs to cold wallets, make NFTs inconvenient to use. + +Having a validation step before every `transfer` and `approve` would give Smart Contract developers the opportunity to create secure NFT anti-theft schemes. + +An implementation example would be a system where a validator address is responsible for validating all Smart Contract transactions. + +This address would be connected to a dApp where the user could see the validation requests of his NFTs and accept the correct ones. + +Giving this address only the power to validate transactions would make a much more secure system where to steal an NFT the thief would have to have both the user's address and the validator address simultaneously. + +## Specification + +The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY" and "OPTIONAL" in this document are to be interpreted as described in RFC 2119. + +[ERC-721](./eip-721.md) compliant contracts MAY implement this EIP. + +All the operations that change the ownership of an NFT, like a `transferFrom`/`safeTransferFrom`, SHALL create a `TransferValidation` pending to be validated and emit a `ValidateTransfer`, and SHALL NOT transfer the ownership of an NFT. + +All the operations that enable an approval to manage an NFT, like an `approve`/`setApprovalForAll`, SHALL create an `ApprovalValidation` pending to be validated and emit a `ValidateApproval`, and SHALL NOT enable an approval. + +When the transfer is called by an approved account and not the owner, it MUST be executed directly without the need for validation. This is in order to adapt to all current marketplaces that require approve to directly move your NFTs. + +When validating a `TransferValidation` or `ApprovalValidation` the valid field MUST be set to true and MUST NOT be validated again. + +The operations that validate a `TransferValidation` SHALL change the ownership of the NFT or enable the approval. + +The operations that validate an `ApprovalValidation` SHALL enable the approval. + +### Contract Interface + +```solidity + interface IERC6997 { + + struct TransferValidation { + // The address of the owner. + address from; + // The address of the receiver. + address to; + // The token Id. + uint256 tokenId; + // Whether is a valid transfer. + bool valid; + } + + struct ApprovalValidation { + // The address of the owner. + address owner; + // The approved address. + address approve; + // The token Id. + uint256 tokenId; + // Wether is a total approvement. + bool approveAll; + // Whether is a valid approve. + bool valid; + } + + /** + * @dev Emitted when a new transfer validation has been requested. + */ + event ValidateTransfer(address indexed from, address to, uint256 indexed tokenId, uint256 indexed transferValidationId); + + /** + * @dev Emitted when a new approval validation has been requested. + */ + event ValidateApproval(address indexed owner, address approve, uint256 tokenId, bool indexed approveAll, uint256 indexed approvalValidationId); + + /** + * @dev Returns true if this contract is a validator ERC721. + */ + function isValidatorContract() external view returns (bool); + + /** + * @dev Returns the transfer validation struct using the transfer ID. + * + */ + function transferValidation(uint256 transferId) external view returns (TransferValidation memory); + + /** + * @dev Returns the approval validation struct using the approval ID. + * + */ + function approvalValidation(uint256 approvalId) external view returns (ApprovalValidation memory); + + /** + * @dev Return the total amount of transfer validations created. + * + */ + function totalTransferValidations() external view returns (uint256); + + /** + * @dev Return the total amount of transfer validations created. + * + */ + function totalApprovalValidations() external view returns (uint256); +} + ``` + +The `isValidatorContract()` function MUST be implemented as `public`. + +The `transferValidation(uint256 transferId)` function MAY be implemented as `public` or `external`. + +The `approvalValidation(uint256 approveId)` function MAY be implemented as `public` or `external`. + +The `totalTransferValidations()` function MAY be implemented as `pure` or `view`. + +The `totalApprovalValidations()` function MAY be implemented as `pure` or `view`. + +## Rationale + +### Universality + +The standard only defines the validation functions, but not how they should be used. It defines the validations as internal and lets the user decide how to manage them. + +An example could be to have an address validator connected to a dApp so that users could manage their validations. + +This validator could be used for all NFTs or only for some users. + +It could also be used as a wrapped Smart Contract for existing ERC-721, allowing 1/1 conversion with existing NFTs. + +### Extensibility + +This standard only defines the validation function, but does not define the system with which it has to be validated. A third-party protocol can define how it wants to call these functions as it wishes. + +## Backwards Compatibility + +This standard is an extension of [ERC-721](./eip-721.md), compatible with all the operations except `transferFrom`/`safeTransferFrom`/`approve`/`setApprovalForAll`. + +This operations will be overridden to create a validation petition instead of transfer ownership of an NFT or enable an approval. + +## Reference Implementation + +```solidity +// SPDX-License-Identifier: CC0-1.0 + +pragma solidity ^0.8.0; + +import "./IERC6997.sol"; +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; + +/** + * @dev Implementation of ERC6997 + */ +contract ERC6997 is IERC6997, ERC721 { + + // Mapping from transfer ID to transfer validation + mapping(uint256 => TransferValidation) private _transferValidations; + + // Mapping from approval ID to approval validation + mapping(uint256 => ApprovalValidation) private _approvalValidations; + + // Total number of transfer validations + uint256 private _totalTransferValidations; + + // Total number of approval validations + uint256 private _totalApprovalValidations; + + /** + * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. + */ + constructor(string memory name_, string memory symbol_) ERC721(name_, symbol_){ + } + + /** + * @dev Returns true if this contract is a validator ERC721. + */ + function isValidatorContract() public pure returns (bool) { + return true; + } + + /** + * @dev Returns the transfer validation struct using the transfer ID. + * + */ + function transferValidation(uint256 transferId) public view override returns (TransferValidation memory) { + require(transferId < _totalTransferValidations, "ERC6997: invalid transfer ID"); + TransferValidation memory v = _transferValidation(transferId); + + return v; + } + + /** + * @dev Returns the approval validation struct using the approval ID. + * + */ + function approvalValidation(uint256 approvalId) public view override returns (ApprovalValidation memory) { + require(approvalId < _totalApprovalValidations, "ERC6997: invalid approval ID"); + ApprovalValidation memory v = _approvalValidation(approvalId); + + return v; + } + + /** + * @dev Return the total amount of transfer validations created. + * + */ + function totalTransferValidations() public view override returns (uint256) { + return _totalTransferValidations; + } + + /** + * @dev Return the total amount of approval validations created. + * + */ + function totalApprovalValidations() public view override returns (uint256) { + return _totalApprovalValidations; + } + + /** + * @dev Returns the transfer validation of the `transferId`. Does NOT revert if transfer doesn't exist + */ + function _transferValidation(uint256 transferId) internal view virtual returns (TransferValidation memory) { + return _transferValidations[transferId]; + } + + /** + * @dev Returns the approval validation of the `approvalId`. Does NOT revert if transfer doesn't exist + */ + function _approvalValidation(uint256 approvalId) internal view virtual returns (ApprovalValidation memory) { + return _approvalValidations[approvalId]; + } + + /** + * @dev Validate the transfer using the transfer ID. + * + */ + function _validateTransfer(uint256 transferId) internal virtual { + TransferValidation memory v = transferValidation(transferId); + require(!v.valid, "ERC6997: the transfer is already validated"); + + address from = v.from; + address to = v.to; + uint256 tokenId = v.tokenId; + + super._transfer(from, to, tokenId); + + _transferValidations[transferId].valid = true; + } + + /** + * @dev Validate the approval using the approval ID. + * + */ + function _validateApproval(uint256 approvalId) internal virtual { + ApprovalValidation memory v = approvalValidation(approvalId); + require(!v.valid, "ERC6997: the approval is already validated"); + + if(!v.approveAll) { + require(v.owner == ownerOf(v.tokenId), "ERC6997: The token have a new owner"); + super._approve(v.approve, v.tokenId); + } + else { + super._setApprovalForAll(v.owner, v.approve, true); + } + + _approvalValidations[approvalId].valid = true; + } + + /** + * @dev Create a transfer petition of `tokenId` from `from` to `to`. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {TransferValidate} event. + */ + function _transfer( + address from, + address to, + uint256 tokenId + ) internal virtual override { + require(ERC721.ownerOf(tokenId) == from, "ERC6997: transfer from incorrect owner"); + require(to != address(0), "ERC6997: transfer to the zero address"); + + if(_msgSender() == from) { + TransferValidation memory v; + + v.from = from; + v.to = to; + v.tokenId = tokenId; + + _transferValidations[_totalTransferValidations] = v; + + emit ValidateTransfer(from, to, tokenId, _totalTransferValidations); + + _totalTransferValidations++; + } else { + super._transfer(from, to, tokenId); + } + } + + /** + * @dev Create an approval petition from `to` to operate on `tokenId` + * + * Emits an {ValidateApproval} event. + */ + function _approve(address to, uint256 tokenId) internal override virtual { + ApprovalValidation memory v; + + v.owner = ownerOf(tokenId); + v.approve = to; + v.tokenId = tokenId; + + _approvalValidations[_totalApprovalValidations] = v; + + emit ValidateApproval(v.owner, to, tokenId, false, _totalApprovalValidations); + + _totalApprovalValidations++; + } + + /** + * @dev If approved is true create an approval petition from `operator` to operate on + * all of `owner` tokens, if not remove `operator` from operate on all of `owner` tokens + * + * Emits an {ValidateApproval} event. + */ + function _setApprovalForAll( + address owner, + address operator, + bool approved + ) internal override virtual { + require(owner != operator, "ERC6997: approve to caller"); + + if(approved) { + ApprovalValidation memory v; + + v.owner = owner; + v.approve = operator; + v.approveAll = true; + + _approvalValidations[_totalApprovalValidations] = v; + + emit ValidateApproval(v.owner, operator, 0, true, _totalApprovalValidations); + + _totalApprovalValidations++; + } + else { + super._setApprovalForAll(owner, operator, approved); + } + } +} +``` + +## Security Considerations + +As is defined in the Specification the operations that change the ownership of an NFT or enable an approval to manage the NFT SHALL create a `TransferValidation` or an `ApprovalValidation` pending to be validated and SHALL NOT transfer the ownership of an NFT or enable an approval. + +With this premise in mind, the operations in charge of validating a `TransferValidation` or an `ApprovalValidation` must be protected with the maximum security required by the applied system. + +For example, a valid system would be one where there is a validator address in charge of validating the transactions. + +To give another example, a system where each user could choose his validator address would also be correct. + +In any case, the importance of security resides in the fact that no address can validate a `TransferValidation` or an `ApprovalValidation` without the permission of the chosen system. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-7007.md b/EIPS/eip-7007.md new file mode 100644 index 0000000000000..1f439f0085ceb --- /dev/null +++ b/EIPS/eip-7007.md @@ -0,0 +1,164 @@ +--- +eip: 7007 +title: Zero-Knowledge AI-Generated Content Token +description: An ERC-721 extension interface for zkML based AIGC-NFTs. +author: Cathie So (@socathie), Xiaohang Yu (@xhyumiracle), Huaizhe Xu (@HuaizheXu), Kartin +discussions-to: https://ethereum-magicians.org/t/eip-7007-zkml-aigc-nfts-an-erc-721-extension-interface-for-zkml-based-aigc-nfts/14216 +status: Draft +type: Standards Track +category: ERC +created: 2023-05-10 +requires: 165, 721 +--- + +## Abstract + +The Zero-Knowledge Machine Lerning (zkML) AI-Generated Content (AIGC) non-fungible token (NFT) standard is an extension of the [ERC-721](./eip-721.md) token standard for AIGC. It proposes a set of interfaces for basic interactions and enumerable interactions for AIGC-NFTs. The standard includes a new mint event and a JSON schema for AIGC-NFT metadata. Additionally, it incorporates zkML capabilities to enable verification of AIGC-NFT ownership. In this standard, the `tokenId` is indexed by the `prompt`. + +## Motivation + +The zkML AIGC-NFTs standard aims to extend the existing [ERC-721](./eip-721.md) token standard to accommodate the unique requirements of AI-Generated Content NFTs representing models in a collection. This standard provides interfaces to use zkML to verify whether or not the AIGC data for an NFT is generated from a certain ML model with certain input (prompt). The proposed interfaces allow for additional functionality related to minting, verifying, and enumerating AIGC-NFTs. Additionally, the metadata schema provides a structured format for storing information related to AIGC-NFTs, such as the prompt used to generate the content and the proof of ownership. + +With this standard, model owners can publish their trained model and its ZKP verifier to Ethereum. Any user can claim an input (prompt) and publish the inference task, any node that maintains the model and the proving circuit can perform the inference and proving, then submit the output of inference and the ZK proof for the inference trace into the verifier that is deployed by the model owner. The user that initiates the inference task will own the output for the inference of that model and input (prompt). + +## Specification + +The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. + +**Every compliant contract must implement the [ERC-7007](./eip-7007.md), [ERC-721](./eip-721.md), and [ERC-165](./eip-165.md) interfaces.** + +The zkML AIGC-NFTs standard includes the following interfaces: + +`IERC7007`: Defines a mint event and a mint function for minting AIGC-NFTs. It also includes a verify function to check the validity of a combination of prompt and proof using zkML techniques. + +```solidity +pragma solidity ^0.8.18; + +/** + * @dev Required interface of an ERC7007 compliant contract. + * Note: the ERC-165 identifier for this interface is 0x7e52e423. + */ +interface IERC7007 is IERC165, IERC721 { + /** + * @dev Emitted when `tokenId` token is minted. + */ + event Mint( + uint256 indexed tokenId, + bytes indexed prompt, + bytes indexed aigcData, + string uri, + bytes proof + ); + + /** + * @dev Mint token at `tokenId` given `prompt`, `aigcData`, `uri` and `proof`. + * + * Requirements: + * - `tokenId` must not exist.' + * - verify(`prompt`, `aigcData`, `proof`) must return true. + * + * Optional: + * - `proof` should not include `aigcData` to save gas. + */ + function mint( + bytes calldata prompt, + bytes calldata aigcData, + string calldata uri, + bytes calldata proof + ) external returns (uint256 tokenId); + + /** + * @dev Verify the `prompt`, `aigcData` and `proof`. + */ + function verify( + bytes calldata prompt, + bytes calldata aigcData, + bytes calldata proof + ) external view returns (bool success); +} +``` + +Optional Extension: Enumerable + +The **enumeration extension** is OPTIONAL for [ERC-7007](./eip-7007.md) smart contracts. This allows your contract to publish its full list of mapping between `tokenId` and `prompt` and make them discoverable. + +```solidity +pragma solidity ^0.8.18; + +/** + * @title ERC7007 Token Standard, optional enumeration extension + * Note: the ERC-165 identifier for this interface is 0xfa1a557a. + */ +interface IERC7007Enumerable is IERC7007 { + /** + * @dev Returns the token ID given `prompt`. + */ + function tokenId(bytes calldata prompt) external view returns (uint256); + + /** + * @dev Returns the prompt given `tokenId`. + */ + function prompt(uint256 tokenId) external view returns (string calldata); +} +``` + +ERC-7007 Metadata JSON Schema for reference + +```json +{ + "title": "AIGC Metadata", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Identifies the asset to which this NFT represents" + }, + "description": { + "type": "string", + "description": "Describes the asset to which this NFT represents" + }, + "image": { + "type": "string", + "description": "A URI pointing to a resource with mime type image/* representing the asset to which this NFT represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive." + }, + + "prompt": { + "type": "string", + "description": "Identifies the prompt from which this AIGC NFT generated" + }, + "aigc_type": { + "type": "string", + "description": "image/video/audio..." + }, + "aigc_data": { + "type": "string", + "description": "A URI pointing to a resource with mime type image/* representing the asset to which this AIGC NFT represents." + } + } +} +``` + +## Rationale + +TBD + +## Backwards Compatibility + +This standard is backward compatible with the [ERC-721](./eip-721.md) as it extends the existing functionality with new interfaces. + +## Test Cases + +The reference implementation includes sample implementations of the [ERC-7007](./eip-7007.md) interfaces under `contracts/` and corresponding unit tests under `test/`. This repo can be used to test the functionality of the proposed interfaces and metadata schema. + +## Reference Implementation + +* [ERC-7007](../assets/eip-7007/contracts/ERC7007.sol) +* [ERC-7007 Enumerable Extension](../assets/eip-7007/contracts/ERC7007Enumerable.sol) + +## Security Considerations + +Needs discussion. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-7015.md b/EIPS/eip-7015.md new file mode 100644 index 0000000000000..480ec88d067f5 --- /dev/null +++ b/EIPS/eip-7015.md @@ -0,0 +1,184 @@ +--- +eip: 7015 +title: NFT Creator Attribution +description: Extending ERC-721 with cryptographically secured creator attribution. +author: Carlos Flores (@strollinghome) +discussions-to: https://ethereum-magicians.org/t/eip-authorship-attribution-for-erc721/14244 +status: Draft +type: Standards Track +category: ERC +created: 2023-05-11 +requires: 55, 155, 712, 721 +--- + +## Abstract + +This Ethereum Improvement Proposal aims to solve the issue of creator attribution for [ERC-721](./eip-721.md) Non-Fungible Tokens (NFT). To achieve this, this EIP proposes a mechanism where the NFT creator signs the required parameters for the NFT creation, including the NFT metadata and a hash of any other relevant information. The signed parameters and the signature are then validated and emitted during the deployment transaction, which allows the NFT to validate the creator and NFT platforms to attribute creatorship correctly. This method ensures that even if a different wallet sends the deployment transaction, the correct account is attributed as the creator. + +## Motivation + +Current NFT platforms assume that the wallet deploying the smart contract is the creator of the NFT, leading to a misattribution in cases where a different wallet sends the deployment transaction. This happens often when working with smart wallet accounts, and new contract deployment strategies such as the first collector deploying the NFT contract. This proposal aims to solve the problem by allowing creators to sign the parameters required for NFT creation so that any wallet can send the deployment transaction with an signal in a verifiable way who is the creator. + +## Specification + +The keywords “MUST,” “MUST NOT,” “REQUIRED,” “SHALL,” “SHALL NOT,” “SHOULD,” “SHOULD NOT,” “RECOMMENDED,” “MAY,” and “OPTIONAL” in this document are to be interpreted as described in RFC 2119. + +ERC-721 compliant contracts MAY implement this NFT Creator Attribution extension to provide a standard event to be emitted that defines the NFT creator at the time of contract creation. + +This EIP takes advantage of the fact that contract addresses can be precomputed before a contract is deployed. Whether the NFT contract is deployed through another contract (a factory) or through an EOA, the creator can be correctly attributed using this specification. + +**Signing Mechanism** + +Creator consent is given by signing an [EIP-712](./eip-712.md) compatible message; all signatures compliant with this EIP MUST include all fields defined. The struct signed is: + +```solidity +struct CreatorAttribution { + string name; + string symbol; + bytes32 salt; + address token; +} +``` + +Where `name` and `symbol` are the ERC-721 metadata parameters, `salt` is an additional randomness parameter, and `token` is the NFTs address that will be deployed. Any extra parameters used to deploy the NFT contract MAY be hashed into the `salt` parameter. + +**Signature Validation** + +Creator attribution is given through a signature verification that MUST be verified by the NFT contract and an event that MUST be emitted by the NFT contract during the deployment transaction. The event includes all the necessary fields for reconstructing the signed digest and validating the signature to ensure it matches the specified creator. The event name is `CreatorAttribution` and includes the following fields: + +- `name`: ERC-721Metadata name parameter +- `symbol`: ERC-721Metadata symbol parameter +- `salt`: an extra randomness parameter that encodes other relevant information for deploying the NFT contract +- `domainName`: the domain name of the contract verifying the singature (for EIP-712 signature validation) +- `version`: the version of the contract verifying the signature (for EIP-712 signature validation) +- `creator`: the account address for the creator of the NFT +- `signature`: the creator’s signature + +The event is defined as follows: + +```solidity +event CreatorAttribution( + string name, // <------------------------------------- + string symbol, // Parameters signed by creator | + bytes32 salt, // | + string domainName, // <--- EIP-712 Domain Data ------------- + string version, // <------------------------------------- + address creator, // <--- Creator -------------------------- + bytes signature // <--- Creator Signature ---------------- +); +``` + +Note that although the `chainId` parameters is necessary for [EIP-712](./eip-712.md) signatures, we omit the parameter from the event as it can be inferred through the transaction data. Similarly, the `token` parameter in the `CreatorAttribution` stuct MUST match the address of the `emitter` field of the event, hence we omit it as well. + +A platform can verify the validity of the creator attribution by reconstructing the signature digest with the parameters emitted and recovering the signer from the `signature` parameter. The `creator` parameter MUST match the recovered signer from the `signature` parameter. After verification, platforms can safely attribute the `creator` address as the creator instead of the account that submitted the transaction. + +### Reference Implementation + +#### Example signature validator + +```solidity +// SPDX-License-Identifier: CC0-1.0 +pragma solidity 0.8.19; + +import "openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol"; +import "openzeppelin-contracts/contracts/interfaces/IERC1271.sol"; + +abstract contract ERC7015 is EIP712 { + error Invalid_Signature(); + + event CreatorAttribution( + string name, + string symbol, + bytes32 salt, + string domainName, + string version, + address creator, + bytes signature + ); + + /// @notice Define magic value to verify smart contract signatures (ERC1271). + bytes4 internal constant MAGIC_VALUE = + bytes4(keccak256("isValidSignature(bytes32,bytes)")); + + bytes32 public constant TYPEHASH = + keccak256( + "CreatorAttribution(string name,string symbol,bytes32 salt,address token)" + ); + + constructor() EIP712("ERC7015", "1") {} + + function _validateSignature( + string memory name, + string memory symbol, + bytes32 salt, + address creator, + bytes memory signature + ) internal { + if (!_isValid(name, symbol, salt, address(this), creator, signature)) + revert Invalid_Signature(); + + emit CreatorAttribution( + name, + symbol, + salt, + "ERC7015", + "1", + creator, + signature + ); + } + + function _isValid( + string memory name, + string memory symbol, + bytes32 salt, + address token, + address signer, + bytes memory signature + ) internal view returns (bool) { + require(signer != address(0), "cannot validate"); + + bytes32 digest = _hashTypedDataV4( + keccak256(abi.encode(TYPEHASH, name, symbol, salt, token)) + ); + + if (signer.code.length != 0) { + try IERC1271(signer).isValidSignature(digest, signature) returns ( + bytes4 magicValue + ) { + return MAGIC_VALUE == magicValue; + } catch { + return false; + } + } + + address recoveredSigner = ECDSA.recover(digest, signature); + + return recoveredSigner == signer; + } +} +``` + +## Rationale + +By standardizing the `CreatorAttribution` event, this EIP enables platforms to ascertain creator attribution without relying on implicit assumptions. Establishing a standard for creator attribution empowers platforms to manage the complex aspects of deploying contracts while preserving accurate onchain creator information. This approach ensures a more reliable and transparent method for identifying NFT creators, fostering trust among participants in the NFT ecosystem. + +[ERC-5375](./eip-5375.md) attempts to solve the same issue and although offchain data offers improved backward compatibility, ensuring accurate and immutable creator attribution is vital for NFTs. A standardized onchain method for creator attribution is inherently more reliable and secure. + +In contrast to this proposal, ERC-5375 does not facilitate specifying creators for all tokens within an NFT collection, which is a prevalent practice, particularly in emerging use cases. + +Both this proposal and ERC-5375 share similar limitations regarding address-based creator attribution: + +> The standard defines a protocol to verify that a certain *address* provided consent. However, it does not guarantee that the address corresponds to the expected creator […]. Proving a link between an address and the entity behind it is beyond the scope of this document. + +## Backwards Compatibility + +Since the standard requires an event to be emitted during the NFTs deployment transaction, existing NFTs cannot implement this standard. + +## Security Considerations + +A potential attack exploiting this proposal could involve deceiving creators into signing creator attribution consent messages unintentionally. Consequently, creators MUST ensure that all signature fields correspond to the necessary ones before signing. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-7045.md b/EIPS/eip-7045.md new file mode 100644 index 0000000000000..e8fdf043988b0 --- /dev/null +++ b/EIPS/eip-7045.md @@ -0,0 +1,77 @@ +--- +eip: 7045 +title: Increase max attestation inclusion slot +description: Increases max attestaton inclusion slot to the last slot in `N+1` where `N` is the epoch containing the attestation's slot. +author: Danny Ryan (@djrtwo) +discussions-to: https://ethereum-magicians.org/t/eip-7045-increase-attestation-slot-inclusion-range/14342 +status: Draft +type: Standards Track +category: Core +created: 2023-05-18 +--- + +## Abstract + +Increases max attestation inclusion slot from `attestation.slot + SLOTS_PER_EPOCH` to the last slot of epoch `N+1` where `N` is the epoch containing the attestation slot. + +This increase is critical to the current LMD-GHOST security analysis as well as the confirmation rule. + +## Motivation + +Attestations can currently be included after some minimum delay (`1` slot on mainnet) up until `SLOTS_PER_EPOCH` slots after the slot the attestation was created in. This rolling window of one epoch was decided upon during Phase 0 because the equal inclusion window for any attestation was assessed as "fair". The alternative considered path was to allow inclusion during the current and next epoch which means attestations created during the start of an epoch have more potential slots of inclusion than those at the end of the epoch. + +Since this decision, it has become apparent that the alternative design is critical for current LMD-GHOST security proofs as well as a new confirmation rule (which will allow for block confirmations in approximately 3-4 slots in normal mainnet conditions). + +This specification thus increases the max inclusion slot for attestations in accordance with the learned security proof and confirmation rule needs. + +## Specification + +### Constants + +| Name | Value | Comment | +| - | - | - | +|`FORK_TIMESTAMP` | *TBD* | Mainnet | + +### Execution layer + +This requires no changes to the Execution Layer. + +### Consensus layer + +Specification changes are built into the Consensus Specs Deneb upgrade. + +The specification makes two minor changes to the state transition function: + +* Modify [`process_attestation`](https://github.com/ethereum/consensus-specs/blob/95f36d99cf4aa59974da06af24ef9a7c12d3c301/specs/deneb/beacon-chain.md#modified-process_attestation) to not have an upper bound on the slot check and instead define the inclusion range via the minimum slot as well as the target epoch being in either current or previous epoch. +* Modify [`get_attestation_participation_flag_indices`](https://github.com/ethereum/consensus-specs/blob/95f36d99cf4aa59974da06af24ef9a7c12d3c301/specs/deneb/beacon-chain.md#modified-get_attestation_participation_flag_indices) to set the `TIMELY_TARGET_FLAG` without consideration of `inclusion_delay` to ensure that the extended inclusion attestations have a non-zero reward. + +Additionally, the specification modifies the [attestation](https://github.com/ethereum/consensus-specs/blob/95f36d99cf4aa59974da06af24ef9a7c12d3c301/specs/deneb/p2p-interface.md#beacon_attestation_subnet_id) and [aggregate attestation](https://github.com/ethereum/consensus-specs/blob/95f36d99cf4aa59974da06af24ef9a7c12d3c301/specs/deneb/p2p-interface.md#beacon_aggregate_and_proof) gossip conditions to allow for gossip during this extended range. + +## Rationale + +### Extended max inclusion slot + +As discussed in the Motivation, extending this max inclusion slot to the end of the next epoch is critical for LMD-GHOST security proofs and confirmation rule. + +### Removal of `inclusion_delay` consideration for target reward + +Previously, `get_attestation_participation_flag_indices` would only set the `TIMELY_TARGET_FLAG` (and thus reward for an attestation with correct target vote) if the attestation was included within a `SLOTS_PER_EPOCH` window. + +The `inclusion_delay` consideration for this flag is removed to ensure that whatever the valid inclusion window is for an attestation, it can receive a baseline non-zero reward for correct target. This ensures that clients will still attempt to pack such attestations into blocks which is important for the security analysis. + +Note, this was the intended behavior with the previously defined range which was equivalent to the max. + +## Backwards Compatibility + +This EIP introduces backwards incompatible changes to the block validation rule set on the consensus layer and must be accompanied by a hard fork. + +## Security Considerations + +This improves LMD-GHOST security as well as enables a fast confirmation rule. + +There are no known negative impacts to security. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). + diff --git a/EIPS/eip-7053.md b/EIPS/eip-7053.md new file mode 100644 index 0000000000000..2daf5d5de54a4 --- /dev/null +++ b/EIPS/eip-7053.md @@ -0,0 +1,117 @@ +--- +eip: 7053 +title: Interoperable Digital Media Indexing +description: Interoperable Indexing of Digital Media on the EVM-compatible Blockchains. +author: Bofu Chen (@bafu), Tammy Yang (@tammyyang) +discussions-to: https://ethereum-magicians.org/t/eip-7053-interoperable-digital-media-indexing/14394 +status: Draft +type: Standards Track +category: ERC +created: 2023-05-22 +--- + +## Abstract + +This EIP proposes an interoperable indexing strategy designed to enhance the organization and retrieval of digital media information across multiple smart contracts and EVM-compatible blockchains. This system enhances the traceability and verification of cross-contract and cross-chain data, facilitating a more efficient discovery of storage locations and crucial information related to media assets. The major purpose is to foster an integrated digital media environment on the blockchain. + +## Motivation + +Given the significant role digital media files play on the Internet, it's crucial to have a robust and efficient method for indexing immutable information. Existing systems encounter challenges due to the absence of a universal, interoperable identifier for digital media content. This leads to fragmentation and complications in retrieving metadata, storage information, or the provenance of specific media assets. The issues become increasingly critical as the volume of digital media continues to expand. + +The motivation behind this EIP is to establish a standardized, decentralized, and interoperable approach to index digital media across EVM-compatible networks. By integrating Decentralized Content Identifiers (CIDs) and Commit events, this EIP puts forward a mechanism enabling unique identification and indexing of each digital media file. Moreover, this system suggests a way for users to access a complete history of data associated with digital media assets, from creation to the current status. This full view enhances transparency, thereby providing users with the necessary information for future interactions with digital media. + +This method creates a common interface that any digital media system can use to provide a standard way of indexing and searching their content. + +|| +|:--:| +| ![](../assets/eip-7053/digital-media-indexing-system-and-metadata-lookup.jpg) | +| Figure 1: Digital Media Indexing Relationships and Lookup | + +This EIP aims to create an interoperable indexing system to associate all data of the same digital content together (Figure 1). This will make it easier for users to find and trust digital media content, and it will also make it easier for systems to share and exchange information about this digital media content. + +## Specification + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. + +### Content Identifier + +Content Identifier in this EIP is the the content address generated by passing the content of a digital media through a cryptographic hash function. Before the indexing process for digital media can begin, it is REQUIRED to generate unique Content Identifiers for each file. This identifier should the same as the Content Identifiers on the decentralized storage, ensuring each identifier provides access to the metadata, media information, and the content file itself. + +### Commit Function + +To index digital media, we shall call the commit function and generate Commit event: + +```solidity +/** + * @notice Emitted when a new commit is made. + * @param recorder The address of the account making the commit. + * @param assetCid The content identifier of the asset being committed. + * @param commitData The data associated with the commit. + */ +event Commit(address indexed recorder, string indexed assetCid, string commitData); + +/** + * @notice Registers a commit for an asset. + * Emits a Commit event and records the block number of the commit in the recordLogs mapping for the provided assetCid. + * @dev Emits a Commit event and logs the block number of the commit event. + * @param assetCid The content identifier of the asset being committed. + * @param commitData The data associated with the commit. + * @return The block number at which the commit was made. + */ +function commit(string memory assetCid, string memory commitData) public returns (uint256 blockNumber); +``` + +## Rationale + +The design decisions in this EIP prioritize the effectiveness and efficiency of the indexing method. To achieve this, Decentralized Content Identifiers (CIDs) are utilized to uniquely identify digital media content across all systems. This approach offers accurate and precise searching of media, along with the following benefits: + +1. Strengthened data integrity: CIDs serve as cryptographic hashes of the content, ensuring their uniqueness and preventing forgery. With the content in hand, obtaining the CID allows for searching relevant information associated with that content. + +2. Streamlined data portability: CIDs enable the seamless transfer of digital media content across different systems, eliminating the need for re-encoding or reconfiguration of protocols. This promotes a more interoperable and open indexing system. For example, in cases where Non-Fungible Tokens (NFTs) are created prior to Commit events, the digital media content can still be indexed by converting the file referenced by the tokenURI using the same mechanism. This conversion process ensures that the digital media content associated with NFT tokens can be indexed with a consistent identification approach. + +## Reference Implementation + +```solidity +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.4; + +import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; +import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +contract CommitRegister is Initializable { + using ECDSA for bytes32; + + mapping(string => uint[]) public commitLogs; + + event Commit(address indexed recorder, string indexed assetCid, string commitData); + + function initialize() public initializer {} + + function commit(string memory assetCid, string memory commitData) public returns (uint256 blockNumber) { + emit Commit(msg.sender, assetCid, commitData); + commitLogs[assetCid].push(block.number); + return block.number; + } + + function getCommits(string memory assetCid) public view returns (uint[] memory) { + return commitLogs[assetCid]; + } +} +``` + +## Security Considerations + +When implementing this EIP, it's essential to address several security aspects to ensure the safety and integrity of the digital media index: + +1. Input Validation: Given that commit function accepts string parameters, it's important to validate these inputs to avoid potential injection attacks. Although such attacks are less common in smart contracts than traditional web development, caution should be exercised. + +2. Data Integrity: The commit function relies on CIDs, which are assumed to be correct and point to the right data. It's important to note that this EIP doesn't validate the content behind the CIDs and the commit data, which remains a responsibility of the users or implementing applications. + +3. Event Listening: Systems relying on listening to the Commit events for changes need to be aware of potential missed events or incorrect ordering, especially during periods of network congestion or reorganizations. + +Implementers should consider these security aspects in the context of their specific use case and deployment scenario. It is strongly recommended to perform a comprehensive security audit before deploying any implementation of this EIP to a live network. + + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-7069.md b/EIPS/eip-7069.md new file mode 100644 index 0000000000000..7cd6448a9a35c --- /dev/null +++ b/EIPS/eip-7069.md @@ -0,0 +1,153 @@ +--- +eip: 7069 +title: Revamped CALL instructions +description: Introduce CALL2, DELEGATECALL2 and STATICCALL2 with simplified semantics +author: Alex Beregszaszi (@axic), Paweł Bylica (@chfast), Danno Ferrin (@shemnon), Andrei Maiboroda (@gumb0) +discussions-to: https://ethereum-magicians.org/t/eip-revamped-call-instructions/14432 +status: Draft +type: Standards Track +category: Core +created: 2023-05-05 +requires: 150, 211, 214, 2929 +--- + +## Abstract + +Introduce three new call instructions, `CALL2`, `DELEGATECALL2` and `STATICCALL2`, with simplified semantics. The existing call instructions remain unchanged. + +The new instructions do not allow specifying a gas limit, but rather rely on the "63/64th rule" ([EIP-150](./eip-150.md)) to limit gas. An important improvement is the rules around the "stipend" are simplified, and callers do not need to perform special calculation whether the value is sent or not. + +Furthermore, the obsolete functionality of specifying output buffer address is removed in favor of using `RETURNDATACOPY` instead. + +Lastly, instead of returning a boolean for execution status, an extensible list of status codes is returned: `0` for success, `1` for revert, `2` for failure. + +We expect most new contracts to rely on the new instructions (for simplicity and in order to save gas), and some specific contracts where gas limiting is required to keep using the old instructions (e.g. [ERC-4337](./eip-4337.md)). + +## Motivation + +Observability of gas has been a problem for very long. The system of gas has been (and likely must be) flexible in adapting to changes to both how Ethereum is used as well as changes in underlying hardware. + +Unfortunately, in many cases compromises or workarounds had to be made to avoid affecting call instructions negatively, mostly due to the complex semantics and expectations of them. + +This change aims to remove gas observability from the new instructions and opening the door for new classes of contracts that are not affected by repricings. Furthermore, once the EVM Object Format (EOF) is introduced, the legacy call instructions can be rejected within EOF contracts, making sure they are mostly unaffected by changes in gas fees. Because these operations are required for removing gas observability they will be required for EOF in lieu of the existing instructions. + +It is important to note that starting Solidity 0.4.21, the compiler already passes all remaining gas to calls (using `call(gas(), ...`), unless the developer uses the explicit override (`{gas: ...}`) in the language. This suggests most contracts don't rely on controlling gas. + +Besides the above, this change introduces a convenience feature of returning more detailed status codes: success (0), revert (1), failure (2). This moves from the boolean option to codes, which are extensible in the future. + +Lastly, the introduction of the `RETURNDATA*` instructions ([EIP-211](./eip-211.md)) has obsoleted the output parameters of calls, in a large number of cases rendering them unused. Using the output buffers have caused "bugs" in the past: in the case of [ERC-20](./eip-20.md), conflicting implementations caused a lot of trouble, where some would return something, while others would not. With relying on `RETURNDATA*` instructions this is implicitly clarified. + +## Specification + +| Name | Value | Comment | +|------|-------|---------| +| WARM_STORAGE_READ_COST | 100 | From [EIP-2929](./eip-2929.md) | +| COLD_ACCOUNT_ACCESS | 2600 | From [EIP-2929](./eip-2929.md) | +| ACCOUNT_CREATION_COST | 25000 | | +| MIN_RETAINED_GAS | 5000 | | +| MIN_CALLEE_GAS | 2300 | | + +We introduce three new instructions: + +- `CALL2` (`0xf8`) with arguments `(target_address, input_offset, input_size, value)` +- `DELEGATECALL2` (`0xf9`) with arguments `(target_address, input_offset, input_size)` +- `STATICCALL2` (`0xfb`) with arguments `(target_address, input_offset, input_size)` + +Execution semantics: + +1. Charge `WARM_STORAGE_READ_COST` (100) gas. +2. Pop required arguments from stack, fail with error on stack underflow. +4. If `value` is non-zero: + 3a. Fail with error if the current frame is in `static-mode`. + 3b. Fail with error if the balance of the current account is less than `value`. +4. Peform (and charge for) memory expansion using `[input_offset, input_size]`. +5. If `target_address` is not in the `warm_account_list`, charge `COLD_ACCOUNT_ACCESS - WARM_STORAGE_READ_COST` (2500) gas. +6. If `target_address` is not in the state and the call configuration would result in account creation, charge `ACCOUNT_CREATION_COST` (25000) gas. + - The only such case in this EIP is if `value` is non-zero. +7. Calculate the gas available to callee as caller's remaining gas reduced by `max(ceil(gas/64), MIN_RETAINED_GAS)` (`MIN_RETAINED_GAS` is 5000). +8. Fail with error if the gas available to callee at this point is less than `MIN_CALLEE_GAS` (2300). +9. Perform the call with the available gas and configuration. +10. Push a status code on the stack: + 11a. `0` if the call was successful. + 11b. `1` if the call has reverted. + 11c. `2` if the call has failed. +11. Gas not used by the callee is returned to the caller. + +Note: Unlike `CALL` there is no extra charge for value bearing calls. + + + + + + + +## Rationale + +### Removing gas selectability + +One major change from the original `CALL` series of instructions is that the caller has no control over the amount of gas passed in as part of the call. The number of cases where such a feature is essential are probably better served by direct protocol integration. + +Removing gas selectability also introduces a valuable property that future revisions to the gas schedule will benefit from: you can always overcome Out of Gas (OOG) errors by sending more gas as part of the transaction (subject to the block gas limit). Previously when raising storage costs ([EIP-1884](./eip-1884.md)) some contracts that sent only a limited amount of gas to their calls were broken by the new costing. + +Hence some contracts had a gas ceiling they were sending to their next call, permanently limiting the amount of gas they could spend. No amount of extra gas could fix the issue as the call would limit the amount sent. The notion of a stipend floor is retained in this spec. This floor can be changed independent of the smart contracts and still preserve the feature that OOG halts can be fixed by sending more gas as part of the transaction. + +### Stipend and 63/64th rule + +The purpose of the stipend is to have enough gas to emit logs (i.e. perform non-state-changing operations) when a "contract wallet" is called. The stipend is only added when the target has code and the call value is non-zero. + +The 63/64th rule has multiple purposes: + +a. to limit call depth, +b. to ensure the caller has gas left to make state changes after a callee returns. + +Additionally there is a call depth counter, and calls fail if the depth would exceed 1024. + +Before the 63/64th rule was introduced, it was required to calculate available gas semi-accurately on caller side. Solidity has a complicated ruleset where it tries to estimate how much it will cost on the caller side to perform the call itself, in order to set a reasonable gas value. + +We have changed the ruleset: + +1. Removed the call depth check. +2. Use the 63/64th rule, but + 2a. ensure that at least 5000 gas is retained prior to executing the callee, + 2b. ensure that at least 2300 gas is available to the callee. + +### Output buffers + +The functionality of specifying output buffer address is removed, because it is added complexity and in a large number of cases implementers prefer to use `RETURNDATACOPY` instead. Even if they rely on the output buffer (like in the case of Vyper), they would still check the length with `RETURNDATASIZE`. In Solidity one exception is the case when the expected return size is known (i.e. non-dynamic return values), in this case Solidity still uses the output buffer. + +### Status codes + +Current call instructions return a boolean value to signal success: 0 means failure, 1 means success. The Solidity compiler assumed this value is a boolean and thus uses the value as branch condition to status (`if iszero(status) { /* failure */ }`). This prevents us from introducing new status codes without breaking existing contracts. At the time of the design of [EIP-211](./eip-211.md) the idea of return a specific code for revert was discussed, but ultimately abandoned for the above reason. + +We change the value from boolean to a status code, where `0` signals success and thus it will be possible to introduce more non-success codes in the future, if desired. + +### Parameter order + +The order of parameters has been changed to move the `value` field to be the last. This allows the instructions to have identical encoding with the exception of the last parameter, and simplifies EVM and compiler implementations slightly. + +### Opcode encoding + +Instead of introducing three new opcodes we have discussed a version with an immediate configuration byte (flags). There are two main disadvantages to this: + +1. Some combination of flags may not be useful/be invalid, and this increases the testing/implementation surface. +2. The instruction could take variable number of stack items (i.e. `value` for `CALL2`) would be a brand new concept no other instruction has. + +It is also useful to have these as new opcodes instead of modifying the exiting CALL series inside of EOF. This creates an "escape hatch" in case gas observability needs to be restored to EOF contracts. This is done by adding the GAS and original CALL series opcodes to the valid EOF opcode list. + +### `CALLCODE` + +Since `CALLCODE` is deprecated, we do not introduce a counterpart here. + +## Backwards Compatibility + +No existing instructions are changed and so we do not think any backwards compatibility issues can occur. + +## Security Considerations + +It is expected that the attack surface will not grow. All of these operations can be modeled by existing operations with fixed gas (all available) and output range (zero length at zero memory). + +When implemented in EOF (where the GAS opcode and the original CALL operations are removed) existing out of gas attacks will be slightly more difficult, but not entirely prevented. Transactions can still pass in arbitrary gas values and clever contract construction can still result in specific gas values being passed to specific calls. It is expected the same surface will remain in EOF, but the ease of explotation will be reduced. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/assets/eip-6065/ERC6065.sol b/assets/eip-6065/Implementation.sol similarity index 100% rename from assets/eip-6065/ERC6065.sol rename to assets/eip-6065/Implementation.sol diff --git a/assets/eip-6065/corporate-structure.png b/assets/eip-6065/corporate-structure.png index 2fe581eafe4f7..75c442293345c 100644 Binary files a/assets/eip-6065/corporate-structure.png and b/assets/eip-6065/corporate-structure.png differ diff --git a/assets/eip-6123/contracts/ISDC.sol b/assets/eip-6123/contracts/ISDC.sol index 0dac18912be9e..45059fa2176a6 100644 --- a/assets/eip-6123/contracts/ISDC.sol +++ b/assets/eip-6123/contracts/ISDC.sol @@ -136,8 +136,9 @@ interface ISDC { * @dev emits a {TradeIncepted} event * @param _tradeData a description of the trade specification e.g. in xml format, suggested structure - see assets/eip-6123/doc/sample-tradedata-filestructure.xml * @param _initialSettlementData the initial settlement data (e.g. initial market data at which trade was incepted) + * @param _upfrontPayment provides an initial payment amount upfront */ - function inceptTrade(string memory _tradeData, string memory _initialSettlementData) external; + function inceptTrade(string memory _tradeData, string memory _initialSettlementData, int256 _upfrontPayment) external; /** * @notice Performs a matching of provided trade data and settlement data diff --git a/assets/eip-6123/contracts/SDC.sol b/assets/eip-6123/contracts/SDC.sol index 02616ea3b480c..6865c519be6c7 100644 --- a/assets/eip-6123/contracts/SDC.sol +++ b/assets/eip-6123/contracts/SDC.sol @@ -174,11 +174,13 @@ contract SDC is ISDC { * emits a TradeIncepted * can be called only when TradeState = Incepted */ - function inceptTrade(string memory _tradeData, string memory _initialSettlementData) external override onlyCounterparty onlyWhenTradeInactive + function inceptTrade(string memory _tradeData, string memory _initialSettlementData, int256 _upfrontPayment) external override onlyCounterparty onlyWhenTradeInactive { processState = ProcessState.Initiation; tradeState = TradeState.Incepted; // Set TradeState to Incepted + _upfrontPayment; // To silence warning... TODO: Implement new feature. + uint256 hash = uint256(keccak256(abi.encode(_tradeData, _initialSettlementData))); pendingRequests[hash] = msg.sender; tradeID = Strings.toString(hash); diff --git a/assets/eip-6123/contracts/SDCToken.sol b/assets/eip-6123/contracts/SDCToken.sol index 45de674b99858..0e39df3e83613 100644 --- a/assets/eip-6123/contracts/SDCToken.sol +++ b/assets/eip-6123/contracts/SDCToken.sol @@ -5,11 +5,11 @@ pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract SDCToken is ERC20{ - constructor() ERC20("SDCToken", "SDCT"){ + constructor() ERC20("SDCToken", "SDCT") { } - function mint(address to, uint256 amount) public{ - _mint(to,amount); + function mint(address to, uint256 amount) public { + _mint(to, amount); } } \ No newline at end of file diff --git a/assets/eip-6123/test/SDC.js b/assets/eip-6123/test/SDC.js index 06b579b10d4ae..75049c9c7314b 100644 --- a/assets/eip-6123/test/SDC.js +++ b/assets/eip-6123/test/SDC.js @@ -53,10 +53,10 @@ describe("Livecycle Unit-Tests for Smart Derivative Contract", () => { }); it("Counterparty1 incepts a trade", async () => { - const incept_call = await sdc.connect(counterparty1).inceptTrade(trade_data,"initialMarketData"); + const incept_call = await sdc.connect(counterparty1).inceptTrade(trade_data, "initialMarketData", 0); let tradeid = await sdc.connect(counterparty1).getTradeID(); //console.log("TradeId: %s", tradeid); - await expect(incept_call).to.emit(sdc, "TradeIncepted").withArgs(counterparty1.address,tradeid,trade_data); + await expect(incept_call).to.emit(sdc, "TradeIncepted").withArgs(counterparty1.address, tradeid, trade_data); let trade_state = await sdc.connect(counterparty1).getTradeState(); await expect(trade_state).equal(TradeState.Incepted); }); diff --git a/assets/eip-6358/src/contracts/ERC6358FungibleExample.sol b/assets/eip-6358/src/contracts/ERC6358FungibleExample.sol index 5b3b98ba32723..a74a7c764a0e9 100644 --- a/assets/eip-6358/src/contracts/ERC6358FungibleExample.sol +++ b/assets/eip-6358/src/contracts/ERC6358FungibleExample.sol @@ -251,7 +251,7 @@ contract ERC6358FungibleExample is ERC20, Ownable, IERC6358Fungible { emit OmniverseTokenTransfer(_from, _to, _amount); - address toAddr = _pkToAddress(_to); + address toAddr = OmniverseProtocolHelper.pkToAddress(_to); accountsMap[toAddr] = _to; } @@ -259,7 +259,7 @@ contract ERC6358FungibleExample is ERC20, Ownable, IERC6358Fungible { * @notice Check if the public key is the owner */ function _checkOwner(bytes memory _pk) internal view { - address fromAddr = _pkToAddress(_pk); + address fromAddr = OmniverseProtocolHelper.pkToAddress(_pk); require(fromAddr == owner(), "Not owner"); } @@ -270,7 +270,7 @@ contract ERC6358FungibleExample is ERC20, Ownable, IERC6358Fungible { omniverseBalances[_to] += _amount; emit OmniverseTokenTransfer("", _to, _amount); - address toAddr = _pkToAddress(_to); + address toAddr = OmniverseProtocolHelper.pkToAddress(_to); accountsMap[toAddr] = _to; } @@ -290,14 +290,6 @@ contract ERC6358FungibleExample is ERC20, Ownable, IERC6358Fungible { emit OmniverseTokenTransfer(_from, "", _amount); } - /** - * @notice Convert the public key to evm address - */ - function _pkToAddress(bytes memory _pk) internal pure returns (address) { - bytes32 hash = keccak256(_pk); - return address(uint160(uint256(hash))); - } - /** * @notice Add new chain members to the token */ @@ -350,7 +342,7 @@ contract ERC6358FungibleExample is ERC20, Ownable, IERC6358Fungible { /** * @notice Set the cooling down time of an omniverse transaction */ - function setCooingDownTime(uint256 _time) external { + function setCoolingDownTime(uint256 _time) external { cdTime = _time; } diff --git a/assets/eip-6358/src/contracts/ERC6358NonFungibleExample.sol b/assets/eip-6358/src/contracts/ERC6358NonFungibleExample.sol index c8128b910336e..842bec82ac901 100644 --- a/assets/eip-6358/src/contracts/ERC6358NonFungibleExample.sol +++ b/assets/eip-6358/src/contracts/ERC6358NonFungibleExample.sol @@ -2,6 +2,9 @@ pragma solidity >=0.8.0 <0.9.0; import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; +import "@openzeppelin/contracts/utils/Strings.sol"; import "./libraries/OmniverseProtocolHelper.sol"; import "./interfaces/IERC6358NonFungible.sol"; @@ -27,7 +30,9 @@ struct NonFungible { /** * @notice Implementation of the {IERC6358NonFungible} interface */ -contract ERC6358NonFungibleExample is Ownable, IERC6358NonFungible { +contract ERC6358NonFungibleExample is Ownable, IERC6358NonFungible, IERC721, IERC721Metadata { + using Strings for uint256; + uint8 constant TRANSFER = 0; uint8 constant MINT = 1; uint8 constant BURN = 2; @@ -52,9 +57,11 @@ contract ERC6358NonFungibleExample is Ownable, IERC6358NonFungible { } // Token name - string public name; + string private tokenName; // Token symbol - string public symbol; + string private tokenSymbol; + // Base URI + string public baseURI; // Chain id used to distinguish different chains uint32 chainId; // O-transaction cooling down time @@ -85,8 +92,18 @@ contract ERC6358NonFungibleExample is Ownable, IERC6358NonFungible { */ constructor(uint32 _chainId, string memory _name, string memory _symbol) { chainId = _chainId; - name = _name; - symbol = _symbol; + tokenName = _name; + tokenSymbol = _symbol; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return + interfaceId == type(IERC721).interfaceId || + interfaceId == type(IERC721Metadata).interfaceId || + interfaceId == type(IERC165).interfaceId; } /** @@ -129,6 +146,120 @@ contract ERC6358NonFungibleExample is Ownable, IERC6358NonFungible { _omniverseBurn(nonFungible.exData, nonFungible.tokenId); } } + + /** + * @notice See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view returns (uint256 balance) { + bytes storage pk = accountsMap[owner]; + if (pk.length == 0) { + balance = 0; + } + else { + balance = omniverseBalances[pk]; + } + } + + /** + * @notice See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) external view returns (address owner) { + bytes memory ret = this.omniverseOwnerOf(tokenId); + return OmniverseProtocolHelper.pkToAddress(ret); + } + + /** + * @notice See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external { + + } + + /** + * @notice See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external { + + } + + /** + * @notice See {IERC721-transferFrom}. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external { + + } + + /** + * @notice See {IERC721-approve}. + */ + function approve(address /*to*/, uint256 /*tokenId*/) external { + + } + + /** + * @notice See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address /*operator*/, bool /*_approved*/) external { + + } + + /** + * @notice See {IERC721-getApproved}. + */ + function getApproved(uint256 /*tokenId*/) external pure returns (address /*operator*/) { + revert("Forbidden"); + } + + /** + * @notice See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address /*owner*/, address /*operator*/) external pure returns (bool) { + return false; + } + + /** + * @notice See {IERC721Metadata-name}. + */ + function name() external view returns (string memory) { + return tokenName; + } + + /** + * @notice See {IERC721Metadata-symbol}. + */ + function symbol() external view returns (string memory) { + return tokenSymbol; + } + + /** + * @notice See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) external view returns (string memory) { + bytes memory ret = omniverseOwners[tokenId]; + require(keccak256(ret) != keccak256(bytes("")), "ERC721Metadata: URI query for nonexistent token"); + + return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; + } + + /** + * @notice Sets the base URI. + */ + function setBaseURI(string calldata _baseURI) public { + baseURI = _baseURI; + } /** * @notice Check if the transaction can be executed successfully @@ -189,27 +320,6 @@ contract ERC6358NonFungibleExample is Ownable, IERC6358NonFungible { return ret; } - /** - * @notice See {IERC721-balanceOf}. - */ - function balanceOf(address account) public view returns (uint256) { - bytes storage pk = accountsMap[account]; - if (pk.length == 0) { - return 0; - } - else { - return omniverseBalances[pk]; - } - } - - /** - * @notice See {IERC721-ownerOf}. - */ - function ownerOf(uint256 tokenId) public view returns (address owner) { - bytes memory ret = this.omniverseOwnerOf(tokenId); - return _pkToAddress(ret); - } - /** * @notice Receive and check an omniverse transaction */ @@ -272,15 +382,17 @@ contract ERC6358NonFungibleExample is Ownable, IERC6358NonFungible { emit OmniverseTokenTransfer(_from, _to, _tokenId); - address toAddr = _pkToAddress(_to); + address fromAddr = OmniverseProtocolHelper.pkToAddress(_from); + address toAddr = OmniverseProtocolHelper.pkToAddress(_to); accountsMap[toAddr] = _to; + emit Transfer(fromAddr, toAddr, _tokenId); } /** * @notice Check if the public key is the owner */ function _checkOwner(bytes memory _pk) internal view { - address fromAddr = _pkToAddress(_pk); + address fromAddr = OmniverseProtocolHelper.pkToAddress(_pk); require(fromAddr == owner(), "Not owner"); } @@ -301,8 +413,9 @@ contract ERC6358NonFungibleExample is Ownable, IERC6358NonFungible { omniverseBalances[_to] += 1; emit OmniverseTokenTransfer("", _to, _tokenId); - address toAddr = _pkToAddress(_to); + address toAddr = OmniverseProtocolHelper.pkToAddress(_to); accountsMap[toAddr] = _to; + emit Transfer(address(0), toAddr, _tokenId); } /** @@ -319,14 +432,9 @@ contract ERC6358NonFungibleExample is Ownable, IERC6358NonFungible { delete omniverseOwners[_tokenId]; omniverseBalances[_from] -= 1; emit OmniverseTokenTransfer(_from, "", _tokenId); - } - /** - * @notice Convert the public key to evm address - */ - function _pkToAddress(bytes memory _pk) internal pure returns (address) { - bytes32 hash = keccak256(_pk); - return address(uint160(uint256(hash))); + address fromAddr = OmniverseProtocolHelper.pkToAddress(_from); + emit Transfer(fromAddr, address(0), _tokenId); } /** @@ -374,7 +482,7 @@ contract ERC6358NonFungibleExample is Ownable, IERC6358NonFungible { /** * @notice Set the cooling down time of an omniverse transaction */ - function setCooingDownTime(uint256 _time) external { + function setCoolingDownTime(uint256 _time) external { cdTime = _time; } diff --git a/assets/eip-6358/src/contracts/libraries/OmniverseProtocolHelper.sol b/assets/eip-6358/src/contracts/libraries/OmniverseProtocolHelper.sol index f7144fa61d6a7..eccfbeb55f175 100644 --- a/assets/eip-6358/src/contracts/libraries/OmniverseProtocolHelper.sol +++ b/assets/eip-6358/src/contracts/libraries/OmniverseProtocolHelper.sol @@ -3,6 +3,7 @@ pragma solidity >=0.8.0 <0.9.0; import "../interfaces/IERC6358.sol"; import "../interfaces/IERC6358Application.sol"; +import "@openzeppelin/contracts/utils/Strings.sol"; /** * @notice Used to record one omniverse transaction data @@ -47,13 +48,21 @@ enum VerifyResult { * NOTE The verification method is for reference only, and developers can design appropriate * verification mechanism based on their bussiness logic. */ -library OmniverseProtocolHelper { +library OmniverseProtocolHelper { /** - * @notice Get the hash of a transaction + * @notice Get the raw data of a transaction */ - function getTransactionHash(ERC6358TransactionData memory _data) internal view returns (bytes32) { + function getRawData(ERC6358TransactionData memory _data) internal view returns (bytes memory) { bytes memory payloadRawData = IERC6358Application(address(this)).getPayloadRawData(_data.payload); bytes memory rawData = abi.encodePacked(_data.nonce, _data.chainId, _data.initiateSC, _data.from, payloadRawData); + return rawData; + } + + /** + * @notice Get the hash of a transaction + */ + function getTransactionHash(ERC6358TransactionData memory _data) internal view returns (bytes32) { + bytes memory rawData = getRawData(_data); return keccak256(rawData); } @@ -70,31 +79,46 @@ library OmniverseProtocolHelper { v := mload(add(_signature, 65)) } address recovered = ecrecover(_hash, v, r, s); - require(recovered != address(0), "Verify failed"); return recovered; } /** - * @notice Check if the public key matches the recovered address + * @notice Convert the public key to evm address */ - function checkPkMatched(bytes memory _pk, address _address) public pure { + function pkToAddress(bytes memory _pk) public pure returns (address) { bytes32 hash = keccak256(_pk); - address pkAddress = address(uint160(uint256(hash))); - require(_address == pkAddress, "Signer not sender"); + return address(uint160(uint256(hash))); + } + + /** + * @notice Verify if the signature matches the address + */ + function verifySignature(bytes memory _rawData, bytes memory _signature, address _address) public pure returns (bool) { + bytes32 hash = keccak256(_rawData); + address pkAddress = recoverAddress(hash, _signature); + bytes memory PREFIX = hex"19457468657265756d205369676e6564204d6573736167653a0a"; + + if (pkAddress == address(0) || pkAddress != _address) { + hash = keccak256(abi.encodePacked(PREFIX, bytes(Strings.toString(_rawData.length)), _rawData)); + pkAddress = recoverAddress(hash, _signature); + if (pkAddress == address(0) || pkAddress != _address) { + return false; + } + } + + return true; } /** * @notice Verify an omniverse transaction */ function verifyTransaction(RecordedCertificate storage rc, ERC6358TransactionData memory _data) public returns (VerifyResult) { - uint256 nonce = rc.txList.length; - - bytes32 txHash = getTransactionHash(_data); - address recoveredAddress = recoverAddress(txHash, _data.signature); - // Signature verified failed - checkPkMatched(_data.from, recoveredAddress); + bytes memory rawData = getRawData(_data); + address senderAddress = pkToAddress(_data.from); + require(verifySignature(rawData, _data.signature, senderAddress), "Signature error"); // Check nonce + uint256 nonce = rc.txList.length; if (nonce == _data.nonce) { return VerifyResult.Success; } @@ -102,6 +126,7 @@ library OmniverseProtocolHelper { // The message has been received, check conflicts OmniverseTx storage hisTx = rc.txList[_data.nonce]; bytes32 hisTxHash = getTransactionHash(hisTx.txData); + bytes32 txHash = getTransactionHash(_data); if (hisTxHash != txHash) { // to be continued, add to evil list, but can not be duplicated EvilTxData storage evilTx = rc.evilTxList.push(); diff --git a/assets/eip-6358/src/test/ERC6358Fungible.test.js b/assets/eip-6358/src/test/ERC6358Fungible.test.js index bc0cbb6d50982..86a484ffeaadd 100644 --- a/assets/eip-6358/src/test/ERC6358Fungible.test.js +++ b/assets/eip-6358/src/test/ERC6358Fungible.test.js @@ -3,9 +3,9 @@ const BN = require('bn.js'); const secp256k1 = require('secp256k1'); const keccak256 = require('keccak256'); const Web3 = require('web3'); -const web3js = new Web3(Web3.givenProvider); +const providerUrl = 'http://localhost:8545'; +const web3js = new Web3(providerUrl); const assert = require('assert'); -// const { util } = require('config'); const CHAIN_ID = 0; const ONE_TOKEN = '1000000000000000000'; @@ -113,7 +113,7 @@ contract('ERC6358Fungible', function() { fungible = await Fungible.new(CHAIN_ID, TOKEN_SYMBOL, TOKEN_SYMBOL, {from: owner}); Fungible.address = fungible.address; await fungible.setMembers([[CHAIN_ID, Fungible.address]]); - await fungible.setCooingDownTime(COOL_DOWN); + await fungible.setCoolingDownTime(COOL_DOWN); } const mintToken = async function(from, toPk, amount) { @@ -121,7 +121,7 @@ contract('ERC6358Fungible', function() { let txData = encodeMint(from, toPk, amount, nonce); await fungible.sendOmniverseTransaction(txData); await utils.sleep(COOL_DOWN); - await utils.evmMine(1); + await utils.evmMine(1, web3js.currentProvider); let ret = await fungible.triggerExecution(); } @@ -135,7 +135,7 @@ contract('ERC6358Fungible', function() { let nonce = await fungible.getTransactionCount(user1Pk); let txData = encodeTransfer({pk: user1Pk, sk: user1Sk}, user2Pk, TEN_TOKEN, nonce); txData.signature = txData.signature.slice(0, -2); - await utils.expectThrow(fungible.sendOmniverseTransaction(txData), 'Verify failed'); + await utils.expectThrow(fungible.sendOmniverseTransaction(txData), 'Signature error'); }); }); @@ -144,7 +144,7 @@ contract('ERC6358Fungible', function() { let nonce = await fungible.getTransactionCount(user1Pk); let txData = encodeTransfer({pk: user1Pk, sk: user1Sk}, user2Pk, TEN_TOKEN, nonce); txData.from = ownerPk; - await utils.expectThrow(fungible.sendOmniverseTransaction(txData), 'Signer not sender'); + await utils.expectThrow(fungible.sendOmniverseTransaction(txData), 'Signature error'); }); }); @@ -165,7 +165,7 @@ contract('ERC6358Fungible', function() { let count = await fungible.getTransactionCount(ownerPk); assert(count == 0, "The count should be zero"); await utils.sleep(COOL_DOWN); - await utils.evmMine(1); + await utils.evmMine(1, web3js.currentProvider); ret = await fungible.triggerExecution(); count = await fungible.getTransactionCount(ownerPk); assert(count == 1, "The count should be one"); @@ -193,10 +193,10 @@ contract('ERC6358Fungible', function() { describe('Cooled down', function() { it('should succeed', async () => { await utils.sleep(COOL_DOWN); - await utils.evmMine(1); + await utils.evmMine(1, web3js.currentProvider); let nonce = await fungible.getTransactionCount(ownerPk); await utils.sleep(COOL_DOWN); - await utils.evmMine(1); + await utils.evmMine(1, web3js.currentProvider); ret = await fungible.triggerExecution(); let count = await fungible.getTransactionCount(ownerPk); assert(count == 2); @@ -214,6 +214,31 @@ contract('ERC6358Fungible', function() { }); }); + describe('Personal signing', function() { + before(async function() { + await initContract(); + }); + + describe('All conditions satisfied', function() { + it('should succeed', async () => { + let nonce = await fungible.getTransactionCount(ownerPk); + let txData = encodeMint({pk: ownerPk, sk: ownerSk}, user2Pk, TEN_TOKEN, nonce); + let bData = getRawData(txData, MINT, [user2Pk, TEN_TOKEN]); + let hash = keccak256(Buffer.concat([Buffer.from('\x19Ethereum Signed Message:\n' + bData.length), bData])); + txData.signature = signData(hash, ownerSk); + let ret = await fungible.sendOmniverseTransaction(txData); + assert(ret.logs[0].event == 'TransactionSent'); + let count = await fungible.getTransactionCount(ownerPk); + assert(count == 0, "The count should be zero"); + await utils.sleep(COOL_DOWN); + await utils.evmMine(1, web3js.currentProvider); + ret = await fungible.triggerExecution(); + count = await fungible.getTransactionCount(ownerPk); + assert(count == 1, "The count should be one"); + }); + }); + }); + describe('Omniverse Transaction', function() { before(async function() { await initContract(); @@ -236,7 +261,7 @@ contract('ERC6358Fungible', function() { let count = await fungible.getDelayedTxCount(); assert(count == 1, 'The number of delayed txs should be one'); await utils.sleep(COOL_DOWN); - await utils.evmMine(1); + await utils.evmMine(1, web3js.currentProvider); ret = await fungible.triggerExecution(); }); }); @@ -278,7 +303,7 @@ contract('ERC6358Fungible', function() { describe('Cooled down', function() { it('should be one transaction', async () => { await utils.sleep(COOL_DOWN); - await utils.evmMine(1); + await utils.evmMine(1, web3js.currentProvider); let tx = await fungible.getExecutableDelayedTx(); assert(tx.sender == ownerPk, 'There should be one transaction'); }); @@ -325,7 +350,7 @@ contract('ERC6358Fungible', function() { let txData = encodeMint({pk: ownerPk, sk: ownerSk}, user1Pk, ONE_TOKEN, nonce); await fungible.sendOmniverseTransaction(txData); await utils.sleep(COOL_DOWN); - await utils.evmMine(1); + await utils.evmMine(1, web3js.currentProvider); let ret = await fungible.triggerExecution(); assert(ret.logs[0].event == 'OmniverseTokenTransfer'); let balance = await fungible.omniverseBalanceOf(user1Pk); @@ -362,7 +387,7 @@ contract('ERC6358Fungible', function() { let txData = encodeBurn({pk: ownerPk, sk: ownerSk}, user1Pk, ONE_TOKEN, nonce); await fungible.sendOmniverseTransaction(txData); await utils.sleep(COOL_DOWN); - await utils.evmMine(1); + await utils.evmMine(1, web3js.currentProvider); let ret = await fungible.triggerExecution(); assert(ret.logs[0].event == 'OmniverseTokenTransfer'); let balance = await fungible.omniverseBalanceOf(user1Pk); @@ -391,7 +416,7 @@ contract('ERC6358Fungible', function() { let txData = encodeTransfer({pk: user1Pk, sk: user1Sk}, user2Pk, ONE_TOKEN, nonce); await fungible.sendOmniverseTransaction(txData); await utils.sleep(COOL_DOWN); - await utils.evmMine(1); + await utils.evmMine(1, web3js.currentProvider); let ret = await fungible.triggerExecution(); assert(ret.logs[0].event == 'OmniverseTokenTransfer'); let balance = await fungible.omniverseBalanceOf(user1Pk); diff --git a/assets/eip-6358/src/test/ERC6358NonFungible.test.js b/assets/eip-6358/src/test/ERC6358NonFungible.test.js index ffce3741892f9..b78b2e675ec00 100644 --- a/assets/eip-6358/src/test/ERC6358NonFungible.test.js +++ b/assets/eip-6358/src/test/ERC6358NonFungible.test.js @@ -3,9 +3,9 @@ const BN = require('bn.js'); const secp256k1 = require('secp256k1'); const keccak256 = require('keccak256'); const Web3 = require('web3'); -const web3js = new Web3(Web3.givenProvider); +const providerUrl = 'http://localhost:8545'; +const web3js = new Web3(providerUrl); const assert = require('assert'); -// const { util } = require('config'); const CHAIN_ID = 0; const TOKEN_ID = 1; @@ -112,7 +112,7 @@ contract('ERC6358NonFungible', function() { nonFungible = await NonFungible.new(CHAIN_ID, TOKEN_SYMBOL, TOKEN_SYMBOL, {from: owner}); NonFungible.address = nonFungible.address; await nonFungible.setMembers([[CHAIN_ID, NonFungible.address]]); - await nonFungible.setCooingDownTime(COOL_DOWN); + await nonFungible.setCoolingDownTime(COOL_DOWN); } const mintToken = async function(from, toPk, tokenId) { @@ -120,7 +120,7 @@ contract('ERC6358NonFungible', function() { let txData = encodeMint(from, toPk, tokenId, nonce); await nonFungible.sendOmniverseTransaction(txData); await utils.sleep(COOL_DOWN); - await utils.evmMine(1); + await utils.evmMine(1, web3js.currentProvider); let ret = await nonFungible.triggerExecution(); } @@ -134,7 +134,7 @@ contract('ERC6358NonFungible', function() { let nonce = await nonFungible.getTransactionCount(user1Pk); let txData = encodeTransfer({pk: user1Pk, sk: user1Sk}, user2Pk, TOKEN_ID, nonce); txData.signature = txData.signature.slice(0, -2); - await utils.expectThrow(nonFungible.sendOmniverseTransaction(txData), 'Verify failed'); + await utils.expectThrow(nonFungible.sendOmniverseTransaction(txData), 'Signature error'); }); }); @@ -143,7 +143,7 @@ contract('ERC6358NonFungible', function() { let nonce = await nonFungible.getTransactionCount(user1Pk); let txData = encodeTransfer({pk: user1Pk, sk: user1Sk}, user2Pk, TOKEN_ID, nonce); txData.from = ownerPk; - await utils.expectThrow(nonFungible.sendOmniverseTransaction(txData), 'Signer not sender'); + await utils.expectThrow(nonFungible.sendOmniverseTransaction(txData), 'Signature error'); }); }); @@ -164,7 +164,7 @@ contract('ERC6358NonFungible', function() { let count = await nonFungible.getTransactionCount(ownerPk); assert(count == 0, "The count should be zero"); await utils.sleep(COOL_DOWN); - await utils.evmMine(1); + await utils.evmMine(1, web3js.currentProvider); ret = await nonFungible.triggerExecution(); count = await nonFungible.getTransactionCount(ownerPk); assert(count == 1, "The count should be one"); @@ -192,10 +192,10 @@ contract('ERC6358NonFungible', function() { describe('Cooled down', function() { it('should succeed', async () => { await utils.sleep(COOL_DOWN); - await utils.evmMine(1); + await utils.evmMine(1, web3js.currentProvider); let nonce = await nonFungible.getTransactionCount(ownerPk); await utils.sleep(COOL_DOWN); - await utils.evmMine(1); + await utils.evmMine(1, web3js.currentProvider); ret = await nonFungible.triggerExecution(); let count = await nonFungible.getTransactionCount(ownerPk); assert(count == 2); @@ -212,6 +212,31 @@ contract('ERC6358NonFungible', function() { }); }); }); + + describe('Personal signing', function() { + before(async function() { + await initContract(); + }); + + describe('All conditions satisfied', function() { + it('should succeed', async () => { + let nonce = await nonFungible.getTransactionCount(ownerPk); + let txData = encodeMint({pk: ownerPk, sk: ownerSk}, user2Pk, TOKEN_ID, nonce); + let bData = getRawData(txData, MINT, [user2Pk, TOKEN_ID]); + let hash = keccak256(Buffer.concat([Buffer.from('\x19Ethereum Signed Message:\n' + bData.length), bData])); + txData.signature = signData(hash, ownerSk); + let ret = await nonFungible.sendOmniverseTransaction(txData); + assert(ret.logs[0].event == 'TransactionSent'); + let count = await nonFungible.getTransactionCount(ownerPk); + assert(count == 0, "The count should be zero"); + await utils.sleep(COOL_DOWN); + await utils.evmMine(1, web3js.currentProvider); + ret = await nonFungible.triggerExecution(); + count = await nonFungible.getTransactionCount(ownerPk); + assert(count == 1, "The count should be one"); + }); + }); + }); describe('Omniverse Transaction', function() { before(async function() { @@ -235,7 +260,7 @@ contract('ERC6358NonFungible', function() { let count = await nonFungible.getDelayedTxCount(); assert(count == 1, 'The number of delayed txs should be one'); await utils.sleep(COOL_DOWN); - await utils.evmMine(1); + await utils.evmMine(1, web3js.currentProvider); ret = await nonFungible.triggerExecution(); }); }); @@ -277,7 +302,7 @@ contract('ERC6358NonFungible', function() { describe('Cooled down', function() { it('should be one transaction', async () => { await utils.sleep(COOL_DOWN); - await utils.evmMine(1); + await utils.evmMine(1, web3js.currentProvider); let tx = await nonFungible.getExecutableDelayedTx(); assert(tx.sender == ownerPk, 'There should be one transaction'); }); @@ -324,7 +349,7 @@ contract('ERC6358NonFungible', function() { let txData = encodeMint({pk: ownerPk, sk: ownerSk}, user1Pk, TOKEN_ID, nonce); await nonFungible.sendOmniverseTransaction(txData); await utils.sleep(COOL_DOWN); - await utils.evmMine(1); + await utils.evmMine(1, web3js.currentProvider); let ret = await nonFungible.triggerExecution(); assert(ret.logs[0].event == 'OmniverseTokenTransfer'); let tokenOwner = await nonFungible.omniverseOwnerOf(TOKEN_ID); @@ -363,7 +388,7 @@ contract('ERC6358NonFungible', function() { let txData = encodeBurn({pk: ownerPk, sk: ownerSk}, user1Pk, TOKEN_ID, nonce); await nonFungible.sendOmniverseTransaction(txData); await utils.sleep(COOL_DOWN); - await utils.evmMine(1); + await utils.evmMine(1, web3js.currentProvider); let ret = await nonFungible.triggerExecution(); await utils.expectThrow(nonFungible.omniverseOwnerOf(TOKEN_ID), "Token not exist"); assert(ret.logs[0].event == 'OmniverseTokenTransfer'); @@ -393,7 +418,7 @@ contract('ERC6358NonFungible', function() { let txData = encodeTransfer({pk: user1Pk, sk: user1Sk}, user2Pk, TOKEN_ID, nonce); await nonFungible.sendOmniverseTransaction(txData); await utils.sleep(COOL_DOWN); - await utils.evmMine(1); + await utils.evmMine(1, web3js.currentProvider); let ret = await nonFungible.triggerExecution(); assert(ret.logs[0].event == 'OmniverseTokenTransfer'); let tokenOwner = await nonFungible.omniverseOwnerOf(TOKEN_ID); diff --git a/assets/eip-6381/contracts/EmotableRepository.sol b/assets/eip-6381/contracts/EmotableRepository.sol index d66c36b59b949..445ae2454f4fa 100644 --- a/assets/eip-6381/contracts/EmotableRepository.sol +++ b/assets/eip-6381/contracts/EmotableRepository.sol @@ -5,7 +5,20 @@ pragma solidity ^0.8.16; import "./IERC6381.sol"; import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +error BulkParametersOfUnequalLength(); +error ExpiredPresignedEmote(); +error InvalidSignature(); + contract EmotableRepository is IERC6381 { + bytes32 public immutable DOMAIN_SEPARATOR = keccak256( + abi.encode( + "ERC-6381: Public Non-Fungible Token Emote Repository", + "1", + block.chainid, + address(this) + ) + ); + // Used to avoid double emoting and control undoing mapping(address => mapping(address => mapping(uint256 => mapping(bytes4 => uint256)))) private _emotesUsedByEmoter; // Cheaper than using a bool @@ -20,6 +33,28 @@ contract EmotableRepository is IERC6381 { return _emotesPerToken[collection][tokenId][emoji]; } + function bulkEmoteCountOf( + address[] memory collections, + uint256[] memory tokenIds, + bytes4[] memory emojis + ) public view returns (uint256[] memory) { + if( + collections.length != tokenIds.length || + collections.length != emojis.length + ){ + revert BulkParametersOfUnequalLength(); + } + + uint256[] memory counts = new uint256[](collections.length); + for (uint256 i; i < collections.length; ) { + counts[i] = _emotesPerToken[collections[i]][tokenIds[i]][emojis[i]]; + unchecked { + ++i; + } + } + return counts; + } + function hasEmoterUsedEmote( address emoter, address collection, @@ -29,6 +64,30 @@ contract EmotableRepository is IERC6381 { return _emotesUsedByEmoter[emoter][collection][tokenId][emoji] == 1; } + function haveEmotersUsedEmotes( + address[] memory emoters, + address[] memory collections, + uint256[] memory tokenIds, + bytes4[] memory emojis + ) public view returns (bool[] memory) { + if( + emoters.length != collections.length || + emoters.length != tokenIds.length || + emoters.length != emojis.length + ){ + revert BulkParametersOfUnequalLength(); + } + + bool[] memory states = new bool[](collections.length); + for (uint256 i; i < collections.length; ) { + states[i] = _emotesUsedByEmoter[emoters[i]][collections[i]][tokenIds[i]][emojis[i]] == 1; + unchecked { + ++i; + } + } + return states; + } + function emote( address collection, uint256 tokenId, @@ -51,6 +110,218 @@ contract EmotableRepository is IERC6381 { } } + function bulkEmote( + address[] memory collections, + uint256[] memory tokenIds, + bytes4[] memory emojis, + bool[] memory states + ) public { + if( + collections.length != tokenIds.length || + collections.length != emojis.length || + collections.length != states.length + ){ + revert BulkParametersOfUnequalLength(); + } + + bool currentVal; + for (uint256 i; i < collections.length; ) { + currentVal = _emotesUsedByEmoter[msg.sender][collections[i]][tokenIds[i]][ + emojis[i] + ] == 1; + if (currentVal != states[i]) { + if (states[i]) { + _emotesPerToken[collections[i]][tokenIds[i]][emojis[i]] += 1; + } else { + _emotesPerToken[collections[i]][tokenIds[i]][emojis[i]] -= 1; + } + _emotesUsedByEmoter[msg.sender][collections[i]][tokenIds[i]][emojis[i]] = states[i] + ? 1 + : 0; + emit Emoted(msg.sender, collections[i], tokenIds[i], emojis[i], states[i]); + } + unchecked { + ++i; + } + } + } + + function prepareMessageToPresignEmote( + address collection, + uint256 tokenId, + bytes4 emoji, + bool state, + uint256 deadline + ) public view returns (bytes32) { + return keccak256( + abi.encode( + DOMAIN_SEPARATOR, + collection, + tokenId, + emoji, + state, + deadline + ) + ); + } + + function bulkPrepareMessagesToPresignEmote( + address[] memory collections, + uint256[] memory tokenIds, + bytes4[] memory emojis, + bool[] memory states, + uint256[] memory deadlines + ) public view returns (bytes32[] memory) { + if( + collections.length != tokenIds.length || + collections.length != emojis.length || + collections.length != states.length || + collections.length != deadlines.length + ){ + revert BulkParametersOfUnequalLength(); + } + + bytes32[] memory messages = new bytes32[](collections.length); + for (uint256 i; i < collections.length; ) { + messages[i] = keccak256( + abi.encode( + DOMAIN_SEPARATOR, + collections[i], + tokenIds[i], + emojis[i], + states[i], + deadlines[i] + ) + ); + unchecked { + ++i; + } + } + + return messages; + } + + function presignedEmote( + address emoter, + address collection, + uint256 tokenId, + bytes4 emoji, + bool state, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) public { + if(block.timestamp > deadline){ + revert ExpiredPresignedEmote(); + } + bytes32 digest = keccak256( + abi.encodePacked( + "\x19Ethereum Signed Message:\n32", + keccak256( + abi.encode( + DOMAIN_SEPARATOR, + collection, + tokenId, + emoji, + state, + deadline + ) + ) + ) + ); + address signer = ecrecover(digest, v, r, s); + if(signer != emoter){ + revert InvalidSignature(); + } + + bool currentVal = _emotesUsedByEmoter[signer][collection][tokenId][ + emoji + ] == 1; + if (currentVal != state) { + if (state) { + _emotesPerToken[collection][tokenId][emoji] += 1; + } else { + _emotesPerToken[collection][tokenId][emoji] -= 1; + } + _emotesUsedByEmoter[signer][collection][tokenId][emoji] = state + ? 1 + : 0; + emit Emoted(signer, collection, tokenId, emoji, state); + } + } + + function bulkPresignedEmote( + address[] memory emoters, + address[] memory collections, + uint256[] memory tokenIds, + bytes4[] memory emojis, + bool[] memory states, + uint256[] memory deadlines, + uint8[] memory v, + bytes32[] memory r, + bytes32[] memory s + ) public { + if( + emoters.length != collections.length || + emoters.length != tokenIds.length || + emoters.length != emojis.length || + emoters.length != states.length || + emoters.length != deadlines.length || + emoters.length != v.length || + emoters.length != r.length || + emoters.length != s.length + ){ + revert BulkParametersOfUnequalLength(); + } + + bytes32 digest; + address signer; + bool currentVal; + for (uint256 i; i < collections.length; ) { + if (block.timestamp > deadlines[i]){ + revert ExpiredPresignedEmote(); + } + digest = keccak256( + abi.encodePacked( + "\x19Ethereum Signed Message:\n32", + keccak256( + abi.encode( + DOMAIN_SEPARATOR, + collections[i], + tokenIds[i], + emojis[i], + states[i], + deadlines[i] + ) + ) + ) + ); + signer = ecrecover(digest, v[i], r[i], s[i]); + if(signer != emoters[i]){ + revert InvalidSignature(); + } + + currentVal = _emotesUsedByEmoter[signer][collections[i]][tokenIds[i]][ + emojis[i] + ] == 1; + if (currentVal != states[i]) { + if (states[i]) { + _emotesPerToken[collections[i]][tokenIds[i]][emojis[i]] += 1; + } else { + _emotesPerToken[collections[i]][tokenIds[i]][emojis[i]] -= 1; + } + _emotesUsedByEmoter[signer][collections[i]][tokenIds[i]][emojis[i]] = states[i] + ? 1 + : 0; + emit Emoted(signer, collections[i], tokenIds[i], emojis[i], states[i]); + } + unchecked { + ++i; + } + } + } + function supportsInterface( bytes4 interfaceId ) public view virtual returns (bool) { diff --git a/assets/eip-6381/contracts/IERC6381.sol b/assets/eip-6381/contracts/IERC6381.sol index 0d31de0a6aaf0..a579c5825d962 100644 --- a/assets/eip-6381/contracts/IERC6381.sol +++ b/assets/eip-6381/contracts/IERC6381.sol @@ -17,6 +17,12 @@ interface IERC6381 { bytes4 emoji ) external view returns (uint256); + function bulkEmoteCountOf( + address[] memory collections, + uint256[] memory tokenIds, + bytes4[] memory emojis + ) external view returns (uint256[] memory); + function hasEmoterUsedEmote( address emoter, address collection, @@ -24,10 +30,64 @@ interface IERC6381 { bytes4 emoji ) external view returns (bool); + function haveEmotersUsedEmotes( + address[] memory emoters, + address[] memory collections, + uint256[] memory tokenIds, + bytes4[] memory emojis + ) external view returns (bool[] memory); + + function prepareMessageToPresignEmote( + address collection, + uint256 tokenId, + bytes4 emoji, + bool state, + uint256 deadline + ) external view returns (bytes32); + + function bulkPrepareMessagesToPresignEmote( + address[] memory collections, + uint256[] memory tokenIds, + bytes4[] memory emojis, + bool[] memory states, + uint256[] memory deadlines + ) external view returns (bytes32[] memory); + function emote( address collection, uint256 tokenId, bytes4 emoji, bool state ) external; + + function bulkEmote( + address[] memory collections, + uint256[] memory tokenIds, + bytes4[] memory emojis, + bool[] memory states + ) external; + + function presignedEmote( + address emoter, + address collection, + uint256 tokenId, + bytes4 emoji, + bool state, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + function bulkPresignedEmote( + address[] memory emoters, + address[] memory collections, + uint256[] memory tokenIds, + bytes4[] memory emojis, + bool[] memory states, + uint256[] memory deadlines, + uint8[] memory v, + bytes32[] memory r, + bytes32[] memory s + ) external; } \ No newline at end of file diff --git a/assets/eip-6381/test/emotableRepository.ts b/assets/eip-6381/test/emotableRepository.ts index 11dd7d2e1be5e..18345bf4032d6 100644 --- a/assets/eip-6381/test/emotableRepository.ts +++ b/assets/eip-6381/test/emotableRepository.ts @@ -40,8 +40,8 @@ describe("RMRKEmotableRepositoryMock", async function () { repository = await loadFixture(emotableRepositoryFixture); }); - it("can support IEmotableRepository", async function () { - expect(await repository.supportsInterface("0x08eb97a6")).to.equal(true); + it("can support IERC6381", async function () { + expect(await repository.supportsInterface("0xd9fac55a")).to.equal(true); }); it("can support IERC165", async function () { @@ -132,5 +132,361 @@ describe("RMRKEmotableRepositoryMock", async function () { await repository.emoteCountOf(token.address, tokenId, emoji2) ).to.equal(bn(0)); }); + + it("can bulk emote", async function () { + expect( + await repository.bulkEmoteCountOf( + [token.address, token.address], + [tokenId, tokenId], + [emoji1, emoji2] + ) + ).to.eql([bn(0), bn(0)]); + + expect( + await repository.haveEmotersUsedEmotes( + [owner.address, owner.address], + [token.address, token.address], + [tokenId, tokenId], + [emoji1, emoji2] + ) + ).to.eql([false, false]); + + await expect( + repository.bulkEmote( + [token.address, token.address], + [tokenId, tokenId], + [emoji1, emoji2], + [true, true] + ) + ) + .to.emit(repository, "Emoted") + .withArgs( + owner.address, + token.address, + tokenId.toNumber(), + emoji1, + true + ) + .to.emit(repository, "Emoted") + .withArgs( + owner.address, + token.address, + tokenId.toNumber(), + emoji2, + true + ); + + expect( + await repository.bulkEmoteCountOf( + [token.address, token.address], + [tokenId, tokenId], + [emoji1, emoji2] + ) + ).to.eql([bn(1), bn(1)]); + + expect( + await repository.haveEmotersUsedEmotes( + [owner.address, owner.address], + [token.address, token.address], + [tokenId, tokenId], + [emoji1, emoji2] + ) + ).to.eql([true, true]); + }); + + it("can bulk undo emote", async function () { + await expect( + repository.bulkEmote( + [token.address, token.address], + [tokenId, tokenId], + [emoji1, emoji2], + [true, true] + ) + ) + .to.emit(repository, "Emoted") + .withArgs( + owner.address, + token.address, + tokenId.toNumber(), + emoji1, + true + ) + .to.emit(repository, "Emoted") + .withArgs( + owner.address, + token.address, + tokenId.toNumber(), + emoji2, + true + ); + + expect( + await repository.bulkEmoteCountOf( + [token.address, token.address], + [tokenId, tokenId], + [emoji1, emoji2] + ) + ).to.eql([bn(1), bn(1)]); + + expect( + await repository.haveEmotersUsedEmotes( + [owner.address, owner.address], + [token.address, token.address], + [tokenId, tokenId], + [emoji1, emoji2] + ) + ).to.eql([true, true]); + + await expect( + repository.bulkEmote( + [token.address, token.address], + [tokenId, tokenId], + [emoji1, emoji2], + [false, false] + ) + ) + .to.emit(repository, "Emoted") + .withArgs( + owner.address, + token.address, + tokenId.toNumber(), + emoji1, + false + ) + .to.emit(repository, "Emoted") + .withArgs( + owner.address, + token.address, + tokenId.toNumber(), + emoji2, + false + ); + + expect( + await repository.bulkEmoteCountOf( + [token.address, token.address], + [tokenId, tokenId], + [emoji1, emoji2] + ) + ).to.eql([bn(0), bn(0)]); + + expect( + await repository.haveEmotersUsedEmotes( + [owner.address, owner.address], + [token.address, token.address], + [tokenId, tokenId], + [emoji1, emoji2] + ) + ).to.eql([false, false]); + }); + + it("can bulk emote and unemote at the same time", async function () { + await repository.emote(token.address, tokenId, emoji2, true); + + expect( + await repository.bulkEmoteCountOf( + [token.address, token.address], + [tokenId, tokenId], + [emoji1, emoji2] + ) + ).to.eql([bn(0), bn(1)]); + + expect( + await repository.haveEmotersUsedEmotes( + [owner.address, owner.address], + [token.address, token.address], + [tokenId, tokenId], + [emoji1, emoji2] + ) + ).to.eql([false, true]); + + await expect( + repository.bulkEmote( + [token.address, token.address], + [tokenId, tokenId], + [emoji1, emoji2], + [true, false] + ) + ) + .to.emit(repository, "Emoted") + .withArgs( + owner.address, + token.address, + tokenId.toNumber(), + emoji1, + true + ) + .to.emit(repository, "Emoted") + .withArgs( + owner.address, + token.address, + tokenId.toNumber(), + emoji2, + false + ); + + expect( + await repository.bulkEmoteCountOf( + [token.address, token.address], + [tokenId, tokenId], + [emoji1, emoji2] + ) + ).to.eql([bn(1), bn(0)]); + + expect( + await repository.haveEmotersUsedEmotes( + [owner.address, owner.address], + [token.address, token.address], + [tokenId, tokenId], + [emoji1, emoji2] + ) + ).to.eql([true, false]); + }); + + it("can not bulk emote if passing arrays of different length", async function () { + await expect( + repository.bulkEmote( + [token.address, token.address], + [tokenId, tokenId], + [emoji1, emoji2], + [true] + ) + ).to.be.revertedWithCustomError( + repository, + "BulkParametersOfUnequalLength" + ); + + await expect( + repository.bulkEmote( + [token.address], + [tokenId, tokenId], + [emoji1, emoji2], + [true, true] + ) + ).to.be.revertedWithCustomError( + repository, + "BulkParametersOfUnequalLength" + ); + + await expect( + repository.bulkEmote( + [token.address, token.address], + [tokenId], + [emoji1, emoji2], + [true, true] + ) + ).to.be.revertedWithCustomError( + repository, + "BulkParametersOfUnequalLength" + ); + + await expect( + repository.bulkEmote( + [token.address, token.address], + [tokenId, tokenId], + [emoji1], + [true, true] + ) + ).to.be.revertedWithCustomError( + repository, + "BulkParametersOfUnequalLength" + ); + }); + + it("can use presigned emote to react to token", async function () { + const message = await repository.prepareMessageToPresignEmote( + token.address, + tokenId, + emoji1, + true, + bn(9999999999) + ); + + const signature = await owner.signMessage(ethers.utils.arrayify(message)); + + const r: string = signature.substring(0, 66); + const s: string = "0x" + signature.substring(66, 130); + const v: number = parseInt(signature.substring(130, 132), 16); + + await expect( + repository + .connect(addrs[0]) + .presignedEmote( + owner.address, + token.address, + tokenId, + emoji1, + true, + bn(9999999999), + v, + r, + s + ) + ) + .to.emit(repository, "Emoted") + .withArgs( + owner.address, + token.address, + tokenId.toNumber(), + emoji1, + true + ); + }); + + it("can use presigned emotes to bulk react to token", async function () { + const messages = await repository.bulkPrepareMessagesToPresignEmote( + [token.address, token.address], + [tokenId, tokenId], + [emoji1, emoji2], + [true, true], + [bn(9999999999), bn(9999999999)] + ); + + const signature1 = await owner.signMessage( + ethers.utils.arrayify(messages[0]) + ); + const signature2 = await owner.signMessage( + ethers.utils.arrayify(messages[1]) + ); + + const r1: string = signature1.substring(0, 66); + const s1: string = "0x" + signature1.substring(66, 130); + const v1: number = parseInt(signature1.substring(130, 132), 16); + const r2: string = signature2.substring(0, 66); + const s2: string = "0x" + signature2.substring(66, 130); + const v2: number = parseInt(signature2.substring(130, 132), 16); + + await expect( + repository + .connect(addrs[0]) + .bulkPresignedEmote( + [owner.address, owner.address], + [token.address, token.address], + [tokenId, tokenId], + [emoji1, emoji2], + [true, true], + [bn(9999999999), bn(9999999999)], + [v1, v2], + [r1, r2], + [s1, s2] + ) + ) + .to.emit(repository, "Emoted") + .withArgs( + owner.address, + token.address, + tokenId.toNumber(), + emoji1, + true + ) + .to.emit(repository, "Emoted") + .withArgs( + owner.address, + token.address, + tokenId.toNumber(), + emoji2, + true + ); + }); }); }); diff --git a/assets/eip-6785/contracts/ERC6785.sol b/assets/eip-6785/contracts/ERC6785.sol new file mode 100644 index 0000000000000..7dfbc98e8750f --- /dev/null +++ b/assets/eip-6785/contracts/ERC6785.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; +import "./IERC6785.sol"; + +contract ERC6785 is ERC721, Ownable, IERC6785 { + + /* + * bytes4(keccak256('setUtilityUri(uint256,string)')) = 0x4a048176 + * bytes4(keccak256('utilityUriOf(uint256)')) = 0x5e470cbc + * bytes4(keccak256('utilityHistoryOf(uint256)')) = 0xf96090b9 + * + * => 0x4a048176 ^ 0x5e470cbc ^ 0xf96090b9 == 0xed231d73 + */ + bytes4 public constant _INTERFACE_ID_ERC6785 = 0xed231d73; + + mapping(uint => string[]) private utilities; + + constructor(string memory name_, string memory symbol_) ERC721(name_, symbol_) {} + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return + interfaceId == type(IERC6785).interfaceId || super.supportsInterface(interfaceId); + } + + function setUtilityUri(uint256 tokenId, string calldata utilityUri) override external onlyOwner { + utilities[tokenId].push(utilityUri); + emit UpdateUtility(tokenId, utilityUri); + } + + function utilityUriOf(uint256 tokenId) override external view returns (string memory) { + uint last = utilities[tokenId].length - 1; + return utilities[tokenId][last]; + } + + function utilityHistoryOf(uint256 tokenId) override external view returns (string[] memory){ + return utilities[tokenId]; + } +} diff --git a/assets/eip-6785/contracts/IERC6785.sol b/assets/eip-6785/contracts/IERC6785.sol new file mode 100644 index 0000000000000..fc933dba28bfc --- /dev/null +++ b/assets/eip-6785/contracts/IERC6785.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.0; + +interface IERC6785 { + + // Logged when the utility description URL of an NFT is changed + /// @notice Emitted when the utilityURL of an NFT is changed + /// The empty string for `utilityUri` indicates that there is no utility associated + event UpdateUtility(uint256 indexed tokenId, string utilityUri); + + /// @notice set the new utilityUri - remember the date it was set on + /// @dev The empty string indicates there is no utility + /// Throws if `tokenId` is not valid NFT + /// @param utilityUri The new utility description of the NFT + function setUtilityUri(uint256 tokenId, string calldata utilityUri) external; + + /// @notice Get the utilityUri of an NFT + /// @dev The empty string for `utilityUri` indicates that there is no utility associated + /// @param tokenId The NFT to get the user address for + /// @return The utility uri for this NFT + function utilityUriOf(uint256 tokenId) external view returns (string memory); + + /// @notice Get the changes made to utilityUri + /// @param tokenId The NFT to get the user address for + /// @return The history of changes to `utilityUri` for this NFT + function utilityHistoryOf(uint256 tokenId) external view returns(string[] memory); +} diff --git a/assets/eip-6785/test/ERC6785.test.js b/assets/eip-6785/test/ERC6785.test.js new file mode 100644 index 0000000000000..d585bfb4e9fc3 --- /dev/null +++ b/assets/eip-6785/test/ERC6785.test.js @@ -0,0 +1,56 @@ +const {deployContracts} = require("../scripts/deploy_contracts"); +const {expect} = require('chai'); + +describe('ERC6785', () => { + let erc6785; + const tokenId = 123; + const utilityUrl1 = 'https://utility.url'; + + beforeEach(async () => { + erc6785 = await deployContracts(); + }); + + it('should support ERC6785 interface', async () => { + await expect(await erc6785.supportsInterface( + await erc6785._INTERFACE_ID_ERC6785(), + )).to.be.true; + }); + + it('should allow setting first utility NFT', async () => { + await expect(erc6785.setUtilityUri( + tokenId, + utilityUrl1, + )).to.emit(erc6785, 'UpdateUtility').withArgs(tokenId, utilityUrl1); + }); + + it('should allow retrieving initial royalties amount for a NFT', + async () => { + await expect(erc6785.setUtilityUri( + tokenId, + utilityUrl1, + )).to.emit(erc6785, 'UpdateUtility').withArgs(tokenId, utilityUrl1); + + await expect(await erc6785.utilityUriOf( + tokenId, + )).to.equal(utilityUrl1); + }) + + it('should allow retrieving utility history for the NFT', async () => { + await expect(erc6785.setUtilityUri( + tokenId, + utilityUrl1, + )).to.emit(erc6785, 'UpdateUtility').withArgs(tokenId, utilityUrl1); + let utilityUrl2 = utilityUrl1 + '_2'; + await expect(erc6785.setUtilityUri( + tokenId, + utilityUrl2, + )).to.emit(erc6785, 'UpdateUtility').withArgs(tokenId, utilityUrl2); + + let history = await erc6785.utilityHistoryOf( + tokenId, + ); + await expect(history.length).to.equal(2); + await expect(history[0]).to.equal(utilityUrl1); + await expect(history[1]).to.equal(utilityUrl2); + }) +}); diff --git a/assets/eip-6786/README.md b/assets/eip-6786/README.md new file mode 100644 index 0000000000000..cc3a5481a726d --- /dev/null +++ b/assets/eip-6786/README.md @@ -0,0 +1,27 @@ +
+ +# ERC6786 Royalty Debt Registry + +
+ +This project provides a reference implementation of the proposed `ERC-6786 Royalty Debt Registry`. + +## Install + +In order to install the required dependencies you need to execute: +```shell +npm install +``` + +## Compile + +In order to compile the solidity contracts you need to execute: +```shell +npx hardhat compile +``` + +## Tests + +```shell +npx hardhat test +``` \ No newline at end of file diff --git a/assets/eip-6786/contracts/ERC6786.sol b/assets/eip-6786/contracts/ERC6786.sol new file mode 100644 index 0000000000000..8910fe39930d8 --- /dev/null +++ b/assets/eip-6786/contracts/ERC6786.sol @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import "./IERC6786.sol"; +import "./utils/IERC2981.sol"; + +contract ERC6786 is IERC6786, ERC165 { + + //Mapping from token (address and id) to the amount of paid royalties + mapping(address => mapping(uint256 => uint256)) private _paidRoyalties; + + /* + * bytes4(keccak256('payRoyalties(address,uint256)')) == 0xf511f0e9 + * bytes4(keccak256('getPaidRoyalties(address,uint256)')) == 0xd02ad759 + * + * => 0xf511f0e9 ^ 0xd02ad759 == 0x253b27b0 + */ + bytes4 private constant _INTERFACE_ID_ERC6786 = 0x253b27b0; + + /* + * bytes4(keccak256('royaltyInfo(uint256,uint256)')) == 0x2a55205a + */ + bytes4 private constant _INTERFACE_ID_ERC2981 = 0x2a55205a; + + /// @notice This is thrown when there is no creator related information + /// @param tokenAddress -> the address of the contract + /// @param tokenId -> the id of the NFT + error CreatorError(address tokenAddress, uint256 tokenId); + + /// @notice This is thrown when the payment fails + /// @param creator -> the address of the creator + /// @param amount -> the amount to pay + error PaymentError(address creator, uint256 amount); + + function checkRoyalties(address _contract) internal view returns (bool) { + (bool success) = IERC165(_contract).supportsInterface(_INTERFACE_ID_ERC2981); + return success; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return + interfaceId == type(IERC6786).interfaceId || + super.supportsInterface(interfaceId); + } + + function payRoyalties(address tokenAddress, uint256 tokenId) external override payable { + if (!checkRoyalties(tokenAddress)) { + revert CreatorError(tokenAddress, tokenId); + } + (address creator,) = IERC2981(tokenAddress).royaltyInfo(tokenId, 0); + (bool success,) = payable(creator).call{value : msg.value}(""); + if(!success) { + revert PaymentError(creator, msg.value); + } + _paidRoyalties[tokenAddress][tokenId] += msg.value; + + emit RoyaltiesPaid(tokenAddress, tokenId, msg.value); + } + + function getPaidRoyalties(address tokenAddress, uint256 tokenId) external view override returns (uint256) { + return _paidRoyalties[tokenAddress][tokenId]; + } +} diff --git a/assets/eip-6786/contracts/IERC6786.sol b/assets/eip-6786/contracts/IERC6786.sol new file mode 100644 index 0000000000000..9ed6d35b9e9f7 --- /dev/null +++ b/assets/eip-6786/contracts/IERC6786.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.0; + +interface IERC6786 { + + /// @dev Logged when royalties were paid for a NFT + /// @notice Emitted when royalties are paid for the NFT with address tokenAddress and id tokenId + event RoyaltiesPaid(address indexed tokenAddress, uint256 indexed tokenId, uint256 amount); + + /// @notice sends msg.value to the creator for a NFT + /// @dev Throws if there is no on-chain information about the creator + /// @param tokenAddress The address of NFT contract + /// @param tokenId The NFT id + function payRoyalties(address tokenAddress, uint256 tokenId) external payable; + + /// @notice Get the amount of royalties which was paid for + /// @param tokenAddress The address of NFT contract + /// @param tokenId The NFT id + /// @return The amount of royalties paid for the NFT in paymentToken + function getPaidRoyalties(address tokenAddress, uint256 tokenId) external view returns (uint256); +} diff --git a/assets/eip-6786/contracts/token/ERC721Royalty.sol b/assets/eip-6786/contracts/token/ERC721Royalty.sol new file mode 100644 index 0000000000000..94a7d652ab0f1 --- /dev/null +++ b/assets/eip-6786/contracts/token/ERC721Royalty.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "../utils/IERC2981.sol"; + +contract ERC721Royalty is ERC721, IERC2981 { + + address public constant DEFAULT_CREATOR_ADDRESS = 0x4fF5DDB196A32e3dC604abD5422805ecAD22c468; + + constructor(string memory name_, string memory symbol_) ERC721(name_, symbol_) {} + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, IERC165) returns (bool) { + return + interfaceId == type(IERC721).interfaceId || + interfaceId == type(IERC2981).interfaceId || + super.supportsInterface(interfaceId); + } + + function royaltyInfo( + uint256 _tokenId, + uint256 _salePrice + ) external view override returns ( + address receiver, + uint256 royaltyAmount + ) { + receiver = DEFAULT_CREATOR_ADDRESS; + royaltyAmount = _salePrice / 10000; + } +} diff --git a/assets/eip-6786/contracts/utils/IERC2981.sol b/assets/eip-6786/contracts/utils/IERC2981.sol new file mode 100644 index 0000000000000..406d2a3ea1673 --- /dev/null +++ b/assets/eip-6786/contracts/utils/IERC2981.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + +interface IERC2981 is IERC165 { + function royaltyInfo( + uint256 _tokenId, + uint256 _salePrice + ) external view returns ( + address receiver, + uint256 royaltyAmount + ); +} diff --git a/assets/eip-6786/test/ERC6786.test.js b/assets/eip-6786/test/ERC6786.test.js new file mode 100644 index 0000000000000..07a03e33bdb86 --- /dev/null +++ b/assets/eip-6786/test/ERC6786.test.js @@ -0,0 +1,65 @@ +const {deployContracts} = require("../scripts/deploy_contracts"); +const {expect} = require('chai'); + +describe("ERC6786", () => { + + let erc721Royalty; + let erc721; + let royaltyDebtRegistry; + const tokenId = 666; + + beforeEach(async () => { + const contracts = await deployContracts(); + erc721Royalty = contracts.erc721Royalty; + erc721 = contracts.erc721; + royaltyDebtRegistry = contracts.royaltyDebtRegistry; + }) + + it('should support ERC6786 interface', async () => { + await expect(await royaltyDebtRegistry.supportsInterface("0x253b27b0")).to.be.true; + }) + + it('should allow paying royalties for a ERC2981 NFT', async () => { + await expect(royaltyDebtRegistry.payRoyalties( + erc721Royalty.address, + tokenId, + {value: 1000} + )).to.emit(royaltyDebtRegistry, 'RoyaltiesPaid') + .withArgs(erc721Royalty.address, tokenId, 1000); + }) + + it('should not allow paying royalties for a non-ERC2981 NFT', async () => { + await expect(royaltyDebtRegistry.payRoyalties( + erc721.address, + tokenId, + {value: 1000} + )).to.be.revertedWithCustomError(royaltyDebtRegistry,'CreatorError') + .withArgs(erc721.address, tokenId); + }) + + it('should allow retrieving initial royalties amount for a NFT', async () => { + await expect(await royaltyDebtRegistry.getPaidRoyalties( + erc721Royalty.address, + tokenId + )).to.equal(0); + }) + + it('should allow retrieving royalties amount after payments for a NFT', async () => { + await royaltyDebtRegistry.payRoyalties( + erc721Royalty.address, + tokenId, + {value: 2000} + ); + + await royaltyDebtRegistry.payRoyalties( + erc721Royalty.address, + tokenId, + {value: 3666} + ) + + await expect(await royaltyDebtRegistry.getPaidRoyalties( + erc721Royalty.address, + tokenId + )).to.equal(5666); + }) +}); diff --git a/assets/eip-6787/image1.png b/assets/eip-6787/image1.png new file mode 100644 index 0000000000000..e940ea3d2054a Binary files /dev/null and b/assets/eip-6787/image1.png differ diff --git a/assets/eip-6865/contracts/IEIP712Visualizer.sol b/assets/eip-6865/contracts/IEIP712Visualizer.sol new file mode 100644 index 0000000000000..63e2f4a27f390 --- /dev/null +++ b/assets/eip-6865/contracts/IEIP712Visualizer.sol @@ -0,0 +1,43 @@ +pragma solidity ^0.8.0; + +interface IEIP712Visualizer { + struct Liveness { + uint256 from; + uint256 to; + } + + struct UserAssetMovement { + address assetTokenAddress; + uint256 id; + uint256[] amounts; + } + + struct Result { + UserAssetMovement[] assetsIn; + UserAssetMovement[] assetsOut; + Liveness liveness; + } + + /** + * @notice This function processes an EIP-712 payload message and returns a structured data format emphasizing the potential impact on users' assets. + * @dev The function returns assetsOut (assets the user is offering), assetsIn (assets the user would receive), and liveness (validity duration of the EIP-712 message). + * + * - MUST revert if the domainHash identifier is not supported (require(domainHash == DOMAIN_SEPARATOR, "message")). + * - MUST NOT revert if there are no assetsIn, assetsOut, or liveness values; returns nullish values instead. + * - assetsIn MUST include only assets for which the user is the recipient. + * - assetsOut MUST include only assets for which the user is the sender. + * - MUST returns liveness.to as type(uint256).max if the message never expires. + * - MUST returns liveness.from as block.timestamp if the message does not have a validity starting date. + * - MUST returns a set (array) of amounts in assetsIn.amounts and assetsOut.amount where items define the amount per time curve, with time defined within liveness boundaries. + * - amounts items MUST include the minimum amount. + * - MUST returns the minimum amount if amounts set contains only one item + * + * @param encodedMessage The ABI-encoded EIP-712 message (abi.encode(types, params)). + * @param domainHash The hash of the EIP-712 domain separator as defined in the EIP-712 proposal; see https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator. + * @return Result struct containing the user's assets impact and message liveness. + */ + function visualizeEIP712Message( + bytes memory encodedMessage, + bytes32 domainHash + ) external view returns (Result memory); +} diff --git a/assets/eip-6865/contracts/SeaPortEIP712Visualizer.sol b/assets/eip-6865/contracts/SeaPortEIP712Visualizer.sol new file mode 100644 index 0000000000000..43144c633901c --- /dev/null +++ b/assets/eip-6865/contracts/SeaPortEIP712Visualizer.sol @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.17; + +import {IEIP712Visualizer} from "./IEIP712Visualizer.sol"; + +contract SeaPortEIP712Visualizer is IEIP712Visualizer { + bytes32 public constant DOMAIN_SEPARATOR = + 0xb50c8913581289bd2e066aeef89fceb9615d490d673131fd1a7047436706834e; //v1.1 + + enum OrderType { + FULL_OPEN, + PARTIAL_OPEN, + FULL_RESTRICTED, + PARTIAL_RESTRICTED, + CONTRACT + } + + enum ItemType { + NATIVE, + ERC20, + ERC721, + ERC1155, + ERC721_WITH_CRITERIA, + ERC1155_WITH_CRITERIA + } + struct OrderComponents { + address offerer; + address zone; + OfferItem[] offer; + ConsiderationItem[] consideration; + OrderType orderType; + uint256 startTime; + uint256 endTime; + bytes32 zoneHash; + uint256 salt; + bytes32 conduitKey; + uint256 counter; + } + + struct OfferItem { + ItemType itemType; + address token; + uint256 identifierOrCriteria; + uint256 startAmount; + uint256 endAmount; + } + + struct ConsiderationItem { + ItemType itemType; + address token; + uint256 identifierOrCriteria; + uint256 startAmount; + uint256 endAmount; + address payable recipient; + } + + constructor() {} + + function visualizeEIP712Message( + bytes memory encodedMessage, + bytes32 domainHash + ) external view returns (Result memory) { + require( + domainHash == DOMAIN_SEPARATOR, + "SeaPortEIP712Visualizer: unsupported domain" + ); + + OrderComponents memory order = abi.decode( + encodedMessage, + (OrderComponents) + ); + + UserAssetMovement[] memory assetsOut = new UserAssetMovement[]( + order.offer.length + ); + + for (uint256 i = 0; i < order.offer.length; ) { + uint256[] memory amounts = extractAmounts(order.offer[i]); + assetsOut[i] = UserAssetMovement({ + assetTokenAddress: order.offer[i].token, + id: order.offer[i].identifierOrCriteria, + amounts: amounts + }); + + unchecked { + ++i; + } + } + + ConsiderationItem[] memory userConsiderations = fliterByRecepient( + order.consideration, + order.offerer + ); + UserAssetMovement[] memory assetsIn = new UserAssetMovement[]( + userConsiderations.length + ); + + for (uint256 i = 0; i < userConsiderations.length; ) { + uint256[] memory amounts = extractAmounts(userConsiderations[i]); + + assetsIn[i] = UserAssetMovement({ + assetTokenAddress: userConsiderations[i].token, + id: userConsiderations[i].identifierOrCriteria, + amounts: amounts + }); + + unchecked { + ++i; + } + } + + return + Result({ + assetsIn: assetsIn, + assetsOut: assetsOut, + liveness: Liveness({from: order.startTime, to: order.endTime}) + }); + } + + function fliterByRecepient( + ConsiderationItem[] memory consideration, + address recepient + ) private view returns (ConsiderationItem[] memory) { + uint256 recepientItemsCount; + for (uint256 i = 0; i < consideration.length; ) { + if (consideration[i].recipient == recepient) { + unchecked { + ++recepientItemsCount; + } + } + + unchecked { + ++i; + } + } + ConsiderationItem[] memory result = new ConsiderationItem[]( + recepientItemsCount + ); + uint256 resultIndex; + for (uint256 i = 0; i < recepientItemsCount; ) { + if (consideration[i].recipient == recepient) { + result[resultIndex] = consideration[i]; + unchecked { + ++resultIndex; + } + } + + unchecked { + ++i; + } + } + + return result; + } + + function extractAmounts( + OfferItem memory offer + ) private pure returns (uint256[] memory) { + uint256[] memory amounts = new uint256[](2); + if (offer.endAmount == offer.startAmount) { + uint256[] memory amounts = new uint256[](1); + amounts[0] = offer.startAmount; + return amounts; + } else if (offer.endAmount > offer.startAmount) { + amounts[0] = offer.startAmount; + amounts[1] = offer.endAmount; + } else if (offer.endAmount < offer.startAmount) { + amounts[0] = offer.endAmount; + amounts[1] = offer.startAmount; + } + + return amounts; + } + + function extractAmounts( + ConsiderationItem memory consideration + ) private pure returns (uint256[] memory) { + uint256[] memory amounts = new uint256[](2); + if (consideration.endAmount == consideration.startAmount) { + uint256[] memory amounts = new uint256[](1); + amounts[0] = consideration.startAmount; + return amounts; + } else if (consideration.endAmount > consideration.startAmount) { + amounts[0] = consideration.startAmount; + amounts[1] = consideration.endAmount; + } else { + amounts[0] = consideration.endAmount; + amounts[1] = consideration.startAmount; + } + return amounts; + } +} diff --git a/assets/eip-6865/current-EIP-712-signature-wallet-interface.png b/assets/eip-6865/current-EIP-712-signature-wallet-interface.png new file mode 100644 index 0000000000000..9e2a8fb009ff3 Binary files /dev/null and b/assets/eip-6865/current-EIP-712-signature-wallet-interface.png differ diff --git a/assets/eip-6865/vision-EIP-712-signature-wallet-interface.png b/assets/eip-6865/vision-EIP-712-signature-wallet-interface.png new file mode 100644 index 0000000000000..c7bc75c4bb97c Binary files /dev/null and b/assets/eip-6865/vision-EIP-712-signature-wallet-interface.png differ diff --git a/assets/eip-modular-smart-contract-accounts-and-plugins/MSCA_Shared_Components_Diagram.svg b/assets/eip-6900/MSCA_Shared_Components_Diagram.svg similarity index 100% rename from assets/eip-modular-smart-contract-accounts-and-plugins/MSCA_Shared_Components_Diagram.svg rename to assets/eip-6900/MSCA_Shared_Components_Diagram.svg diff --git a/assets/eip-6900/MSCA_Two_Call_Paths_Diagram.svg b/assets/eip-6900/MSCA_Two_Call_Paths_Diagram.svg new file mode 100644 index 0000000000000..96d76a98747b0 --- /dev/null +++ b/assets/eip-6900/MSCA_Two_Call_Paths_Diagram.svg @@ -0,0 +1,16 @@ + + + + + + + SCAEntryPointEOA/SC callA.0B.1A.1A.2Step 1Step 2Step 3Step 4ACalls from Entrypoint (ERC-4337)BCalls from EOAs and other contractsB.2UserOpValidatorvalidateUserOpPre-UserOpValidate Hook(s)Execution FunctionPre-Execution Hook(s)Post-Execution Hook(s)A.3 B.3A.4 B.4fallback & standard executionfrom EntryPoint?RuntimeValidatorPre-RuntimeValidate Hook(s)noyesStep 5 \ No newline at end of file diff --git a/assets/eip-6956/.gitignore b/assets/eip-6956/.gitignore new file mode 100644 index 0000000000000..74956f8d80a99 --- /dev/null +++ b/assets/eip-6956/.gitignore @@ -0,0 +1,8 @@ +node_modules + +#Hardhat files +cache +artifacts +typechain* + +package-lock.json diff --git a/assets/eip-6956/LICENSE.md b/assets/eip-6956/LICENSE.md new file mode 100644 index 0000000000000..1d853863a3b82 --- /dev/null +++ b/assets/eip-6956/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Authentic Vision GmbH + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/assets/eip-6956/README.md b/assets/eip-6956/README.md new file mode 100644 index 0000000000000..dffbad5b12688 --- /dev/null +++ b/assets/eip-6956/README.md @@ -0,0 +1,12 @@ +# ERCxxxx Reference implementation +This reference implementation is [MIT](LICENSE.md) licensed and can therefore be freely used in any project. + +## Getting started +From this directory, run + +``` +npm install && npx hardhat test +``` + + + diff --git a/assets/eip-6956/contracts/ERC6956.sol b/assets/eip-6956/contracts/ERC6956.sol new file mode 100644 index 0000000000000..39543258b1fae --- /dev/null +++ b/assets/eip-6956/contracts/ERC6956.sol @@ -0,0 +1,491 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.18; + +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; +import "@openzeppelin/contracts/security/Pausable.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; +import "@openzeppelin/contracts/utils/Counters.sol"; +import "@openzeppelin/contracts/utils/Strings.sol"; + +import "./IERC6956.sol"; + +/** Used for several authorization mechansims, e.g. who can burn, who can set approval, ... + * @dev Specifying the role in the ecosystem. Used in conjunction with IERC6956.Authorization + */ +enum Role { + OWNER, // =0, The owner of the digital token + ISSUER, // =1, The issuer (contract) of the tokens, typically represented through a MAINTAINER_ROLE, the contract owner etc. + ASSET, // =2, The asset identified by the anchor + INVALID // =3, Reserved, do not use. +} + +/** + * @title ASSET-BOUND NFT minimal reference implementation + * @author Thomas Bergmueller (@tbergmueller) + * + * @dev Error messages + * ``` + * ERROR | Message + * ------|------------------------------------------------------------------- + * E1 | Only maintainer allowed + * E2 | No permission to burn + * E3 | Token does not exist, call transferAnchor first to mint + * E4 | batchSize must be 1 + * E5 | Token not transferable + * E6 | Token already owned + * E7 | Not authorized based on ERC6956Authorization + * E8 | Attestation not signed by trusted oracle + * E9 | Attestation already used + * E10 | Attestation not valid yet + * E11 | Attestation expired + * E12 | Attestation expired (contract limit) + * E13 | Invalid signature length + * E14-20| Reserved for future use + * ``` + */ +contract ERC6956 is + ERC721, + ERC721Enumerable, + ERC721Burnable, + IERC6956 +{ + using Counters for Counters.Counter; + + mapping(bytes32 => bool) internal _anchorIsReleased; // currently released anchors. Per default, all anchors are dropped, i.e. 1:1 bound + + mapping(address => bool) public maintainers; + + /// @notice Resolves tokenID to anchor. Inverse of tokenByAnchor + mapping(uint256 => bytes32) public anchorByToken; + + /// @notice Resolves Anchor to tokenID. Inverse of anchorByToken + mapping(bytes32 => uint256) public tokenByAnchor; + + mapping(address => bool) private _trustedOracles; + + /// @dev stores the anchors for each attestation + mapping(bytes32 => bytes32) private _anchorByUsedAttestation; + + /// @dev stores handed-back tokens (via burn) + mapping (bytes32 => uint256) private _burnedTokensByAnchor; + + + /** + * @dev Counter to keep track of issued tokens + */ + Counters.Counter private _tokenIdCounter; + + /// @dev Default validity timespan of attestation. In validateAttestation the attestationTime is checked for MIN(defaultAttestationvalidity, attestation.expiry) + uint256 public maxAttestationExpireTime = 5*60; // 5min valid per default + + Authorization public burnAuthorization; + Authorization public approveAuthorization; + + + /// @dev Records the number of transfers done for each attestation + mapping(bytes32 => uint256) public attestationsUsedByAnchor; + + modifier onlyMaintainer() { + require(isMaintainer(msg.sender), "ERC6956-E1"); + _; + } + + /** + * @notice Behaves like ERC721 burn() for wallet-cleaning purposes. Note only the tokenId (as a wrapper) is burned, not the ASSET represented by the ANCHOR. + * @dev + * - tokenId is remembered for the anchor, to ensure a later transferAnchor(), which would mint, assigns the same tokenId. This ensures strict 1:1 relation + * - For burning, the anchor needs to be released. This forced release FOR BURNING ONLY is allowed for owner() or approvedOwner(). + * + * @param tokenId The token that shall be burned + */ + function burn(uint256 tokenId) public override + { + // remember the tokenId of burned tokens, s.t. one can issue the token with the same number again + bytes32 anchor = anchorByToken[tokenId]; + require(_roleBasedAuthorization(anchor, createAuthorizationMap(burnAuthorization)), "ERC6956-E2"); + _burn(tokenId); + } + + function burnAnchor(bytes memory attestation, bytes memory data) public virtual + authorized(Role.ASSET, createAuthorizationMap(burnAuthorization)) + { + address to; + bytes32 anchor; + bytes32 attestationHash; + (to, anchor, attestationHash) = decodeAttestationIfValid(attestation, data); + _commitAttestation(to, anchor, attestationHash); + uint256 tokenId = tokenByAnchor[anchor]; + // remember the tokenId of burned tokens, s.t. one can issue the token with the same number again + _burn(tokenId); + } + + function burnAnchor(bytes memory attestation) public virtual { + return burnAnchor(attestation, ""); + } + + function approveAnchor(bytes memory attestation, bytes memory data) public virtual + authorized(Role.ASSET, createAuthorizationMap(approveAuthorization)) + { + address to; + bytes32 anchor; + bytes32 attestationHash; + (to, anchor, attestationHash) = decodeAttestationIfValid(attestation, data); + _commitAttestation(to, anchor, attestationHash); + require(tokenByAnchor[anchor]>0, "ERC6956-E3"); + _approve(to, tokenByAnchor[anchor]); + } + + // approveAuth == ISSUER does not really make sense.. so no separate implementation, since ERC-721.approve already implies owner... + + function approve(address to, uint256 tokenId) public virtual override(ERC721,IERC721) + authorized(Role.OWNER, createAuthorizationMap(approveAuthorization)) + { + super.approve(to, tokenId); + } + + function approveAnchor(bytes memory attestation) public virtual { + return approveAnchor(attestation, ""); + } + + /** + * @notice Adds or removes a trusted oracle, used when verifying signatures in `decodeAttestationIfValid()` + * @dev Emits OracleUpdate + * @param oracle address of oracle + * @param doTrust true to add, false to remove + */ + function updateOracle(address oracle, bool doTrust) public + onlyMaintainer() + { + _trustedOracles[oracle] = doTrust; + emit OracleUpdate(oracle, doTrust); + } + + /** + * @dev A very simple function wich MUST return false, when `a` is not a maintainer + * When derived contracts extend ERC6956 contract, this function may be overridden + * e.g. by using AccessControl, onlyOwner or other common mechanisms + * + * Having this simple mechanism in the reference implementation ensures that the reference + * implementation is fully ERC-6956 compatible + */ + function isMaintainer(address a) public virtual view returns (bool) { + return maintainers[a]; + } + + + function createAuthorizationMap(Authorization _auth) public pure returns (uint256) { + uint256 authMap = 0; + if(_auth == Authorization.OWNER + || _auth == Authorization.OWNER_AND_ASSET + || _auth == Authorization.OWNER_AND_ISSUER + || _auth == Authorization.ALL) { + authMap |= uint256(1< 0) { + from = ownerOf(fromToken); + require(from != to, "ERC6956-E6"); + _safeTransfer(from, to, fromToken, ""); + } else { + _safeMint(to, anchor); + } + } + + function transferAnchor(bytes memory attestation) public virtual { + return transferAnchor(attestation, ""); + } + + + function hasAuthorization(Role _role, uint256 _auth ) public pure returns (bool) { + uint256 result = uint256(_auth & (1 << uint256(_role))); + return result > 0; + } + + modifier authorized(Role _role, uint256 _authMap) { + require(hasAuthorization(_role, _authMap), "ERC6956-E7"); + _; + } + + // The following functions are overrides required by Solidity, EIP-165. + function supportsInterface(bytes4 interfaceId) + public + view + virtual + override(ERC721, ERC721Enumerable) + returns (bool) + { + return + interfaceId == type(IERC6956).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @notice Returns whether a certain address is registered as trusted oracle, i.e. attestations signed by this address are accepted in `decodeAttestationIfValid` + * @dev This function may be overwritten when extending ERC-6956, e.g. when other oracle-registration mechanics are used + * @param oracleAddress Address of the oracle in question + * @return isTrusted True, if oracle is trusted + */ + function isTrustedOracle(address oracleAddress) public virtual view returns (bool isTrusted) { + return _trustedOracles[oracleAddress]; + } + + + function decodeAttestationIfValid(bytes memory attestation, bytes memory data) public view returns (address to, bytes32 anchor, bytes32 attestationHash) { + uint256 attestationTime; + uint256 validStartTime; + uint256 validEndTime; + bytes memory signature; + bytes32[] memory proof; + + attestationHash = keccak256(attestation); + (to, anchor, attestationTime, validStartTime, validEndTime, signature) = abi.decode(attestation, (address, bytes32, uint256, uint256, uint256, bytes)); + + bytes32 messageHash = keccak256(abi.encodePacked(to, anchor, attestationTime, validStartTime, validEndTime, proof)); + address signer = _extractSigner(messageHash, signature); + + // Check if from trusted oracle + require(isTrustedOracle(signer), "ERC6956-E8"); + require(_anchorByUsedAttestation[attestationHash] <= 0, "ERC6956-E9"); + + // Check expiry + uint256 timestamp = block.timestamp; + require(timestamp > validStartTime, "ERC6956-E10"); + require(attestationTime + maxAttestationExpireTime > block.timestamp, "ERC6956-E11"); + require(validEndTime > block.timestamp, "ERC6956-E112"); + + + // Calling hook! + _beforeAttestationUse(anchor, to, data); + return(to, anchor, attestationHash); + } + + /// @notice Compatible with ERC721.tokenURI(). Returns {baseURI}{anchor} + /// @dev Returns when called for tokenId=5, baseURI=https://myurl.com/collection/ and anchorByToken[5] = 0x12345 + /// Example: https://myurl.com/collection/0x12345 + /// Works for non-burned tokens / active-Anchors only. + /// Anchor-based tokenURIs are needed as an anchor's corresponding tokenId is only known after mint. + /// @param tokenId TokenID + /// @return tokenURI Returns the Uniform Resource Identifier (URI) for `tokenId` token. + function tokenURI(uint256 tokenId) public view override returns (string memory) { + bytes32 anchor = anchorByToken[tokenId]; + string memory anchorString = Strings.toHexString(uint256(anchor)); + return bytes(_baseURI()).length > 0 ? string(abi.encodePacked(_baseURI(), anchorString)) : ""; + } + + function _baseURI() internal view virtual override(ERC721) returns (string memory) { + return _baseUri; + } + + /** + * @dev Base URI, MUST end with a slash. Will be used as `{baseURI}{tokenId}` in tokenURI() function + */ + string internal _baseUri = ""; // needs to end with '/' + + /// @notice Set a new BaseURI. Can be used with dynamic NFTs that have server APIs, IPFS-buckets + /// or any other suitable system. Refer tokenURI(tokenId) for anchor-based or tokenId-based format. + /// @param tokenBaseURI The token base-URI. Must end with slash '/'. + function updateBaseURI(string calldata tokenBaseURI) public onlyMaintainer() { + _baseUri = tokenBaseURI; + } + event BurnAuthorizationChange(Authorization burnAuth, address indexed maintainer); + + function updateBurnAuthorization(Authorization burnAuth) public onlyMaintainer() { + burnAuthorization = burnAuth; + emit BurnAuthorizationChange(burnAuth, msg.sender); + // TODO event + } + + event ApproveAuthorizationChange(Authorization approveAuth, address indexed maintainer); + + function updateApproveAuthorization(Authorization approveAuth) public onlyMaintainer() { + approveAuthorization = approveAuth; + emit ApproveAuthorizationChange(approveAuth, msg.sender); + + // TODO event + } + + constructor(string memory _name, string memory _symbol) + ERC721(_name, _symbol) { + maintainers[msg.sender] = true; // deployer is automatically maintainer + // Indicates general float-ability, i.e. whether anchors can be digitally dropped and released + + // OWNER and ASSET shall normally be in sync anyway, so this is reasonable default + // authorization for approve and burn, as it mimicks ERC-721 behavior + burnAuthorization = Authorization.OWNER_AND_ASSET; + approveAuthorization = Authorization.OWNER_AND_ASSET; + } + + /* + ########################## SIGNATURE MAGIC, + ########################## adapted from https://solidity-by-example.org/signature/ + */ + /** + * Returns the signer of a message. + * + * OFF-CHAIN: + * const [alice] = ethers.getSigners(); // = 0x3c44... + * const messageHash = ethers.utils.solidityKeccak256(["address", "bytes32"], [a, b]); + const sig = await alice.signMessage(ethers.utils.arrayify(messageHash)); + + ONCHAIN In this contract, call from + ``` + function (address a, bytes32 b, bytes memory sig) { + messageHash = keccak256(abi.encodePacked(to, b)); + signer = extractSigner(messageHash, sig); // signer will be 0x3c44... + } + ``` * + * @param messageHash A keccak25(abi.encodePacked(...)) hash + * @param sig Signature (length 65 bytes) + * + * @return The signer + */ + function _extractSigner(bytes32 messageHash, bytes memory sig) internal pure returns (address) { + require(sig.length == 65, "ERC6956-E13"); + /* + Signature is produced by signing a keccak256 hash with the following format: + "\x19Ethereum Signed Message\n" + len(msg) + msg + */ + bytes32 ethSignedMessageHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", messageHash)); + + bytes32 r; + bytes32 s; + uint8 v; + + // Extract the r, s, and v parameters from the signature + assembly { + r := mload(add(sig, 32)) + s := mload(add(sig, 64)) + v := byte(0, mload(add(sig, 96))) + } + + // Ensure the v parameter is either 27 or 28 + // TODO is this needed? + if (v < 27) { + v += 27; + } + + // Recover the public key from the signature and message hash + // and convert it to an address + address signer = ecrecover(ethSignedMessageHash, v, r, s); + return signer; + } +} diff --git a/assets/eip-6956/contracts/ERC6956Full.sol b/assets/eip-6956/contracts/ERC6956Full.sol new file mode 100644 index 0000000000000..d7e67a22c5500 --- /dev/null +++ b/assets/eip-6956/contracts/ERC6956Full.sol @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.18; + +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; +import "@openzeppelin/contracts/security/Pausable.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; +import "@openzeppelin/contracts/utils/Counters.sol"; +import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; + +import "./ERC6956.sol"; +import "./IERC6956AttestationLimited.sol"; +import "./IERC6956Floatable.sol"; +import "./IERC6956ValidAnchors.sol"; + +/** + * @title ASSET-BOUND NFT implementation with all interfaces + * @author Thomas Bergmueller (@tbergmueller) + * @notice Extends ERC6956.sol with additional interfaces and functionality + * + * @dev Error-codes + * ERROR | Message + * ------|------------------------------------------------------------------- + * E1-20 | See ERC6956.sol + * E21 | No permission to start floating + * E22 | No permission to stop floating + * E23 | allowFloating can only be called when changing floating state + * E24 | No attested transfers left + * E25 | data must contain merkle-proof + * E26 | Anchor not valid + * E27 | Updating attestedTransferLimit violates policy + */ +contract ERC6956Full is ERC6956, IERC6956AttestationLimited, IERC6956Floatable, IERC6956ValidAnchors { + Authorization public floatStartAuthorization; + Authorization public floatStopAuthorization; + + /// ############################################################################################################################### + /// ############################################################################################## IERC6956AttestedTransferLimited + /// ############################################################################################################################### + + mapping(bytes32 => uint256) public attestedTransferLimitByAnchor; + mapping(bytes32 => FloatState) public floatingStateByAnchor; + + uint256 public globalAttestedTransferLimitByAnchor; + AttestationLimitPolicy public attestationLimitPolicy; + + bool public allFloating; + + /// @dev The merkle-tree root node, where proof is validated against. Update via updateValidAnchors(). Use salt-leafs in merkle-trees! + bytes32 private _validAnchorsMerkleRoot; + + function _requireValidLimitUpdate(uint256 oldValue, uint256 newValue) internal view { + if(newValue > oldValue) { + require(attestationLimitPolicy == AttestationLimitPolicy.FLEXIBLE || attestationLimitPolicy == AttestationLimitPolicy.INCREASE_ONLY, "ERC6956-E27"); + } else { + require(attestationLimitPolicy == AttestationLimitPolicy.FLEXIBLE || attestationLimitPolicy == AttestationLimitPolicy.DECREASE_ONLY, "ERC6956-E27"); + } + } + + function updateGlobalAttestationLimit(uint256 _nrTransfers) + public + onlyMaintainer() + { + _requireValidLimitUpdate(globalAttestedTransferLimitByAnchor, _nrTransfers); + globalAttestedTransferLimitByAnchor = _nrTransfers; + emit GlobalAttestationLimitUpdate(_nrTransfers, msg.sender); + } + + function updateAttestationLimit(bytes32 anchor, uint256 _nrTransfers) + public + onlyMaintainer() + { + uint256 currentLimit = attestationLimit(anchor); + _requireValidLimitUpdate(currentLimit, _nrTransfers); + attestedTransferLimitByAnchor[anchor] = _nrTransfers; + emit AttestationLimitUpdate(anchor, tokenByAnchor[anchor], _nrTransfers, msg.sender); + } + + function attestationLimit(bytes32 anchor) public view returns (uint256 limit) { + if(attestedTransferLimitByAnchor[anchor] > 0) { // Per anchor overwrites always, even if smaller than globalAttestedTransferLimit + return attestedTransferLimitByAnchor[anchor]; + } + return globalAttestedTransferLimitByAnchor; + } + + function attestationUsagesLeft(bytes32 anchor) public view returns (uint256 nrTransfersLeft) { + // FIXME panics when attestationsUsedByAnchor > attestedTransferLimit + // since this should never happen, maybe ok? + return attestationLimit(anchor) - attestationsUsedByAnchor[anchor]; + } + + /// ############################################################################################################################### + /// ############################################################################################## FLOATABILITY + /// ############################################################################################################################### + + function updateFloatingAuthorization(Authorization startAuthorization, Authorization stopAuthorization) public + onlyMaintainer() { + floatStartAuthorization = startAuthorization; + floatStopAuthorization = stopAuthorization; + emit FloatingAuthorizationChange(startAuthorization, stopAuthorization, msg.sender); + } + + function floatAll(bool doFloatAll) public onlyMaintainer() { + require(doFloatAll != allFloating, "ERC6956-E23"); + allFloating = doFloatAll; + emit FloatingAllStateChange(doFloatAll, msg.sender); + } + + + function _floating(bool defaultFloatState, FloatState anchorFloatState) internal pure returns (bool floats) { + if(anchorFloatState == FloatState.Default) { + return defaultFloatState; + } + return anchorFloatState == FloatState.Floating; + } + + function float(bytes32 anchor, FloatState newFloatState) public + { + bool currentFloatState = floating(anchor); + bool willFloat = _floating(allFloating, newFloatState); + + require(willFloat != currentFloatState, "ERC6956-E23"); + + if(willFloat) { + require(_roleBasedAuthorization(anchor, createAuthorizationMap(floatStartAuthorization)), "ERC6956-E21"); + } else { + require(_roleBasedAuthorization(anchor, createAuthorizationMap(floatStopAuthorization)), "ERC6956-E22"); + } + + floatingStateByAnchor[anchor] = newFloatState; + emit FloatingStateChange(anchor, tokenByAnchor[anchor], newFloatState, msg.sender); + } + + function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize) + internal virtual + override(ERC6956) { + bytes32 anchor = anchorByToken[tokenId]; + + if(!_anchorIsReleased[anchor]) { + // Only write when not already released - this saves gas, as memory-write is quite expensive compared to IF + if(floating(anchor)) { + _anchorIsReleased[anchor] = true; // FIXME OPTIMIZATION, we do not need + } + } + + super._beforeTokenTransfer(from, to, tokenId, batchSize); + } + function _beforeAttestationUse(bytes32 anchor, address to, bytes memory data) internal view virtual override(ERC6956) { + // empty, can be overwritten by derived conctracts. + require(attestationUsagesLeft(anchor) > 0, "ERC6956-E24"); + + // IERC6956ValidAnchors check anchor is indeed valid in contract + require(data.length > 0, "ERC6956-E25"); + bytes32[] memory proof; + (proof) = abi.decode(data, (bytes32[])); // Decode it with potentially more data following. If there is more data, this may be passed on to safeTransfer + require(anchorValid(anchor, proof), "ERC6956-E26"); + + super._beforeAttestationUse(anchor, to, data); + } + + + /// @notice Update the Merkle root containing the valid anchors. Consider salt-leaves! + /// @dev Proof (transferAnchor) needs to be provided from this tree. + /// @dev The merkle-tree needs to contain at least one "salt leaf" in order to not publish the complete merkle-tree when all anchors should have been dropped at least once. + /// @param merkleRootNode The root, containing all anchors we want validated. + function updateValidAnchors(bytes32 merkleRootNode) public onlyMaintainer() { + _validAnchorsMerkleRoot = merkleRootNode; + emit ValidAnchorsUpdate(merkleRootNode, msg.sender); + } + + function anchorValid(bytes32 anchor, bytes32[] memory proof) public virtual view returns (bool) { + return MerkleProof.verify( + proof, + _validAnchorsMerkleRoot, + keccak256(bytes.concat(keccak256(abi.encode(anchor))))); + } + + function floating(bytes32 anchor) public view returns (bool){ + return _floating(allFloating, floatingStateByAnchor[anchor]); + } + + constructor( + string memory _name, + string memory _symbol, + AttestationLimitPolicy _limitUpdatePolicy) + ERC6956(_name, _symbol) { + attestationLimitPolicy = _limitUpdatePolicy; + + // Note per default no-one change floatability. canStartFloating and canStopFloating needs to be configured first! + } + + function supportsInterface(bytes4 interfaceId) + public + view + virtual + override(ERC6956) + returns (bool) + { + return + interfaceId == type(IERC6956AttestationLimited).interfaceId || + interfaceId == type(IERC6956Floatable).interfaceId || + interfaceId == type(IERC6956ValidAnchors).interfaceId || + super.supportsInterface(interfaceId); + } +} diff --git a/assets/eip-6956/contracts/IERC6956.sol b/assets/eip-6956/contracts/IERC6956.sol new file mode 100644 index 0000000000000..a171a930ece2f --- /dev/null +++ b/assets/eip-6956/contracts/IERC6956.sol @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.18; + +/** + * @title IERC6956 Asset-Bound Non-Fungible Tokens + * @notice Asset-bound Non-Fungible Tokens anchor a token 1:1 to a (physical or digital) asset and token transfers are authorized through attestation of control over the asset + * @dev See https://eips.ethereum.org/EIPS/eip-6956 + * Note: The ERC-165 identifier for this interface is 0xa9cf7635 + */ +interface IERC6956 { + + /** @dev Authorization, typically mapped to authorizationMaps, where each bit indicates whether a particular ERC6956Role is authorized + * Typically used in constructor (hardcoded or params) to set burnAuthorization and approveAuthorization + * Also used in optional updateBurnAuthorization, updateApproveAuthorization, I + */ + enum Authorization { + NONE, // = 0, // None of the above + OWNER, // = (1<0) of the anchored token + */ + event AnchorApproval(address indexed owner, address approved, bytes32 indexed anchor, uint256 tokenId); + + /** + * @notice This emits when the ownership of any anchored NFT changes by any mechanism + * @dev This emits together with tokenId-based ERC-721.Transfer and provides an anchor-perspective on transfers + * @param from The previous owner, address(0) indicate there was none. + * @param to The new owner, address(0) indicates the token is burned + * @param anchor The anchor which is bound to tokenId + * @param tokenId ID (>0) of the anchored token + */ + event AnchorTransfer(address indexed from, address indexed to, bytes32 indexed anchor, uint256 tokenId); + /** + * @notice This emits when an attestation has been used indicating no second attestation with the same attestationHash will be accepted + * @param to The to address specified in the attestation + * @param anchor The anchor specificed in the attestation + * @param attestationHash The hash of the attestation, see ERC-6956 for details + * @param totalUsedAttestationsForAnchor The total number of attestations already used for the particular anchor + */ + event AttestationUse(address indexed to, bytes32 indexed anchor, bytes32 indexed attestationHash, uint256 totalUsedAttestationsForAnchor); + + /** + * @notice This emits when the trust-status of an oracle changes. + * @dev Trusted oracles must explicitely be specified. + * If the last event for a particular oracle-address indicates it's trusted, attestations from this oracle are valid. + * @param oracle Address of the oracle signing attestations + * @param trusted indicating whether this address is trusted (true). Use (false) to no longer trust from an oracle. + */ + event OracleUpdate(address indexed oracle, bool indexed trusted); + + /** + * @notice Returns the 1:1 mapped anchor for a tokenId + * @param tokenId ID (>0) of the anchored token + * @return anchor The anchor bound to tokenId, 0x0 if tokenId does not represent an anchor + */ + function anchorByToken(uint256 tokenId) external view returns (bytes32 anchor); + /** + * @notice Returns the ID of the 1:1 mapped token of an anchor. + * @param anchor The anchor (>0x0) + * @return tokenId ID of the anchored token, 0 if no anchored token exists + */ + function tokenByAnchor(bytes32 anchor) external view returns (uint256 tokenId); + + /** + * @notice The number of attestations already used to modify the state of an anchor or its bound tokens + * @param anchor The anchor(>0) + * @return attestationUses The number of attestation uses for a particular anchor, 0 if anchor is invalid. + */ + function attestationsUsedByAnchor(bytes32 anchor) view external returns (uint256 attestationUses); + /** + * @notice Decodes and returns to-address, anchor and the attestation hash, if the attestation is valid + * @dev MUST throw when + * - Attestation has already been used (an AttestationUse-Event with matching attestationHash was emitted) + * - Attestation is not signed by trusted oracle (the last OracleUpdate-Event for the signer-address does not indicate trust) + * - Attestation is not valid yet or expired + * - [if IERC6956AttestationLimited is implemented] attestationUsagesLeft(attestation.anchor) <= 0 + * - [if IERC6956ValidAnchors is implemented] validAnchors(data) does not return true. + * @param attestation The attestation subject to the format specified in ERC-6956 + * @param data Optional additional data, may contain proof as the first abi-encoded argument when IERC6956ValidAnchors is implemented + * @return to Address where the ownership of an anchored token or approval shall be changed to + * @return anchor The anchor (>0) + * @return attestationHash The attestation hash computed on-chain as `keccak256(attestation)` + */ + function decodeAttestationIfValid(bytes memory attestation, bytes memory data) external view returns (address to, bytes32 anchor, bytes32 attestationHash); + + /** + * @notice Indicates whether any of ASSET, OWNER, ISSUER is authorized to burn + */ + function burnAuthorization() external view returns(Authorization burnAuth); + + /** + * @notice Indicates whether any of ASSET, OWNER, ISSUER is authorized to approve + */ + function approveAuthorization() external view returns(Authorization approveAuth); + + /** + * @notice Corresponds to transferAnchor(bytes,bytes) without additional data + * @param attestation Attestation, refer ERC-6956 for details + */ + function transferAnchor(bytes memory attestation) external; + + /** + * @notice Changes the ownership of an NFT mapped to attestation.anchor to attestation.to address. + * @dev Permissionless, i.e. anybody invoke and sign a transaction. The transfer is authorized through the oracle-signed attestation. + * - Uses decodeAttestationIfValid() + * - When using a centralized "gas-payer" recommended to implement IERC6956AttestationLimited. + * - Matches the behavior of ERC-721.safeTransferFrom(ownerOf[tokenByAnchor(attestation.anchor)], attestation.to, tokenByAnchor(attestation.anchor), ..) and mint an NFT if `tokenByAnchor(anchor)==0`. + * - Throws when attestation.to == ownerOf(tokenByAnchor(attestation.anchor)) + * - Emits AnchorTransfer + * + * @param attestation Attestation, refer EIP-6956 for details + * @param data Additional data, may be used for additional transfer-conditions, may be sent partly or in full in a call to safeTransferFrom + * + */ + function transferAnchor(bytes memory attestation, bytes memory data) external; + + /** + * @notice Corresponds to approveAnchor(bytes,bytes) without additional data + * @param attestation Attestation, refer ERC-6956 for details + */ + function approveAnchor(bytes memory attestation) external; + + /** + * @notice Approves attestation.to the token bound to attestation.anchor. . + * @dev Permissionless, i.e. anybody invoke and sign a transaction. The transfer is authorized through the oracle-signed attestation. + * - Uses decodeAttestationIfValid() + * - When using a centralized "gas-payer" recommended to implement IERC6956AttestationLimited. + * - Matches the behavior of ERC-721.approve(attestation.to, tokenByAnchor(attestation.anchor)). + * - Throws when ASSET is not authorized to approve. + * + * @param attestation Attestation, refer EIP-6956 for details + */ + function approveAnchor(bytes memory attestation, bytes memory data) external; + + /** + * @notice Corresponds to burnAnchor(bytes,bytes) without additional data + * @param attestation Attestation, refer ERC-6956 for details + */ + function burnAnchor(bytes memory attestation) external; + + /** + * @notice Burns the token mapped to attestation.anchor. Uses ERC-721._burn. + * @dev Permissionless, i.e. anybody invoke and sign a transaction. The transfer is authorized through the oracle-signed attestation. + * - Uses decodeAttestationIfValid() + * - When using a centralized "gas-payer" recommended to implement IERC6956AttestationLimited. + * - Throws when ASSET is not authorized to burn + * + * @param attestation Attestation, refer EIP-6956 for details + */ + function burnAnchor(bytes memory attestation, bytes memory data) external; +} \ No newline at end of file diff --git a/assets/eip-6956/contracts/IERC6956AttestationLimited.sol b/assets/eip-6956/contracts/IERC6956AttestationLimited.sol new file mode 100644 index 0000000000000..6667c3751af20 --- /dev/null +++ b/assets/eip-6956/contracts/IERC6956AttestationLimited.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.18; +import "./IERC6956.sol"; + +/** + * @title Attestation-limited Asset-Bound NFT + * @dev See https://eips.ethereum.org/EIPS/eip-6956 + * Note: The ERC-165 identifier for this interface is 0x75a2e933 + */ +interface IERC6956AttestationLimited is IERC6956 { + enum AttestationLimitPolicy { + IMMUTABLE, + INCREASE_ONLY, + DECREASE_ONLY, + FLEXIBLE + } + + /// @notice Returns the attestation limit for a particular anchor + /// @dev MUST return the global attestation limit per default + /// and override the global attestation limit in case an anchor-based limit is set + function attestationLimit(bytes32 anchor) external view returns (uint256 limit); + + /// @notice Returns number of attestations left for a particular anchor + /// @dev Is computed by comparing the attestationsUsedByAnchor(anchor) and the current attestation limit + /// (current limited emitted via GlobalAttestationLimitUpdate or AttestationLimt events) + function attestationUsagesLeft(bytes32 anchor) external view returns (uint256 nrTransfersLeft); + + /// @notice Indicates the policy, in which direction attestation limits can be updated (globally or per anchor) + function attestationLimitPolicy() external view returns (AttestationLimitPolicy policy); + + /// @notice This emits when the global attestation limt is updated + event GlobalAttestationLimitUpdate(uint256 indexed transferLimit, address updatedBy); + + /// @notice This emits when an anchor-specific attestation limit is updated + event AttestationLimitUpdate(bytes32 indexed anchor, uint256 indexed tokenId, uint256 indexed transferLimit, address updatedBy); + + /// @dev This emits in the transaction, where attestationUsagesLeft becomes 0 + event AttestationLimitReached(bytes32 indexed anchor, uint256 indexed tokenId, uint256 indexed transferLimit); +} diff --git a/assets/eip-6956/contracts/IERC6956Floatable.sol b/assets/eip-6956/contracts/IERC6956Floatable.sol new file mode 100644 index 0000000000000..6c345fdc25fca --- /dev/null +++ b/assets/eip-6956/contracts/IERC6956Floatable.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.18; +import "./IERC6956.sol"; + +/** + * @title Floatable Asset-Bound NFT + * @notice A floatable Asset-Bound NFT can (temporarily) be transferred without attestation + * @dev See https://eips.ethereum.org/EIPS/eip-6956 + * Note: The ERC-165 identifier for this interface is 0xf82773f7 + */ +interface IERC6956Floatable is IERC6956 { + enum FloatState { + Default, // 0, inherits from floatAll + Floating, // 1 + Anchored // 2 + } + + /// @notice Indicates that an anchor-specific floating state changed + event FloatingStateChange(bytes32 indexed anchor, uint256 indexed tokenId, FloatState isFloating, address operator); + /// @notice Emits when FloatingAuthorization is changed. + event FloatingAuthorizationChange(Authorization startAuthorization, Authorization stopAuthorization, address maintainer); + /// @notice Emits, when the default floating state is changed + event FloatingAllStateChange(bool areFloating, address operator); + + /// @notice Indicates whether an anchored token is floating, namely can be transferred without attestation + function floating(bytes32 anchor) external view returns (bool); + + /// @notice Indicates whether any of OWNER, ISSUER, (ASSET) is allowed to start floating + function floatStartAuthorization() external view returns (Authorization canStartFloating); + + /// @notice Indicates whether any of OWNER, ISSUER, (ASSET) is allowed to stop floating + function floatStopAuthorization() external view returns (Authorization canStartFloating); + + /** + * @notice Allows to override or reset to floatAll-behavior per anchor + * @dev Must throw when newState == Floating and floatStartAuthorization does not authorize msg.sender + * @dev Must throw when newState == Anchored and floatStopAuthorization does not authorize msg.sender + * @param anchor The anchor, whose anchored token shall override default behavior + * @param newState Override-State. If set to Default, the anchor will behave like floatAll + */ + function float(bytes32 anchor, FloatState newState) external; +} \ No newline at end of file diff --git a/assets/eip-6956/contracts/IERC6956ValidAnchors.sol b/assets/eip-6956/contracts/IERC6956ValidAnchors.sol new file mode 100644 index 0000000000000..7de78697c886e --- /dev/null +++ b/assets/eip-6956/contracts/IERC6956ValidAnchors.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.18; +import "./IERC6956.sol"; + +/** + * @title Anchor-validating Asset-Bound NFT + * @dev See https://eips.ethereum.org/EIPS/eip-6956 + * Note: The ERC-165 identifier for this interface is 0x051c9bd8 + */ +interface IERC6956ValidAnchors is IERC6956 { + /** + * @notice Emits when the valid anchors for the contract are updated. + * @param validAnchorHash Hash representing all valid anchors. Typically Root of MerkleTree + * @param maintainer msg.sender updating the hash + */ + event ValidAnchorsUpdate(bytes32 indexed validAnchorHash, address indexed maintainer); + + /** + * @notice Indicates whether an anchor is valid in the present contract + * @dev Typically implemented via MerkleTrees, where proof is used to verify anchor is part of the MerkleTree + * MUST return false when no ValidAnchorsUpdate-event has been emitted yet + * @param anchor The anchor in question + * @param proof Proof that the anchor is valid, typically MerkleProof + * @return isValid True, when anchor and proof can be verified against validAnchorHash (emitted via ValidAnchorsUpdate-event) + */ + function anchorValid(bytes32 anchor, bytes32[] memory proof) external view returns (bool isValid); +} \ No newline at end of file diff --git a/assets/eip-6956/img/erc6956_concept.svg b/assets/eip-6956/img/erc6956_concept.svg new file mode 100644 index 0000000000000..c9da78ca98283 --- /dev/null +++ b/assets/eip-6956/img/erc6956_concept.svg @@ -0,0 +1,16 @@ + + + eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO196VIjSbbm/3qKtLp/7pi14vq+tI2NXHUwMDE5XHUwMDAyxFwiQGxim1x1MDAxZcO0XCJASGhhbevnue9xn2y+I0hcYoVcIlx1MDAxNFx1MDAxMkikspro6swqJFxcLvfznfNcdTAwMWT3s/zzj1x1MDAxZj/+7D/d1v78+48/a4+VUvOy2i09/Pk3+vl9rdu7bLfwklx1MDAxOPx3r33XrVxm3tno9297f/+v/6L3XHUwMDA2l+XaY9Bo9/ovv1Vr1m5qrX5cdTAwMGbv+7/471x1MDAxZj/+Ofgz9DndWqVfal00a4NfXHUwMDE4vPT+UUZ4XHUwMDE2/fFOuzX4XFwtJOdWcvH2hsveXG4+r1+r4tV6qdmrvb9SXHUwMDFkTHRX3m6621pVbVTWs+py/arvVt8/tn7ZbFx1MDAxZfSfmoNp9dr48u+v9frd9nXt+LLab/xcXIHQz5N+q9u+u2i0aj36+vztp+3bUuWy/0Q/Y+/f7mVccv7+4/0nj/RJnrnAOauUY1x1MDAxMv9o/fYyXHKQUcZcdTAwMDTCcOdcdTAwMDU3+INFZ7bcbra7NLP/YIPnfW7lUuX6XHUwMDAyXHUwMDEzbFXf31Ov19/f8PD6Zbk1gffScO6x5EqEptCoXV40+jRN41x1MDAwMm2tt5xzKbR9f0uvNthcdTAwMGWOXzWOZvD2XG59+O1G9V00XHUwMDA2P21t+Ov8WaV612ndnK2uPSzdyUb2bVJ4g2c79Y31o7tVrjtcdTAwMTct8cw2i42l8Fx1MDAxYpbrtr+yvbV+WLqSq9nuoz7qXHUwMDE1M3++vv7/ojvXKHVvX3foz1x1MDAxZf1HaIVocVajXHUwMDAyXHUwMDFjXHUwMDE24iFBLnW77YfQRN7Ebjl3x7Jq++GcPyzz9fLFo8v12J9v7/vX3z447slG83ynUcr191x1MDAwYozdnujdjjkqzmDc1Vb18uAw13zkS4f2vpI9urq4r6WP+/LLhfbDfud0s7Zj93dPV1x1MDAxYlvV5iarXHJ/yvBcdTAwMDQmXHUwMDFj92CjsFxczoh+y963Kvkl5/3p+c5cZsZduezrZpOxO3t7f5S9Km2vP+2tTTbuiEjd3VZLL9pcdTAwMDdgXHUwMDE0mlugU0n39nrzsnWNXHUwMDE3W3fN5lx1MDAxZqGZjajEfu2xXHUwMDFmp1xyueMu+uOf2lAwy5mWTJuJ1eHR9v5WR51dbvWLsnJfvdjJNJd0gjpslCqNu24tSSHyKKzmqFx1MDAxMJVccpyWinnDlORGXHUwMDBlK0RhXHUwMDE4tFx1MDAxNdPeXHUwMDE47aA1ozObSiH2u6VW77bUhVx1MDAwMlx1MDAxONWLXHUwMDBlmldK5aRlXHUwMDBlmlm8T+RNLWo5UM7Qh0455ZmNqkUlXHUwMDA0plxi5ZiiXHUwMDE1f6HS+5B4v1x1MDAwYlG71T+4fK5ccr5roFx1MDAxNDfMWss1TFx1MDAxNVND78qVbi6bT0NyMcBcdTAwMDGmuJM7XGZvU6+GT6JcdTAwMTGlTVpe+s2l5uVcdTAwMDWh5s9cbr5KrTtcdTAwMDSo/iXIzdtcdTAwMWL67dBcdTAwMDJUMJdcdTAwMTLG725Uo1+m3b28uGyVmoeheY1cdTAwMDXyYJ4xQNbgNYlA5kpcbpJcXDY5kI9WXHUwMDE0v2+d7YvN9rPbbm7XKvWrj/Caj8CYfVxixpJxXHUwMDE1cKWMgjhoyMUwiqW2gTWKS+edV9579Vx1MDAxOVx1MDAxOMfzXHUwMDFhZVx1MDAwMmOdZoxDjL1cdTAwMGKJY1x1MDAxOL9cdTAwMWW0R1pcdTAwMGZlormTUfxy5lx1MDAwNDSNdSpcdTAwMDXAxZWjs7OGXFzKPD+vN9RRv5G/eJJhXHUwMDAwd/OZ5pNr9ct3ailb36q4YvGiN1x1MDAxYoRcdTAwMGZcdTAwMTZjblxi7/VL3X72XHUwMDEynKF1XHUwMDExfa3Wqia80iz1+svtm5vLPj5vt33Z6seOu0Qmt1ErjUBcdTAwMTEjJ752S8Nccq//+7/9eFx1MDAxN8TBf7z9+//7W+y7IaXOXHUwMDEzc+XKK6hrXHUwMDE5/m1cdTAwMWUoMHPwYulcZodcdTAwMWRgOm04XHUwMDFiMFx1MDAwZaPFmNCMw4r5v1xyfZZmwnpcdTAwMGWRgtBcdGNTh+MscIY52DujmdaG6fB4sD7ScSaAI600XHUwMDAzoNLGXHUwMDEzPNCe8OhcdTAwMDA968w7m3hcdTAwMTlPOsWdXHUwMDE1VkOFXHUwMDBiLVKHU4FXRkphXHUwMDA1ZsjwvYaHs1xcXHUwMDE5i5U1QjAptUtcdTAwMWTPXHUwMDA2Wlx1MDAxYVxy2+FcdTAwMWT9ilx1MDAxON5cZqO5sFJ6xiSmx1NXT/KAS3whXHUwMDA2r4Vp4YZcdTAwMTYvg6VV2oNzWe+AXHUwMDAyL1NXT4qAXHUwMDBiXCJcdTAwMDOcK23hK4XHXHUwMDEzgXbYVKZcdTAwMTXXynrGJ1x1MDAxOFxyK0aSx5WAnLnwaDrwQjHNtYVXXGLvLHUrpFx1MDAwZUBRICxcXGjv7butpMdcdTAwMDfMcc1pp6Sx4DSpo5lcdTAwMDA6XHUwMDEx31x1MDAwNsIslFx1MDAxZt5cdTAwMDdHq1x1MDAwMM3OXGJcdTAwMTJcdTAwMTCY9HXTgVGCfkHYwYZcZolcdG26XHUwMDAzuZXOQVx1MDAxYnEr0mcnXHUwMDAyQdKLlcOXglf6t+FNXHUwMDE3XHUwMDEwXHUwMDE0XHJcdTAwMDFcdTAwMTKAXHUwMDFhM3ZcdTAwMDKps5iTI6lzXHUwMDA08mEpJpRBXHUwMDAxWG7hgGuXLsRcIrBkTFx1MDAxONZcdTAwMWPAsGxIpUhF++S5slx1MDAwNipCeTlcdTAwMDHGmGdcdTAwMDYqxYFVecmGpFx1MDAwZUuroVx1MDAxOaBMvFx1MDAwNS1cdTAwMTbapI6H3zDYVXxbXHUwMDBl4Ye/PzSeXHUwMDBiMGOutfCC5skmXHUwMDE5XHUwMDBm+2ZpPIE9XHUwMDE2Q5tcdTAwMDFcdTAwMWKMdbBCK5JzqJVJRmOGLD5cdTAwMTgkuINcdTAwMWVcdTAwMWFO81x1MDAwMJZaa1x1MDAwZdZcdTAwMDDUpqs7aHdviIs6I5mTw1uhXHUwMDA1XHUwMDFjXHKvJJBcZiE3PF27c4KskVhxJWA1vFx1MDAxOVx1MDAxZU9cdTAwMDa0T9xj+72zSqauXHUwMDFk1DuGguZkXHUwMDEyptg5ySPfVkNKXHUwMDAwWKh+MCaV+n0xXHUwMDFls570p9T4a0ijKFx1MDAxZIBoWehjfFx1MDAwMS9N+mhg35ZDXHJDqjyUN+eRnVx1MDAxNfCKlOBANPRd+nBcIsB34Yq2XHUwMDE2Slxi+1x1MDAxMpVcdTAwMTRccqrIXHUwMDE0lkIw8lx1MDAxZdLGy3DAllx1MDAxY0XGXGYkWVx1MDAxOT2kplx1MDAxNHBcdTAwMDNTXHUwMDA2OVx1MDAxMbSK2JnUXHUwMDAxVVx1MDAwMPUjSVLhclx1MDAxOOmGvrD0XHUwMDAxXlx1MDAwM1WEblx1MDAxZohN6nDgXHUwMDAySurB+nGokOHvXHUwMDBi34ZcdTAwMTmB5YWQMytF+tf1gXOC1FxuxlSQXHUwMDE1XHUwMDFi0Vx1MDAwM9BPkHBoXGJ8Z5s+nCFRVsRUwHx0RPSmVytcdTAwMTmoSa9cYrpcdTAwMWO0XHUwMDEyXHUwMDAzusi3XHUwMDA118BcdTAwMWXhi0KShE+FXHUwMDFhzDOANNhdXHUwMDA2XHUwMDE1XG68qyG1rFx1MDAwMFx1MDAxZPqqmCPHzlx1MDAwYp9qNKD2gCRGRkjAXHUwMDFhXHKpPfJdofcg7/A0IX2pm1x1MDAwYpNBxFx1MDAwMqtnIdPDi6egpdiAWHMn6LQ0bTBPOk/QziroXHUwMDBlPsxcdTAwMDTwRYVcdTAwMDO/k5Jb+szUL0pKgEkzUFx1MDAwMmD5XHUwMDEw5shOWMlcdTAwMDfmjvRouqBwkChsKeko6DtlXCJcdTAwMWNcdTAwMGaCwiU+XHKEXGKULH3hoEI10WlcdTAwMDBcdTAwMWOS71wiSkpcdTAwMTJFhpLS3ijY0Fx0VLJccjiUsVwikEFYRMQ6SrxcbnZvPLP0XHUwMDE1UllcdTAwMTRcdTAwMGYgaJpkzlhDXGZcIsIspIfgWJpcdTAwMWPsN0ulXHUwMDAyXHUwMDEwYqv9wIGFdIHZXGbJXHRcdTAwMTFcdTAwMWaoXHUwMDA2zNvB+4RPkFx1MDAwZVxuUFx1MDAwYmU1yVx1MDAxZFx1MDAxMUdcdDZcdTAwMTVhZlx1MDAwMl+XXHUwMDBiclg5XGZ4quRBh8JcdTAwMTOk3WCKw1CCXHUwMDBiXHUwMDBm80aliN87onlYjvTlg8M8UPFcdTAwMTLmXHUwMDA3LsvQ5pI+JNdcdTAwMDLrQDzKp+uoXHUwMDE0XHUwMDFkXHUwMDAwXHUwMDA3XHUwMDAzI8EjXHUwMDAwJbfO6lThS3Jccv9cYv+ddNhTazYvb3ux5z0ypI2j5z3EoGExQs5M6nnPfft+9fn0qNraK1xcXHUwMDFj3dvM/uXJ/d2i32Np+FNkueGIXHUwMDAyOfz9mPrlXHUwMDFlXHUwMDBiuFx1MDAwN6+0XG6kXHUwMDBldMKGjnVnfW5cdTAwMGJcbktcIqhIX0pjzPtcIryd+0BDO+hcdTAwMTn4XHUwMDA38K3hwMj32f48+HEwXHUwMDEx5N28XHUwMDFmjiRcdTAwMWP8bO8+sPvt/OOz7p9cdTAwMWafnj6K6noxfK5zt7FZ6lxcZTtHXHUwMDE3ZfG82eo86otSdoGPdsdiIOnAXHUwMDEzpk4mXHUwMDAxgO5cdTAwMTah0ZWaWP6vT4+fTHl7o7Z9dpI7XbY92dG9RZd/I1x1MDAwM1LhXG6+XHUwMDFkSJ1Ww/IvjVx1MDAwN0HDOFx1MDAwM2xcYqn0Z+T/Pyq1qqqWRmVfQPQ9hy3xsPFcdTAwMWFKOEb2XHUwMDFk4Vx1MDAxNNrS4k109lx1MDAxYVx1MDAxNX38VFx1MDAxMHE2XHUwMDBiLPnzPfL8bVx1MDAwZS8ziftNz8hOT2nwksH+zotGrFx1MDAxZChcdOndKdCuVlx1MDAwZawvnph85uzq8rRfPL1+PLdcdTAwMGKPdkaHPNBrcNylNVx1MDAxMWtcdTAwMDefJOB03MDgkinBrJ1cdTAwMGLauVxmpFRcXDNiSLT9MVdcdTAwMWMgmVx1MDAwMkbO0iUmaKZcdTAwMGJdRb7iXcPhYJCOtDvKb7z/crwnbzg9o1s9K8DbkCGJXHUwMDAyXjm4uDSjiVx1MDAwMd/IXHUwMDFmP1+3j9pcdTAwMWL3YuPser/TPthXXHUwMDFmus78UsDD+Vx1MDAwM+DhqEunQmFYr3hcdTAwMTd0XHUwMDE2xVx1MDAwNN6nKWZgPsadXHUwMDA38DuZgdNoLDfy/UApXHUwMDA0d1x1MDAxNcAvNeRjYVwiTo1cdTAwMDZqXHUwMDE5UFs43lwi9UbzXHUwMDFi7r9cdTAwMWHumeRcdTAwMWSnZ2SvZ1x1MDAwNneeXHUwMDE4vcBcdTAwMTlcZlx1MDAwNVx1MDAwNbRMXHUwMDBl9/v13EVp76GU0etcdTAwMWR11dstne9cdTAwMTTMosNdqUBcdTAwMWFcdTAwMDDace6cj5p3cH3BtDOGTr6k/lxcUGaidXeBXHUwMDA1XHUwMDEzV1x1MDAwM51cdTAwMDLtXHUwMDEyw+XxXHUwMDE2XHUwMDA214uOt4VnUo/ELzhcdTAwMWGBmW+sLzzWXHUwMDEzd/v1xeF9nlx1MDAxOdLVmHMryUDmJ1x1MDAwZjd8rO3VXHUwMDFmt05qdzfVm+5Sd+uhfLq+sug4h1mn4CCpvfXGhVbjXHUwMDA16MpcdTAwMDR0klx01Sukk4bPh8eDuDHHXHUwMDFk3U5IuE9KxUFdXHUwMDA3wkq6jFFcdTAwMTBcdTAwMDXlzEisoVdcdTAwMTa8z3377YtcdTAwMGb25FxypyczutczwjuGM0l4x1x1MDAxYXO6cZnccT/Jbub3187valx1MDAxN5ut50y/fGOXslx1MDAxZjqm+8roYq1cdTAwMDJvKVxiyzvvRPSUmrmAokawTlx1MDAxMmD6JI9XXHUwMDE1U6vrUbhrXHUwMDFmXHUwMDE4q5VcdTAwMDOTYiBuPC7fQlx1MDAwNFx1MDAwMsTDKK244GzouPyVx1x1MDAwYu1AU0L3Z1x0cP9t0fxcdTAwMTdcdTAwMGY85DZQRlhFXHUwMDEwt4yipod1XHUwMDAwVIRkXHUwMDE0/Owp7I+l31wiS1x1MDAxOTjDPeRXXGLufWQ8XHUwMDE2MC0ocJ5cdTAwMDZcdTAwMWSETaWHWfHAa1x1MDAwZcZcdTAwMDFcblx0qFxmX/yKwEkpXGajyFx1MDAxZkr9SVx1MDAwZmSSLKA4XHUwMDExXHUwMDAzhcfwvb2IXHUwMDA0vJG8W2cpXHUwMDFjRttcdO5WKZCJoiyFt1xuiFxyXTC8zE/iu1x1MDAxYUbXmzCMMv3ul1x1MDAwNnRcXGpjPFxiXHUwMDAxXHUwMDFlJ4Z3JFx1MDAwMFx1MDAxMD3YXHUwMDAyXVx1MDAxOOGru9RcdTAwMTFZYChg0Ugoerzf2WhcdTAwMDBcIlx1MDAwNVx1MDAxMdFtOL6CoSiGWdE6wVx1MDAxMvNIrMFyOSEmV/O3ZqVeydur3G6n2bm9vcpcdTAwMTftQT9Bzc8hjeRj8edYUVx1MDAxObBBXGIj/Fx1MDAxZlxuQ41oeiFcdTAwMDPwPZg8TdEqnzugXHUwMDFke1x1MDAxZKlcdTAwMThQXHUwMDA0k6NcdTAwMTT0nlchevbO7WxgjKNJek1RXHUwMDFiYbvz8zpSa9BcdTAwMDTL0jy5b22/mNpcdTAwMWVgx1xuSFx03axgzoW0Q9o041x1MDAwNoFcdTAwMWTa4zVvSFx1MDAwNFJcdTAwMDfk8FxcKJpcdTAwMTfC5Z0yKjqc4aT7XGbFck5cdTAwMTD6XHUwMDA2XHUwMDExxNtcdTAwMDRFVVx1MDAwMzDgRlx1MDAxMUY6XCKhqeZccsbD0rmwXHUwMDA2l6Iw06FIlYxcblx1MDAxOJ1EWlx1MDAwNoVrtfPpgaEyoFx1MDAxMG0rYDqk0yxiLaFLraBAJIylwJhTp1x1MDAxN3BLRohcImXwp1x1MDAxY1x1MDAwZVx1MDAwN8vYwFx1MDAwZlx1MDAwZUlcdTAwMDUgZ4bi9CdSzGNznr1NTHmmyHxcdTAwMDWn4Fx1MDAxZCppynl//2Dl+jy/vCQqrW7v9vjp+eHhZvFz/Fx1MDAwNC0wN57i/L30UeVcZpKuIW6Cw0BiWz+VXHUwMDFjNFY5c0VcdTAwMTd1mlKvgUtcdTAwMTXOXHUwMDAwXG5pZ1x1MDAxZlCEkXKDSFx1MDAxZVx1MDAxNnOmTlx1MDAxN6xcdTAwMTS+m3aF9pdcYvXgLplcXGCRrFxmXHUwMDA3/6TeXHUwMDA1XdV3XHUwMDBiXHUwMDA3h6rbzl2Xzp86vtmpPS62XHUwMDBmmXGQXjBLcDtcYjIzUenl3Fx1MDAwNFCkkq594UWCOM/FizTg01x1MDAxNFPrKJFcYmYjzouUXG6MlktKYpPg1Wrk7lcwUsA6fJxcdTAwMWYvuTu1vM/zi8zWTnmHburrp7Wq/6ZccvM/XHUwMDE1hiZU0ISKwls5XHUwMDFizpzJkGqC6+DgKUpcdTAwMDH1NIFPpym72tCNLlWVsHyYN7CAklx1MDAxMZjXQkhccq4yQU5cdTAwMTSFdlOSLtxcdTAwMWOKi41cXEljflxu3qjjoFx1MDAwZuT1pVx1MDAwZSdEwIm5XHUwMDAwOLBcdTAwMTLDNFx1MDAwNGbBQY7hyFx1MDAwMn1Cpae7ZVx1MDAwML7AwoeVSjhcbipcdTAwMWXOn1x1MDAxM3TJg4Xzjlx1MDAxMKQmXGKXXHUwMDA1yaCEXHUwMDE2XHUwMDE4XGbLIKBeRGhcYlx1MDAwZiyDUYNcdTAwMDNcdTAwMGI/XHUwMDE2fD01otfAJ9Z0XHUwMDBlXHUwMDAwJkfR8cMsiVx1MDAxMko47bpXms6oZ3XDh81cdTAwMWRTaEBRvtFcdTAwMTRcdTAwMGVi7+pova/Y2o44WC/4y/WNXHUwMDAzs1JbdFx1MDAwNzFcdTAwMDPOXHUwMDE3gMk6aHPrgYZIwFx1MDAxZWQ1ILtcdTAwMGXX3TtcdTAwMTD2OTqIUlBcdTAwMDaV8Vx1MDAxYU6eZbFcdTAwMTTEXHUwMDE5SlFzSpBcdTAwMTgzx0fiVWF1PfhUalx1MDAxMM+3XHUwMDFl/zXun1xuKPWFquTA3zA6kn6S8VQ7QYPuQpVCWaZH2mfwnoBcdTAwMDJRrFx1MDAxMoaTryeiXHUwMDAzalAxzYmYkulPXHUwMDFm0FxysjThfHjKzeJi2DKMimCq7Vx1MDAxMibQUFvwd+DokWxcdTAwMGZ7gPSVpaLaR1TlKT1cdTAwMWJcdTAwMDC+WFx1MDAwMIeMsjnAvqK5XHUwMDBmcFx1MDAwMVx1MDAxZD5cdTAwMGVcdTAwMTCQXHUwMDFlLpTx6Vx1MDAxOVVcXJBLiVx1MDAwNdSUkIl1XHUwMDFhnqCTVFx1MDAxNokxrK/A9/bTns5cctffXHTfwrjES1x1MDAxOLqCYZxcIjom1r5Xu/t7j7X7pa3a2naPXHUwMDFkiWpz4yEpfDJF+0b9rDlyaEPEhnFwXHUwMDFimElKgYxwaNhtRZGkimyjVmMuXuuD51x1MDAxM2VeQDhATqDiwYvoMH5U/UJU6dSB8oyE8mr06pVTVlx1MDAxMFi2S7uM2Tnb2MuX7kU+q4qnZ/xiU663Nv6d1G9cdTAwMTRcdTAwMTVcdTAwMTFcclx1MDAxY315tqVcdTAwMWVop1x1MDAwN+mHXHUwMDFhvJpcdTAwMGafxit4U9YzZZV1XHUwMDA2tDGd+SZcblx1MDAwZT1cdTAwMTkqtDBcYtsykkK0VDir/VPcbVxmdaP7XHTHrJhcItXoeNVcdTAwMWZcdTAwMTTb+unuvlsrXHUwMDE1l1x1MDAxYvl89TApXHUwMDE2c4G0XHUwMDA3JfDAZDA4Pt6ISM08TjdNnlLsQaacZzL5/OizyoPBWYHzXHUwMDAz41x1MDAwNvfGY/ljko1cdTAwMWOju1xc+FxmgzR4IeOuclx1MDAwNadiXG5pkVx1MDAxYv/22uOXnd0n7fLg5ZFccp5cdTAwMTLp41x1MDAxMlx1MDAwYkN5RCOZXHUwMDE2YPtcdTAwMTZMcnJH7dJuXHUwMDE01nf2XHUwMDFhe0f99W2+28qvWP5cdTAwMWJQXHUwMDA1ZVx1MDAwMkrzdlx1MDAxNJBpXFzUT4NcdTAwMTOvPHfE+1x1MDAxONxknpxY9Vmwgy96byibn1x0b3VcXGIh3qK8XHUwMDAxgfOYraRcXMdcdTAwMTGw06mgkWHGM2uwf/1ZcVJBQ1xmmSS+gkvKwJymXGba+Um196wvXHUwMDFhl6JS4ftP9vSgepdZePF1TFx1MDAwNFYqUERcdTAwMGbSIaKHxZSiXHUwMDBl50NcYmmEsC45Lfaz0itcdTAwMTmnTzI/n7jcQGNcdTAwMDIqhCRcdTAwMWRcdTAwMDU1w7yO5Fx1MDAwNkqFV1VSObTFqEOosaKajD+d7eB7hCabUoeQPXIhgyBcdTAwMDA4w+v8Vo9QJS7PUD3CZq0+jIbZVCNcZs/uQ8yR82RjQrUqyNWanDluXFyoKuOieWnLvna69Sgy14eNRb95zHjrXHUwMDAz55X7icdcYlx1MDAxYYFcdTAwMTGmrZaeXHUwMDA0T3o3v1M/QU5l6OExyTxcXFNcdTAwMTmW0KOieISvojhlJE2Px29K+KnMnMTto2d046akhElcdTAwMDY1+eqVc6Kg3E3OXHUwMDA2W/XGbvepu37erbdWtK1cdTAwMTX3bPlg4Vx1MDAwMcyhgLHyjqSQ0Vx1MDAwMdFwKlx1MDAxZVx1MDAxNlx1MDAxZT7+XHUwMDBievHnXHUwMDFjq0xcYlx1MDAxMzjpwUipYlx1MDAxZDzRuLguwYbEYPTgSFCIomQ2/th+MeypN1RcdTAwMDXm7Vx0UbpcdTAwMTRzunRwsFx1MDAxYV/Yl1x1MDAwZf/i1+UrXGbpy7w+ZEKlTIzdobBcdTAwMDfKXHUwMDFim5zPXts91rxfPl7Onm1tXFzkXHUwMDFllrN76nrhXHUwMDAxaFx1MDAwNmXzKGZcdTAwMDZcdTAwMTRLqvdcbqevJtQrwJNcbq9cYmnZJ3PjUlx1MDAxMVxiXHUwMDFmWHmmJIx2nFx1MDAwMZV0qqeUo8pyXFxhsiNnL3BD4I8xmVx1MDAxMFj5bUHnZkFcdTAwMTO37+XVkZ2bkVx1MDAwNVx1MDAxNckl9qlcdTAwMTAs1XTzk4cv9fdLRVvJP3T2no/9/eamUUc3nYWHsINcdJVcXFFcdTAwMTFDTTVcdTAwMTmHWTD0fdiEik9Vqlx1MDAxOY9gXHUwMDFiR3pcdTAwMDWPgnTQXHUwMDA1xkr1XHUwMDE3NZM7y+uF/Xg7qYfePXfD+DKTXHUwMDBmWcYxuKJ4YkWhwFx1MDAxM8Pqsah2O2XRWFm+uMg+lq6fj9av1lx1MDAxNlx1MDAxZVbW0IWy5lx1MDAwNjaQ0+HfXHUwMDEwrJxcdIw3ZlAtki7m54YqTlF/L1x1MDAxZkPV8UKh4eGYVlxupYKjXHUwMDBiSaVChqOXXHUwMDEyVIN1cJn+XHUwMDAxzH1cdTAwMWLGT9V4Sdo+ejKjOzcjw1x1MDAxOL5jXHUwMDFmqfHCLJU0n4Lbblx1MDAxZp1cdTAwMWOtrDyudM/36yuP/ijP18++MCbso86l0jbgQlFhbKNtuHzKgNzSveOgXHUwMDE0M1fCaTvPwHRmWFxmbGNso6N6oOFsur+ebcxcdTAwMWOuLq/vXHUwMDE0tlxua6eLYybDk/pcdTAwMTDgpE2uouathvqdXHUwMDAyb8VcXOk4c7i/qsxcdTAwMGXjm2v6WJw1z38t3nxcdTAwMWHcwOdcdTAwMDZlLfBob1348uM1XHUwMDFi21x1MDAwN1JRyFx1MDAxY1x1MDAwNSQrNkeTyX2ghTV0hUiRxzbGZGK7yCPxXii8g6mRu1x1MDAxMc6VXHUwMDFiXHUwMDE05k6LwXzq5c76Z+f5TrO5tlncfPI3x+V3waZptfYya6ZTXFy9riyXsqJ0+Xil7lx1MDAxNqvZk6BbXHUwMDE24jEvyV3hqIZcdTAwMTRI/89/x2JcdTAwMTirn7C8X1x1MDAwMWlMaiyGxyZ0jVx1MDAwM7KTznlcdTAwMGY/amIkXHUwMDFmr+RbleWcOqz2t+qyom5E9nR30ZHMXUDxNtT4htJcYm3kkp5cbiaBQcCkXG6tKG9mfj6lXHUwMDE4XFzBS01Zv1TASceEU0tGUfxSQrVQp46RYGpNfUjgXHUwMDFlLzCQ3z7jn2//9iZBOVe1hcv9hqlVttqGN5ZX2e1eaFohuZ6uReN1/vmylF85Y2dcdTAwMTlzXFzaeF67lrNo0bh5Wrpu9eSKObquMbu+srl227mYwbi1m6eDle1W46ldqObLu/J6u1I+mmzckS2ad6RE+Fxub4R9a052ZYpjqcyd6d/YtdWb7u5GabOi9ONmPymrblF0iFSg3oZcdTAwMDLBX1x1MDAxZVx1MDAxN1EhLFx1MDAxMFx1MDAwNnZBcFAjpbWf39WsdFAhzlx1MDAxMU9lnvJ84lx1MDAxY2i62oFHQdzbXHRcdTAwMTNcdTAwMTPUR4nFylqVlrH/XHUwMDFiXHUwMDE4e69cdTAwMDMjXHUwMDA0aJqgQNZQ3FOKqS/sLy1vrcaae7pcdTAwMDGKXb6vsPav81x1MDAxYVx1MDAwYtTEcy6TXGJURdevXk1cdTAwMTFDUchUSysrl+flh9OtPX2WO2pWdmZcdTAwMWSQVy31XHUwMDFhtVnfwVx1MDAwNpJapjlmrfaSjUDVXHUwMDA2VJHa4FVccmo9P95uhINWkFx1MDAxMGYq1WhYjK23KvBaUVx1MDAxYjVphuf6XHUwMDA2VEHx4OktXHUwMDFla41aeb+yetO4qF5Vm42DcvP2XCL7XHUwMDFkfTv3i6LETaZnZHvfh/sj/PfUMFx1MDAxZlx1MDAxM2lcdTAwMDGPZ1x1MDAxMFx1MDAwNDb5efb9ytHR88Ptff2ynrmpXHUwMDFlblx1MDAxZmSy+8e/XHUwMDAxzuFcdTAwMTUzS4U/qPvKUH3xV6DDJdaMYyjYSeHnXHUwMDE3baE8tTc0ntKM4WhcdTAwMThcdTAwMTNcdTAwMTNtXHUwMDAxZkD5YeD1iiqZcD1cdTAwMTJtQYVDNFVx/kb6QlwiPXmX6Vx1MDAxOd3fKbE+1onnTCVcIp7yXHTZVJHK225/qdRaOt3IXHUwMDE0norVvr9cdTAwMTNcdTAwMDe5XHUwMDA0vC9KVVx1MDAwYi50YKk5qFx1MDAxZCRrKlx1MDAxZDmNg8WnxpGOUS9HakM5n1x1MDAwZSaKmrYywbVhVFxuzsek40HRXHUwMDA3VDbTXHUwMDE4bzllz4+YdEW6ypvUUqhm53zn9vRw5666en25kt153jtYnVxm6J/xzz/hR49MbVZ+6XhscJ98N+SpgppQU6Sh7ORu28/le32ev9g9rVx1MDAxZrVu1NXql7Uz//DdbkDlNzxcdTAwMDNdlC58NPRcdTAwMDJcdTAwMGVpXHUwMDAyKjlHrYlhXHUwMDExwyxzVu3MpfSB8VB7XFwqqpukYmInNFNUesZcdTAwMTloUCv8aL1cdTAwMTfq8WYsJdP8MmTMXnbH5E9xoVx1MDAxMvtSca6dpO7wXHUwMDEzXHUwMDBi7l7hrHizt2+qVZFd48/V0/Pn3dXFXHUwMDE2XFztXHUwMDAyqjZgqUhcdTAwMWM1uo3caHJcdTAwMDeKJyEsmspaQuvOQXCNp2JejFx1MDAwM1x1MDAxYlx1MDAxNisu4/JOXHUwMDEy3/J2y0llSbCZaUeyv5PcJp1cdTAwMDXqZCbCqViopX6yXHUwMDEzXHUwMDBi7dXxkz7PXHUwMDFkbeeOy8dS2p262Mwsfp6GfqlcdTAwMGbgX1x1MDAxMzVkpD6AXHUwMDAzS9CC/4xR0/O7T/BxeVKx9/COKaV46Nr+L3RcdTAwMGa/u18o5DL4Z7mwc7hf2FqEa/iROY1cdTAwMDVbYkl0lXh5ZynVV05zntc4qj+2l7r+VG2c6syzLzZuqs2Fx5pUXHUwMDE0UiRccrXM5HD4I0lRwsrAK0hcdTAwMWIjXHUwMDFi4sck2H76XHUwMDFhnlhcdTAwMTYlXHUwMDA0WICJelx1MDAxN8e17qTwc/hcdTAwMWZSXGIqcONHgciEo+YsXHRcco7m6r77sUD8i7vvybtHT2Zk497H+yP897TWkrPE3mSOUvykncJY3u8+nd8xVV7aLqxd7JSqrVIhl9R5d4FcdTAwMGXqNFx1MDAxZlx1MDAwNMu/JjUyXHUwMDFmOZDnxlx1MDAwNixsLT91UPdcdTAwMWZCuHLNjMI3lE1cdTAwMTmCa1x1MDAxNJ9cdTAwMDJqXHUwMDA0TNSxX2Aox+MzZChDfCPFMvbbsbYwRFS/wlx1MDAxNmJcdTAwMTZcdTAwMWayfoIld/oyimkh1Fx1MDAxNNfO7vL6TDyIk5o5qZxVTPZ22XbXP4aer+tcdTAwMDGU0Vx1MDAxMaZcdTAwMTk55OZcXFx1MDAwNs46/zMhQs0v6FP4mJhPeHDv8aZcIqbvj6CMZUaV1Fx1MDAxNlxyUH9xg5dRwc9dXHUwMDE5/PnuXHUwMDE00KN1XHUwMDEw2jaYxbThhFx1MDAxYvp4ikRWofF5+u9cdTAwMGZ/YrRcdTAwMWVVeDCtXep8klx1MDAxNuNT1tolXHUwMDFhay5cdTAwMTiVXHUwMDE3VFOcx1SerMmf9crNXHUwMDE1cba3b1x1MDAxZbdP2d7hwutcdTAwMWKK79f+Zz1cdTAwMTAjWbT2XHUwMDFk88O+7fyu1Vx1MDAwNDOBXHUwMDBmP3FnipaKaYWeXHUwMDExwk1cdTAwMTXBWWLc62JcdTAwMTh0pYe/qFx1MDAxZnrT2JogpVJcdTAwMTCUSrFWXrGktfmagiCvU1x1MDAxYovEsSf7ytnkWpRcdTAwMDOWrqdpXHUwMDAxmH2uru6v3/aeyuz5hLXOLza6ei9cdTAwMDGQXHUwMDBi0lx1MDAwMpBbKahUn7LcMsbDbTZfUj6YpWN3yY1Qwij+qXzm+Fx1MDAwM1JQrIDK6lx1MDAxOMGhXGaciFx1MDAwMaFcdTAwMDVJwUvYXHUwMDBlTENcdTAwMGXVNfh55eWh06ktdCxcYt+0N1bs8a6/1Vx1MDAxNEfsdPnxYctcdTAwMWPdXFyGwovxhtbN8WbucOn2uf900zxYXdmtdfJnc7xcdTAwMTOLL5dcdTAwMWFcdTAwMTKq5dxcdTAwMWTLqu2Hc/6wzNfLXHUwMDE3jy7XY+kxoKnjnmw0z3dcdTAwMWGlXFx/v8DY7Yne7Zij4lxmxl1cdTAwMDWrOTjMNVx1MDAxZvnSob2vZI+uLu5rk8aszit2d14xtr2VR2aO9rZZt7nVuyia051O9mxcdTAwMDbjtk+LfPu0c9e4PV9Z6dzd8Wp3ozGDcZ98O1tsdtuVTqOWVeaym7vcOZ/BuGeZ8+WVytFT+/mudH113qm3bvdme6dcdTAwMWJr6sZq/sRcIlx1MDAxNt4kK33tqWdwOPw2Tel3XHUwMDBi5dt7bc9U7fbOt2rrK3vPz1x1MDAwYn4rxi24sqJcdTAwMThcdTAwMDNFXHUwMDA0TEarslx0T1RcdTAwMWFWQUIn60+2gYy/zaWihkx5eJeCXHRcdTAwMTeu/Vx1MDAxOe7lLpjiVKnWOpinmCaQ0kI4PE+NXZyj1p/vmelv41xmUnk9Zlx1MDAwNLV8XHUwMDEx0nk1XHUwMDE0pTjoNsU96Fx1MDAwNTU/hMClN3NMlFx1MDAwZnoyQlx1MDAwNkxyyjVXRlN7u5l1hPYu+URcYt9Aej9NeeFC5bLer1/d6qXTnavCSfe6c3aVlFx1MDAwNrwwuoHC3ZU0XHUwMDA2TphcZn/ZgWrQQCWn8lPSUqO0z1WYSo70kFx1MDAwNtRcdTAwMWOI54NAp1x1MDAxON3AXHUwMDAyel2T+zhcYmqMXHSCXHUwMDEyXHUwMDEwR550LPStXHUwMDFivvBmRGhqXHUwMDE45Vx1MDAxZF1NUbO7YSyPbGWqckhcdTAwMTSQl1x1MDAwMalKpVx1MDAxMlx1MDAwMivILIy5nF37aD4mmsZRJ6JpiMPziW7Ut/a2lld31m17m9VcdTAwMGLnS0uLrlx1MDAxYyyMsqHWP4N2K9H+0dzBXGJY9tIlgCpGz4M5UFS2sFx1MDAxNIkp1dA9Z6hfTDDwXHUwMDEyISSwSFbpkVtcdTAwMThQQM5cckuNkPxWXHUwMDBl86/3XHUwMDAxKupcdTAwMWR8d8uUldFe8Cqgpu1SckFtoORcdTAwMDRtllx1MDAxM+Vj8GlcbsRBUZou8Vx1MDAxMUqSnZlukMlcdTAwMTmMXFxbTVx1MDAxMWaTx4heb3VrrHVXqN7teba+1r2/bayaRddcck5cdTAwMTLsLKdcdTAwMGWetLbDyoFcdTAwMWJcdTAwMWVY5amSXG54oDFmXHUwMDBlR0mzUVx1MDAwZUZqOlxmU9/M4VcrXHUwMDA3Q31tXzxyatUo+JBy4CwwkmrkXHRv4XUw7f9iyiaxVpFMrrgg4Ntb7UNcdTAwMWQt03TNVlnr4u7DxdJcdTAwMWV/WFnaldXNnVx1MDAxM7foUVtcdTAwMWP8XCKgLo7YXHUwMDAywUy40OZgXHUwMDAwXHI3hVx1MDAxOU05qVRI6nPKZuwlknaxpatHYs9ccjXVUeHQ1XitMr9cdTAwMDPoXHUwMDA0pVx1MDAwMWg5N4ifXHUwMDE5qzRCt0lUL1x1MDAwNuyJWldcdHDiMOlNuU5a3V/OXHUwMDE4n1BfnodMxtBcdTAwMDVSXHUwMDA136DWncNcdTAwMTXS23TGwjCxk5lPPiuwdG5l7Fx1MDAxNIVPxqfFLGh7XHUwMDA3SZe16lx1MDAxZIU8epLINXQ0NCCn8MrhQlx1MDAwMTMvXHUwMDE5xlx1MDAwMlx1MDAxNnpETDa0XGKsXHUwMDFkdPfEhCVU/WiCyKBcImhiJ7PFXHQmeT+D/7P28lx1MDAxOVx1MDAxYlx1MDAxM6TeXHJcdTAwMDBauaPpZFx1MDAxOFx1MDAxNXnglFxyXHUwMDAzQ1x1MDAwN1x1MDAxY6twg8I/L0q3JEiB4Fxm2tNcbkWNXHUwMDE533pcdTAwMDC+XVx1MDAwNlxmx7EkTWp8TZ/hSTGsXHUwMDA2XGawk4N0XGKt+MikyPmHOcXEyPTCYo9Masb8Zq5d2ZLFlp5cdTAwMTGBnZJBpFx1MDAxNG5KTGujbVd8Kv11q7ZcdTAwMGIn+ZWLZiGfq+j1h6PT49WnRadcdTAwMTHCUMqYpM5WXHUwMDFluI9cdTAwMTRucnTrTCHhnrLa7Fx1MDAxYytcdTAwMDF7XHKkae2p6lx1MDAxMvlIcVx1MDAwNdhgdJnAOzSVPLR8NEmIyk9cdTAwMTmenva5dnVw3b27vTg9L1d6slct+cKVnHva57yuSud1pZk72Vjh4kqZnqvktlrnXHUwMDBm57nm7Vxmxt0qZZ+aprhd7anN/LJ4PNq7za/OYNxS/aydk63n5fbq2sFBXHUwMDAz2mJ3+XiycUe2flZXsOPVj0qmT+ShXHUwMDE5wadcYl3v7md7up59zvRcdTAwMWFnm5fNbvahmLtfePVcdTAwMDPEXHUwMDA3lsN35ZRcdTAwMTTAxPCZXHT3MtBcdTAwMTa2TkhFXHUwMDA1WefYz0OQdlx1MDAwMX8jTlx1MDAwMC3jbVxc2lx1MDAxN3SlJSXFqPAhJaiPqCBcdTAwMGJcIsFMOKl01ipoLicjY4U4uWbZmD7GVMHL2Slqfov67sVV4+E82z3Y2vadji9umaSaXHSLJL9cdTAwMGX83jhmQFB4JE1RMVx1MDAxZVB0XHUwMDAxXHUwMDA37YdcdTAwMTjb+UWOK1x1MDAxMd9+ZkQ+hWZcbqQmNUxsweQzzlx0J8pcdTAwMDCPyoK+ayqVPXEy49iQztAhwOLEcCYh0CTnPlFJXSpUMEVDqEp57aTTzFWqd539dregsrmL41x1MDAwZvZcdTAwMDL+uvhNyTlcdTAwMGZbkGhccmHJhlKfQnE2My9Gpn1cZlx1MDAwNuNsXHUwMDA09XpU9iMtZ74sXtrAyVxmP1x1MDAxM/dQ7GPKrb/DcVNM/KNValVcdTAwMWHtLvYspbNcIlx1MDAwZp2gfU2+VNosP4RHrkMlu2NcdTAwMWGeUlx1MDAxZdFcdTAwMTSUbr2Z7exs3rZcdTAwMGYq9lxc1Fx1MDAwYudPZWNbi1x1MDAwZUjHQZJcdTAwMWN5YtZcdTAwMThcdTAwMWRKQ/mZue9cdTAwMDPuqFx1MDAxYlxiRd9xM7/igOGKfu9cdTAwMDdgblx1MDAwNI+DnC9cbvVbYDhSmTsqsqakclKyyeH4z1x1MDAxZv02XHT2i5X52z9aP35EpJ06XHUwMDEx0497gFSt+vdcdTAwMWb/898//vUjXHUwMDE2pEInXHUwMDFjT89cdKRcdTAwMWad+8c9Mi2S61x1MDAxY1FMn7ThXHUwMDBl72nw3Vxc2TtYO75Yvun2av1u+Trb3L5Z+Hslp0VggVuq7K60VJFLbEnoNlx1MDAwZUvB4Z5cbuHnZ0+F8oHwwKbUSlx1MDAxYavjqlx1MDAwMVxiMOxBnzlyy6RcdTAwMGVL6E90e9BDkX7rVDhcdTAwMTVXe8W8LMna/nanVci7Z7n3fSZcdTAwMTRcdTAwMTl3XHUwMDExw9zHI5olXHUwMDFhZPAwTYxwXG5ElzJytfGwV6/pXVG/r1xc7JZyLb3wiFYmoFx1MDAwM1PttYOh81x1MDAxMYYslFx1MDAwZVxmPHUjmPZcdTAwMDA+n1x1MDAxZqK5dFx1MDAwMafuXHUwMDAwQlxmOtbouOJ+JmDWOipcdTAwMTNBXHUwMDA1tNmIuVx1MDAxNlSmJMFYz1x1MDAwMs5p/us4eMy/4vzsTm+MTDy9XHUwMDE5xJZOcfNRKNZcdTAwMWVue6utXFzmuL98VShs+vra9sLDQqtcdTAwMDDyZalajLAmWm+eM2rwTCnJsD3S89DKz6FccmJA5Ysp29Ir7l1cXFx1MDAxOWuA1MNcdTAwMWFTlVx1MDAxZVxytTVcdTAwMWHu7Z1VVDf11yFjds4nfHbLrLbKMVxuSFxuhdGmXHUwMDFl7Vx1MDAwNMFFqbdbelxuh0uEOKyWSev4Nac9oemNRW1iyIVcdTAwMTGJRz74TlRcXGVyczZeXS1oxIWRVH3eUihcdTAwMDVFWYZcdTAwMWPI14BcdTAwMGJcdTAwMDbcwtLIQVx1MDAxMzc3P9hcbiZcdTAwMDNcdTAwMTgxXHUwMDAw1yi6XHUwMDBmiFxyg1x1MDAxYZRcdTAwMTbxQFx1MDAwMKfyWdyNXHUwMDA2XFzAIbbUL3nhyuFMXHUwMDE4cJFcdTAwMWHb8Fx1MDAxMrTAXHUwMDAzT0VUjKHiqczJcLGMt/BcdTAwMDeKXHUwMDA0cFx1MDAxNlT/5YxsXHUwMDEwwPb6rikjLsYztVx1MDAxZu+hXHUwMDE0ithcdTAwMDQzkoP9KGVjJpVhXHUwMDAxl3C8PYVaUl1qKezIpH6niItkwaVnVGTfx/sj/PfUqsuZZC5O/WGpXHUwMDA03eRRm+NdkVx1MDAwNVVenK5cdTAwMTC5oFKRzIKKy0i1XHUwMDAxwSntz0B7gf6G63jN/LCaavtz5iH80pjwWfR7vFx1MDAwNVx1MDAwNMFB5rlcdTAwMDIvIb4+wjlAj1x1MDAwMGdcbiP+TXXX+Fx1MDAxM5o3LSGo9oI2Wlxmqj/rcGG7ocgtXHRfXHUwMDEy4HJeUY4nvJeP6a7xVTTeZuVcdTAwMDJcdTAwMGZcdTAwMDB7XHUwMDAzJGtKXHUwMDEzVVx0s1x1MDAxYeRcIllcdTAwMDa2XHUwMDAz/cuM0iOz+p2UV6Lg0jMqslPqrvHFUrRMvm5cdTAwMWJ0e1x1MDAwMiOZ3Gu6MTdGbJmKPLfWZzPds8Ja4un+glx1MDAxNEuB9Vx1MDAwZSjMVSkqOSZ4tEWAhiNjJOXHgdNguT7Voys+w8WywFhH7f08XHUwMDE3JFx1MDAwNDGki9lAQFx1MDAxMLizcKeYXHUwMDFmLdaLjdRQv1x0N3DvMDp+qN9fn2h24DOK7+U3q1x1MDAxYrXSPFx1MDAwM8W+a6GEf7nSPNbi4LB+3c9eXe7tPGXytZ38Lz5NScybtzrxOFx1MDAwNSZBO+OmqWx2wi42N3dUvZS3/Fks96pnpU5SO99cdTAwMDVJfzPWXHUwMDA3lFx1MDAxM8s1lVx1MDAxMFx1MDAwZTter1x1MDAxN1x1MDAwNzyg3qCekVx1MDAwMbXzUFxyylCwXHUwMDE4rCFxXHUwMDEyOFx1MDAxMjH3XHUwMDA1Mlx1MDAxMFxu3FZCW1x1MDAwYlx1MDAwZm95tKKGprwnnuSOzUI1fKe2XHJcdTAwMWWqnSZcdTAwMTRcZrWkPnLaXGZVXHUwMDBihsuFPfSSaVx1MDAwMZuj8MVTh0vafHoyMoBcdTAwMTmgljKerq2scOp9vImIQTLuXWIqXHUwMDFhRZsw4lxcXHUwMDEzw75fKi2Jzcddm80s352Zw9JtbeNswWHveGAt/Fx1MDAxNsok5U5GjmOkXHUwMDEyVMzQU4FcdTAwMDNcdTAwMGXv51PHMVx0sNeBNpaq+TiKOYhccoVcdTAwMWL0+1x1MDAxNd5S5iP1KfajUTmgNJz+l3ZR+Fxy/MHziYRcdTAwMGZcdTAwMTPAvdXKQVx1MDAwMUNcdTAwMTVLNlxm1dGtSoV+olx1MDAwMFxmXHUwMDA2ZIFcdTAwMTRWK7hAXG5cdTAwMGWc5z5U+fRz2Hdjqifjsc5cYjU5+OuNh0Zn67DIurp8nlVcIvvYr32oeOJX2nxcdTAwMTdYb6SheiNORa9cdTAwMTax7oEyXFxCXHJiP+Gqzsfoe+HgmzsvvFJx7b5FoCz5K1x1MDAxY/aBhzpcdTAwMWb97FxuSJVX5LfFnz/wXcA9XGam4Vx1MDAxY1x1MDAxNJArZiM4paq4XHUwMDBlQMYrjlpNTGDz4/d+8GlcdTAwMDFVXHUwMDEzNoK6zoNi8GmPXHUwMDAyklEvx1x1MDAxY2NSN1mrp0g+72U2V2qsU3BcdTAwMWR2bJ/zxcrjdS8ppGCBUO+pIShds1xmXHUwMDE1XHJ+LZ7n6KyfqUFMXHUwMDAx5/JTYe/zQj3FIXBvjP2293OGvVx1MDAwM/dcdTAwMDaVd5xpLrSQXHUwMDExlCphXHUwMDA3zWM5RXpNQPR/Ly0y9kBRiMSSOVx1MDAxMFxcLew0pfbO9/NLxe3z1Ua2s3P6vFs5Xz1sJjVfWFx1MDAxMEViOV30Y9cl9adcdTAwMTMqelx1MDAxOWJNwEDrXHUwMDA0XHUwMDEzXHUwMDEyRFCa5OyveqnMmE5RJJH3vEUluaFQ97gm4lxcQ0T0z3/AZkbcXHUwMDA3NSggYX7dgeLsj7qql6WbdliBhVx1MDAwNDe5q6LRjMA3RZT7Vnv1IZsx7DxzvMmO6k/buzZvXHUwMDE3XFxwmVx0KGSIzpKoJGbUXHUwMDAywidm+KngXHUwMDAyKlx1MDAwNX5JckjdZ1x1MDAwNFfEpChcblx1MDAxZFxib97+0XIk4MBLY5hwbn50d6FEVSX7aEZjXHUwMDAz2TSiunptT9z21vX95dbBTqtYP3vulCqLJqo6XHUwMDE4dKtxsC50a1x1MDAxOfp6P0XXU1x1MDAwNJRcdTAwMTNUTkpHw2cgulx1MDAxNKJBXHUwMDFkr+F9yy+UXFxcdTAwMDXLTXlaTFDFWz16NOslh0dtU4tcdTAwMWT/TpI7pnetSK5OwSk8TlxiOUV6bX99u9pYW64ssZsrq263sjsrxfKiiW5cZj2Q1NTAUIMjXHUwMDFi1bJwQ4SkiEmuweRFcnVcbjDLesWOXHUwMDE31eh73qO8YujASFx1MDAwZlx1MDAxNMNcdTAwMWQ1pJ/j4eHXi+Z46pp83Vx1MDAwNYdcdTAwMGaEzvspXHUwMDAyiJ1vq+uT5ee1p9vSiaizjVx1MDAxNit3XHUwMDE3XThVXHUwMDAw06Es/ufxL1HuanigubScnFxuK71LPvr6jHRy+E+Ov/1jQ+r8/c5LXHUwMDA1JsRcdEZTZFx1MDAwNNOKXG4x6LTQ4b+O9CbnTcNwXHUwMDFhK9hcdTAwMTSBaMdup7TRazVcdTAwMWaP2oWj7exSprZReF504Vx1MDAwNX9lXHUwMDFhelUqjn8xo8LLlaR4RzBcdTAwMDFcdTAwMTMqZj9cIrxcdTAwMTUvSqI0Xnij73krXHUwMDFjmOhUTS67nFPLcCo19+9cIrsqXFxDLqp6vVx1MDAxYpQqY5Or3vWTc7O6ff1YOri/K5SzmfvNja1cdTAwMGZcdTAwMTXh/sKWTdr6gHL9Sf9ipV30zlFDfOH7eJBIRq0z5nBcdTAwMDA5kzAkQUXcvGcsrdBuPptfvyx3TUlXXHUwMDFil5vr9Wyjutr5jkOafNx/nziksOM04jUwI0CnpzhULHe6rYKo9PhqvZ4t16/Y5WN3a7FtXHUwMDFi11x1MDAxZdSLXHUwMDAyQVx1MDAwNLeS/o5oXHUwMDA3plx1MDAwMumpziB5x3Ck5lCjfyaRSFYxTi+lubtcdTAwMWZXXHUwMDBl31x1MDAxN1x1MDAxNIPnL1x1MDAxMolcdTAwMDQzk4R8YJ6yXHUwMDAzp4hEqudyXHUwMDFi5jTbLtVXL7JcdTAwMGb+/jBXc72FXHUwMDA3/qD+vpNKce5cIlx1MDAwZZmUOqDuKjC4XHUwMDE0qlx1MDAxZI5cdTAwMTJatEgkXGKIZd4k9FP9XHUwMDA2/nck0stPw127WOJxXGZVTVx1MDAxNCCfk1x1MDAwN1x1MDAxZtcun/J7/N50VO35aa3Y2imKh0Vv2qU9lDjF8TA4kpqHXG5bv0ZcIrFcdTAwMDAsXHUwMDFjsFKUXHUwMDE3XHUwMDFhPjhdpJiEQdVPa1x1MDAxM/KpvpH/XHUwMDFkilx1MDAxNIH9mHpFVLVAWmMmv1wi2FkpP4sncb99fNZcdTAwMTLqeIXll3tJ7dRcdTAwMTdcdPdcdTAwMWFcdTAwMWOeWpBrY0z0JMuLXHUwMDAwgFx1MDAwN6+TUPCh/N6Fgr3iRmrmU8+wvmE/eL5DkWZcdTAwMWaKXHUwMDE0ysdcdTAwMWZccmqkpfLhUl+pl42PW9u16sb+Wa6a7Ww1jp9b7bOLXHUwMDA11yTwxlx1MDAwMmxcdTAwMTVT1Fx1MDAxM1x1MDAxOFx1MDAxYlx1MDAxNy2TRFx1MDAxNTGtclpcdTAwMTK5XHUwMDFio0h+eShcdTAwMTK0ndNKhVx1MDAwYvh89anil0Z4yOSam1x1MDAwMLuHvzdFUm6/vN+8r+RcdTAwMGIud3dn78tn90/7+7eLLrmDjm5cdTAwMWOs13DLRm2gVXhZMlxy3WGE8mw+YXRcdTAwMWaLRuJSXG6p6Y7/30NY9Vx1MDAxOEeNyZfyXHUwMDAyXHUwMDEzXHUwMDBi61Zhv1aV+e1Ded7fq/q1XHUwMDBlq9WWXHUwMDE3TVjHhyNccoTXXHUwMDE4aqLlLL0pKrs6gKcsjKTqK2w+Wvdj0Uhcbj6lnKCD6u8kuGOikaRNjFUmUzTc2C21VU6xcrrk95aWLk6WPL9/eKiuqN+CXHUwMDFmvN+Zj1x1MDAwNivzQFx1MDAxYjhkXG5cdTAwMWNBUKnFRFmdfziSMlJgR+Z4jrBgl+Iy+dZcdTAwMGJMXHUwMDE5xpFNkYi3fNDIXHUwMDFjup1SUdqdbru6fLi3tLrgXHUwMDAxXHUwMDFkkE7oWevhSiqu8S9R9qpV4Fx1MDAxNMRXQJUyXHUwMDFiKlx1MDAxNrN44UiUSmzAwlPbz/51pJcl5pBzcjawkHJy52t5ZXWvfVgyXHLb5zJfb15cdTAwMTWP/enCiy88XHUwMDFmy6FaXHUwMDE5c9KGxPNNfOHQXHUwMDE4R+F08NCT62L98ngkLzh3Yp5nOV8vvEnnj5wlclx1MDAwMvo84aZcdKOrbVx1MDAxOL1UfvaqvFrnq0e5vaXDbFLtg4UpXCJrlYVvpbSgXFxwLXS06ImUcIC8IWavzLhTg083XHUwMDAwYlRDXHUwMDE2zlx1MDAwM/Xqg1x1MDAxOYhpRVwiwLTBfy13SnAvw0Fir8JcdTAwMGLLYIxgXHSpIYtTzi16eJjwym9zLJm4efRkRvftfbw/wn9PXHUwMDBiXzGuNrpcdTAwMTFUfXuKUKHHs7W8aVx1MDAxYlnsNs9yq9m9xtPJ+cOi45dzrVx1MDAwMy2sx8rDsNjI0YnWkrpcdTAwMDdpSWWBrPGfql4yXHUwMDFlv+RcdTAwMDbTtbCl4yqr44xcdTAwMGZ1w6PoXHUwMDA1qFx1MDAxYc6M16G0s5+8X1hcdTAwMDF9o+MjXHUwMDA3vlx1MDAwMTw3XHUwMDAwJ+5cdTAwMWU9o/s2JYBcdTAwMTPbXHIl1yNcdTAwMTRCXHUwMDFhfNRcdTAwMTRcdELqIM+Wn7ebaktt9LZrZv+2cPHB9rVfXHUwMDE4XG5cZjcj3H87klwiJMHXQt2/zPzwq+NcIoDtSMSvcXRcdTAwMTUp/ddcdTAwMDM05P+mVF+HRvThx1xmvWlcXOsvWqB6rbs0aNLzn3jpf4VcdTAwMTf0vVx1MDAwNjtcdTAwMWL61bn3+oqZ1ofgXHUwMDE2jshcdTAwMWG1ly9ccqMn57tcdTAwMDeba9vt3L19auf2enf3+0zI5YXv1+o4peQnwc17R8W+vlx1MDAwMG5WxYTW8dFcYntOfYFcdTAwMTjFQSww4LxcdFTombyR5dLh4erB4dLhRmEnXHUwMDE2aKFcdTAwMTjIr1x1MDAwMFp4OmNcdTAwMDGWkt8ypqiWloJcIigmR5noXFxfdXZZfmel+XR+o/KnK7leddFRRoVcdTAwMDNcdTAwMDOnIUTeSmM9j5w1e1x1MDAwZX/BXHUwMDBivKK9ocDEueFsJn3ZJedmgpY9XHUwMDA3rPXw3Lsuqf0zlr3vP16ZSq/83YErMu7v1pX9WVxcblx1MDAxZFx1MDAxNUqd0vbJbu5eni+v7Fxcbcxg3Ll3e4/X35/QazJRrzlBvbesnfyM97mwbLpPhfX9Zu3oaOn8pqH0tlxcfLVm7CC+xVx06nlcIljkstcxOlx1MDAwNNZcdTAwMTSc5blcdTAwMTSL3+ydycGhTGre9Mc12yfj9j4gw0nkV8vEs17iLN7rKVx1MDAwMlx1MDAxNzr7+7ndUq9QWlary5V9w1x1MDAxZVx1MDAxZmpm4cXXMFx0ibBw8OloTEfZL8TBXHUwMDA11DPFco7/O1x1MDAxMZ3aLM1yTEZZXFy7d1wi6lLrhFx1MDAwM6GvkNBxOny3WivaSq1fbd1087X8Vr1du9mehe09zrjL2ubNwVnxeblkrmuusy7nb1x1MDAxYmK5/ceb1JfLQVx1MDAxMJTL8cz+q7vU/5zMWN2R2PlH8uSLXCJcbqqkXHUwMDEwn4mVx3jLv6CNf1x1MDAwNHnORklcdTAwMDVcdTAwMDfGXHUwMDE4b2yE0msnv+qkylx1MDAwNF5cdTAwMTkhtJbOUaPfUU1izFxih+fOc5jAcHfQiVx1MDAxZOm5XHUwMDE4sdBcdTAwMDdO1OpnvCP4Y7hljlx1MDAxOSTmYlx1MDAxN4Sk7mAu9LbXbmY6cIpL76SQXHUwMDE2/ECNdlx1MDAwNJuo1c+t2i6c5FcumoV8rqLXXHUwMDFmjk6PV5+SZuU1g1MoXHUwMDFk3YMz70cmJVx1MDAwMubeYodBN2P6XHUwMDBm/U6dfiiPlnsqKq8gp6FAO3ok02m/XHUwMDBmg1x1MDAxY2BcdTAwMGaxPcZcdTAwMDNaytmhcHpcYvn7XGJ/hP+ellx1MDAxYckxXHUwMDA1OZRcdTAwMTnU/5uiIMfp4VXtxp7d3VevbkVl5ancPW1fL/o5vFx1MDAxOJQ8TD6H1zLQXr4qN60/V1x1MDAxMjjlID7u6jsmUENxqs6eULFzMVx1MDAwZVx1MDAwNjVcdTAwMGI8V8Jp+/LnpNyhV6rXXHUwMDBlX0+9c932zX/++Efr5S11/Fx1MDAxN/ZuYM7L5b/9/HG/TT8slYKgVPrbj/efXtdaXHUwMDFiVVxuhmVcIv4oX4R2+iuIyHy+2YdQL0xy7p1khmPHp8i96yyt7+5Jt3+33T81S3L7oHC8t/Cdxbm141BcdTAwMGYj9UWcRknKtTLKc2qbXHUwMDE4vqdcdTAwMGa78yMqXHUwMDAwvj+VXHUwMDBmSki0X1xmXHUwMDFkoKhtkjCSw33w6t2EpemA0uC2K/t0SKL+j1x1MDAxNlx0+o///X+AXHUwMDA1LiSoPDYt3rHwX4rnXHRm+TGTrJM79b20n5/mqu60euBqh6WDgyu119PPrq6qudzig9PZgFJcdTAwMGa19lx1MDAxNi6oXHUwMDFmrpLFbSA5QMtccjXDXHUwMDE2ao6nbVJAhkNPTFAwNzKg9CVOMZVgt2Y0SVY4T02dXHUwMDEzstpcdTAwMTZcdTAwMDSsMrCOSUflR+hcItRNitb2XHUwMDAz4FKo/+fAXHUwMDFlkZV687j/0YrFKVc2acG+XHUwMDAyt2PnO1x1MDAxNrGJsaQ28XJdXG7vjJsmXHUwMDE2bUtcXFx1MDAxNevX/Pmsfpo9uD3udcz+fnvGR1x1MDAwNNU2+VAzRaww1E7n3ZxGoqDhb6pAXHUwMDBlsqlcdTAwMDYm1X+qhM34XHUwMDAz8iDmRFxcupFjgUHEXCK1zv6AXHT90mOBv1rEWSa0Q/Rgb95/5Y/w31NHhYZUyUgyXHUwMDAyrCZcXKYporrzfnv16qD9JE+615VcdTAwMGL+VNwtZpLyaT+MxFKvMWskUlx1MDAxOXQhXHJcYlxipXqpyE1cdTAwMTWUVSBcdTAwMDVhlE6Jwm2BZ1xyRFx1MDAxZVB9XCJhnWNOe2Viwl5cZrRcdTAwMDJ0XHUwMDAyrDj1gvaxPNc4xT7Ec79B+pkqM0mbR8/Itk2J30Tqy5PjZ1x1MDAxOJW6UuHMqjT82uXiVXGn8bB0qLLtq6vDLbvfSkoxXlx1MDAxY0vqQSdcdTAwMTlcYvDrwYlcdTAwMWZcdTAwMGXrVpJcdTAwMDdcXPDXpFxmydT8TqOoRr1cdTAwMWR6YvCrh9gxXHUwMDFiXHRiXHUwMDEzykupw1x1MDAxOYyLx3xDN4wpVLeQy2WW15c24kPWlIksxtdedL1P7kPYXHUwMDEzyW4nUFx1MDAwN8M5TZL0Mcvsy81cdTAwMDZbWTncK/VcdTAwMWWuaiumktRcdTAwMGZycaDHJZdjSOxXYk/HXFySx9xsYVx1MDAxNo7ZhF7wc4s7y3Z8ocuW91x1MDAxZfafes2nfrVcbiFVv+aOelxu7O6Mhe7XQnVnXHUwMDEypCZfSYc6XHUwMDE1j3ZX4VRpaYpLm/G7ubBYXHUwMDE1Tlx1MDAwNVwiXHUwMDE5q5yyXb9cdTAwMDSr3MV6nKNgXHUwMDA189ZcIqnP2u/AZJNugsdr+1x1MDAxZu83wSCVVL6W4uRgXHUwMDFlPVx1MDAwYrmBPy+nefDTXHUwMDE5/D1vfoekgZ5pfdtk1LvkS1x1MDAxYlx1MDAwN46F3Z5cIoytWJaP4qT/pPeVLFx1MDAxZa4028vFjaRM+0VCvVx1MDAxZHfMpLhcdTAwMGWohcRXoJ7Ou2Jgz4Khbk4/XHUwMDBmgKnJk1x1MDAxM+5cdTAwMDNcdTAwMDfAXHUwMDBigv15erFzXHUwMDA1ZGZ4p1x1MDAwNj9cdTAwMWFs0pS4TOLNSiT7rGpQRmCaSlx1MDAwMlc3xbzVhyfrJ0fm1LROL8XqUVIn1C+6rvFpoMzQXHKIoVx1MDAwMkKMgsNUtIKLZJSVXHUwMDA3cFx1MDAwYiu48y65XHUwMDAyxmdBaWzc/cxoalx1MDAxNVx1MDAxZERzKdKKtJxcdTAwMWOJx6vtu6fjXHUwMDBl97ZeMmeZzHFm3nUunHGWT1x1MDAxM6NphOBcdTAwMWOK0SphJmbDxYPV/Vx1MDAxZiurR1x1MDAxYsursYT4i9OvwtN5QeFcdTAwMWavK/xn6fb2oI8leuNcdTAwMWZ/3l/WXHUwMDFlsvElbqnK7Vx1MDAxZq9cdTAwMTgmsNRotf/5rz/+9f9cdTAwMDFKsSikIn0= + + + + NFT0x123...456ASSETANCHORANCHOR-TECHNOLOGY§ORACLEPROOF-OF-CONTROLto0xaa..aaERC-69560xaa..aatoken: 2402anchor: 0x123...456{ to: 0xaa..aa, anchor: 0x123..456, signed: § } 0x..gasPayertransferAnchor( )ATTESTATION0xbb...bbsafeTransferFrom( from: 0xbb..bb, to: 0xaa..aa, tokenId: 2402)anchorByToken2402 <> 0x123...456ownerOf(2402) 0xbb...bbOFF-CHAINON-CHAINUSER DEVICE \ No newline at end of file diff --git a/assets/eip-6956/test/ERC6956.ts b/assets/eip-6956/test/ERC6956.ts new file mode 100644 index 0000000000000..01bf26982b8e6 --- /dev/null +++ b/assets/eip-6956/test/ERC6956.ts @@ -0,0 +1,355 @@ +import { time, loadFixture } from "@nomicfoundation/hardhat-network-helpers"; +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { createHash } from 'node:crypto'; +import { StandardMerkleTree } from "@openzeppelin/merkle-tree"; +import { ERC6956Authorization, ERC6956Role, merkleTestAnchors, NULLADDR, createAttestation} from "./commons"; +import { IERC6956AttestationLimitedInterfaceId, IERC6956InterfaceId, IERC6956FloatableInterfaceId, IERC6956ValidAnchorsInterfaceId} from "./commons"; + + + +export async function minimalAttestationExample() { + // #################################### PRELIMINARIES + /*const merkleTestAnchors = [ + ['0x' + createHash('sha256').update('TestAnchor123').digest('hex')], + ['0x' + createHash('sha256').update('TestAnchor124').digest('hex')], + ['0x' + createHash('sha256').update('TestAnchor125').digest('hex')], + ['0x' + createHash('sha256').update('TestAnchor126').digest('hex')], + ['0x' + createHash('sha256').update('SaltLeave').digest('hex')] // shall never be used on-chain! + ] + const merkleTree = StandardMerkleTree.of(merkleTestAnchors, ["bytes32"]);*/ + + // #################################### ACCOUNTS + // Alice shall get the NFT, oracle signs the attestation off-chain + const [alice, oracle] = await ethers.getSigners(); + + // #################################### CREATE AN ATTESTATION + const to = alice.address; + const anchor = merkleTestAnchors[0][0]; + // const proof = merkleTree.getProof([anchor]); + const attestationTime = Math.floor(Date.now() / 1000.0); // Now in seconds UTC + + const validStartTime = 0; + const validEndTime = attestationTime + 15 * 60; // 15 minutes valid from attestation + + // Hash and sign. In practice, oracle shall only sign when Proof-of-Control is established! + const messageHash = ethers.utils.solidityKeccak256(["address", "bytes32", "uint256", 'uint256', "uint256", "bytes32[]"], [to, anchor, attestationTime, validStartTime, validEndTime, proof]); + const sig = await oracle.signMessage(ethers.utils.arrayify(messageHash)); + // Encode + return ethers.utils.defaultAbiCoder.encode(['address', 'bytes32', 'uint256', 'uint256', 'uint256', 'bytes32[]', 'bytes'], [to, anchor, attestationTime, validStartTime, validStartTime, proof, sig]); +} + +describe("ERC6956: Asset-Bound NFT --- Basics", function () { + // Fixture to deploy the abnftContract contract and assigne roles. + // Besides owner there's user, minter and burner with appropriate roles. + async function deployAbNftFixture() { + // Contracts are deployed using the first signer/account by default + const [owner, maintainer, oracle, alice, bob, mallory, hacker, carl, gasProvider ] = await ethers.getSigners(); + + const AbNftContract = await ethers.getContractFactory("ERC6956"); + //const burnAuthorization = ERC6956Authorization.ALL; + //const approveAuthorization = ERC6956Authorization.ALL; + + const abnftContract = await AbNftContract.connect(owner).deploy("Asset-Bound NFT test", "ABNFT"); + await abnftContract.connect(owner).updateMaintainer(maintainer.address, true); + + await expect(abnftContract.connect(maintainer).updateOracle(oracle.address, true)) + .to.emit(abnftContract, "OracleUpdate") + .withArgs(oracle.address, true); + + + return { abnftContract, owner, maintainer, oracle, alice, bob, mallory, hacker, carl, gasProvider }; + } + + async function deployABTandMintTokenToAlice() { + // Contracts are deployed using the first signer/account by default + const {abnftContract, owner, maintainer, oracle, alice, bob, mallory, hacker, carl, gasProvider} = await deployAbNftFixture(); + + const anchor = merkleTestAnchors[0][0]; + const mintAttestationAlice = await createAttestation(alice.address, anchor, oracle); // Mint to alice + + await expect(abnftContract.connect(gasProvider)["transferAnchor(bytes)"](mintAttestationAlice)) + .to.emit(abnftContract, "Transfer") // Standard ERC721 event + .withArgs(NULLADDR, alice.address, 1); + + return { abnftContract, owner, maintainer, oracle, mintAttestationAlice, anchor, alice, bob, mallory, hacker, carl, gasProvider }; + } + + + describe("Deployment & Settings", function () { + it("Should implement EIP-165 support the EIP-6956 interface", async function () { + const { abnftContract } = await loadFixture(deployAbNftFixture); + expect(await abnftContract.supportsInterface(IERC6956InterfaceId)).to.equal(true); + expect(await abnftContract.supportsInterface(IERC6956ValidAnchorsInterfaceId)).to.equal(false); + expect(await abnftContract.supportsInterface(IERC6956FloatableInterfaceId)).to.equal(false); + expect(await abnftContract.supportsInterface(IERC6956AttestationLimitedInterfaceId)).to.equal(false); + }); + }); + + +describe("Authorization Map tests", function () { + it("SHOULD interpret ERC6956Authorization correctly", async function () { + // Create the message to sign + const { abnftContract } = await loadFixture(deployAbNftFixture); + + // OWNER + await expect(await abnftContract.hasAuthorization(ERC6956Role.OWNER, await abnftContract.createAuthorizationMap(ERC6956Authorization.NONE))) + .to.be.equal(false); + await expect(await abnftContract.hasAuthorization(ERC6956Role.OWNER, await abnftContract.createAuthorizationMap(ERC6956Authorization.OWNER))) + .to.be.equal(true); + await expect(await abnftContract.hasAuthorization(ERC6956Role.OWNER, await abnftContract.createAuthorizationMap(ERC6956Authorization.ISSUER))) + .to.be.equal(false); + await expect(await abnftContract.hasAuthorization(ERC6956Role.OWNER, await abnftContract.createAuthorizationMap(ERC6956Authorization.ASSET))) + .to.be.equal(false); + await expect(await abnftContract.hasAuthorization(ERC6956Role.OWNER, await abnftContract.createAuthorizationMap(ERC6956Authorization.OWNER_AND_ASSET))) + .to.be.equal(true); + await expect(await abnftContract.hasAuthorization(ERC6956Role.OWNER, await abnftContract.createAuthorizationMap(ERC6956Authorization.OWNER_AND_ISSUER))) + .to.be.equal(true); + await expect(await abnftContract.hasAuthorization(ERC6956Role.OWNER, await abnftContract.createAuthorizationMap(ERC6956Authorization.ASSET_AND_ISSUER))) + .to.be.equal(false); + await expect(await abnftContract.hasAuthorization(ERC6956Role.OWNER, await abnftContract.createAuthorizationMap(ERC6956Authorization.ALL))) + .to.be.equal(true); + + // ISSUER + await expect(await abnftContract.hasAuthorization(ERC6956Role.ISSUER, await abnftContract.createAuthorizationMap(ERC6956Authorization.NONE))) + .to.be.equal(false); + await expect(await abnftContract.hasAuthorization(ERC6956Role.ISSUER, await abnftContract.createAuthorizationMap(ERC6956Authorization.OWNER))) + .to.be.equal(false); + await expect(await abnftContract.hasAuthorization(ERC6956Role.ISSUER, await abnftContract.createAuthorizationMap(ERC6956Authorization.ISSUER))) + .to.be.equal(true); + await expect(await abnftContract.hasAuthorization(ERC6956Role.ISSUER, await abnftContract.createAuthorizationMap(ERC6956Authorization.ASSET))) + .to.be.equal(false); + await expect(await abnftContract.hasAuthorization(ERC6956Role.ISSUER, await abnftContract.createAuthorizationMap(ERC6956Authorization.OWNER_AND_ASSET))) + .to.be.equal(false); + await expect(await abnftContract.hasAuthorization(ERC6956Role.ISSUER, await abnftContract.createAuthorizationMap(ERC6956Authorization.OWNER_AND_ISSUER))) + .to.be.equal(true); + await expect(await abnftContract.hasAuthorization(ERC6956Role.ISSUER, await abnftContract.createAuthorizationMap(ERC6956Authorization.ASSET_AND_ISSUER))) + .to.be.equal(true); + await expect(await abnftContract.hasAuthorization(ERC6956Role.ISSUER, await abnftContract.createAuthorizationMap(ERC6956Authorization.ALL))) + .to.be.equal(true); + + + // ASSET + await expect(await abnftContract.hasAuthorization(ERC6956Role.ASSET, await abnftContract.createAuthorizationMap(ERC6956Authorization.NONE))) + .to.be.equal(false); + await expect(await abnftContract.hasAuthorization(ERC6956Role.ASSET, await abnftContract.createAuthorizationMap(ERC6956Authorization.OWNER))) + .to.be.equal(false); + await expect(await abnftContract.hasAuthorization(ERC6956Role.ASSET, await abnftContract.createAuthorizationMap(ERC6956Authorization.ISSUER))) + .to.be.equal(false); + await expect(await abnftContract.hasAuthorization(ERC6956Role.ASSET, await abnftContract.createAuthorizationMap(ERC6956Authorization.ASSET))) + .to.be.equal(true); + await expect(await abnftContract.hasAuthorization(ERC6956Role.ASSET, await abnftContract.createAuthorizationMap(ERC6956Authorization.OWNER_AND_ASSET))) + .to.be.equal(true); + await expect(await abnftContract.hasAuthorization(ERC6956Role.ASSET, await abnftContract.createAuthorizationMap(ERC6956Authorization.OWNER_AND_ISSUER))) + .to.be.equal(false); + await expect(await abnftContract.hasAuthorization(ERC6956Role.ASSET, await abnftContract.createAuthorizationMap(ERC6956Authorization.ASSET_AND_ISSUER))) + .to.be.equal(true); + await expect(await abnftContract.hasAuthorization(ERC6956Role.ASSET, await abnftContract.createAuthorizationMap(ERC6956Authorization.ALL))) + .to.be.equal(true); + }); +}); + + + describe("Attestation-based transfers", function () { + it("SHOULD not allow non-trusted oracles to issue attestation", async function () { + // Create the message to sign + const { abnftContract, oracle, mallory, gasProvider } = await loadFixture(deployAbNftFixture); + + const to = "0x1234567890123456789012345678901234567890"; + const anchor = merkleTestAnchors[0][0]; + const attestation = await createAttestation(to, anchor, oracle); + + const fraudAttestation = await createAttestation(to, anchor, mallory); + await expect(abnftContract['transferAnchor(bytes)'](fraudAttestation)) + .to.be.revertedWith("ERC6956-E8"); + }); + + it("SHOULD allow mint and transfer with valid attestations", async function() { + const { abnftContract, oracle, mintAttestationAlice, anchor, alice, bob, hacker, gasProvider } = await loadFixture(deployABTandMintTokenToAlice); + + const attestationBob = await createAttestation(bob.address, anchor, oracle); // Mint to alice + + await expect(abnftContract.connect(gasProvider)["transferAnchor(bytes)"](attestationBob)) + .to.emit(abnftContract, "Transfer") // Standard ERC721 event + .withArgs(alice.address, bob.address, 1) + .to.emit(abnftContract, "AnchorTransfer") + .withArgs(alice.address, bob.address, anchor, 1); + + // Token is now at bob... so alice may hire a hacker quickly and re-use her attestation to get + // the token back from Bob ... which shall of course not work + await expect(abnftContract.connect(hacker)["transferAnchor(bytes)"](mintAttestationAlice)) + .to.revertedWith("ERC6956-E9") // Standard ERC721 event + }) + + + it("SHOULDN'T allow safeTransfer per default", async function() { + const { abnftContract, alice, bob} = await loadFixture(deployABTandMintTokenToAlice); + + await expect(abnftContract.connect(alice).transferFrom(alice.address, bob.address, 1)) + .to.revertedWith("ERC6956-E5"); + }) + + it("SHOULDN'T allow approveAnchor followed by safeTransfer when anchor not floating", async function() { + const { abnftContract, anchor, oracle, alice, bob, gasProvider, mallory,carl} = await loadFixture(deployABTandMintTokenToAlice); + const tokenId = await abnftContract.tokenByAnchor(anchor); + + const attestationBob = await createAttestation(bob.address, anchor, oracle); // Mint to alice + + // somebody approves himself via attestation approves bob to act on her behalf + await expect(abnftContract.connect(gasProvider)["approveAnchor(bytes)"](attestationBob)) + .to.emit(abnftContract, "Approval") // Standard ERC721 event + .withArgs(await abnftContract.ownerOf(tokenId), bob.address, tokenId); + + // Should not allow mallory to transfer, since only bob is approved + await expect(abnftContract.connect(mallory).transferFrom(alice.address, bob.address, 1)) + .to.revertedWith("ERC721: caller is not token owner or approved"); + + // Even though Bob is approved, cannot transfer, since anchor is not floating + await expect(abnftContract.connect(bob).transferFrom(alice.address, carl.address, tokenId)) + .to.revertedWith("ERC6956-E5"); + }) + + it("SHOULDN't allow using attestations before validity ", async function() { + const { abnftContract, maintainer, oracle, alice } = await loadFixture(deployAbNftFixture); + const anchor = merkleTestAnchors[0][0]; + + // Let the oracle create an valid attestation (from the oracle's view) + const curTime = Math.floor(Date.now() / 1000.0); + const twoMinInFuture = curTime + 2 * 60; + const attestationAlice = await createAttestation(alice.address, anchor, oracle, twoMinInFuture); // Mint to alice + await expect(abnftContract.connect(alice)["transferAnchor(bytes)"](attestationAlice)) + .to.revertedWith("ERC6956-E10") + }) + }); + + describe("ERC721Burnable-compatible behavior", function () { + it("SHOULD burn like ERC-721 (direct)", async function() { + const { abnftContract, anchor, alice, bob} = await loadFixture(deployABTandMintTokenToAlice); + const tokenId = await abnftContract.tokenByAnchor(anchor); + + // Let bob try to burn... should not work + await expect(abnftContract.connect(bob).burn(tokenId)) + .to.revertedWith("ERC6956-E2"); + + // Alice then burns, which shall be transaction to 0x0 + await expect(abnftContract.connect(alice).burn(tokenId)) + .to.emit(abnftContract, "Transfer") + .withArgs( alice.address,NULLADDR, tokenId); + }) + it("SHOULD burn like ERC-721 (approved)", async function() { + const { abnftContract, owner, maintainer, oracle, mintAttestationAlice, anchor, alice, bob, mallory, hacker } = await loadFixture(deployABTandMintTokenToAlice); + const tokenId = await abnftContract.tokenByAnchor(anchor); + + // alice approves bob to act on her behalf + await expect(abnftContract.connect(alice).setApprovalForAll(bob.address, true)) + .to.emit(abnftContract, "ApprovalForAll") // Standard ERC721 event + .withArgs(alice.address, bob.address, true); + + // Let mallory try to burn... should not work + await expect(abnftContract.connect(mallory).burn(tokenId)) + .to.revertedWith("ERC6956-E2"); + + // Bob is approved, so bob can burn + await expect(abnftContract.connect(bob).burn(tokenId)) + .to.emit(abnftContract, "Transfer") + .withArgs(alice.address,NULLADDR, tokenId) + .to.emit(abnftContract, "AnchorTransfer") + .withArgs(alice.address,NULLADDR, anchor, tokenId); + }) + + it("SHOULD allow issuer to burn", async function() { + const { abnftContract, owner, maintainer, oracle, mintAttestationAlice, anchor, alice, bob, mallory, hacker } = await loadFixture(deployABTandMintTokenToAlice); + + const tokenId = await abnftContract.tokenByAnchor(anchor); + + await abnftContract.connect(maintainer).updateBurnAuthorization(ERC6956Authorization.ISSUER); + + // Let mallory try to burn... should not work + await expect(abnftContract.connect(mallory).burn(tokenId)) + .to.revertedWith("ERC6956-E2"); + + // Bob is approved, so bob can burn + await expect(abnftContract.connect(maintainer).burn(tokenId)) + .to.emit(abnftContract, "Transfer") + .withArgs(alice.address,NULLADDR, tokenId); + }) + + it("SHOULD burn like ERC-721 (via attestation-approved)", async function() { + const { abnftContract, oracle, anchor, alice, bob, mallory, hacker } = await loadFixture(deployABTandMintTokenToAlice); + const tokenId = await abnftContract.tokenByAnchor(anchor); + const attestationBob = await createAttestation(bob.address, anchor, oracle); // Mint to alice + + // somebody approves himself via attestation approves bob to act on her behalf + await expect(abnftContract.connect(hacker)["approveAnchor(bytes)"](attestationBob)) + .to.emit(abnftContract, "Approval") // Standard ERC721 event + .withArgs(await abnftContract.ownerOf(tokenId), bob.address, tokenId); + + // Let mallory try to burn... should not work + await expect(abnftContract.connect(mallory).burn(tokenId)) + .to.revertedWith("ERC6956-E2"); + + // Bob is approved, so bob can burn + await expect(abnftContract.connect(bob).burn(tokenId)) + .to.emit(abnftContract, "Transfer") + .withArgs(alice.address,NULLADDR, tokenId); + }) + + it("SHOULD burn like ERC-721 (attestation)", async function() { + const { abnftContract, oracle, mintAttestationAlice, anchor, alice, bob, mallory } = await loadFixture(deployABTandMintTokenToAlice); + const tokenId = await abnftContract.tokenByAnchor(anchor); + const burnAttestation = await createAttestation(bob.address, anchor, oracle); // Mint to alice + + // Let mallory try to burn a token based on the creation anchor.. + await expect(abnftContract.connect(mallory)["burnAnchor(bytes)"](mintAttestationAlice)) + .to.revertedWith("ERC6956-E9"); + + // Now, using a fresh attestation, the same guy can burn + await expect(abnftContract.connect(mallory)["burnAnchor(bytes)"](burnAttestation)) + .to.emit(abnftContract, "Transfer") + .withArgs(alice.address,NULLADDR, tokenId); + }) + + + it("SHOULD use same tokenId when anchor is used again after burning", async function() { + const { abnftContract, oracle, anchor, alice, bob, mallory } = await loadFixture(deployABTandMintTokenToAlice); + const tokenId = await abnftContract.tokenByAnchor(anchor); + + // Alice then burns her token, since she does no longer like it in her wallet. This shall be a transaction to 0x0 + await expect(abnftContract.connect(alice).burn(tokenId)) + .to.emit(abnftContract, "Transfer") + .withArgs( alice.address,NULLADDR, tokenId); + + // Bob gets the ASSET, confirmed by ORACLE. Since Alice burned tokenId 1 before, but we have the same anchor + // it is expected that BOB gets a new NFT with same tokenId + const attestationBob = await createAttestation(bob.address, anchor, oracle); // Mint to alice + await expect(abnftContract.connect(mallory)["transferAnchor(bytes)"](attestationBob)) + .to.emit(abnftContract, "Transfer") // Standard ERC721 event + .withArgs(NULLADDR, bob.address, tokenId); + }) +}); + + +describe("Metadata tests", function () { + it("SHOULD allow only maintainer to update baseURI", async function () { + // Create the message to sign + const { abnftContract, maintainer, mallory } = await loadFixture(deployABTandMintTokenToAlice); + + await expect(abnftContract.connect(mallory).updateBaseURI("http://test.xyz/")) + .to.revertedWith("ERC6956-E1"); + + await abnftContract.connect(maintainer).updateBaseURI("http://test.xyz/"); + // FIXME event would be nice + }); + + it("SHOULD use anchor for tokenURI", async function () { + // Create the message to sign + const { abnftContract, anchor, maintainer, alice, mallory } = await loadFixture(deployABTandMintTokenToAlice); + await abnftContract.connect(maintainer).updateBaseURI("http://test.xyz/collection/"); + + expect(await abnftContract.tokenURI(1)) + .to.be.equal("http://test.xyz/collection/0xaa0c61ccb0c754f1c68c699990a456c6073aaa28109c1bd83880c49dcece3d65"); + }); +}); + + +}); diff --git a/assets/eip-6956/test/ERC6956Full.ts b/assets/eip-6956/test/ERC6956Full.ts new file mode 100644 index 0000000000000..fd48f5ce7c226 --- /dev/null +++ b/assets/eip-6956/test/ERC6956Full.ts @@ -0,0 +1,445 @@ +import { time, loadFixture } from "@nomicfoundation/hardhat-network-helpers"; +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { createHash } from 'node:crypto'; +import { StandardMerkleTree } from "@openzeppelin/merkle-tree"; +import { float } from "hardhat/internal/core/params/argumentTypes"; +import { ERC6956Authorization, merkleTestAnchors, NULLADDR, AttestedTransferLimitUpdatePolicy, invalidAnchor, createAttestationWithData} from "./commons"; +import { IERC6956AttestationLimitedInterfaceId, IERC6956InterfaceId, IERC6956FloatableInterfaceId, IERC6956ValidAnchorsInterfaceId} from "./commons"; + +export enum FloatState { + Default, // 0, inherits from floatAll + Floating, // 1 + Anchored // 2 +} + +describe("ERC6956: Asset-Bound NFT --- Full", function () { + // Fixture to deploy the abnftContract contract and assigne roles. + // Besides owner there's user, minter and burner with appropriate roles. + async function deployAbNftFixture() { + // Contracts are deployed using the first signer/account by default + const [owner, maintainer, oracle, alice, bob, mallory, hacker, carl, gasProvider ] = await ethers.getSigners(); + + return actuallyDeploy(10, AttestedTransferLimitUpdatePolicy.FLEXIBLE); + } + + async function deployAbNftAndMintTokenToAliceFixture() { + // Contracts are deployed using the first signer/account by default + const {abnftContract, merkleTree, owner, maintainer, oracle, alice, bob, mallory, hacker, carl, gasProvider} = await deployAbNftFixture(); + + const anchor = merkleTestAnchors[0][0]; + const [mintAttestationAlice, dataAlice] = await createAttestationWithData(alice.address, anchor, oracle, merkleTree); // Mint to alice + + const expectedTokenId = 1; + await expect(abnftContract.connect(gasProvider)["transferAnchor(bytes,bytes)"](mintAttestationAlice, dataAlice)) + .to.emit(abnftContract, "Transfer") // Standard ERC721 event + .withArgs(NULLADDR, alice.address, expectedTokenId) + + return { abnftContract, merkleTree, owner, maintainer, oracle, mintAttestationAlice, anchor, alice, bob, mallory, hacker, carl, gasProvider }; + } + + async function actuallyDeploy(attestationLimitPerAnchor: number, limitUpdatePolicy: AttestedTransferLimitUpdatePolicy) { + const [owner, maintainer, oracle, alice, bob, mallory, hacker, carl, gasProvider ] = await ethers.getSigners(); + + const AbNftContract = await ethers.getContractFactory("ERC6956Full"); + + const abnftContract = await AbNftContract.connect(owner).deploy("Asset-Bound NFT test", "ABNFT", limitUpdatePolicy); + await abnftContract.connect(owner).updateMaintainer(maintainer.address, true); + + // set attestation Limit per anchor + await abnftContract.connect(maintainer).updateGlobalAttestationLimit(attestationLimitPerAnchor); + + // Create Merkle Tree + const merkleTree = StandardMerkleTree.of(merkleTestAnchors, ["bytes32"]); + await abnftContract.connect(maintainer).updateValidAnchors(merkleTree.root); + + await expect(abnftContract.connect(maintainer).updateOracle(oracle.address, true)) + .to.emit(abnftContract, "OracleUpdate") + .withArgs(oracle.address, true); + + // Uncomment to see the merkle tree. + // console.log(merkleTree.dump()); + + return { abnftContract, merkleTree, owner, maintainer, oracle, alice, bob, mallory, hacker, carl, gasProvider }; + } + + async function deployForAttestationLimit(limit: number, policy: AttestedTransferLimitUpdatePolicy) { + return actuallyDeploy(limit, policy); + } + + describe("Deployment & Settings", function () { + it("Should implement EIP-165 support the EIP-6956 interface", async function () { + const { abnftContract } = await loadFixture(deployAbNftFixture); + + expect(await abnftContract.supportsInterface(IERC6956InterfaceId)).to.equal(true); + expect(await abnftContract.supportsInterface(IERC6956FloatableInterfaceId)).to.equal(true); + expect(await abnftContract.supportsInterface(IERC6956ValidAnchorsInterfaceId)).to.equal(true); + expect(await abnftContract.supportsInterface(IERC6956AttestationLimitedInterfaceId)).to.equal(true); + }); + }); + + +describe("Valid Anchors (merkle-trees)", function () { + it("SHOULDN't allow attesting arbitrary anchors", async function() { + const { abnftContract, merkleTree, maintainer, oracle, alice, hacker } = await loadFixture(deployAbNftFixture); + + // Publish root node of a made up tree, s.t. all proofs we use are from a different tree + const madeUpRootNode = '0xaaaaaaaab0c754f1c68c699990a456c6073aaa28109c1bd83880c49dcece3f65'; // random string + abnftContract.connect(maintainer).updateValidAnchors(madeUpRootNode) + const anchor = merkleTestAnchors[0][0]; + + // Let the oracle create an valid attestation (from the oracle's view) + const [attestationAlice, dataAlice] = await createAttestationWithData(alice.address, anchor, oracle, merkleTree); // Mint to alice + await expect(abnftContract.connect(hacker)["transferAnchor(bytes,bytes)"](attestationAlice, dataAlice)) + .to.revertedWith("ERC6956-E26") + }); +}); + +describe("Anchor-Floating", function () { + it("SHOULD only allow maintainer to specify canStartFloating and canStopFloating", async function () { + const { abnftContract, merkleTree, owner, maintainer, mallory } = await loadFixture(deployAbNftAndMintTokenToAliceFixture); + + await expect(abnftContract.connect(mallory).updateFloatingAuthorization(ERC6956Authorization.ALL, ERC6956Authorization.ALL)) + .to.revertedWith("ERC6956-E1"); + + await expect(abnftContract.connect(maintainer).updateFloatingAuthorization(ERC6956Authorization.OWNER_AND_ASSET, ERC6956Authorization.ISSUER)) + .to.emit(abnftContract, "FloatingAuthorizationChange") + .withArgs(ERC6956Authorization.OWNER_AND_ASSET, ERC6956Authorization.ISSUER, maintainer.address); + }); + + it("SHOULD only allow maintainer to modify floatAll behavior w/o affecting previous tokens", async function () { + const { abnftContract, merkleTree, anchor, owner, maintainer, alice, bob, oracle, mallory, gasProvider } = await loadFixture(deployAbNftAndMintTokenToAliceFixture); + + // --------------------------------------------------------------------------------- ALL FLOATING = FALSE + await expect(abnftContract.connect(maintainer).updateFloatingAuthorization(ERC6956Authorization.OWNER_AND_ASSET, ERC6956Authorization.ISSUER)) + .to.emit(abnftContract, "FloatingAuthorizationChange") + .withArgs(ERC6956Authorization.OWNER_AND_ASSET, ERC6956Authorization.ISSUER, maintainer.address); + + // anchor does not float by default + // FLOATING ALL, so both have to float + expect(await abnftContract.floating(anchor)) + .to.be.equal(false); // one was used to mint + + // Now alice, as the owner decides to make it explicitely floatable + expect(await abnftContract.connect(alice).float(anchor, FloatState.Floating)) + .to.emit(abnftContract, "FloatingStateChange") + .withArgs(anchor, 1, FloatState.Floating, alice.address) + + // It is now explicitely floatable + expect(await abnftContract.floating(anchor)) + .to.be.equal(true); // one was used to mint + + + // Mallory mustnot be able to change default behavior + await expect(abnftContract.connect(mallory).floatAll(true)) + .to.revertedWith("ERC6956-E1"); + + // --------------------------------------------------------------------------------- ALL FLOATING = TRUE + // Maintainer must be able to update + await expect(abnftContract.connect(maintainer).floatAll(true)) + .to.emit(abnftContract, "FloatingAllStateChange") + .withArgs(true, maintainer.address); + + const implicitFloatingAnchor = merkleTestAnchors[1][0]; + const [mintToBobAttestation, mintToBobData] = await createAttestationWithData(bob.address, implicitFloatingAnchor, oracle, merkleTree); // Mint to alice + const expectedTokenId = 2; + + // Mint a new token... + await expect(abnftContract.connect(gasProvider)["transferAnchor(bytes,bytes)"](mintToBobAttestation, mintToBobData)) + .to.emit(abnftContract, "Transfer") + .withArgs(NULLADDR, bob.address, expectedTokenId) + + // FLOATING ALL, so both have to float + expect(await abnftContract.floating(anchor)) + .to.be.equal(true); // one was used to mint + + expect(await abnftContract.floating(implicitFloatingAnchor)) + .to.be.equal(true); // one was used to mint + + // --------------------------------------------------------------------------------- ALL FLOATING = FALSE + // REVERT THE FLOATING .... Maintainer must be able to update + await expect(abnftContract.connect(maintainer).floatAll(false)) + .to.emit(abnftContract, "FloatingAllStateChange") + .withArgs(false, maintainer.address); + + + // we expect the original anchor for alice to not be floating, and the new anchor from float to be floating + expect(await abnftContract.floating(anchor)) + .to.be.equal(true); + + expect(await abnftContract.floating(implicitFloatingAnchor)) + .to.be.equal(false); // this was only floating because of floatAll at the time of mint... + }); + + it("SHOULD allow owner to float token only when OWNER is allowed", async function () { + const { abnftContract, anchor, maintainer, alice, mallory } = await loadFixture(deployAbNftAndMintTokenToAliceFixture); + const tokenId = await abnftContract.tokenByAnchor(anchor); + + await expect(abnftContract.connect(maintainer).updateFloatingAuthorization(ERC6956Authorization.ASSET_AND_ISSUER, ERC6956Authorization.ASSET_AND_ISSUER)) + .to.emit(abnftContract, "FloatingAuthorizationChange") + .withArgs(ERC6956Authorization.ASSET_AND_ISSUER, ERC6956Authorization.ASSET_AND_ISSUER, maintainer.address); + + await expect(abnftContract.connect(alice).float(anchor, FloatState.Floating)) + .to.revertedWith("ERC6956-E21") + + await expect(abnftContract.connect(maintainer).updateFloatingAuthorization(ERC6956Authorization.OWNER_AND_ASSET, ERC6956Authorization.OWNER_AND_ASSET)) + .to.emit(abnftContract, "FloatingAuthorizationChange") + .withArgs(ERC6956Authorization.OWNER_AND_ASSET, ERC6956Authorization.OWNER_AND_ASSET, maintainer.address); + + await expect(abnftContract.connect(alice).float(anchor, FloatState.Floating)) + .to.emit(abnftContract, "FloatingStateChange") + .withArgs(anchor, tokenId, FloatState.Floating, alice.address); + }); + + it("SHOULD only allow owner to transfer token when floating", async function () { + const { abnftContract, anchor, maintainer, alice, bob, mallory } = await loadFixture(deployAbNftAndMintTokenToAliceFixture); + const tokenId = await abnftContract.tokenByAnchor(anchor); + + await expect(abnftContract.connect(maintainer).updateFloatingAuthorization(ERC6956Authorization.OWNER_AND_ASSET, ERC6956Authorization.OWNER_AND_ASSET)) + .to.emit(abnftContract, "FloatingAuthorizationChange") + .withArgs(ERC6956Authorization.OWNER_AND_ASSET, ERC6956Authorization.OWNER_AND_ASSET, maintainer.address); + + await expect(abnftContract.connect(alice).float(anchor, FloatState.Floating)) + .to.emit(abnftContract, "FloatingStateChange") + .withArgs(anchor, tokenId, FloatState.Floating, alice.address); + + await expect(abnftContract.connect(mallory).transferFrom(alice.address, mallory.address, tokenId)) + .to.revertedWith("ERC721: caller is not token owner or approved"); + + await expect(abnftContract.connect(alice).transferFrom(alice.address, bob.address, tokenId)) + .to.emit(abnftContract, "Transfer") + .withArgs(alice.address,bob.address, tokenId); + }); + + it("SHOULDN'T allow owner to transfer token when explicitely marked anchored", async function () { + const { abnftContract, anchor, maintainer, alice, bob, mallory } = await loadFixture(deployAbNftAndMintTokenToAliceFixture); + const tokenId = await abnftContract.tokenByAnchor(anchor); + + await expect(abnftContract.connect(maintainer).updateFloatingAuthorization(ERC6956Authorization.ISSUER, ERC6956Authorization.ISSUER)) + .to.emit(abnftContract, "FloatingAuthorizationChange") + .withArgs(ERC6956Authorization.ISSUER, ERC6956Authorization.ISSUER, maintainer.address); + + // Maintainer must be able to update + await expect(abnftContract.connect(maintainer).floatAll(true)) + .to.emit(abnftContract, "FloatingAllStateChange") + .withArgs(true, maintainer.address); + + expect(await abnftContract.floating(anchor)) + .to.be.equal(true); // one was used to mint + + await expect(abnftContract.connect(maintainer).float(anchor, FloatState.Anchored)) + .to.emit(abnftContract, "FloatingStateChange") + .withArgs(anchor, tokenId, FloatState.Anchored, maintainer.address); + + expect(await abnftContract.floating(anchor)) + .to.be.equal(false); // one was used to mint + + await expect(abnftContract.connect(alice).transferFrom(alice.address, bob.address, tokenId)) + .to.revertedWith("ERC6956-E5") + }); + + + it("SHOULD allow maintainer to float ANY token only when ISSUER is allowed", async function () { + const { abnftContract, anchor, maintainer, mallory } = await loadFixture(deployAbNftAndMintTokenToAliceFixture); + const tokenId = await abnftContract.tokenByAnchor(anchor); + + await expect(abnftContract.connect(maintainer).updateFloatingAuthorization(ERC6956Authorization.OWNER_AND_ASSET, ERC6956Authorization.OWNER_AND_ASSET)) + .to.emit(abnftContract, "FloatingAuthorizationChange") + .withArgs(ERC6956Authorization.OWNER_AND_ASSET, ERC6956Authorization.OWNER_AND_ASSET, maintainer.address); + + await expect(abnftContract.connect(maintainer).float(anchor, FloatState.Floating)) + .to.revertedWith("ERC6956-E21") + + await expect(abnftContract.connect(maintainer).updateFloatingAuthorization(ERC6956Authorization.ISSUER, ERC6956Authorization.ISSUER)) + .to.emit(abnftContract, "FloatingAuthorizationChange") + .withArgs(ERC6956Authorization.ISSUER, ERC6956Authorization.ISSUER, maintainer.address); + + await expect(abnftContract.connect(maintainer).float(anchor, FloatState.Floating)) + .to.emit(abnftContract, "FloatingStateChange") + .withArgs(anchor, tokenId, FloatState.Floating, maintainer.address); + }); + + it("SHOULD allow maintainer to float HIS OWN token when OWNER is allowed", async function () { + const { abnftContract, anchor, alice, maintainer, oracle, merkleTree, gasProvider } = await loadFixture(deployAbNftAndMintTokenToAliceFixture); + const tokenId = await abnftContract.tokenByAnchor(anchor); + + // Anchor should not be floating by default... + expect(await abnftContract.floating(anchor)) + .to.be.equal(false); // one was used to mint + + await expect(abnftContract.connect(maintainer).updateFloatingAuthorization(ERC6956Authorization.OWNER, ERC6956Authorization.OWNER)) + .to.emit(abnftContract, "FloatingAuthorizationChange") + .withArgs(ERC6956Authorization.OWNER, ERC6956Authorization.OWNER, maintainer.address); + + await expect(abnftContract.connect(maintainer).float(anchor, FloatState.Floating)) + .to.revertedWith("ERC6956-E21") + + const [attestationMaintainer, dataMaintainer] = await createAttestationWithData(maintainer.address, anchor, oracle, merkleTree); + await expect(abnftContract.connect(gasProvider)["transferAnchor(bytes,bytes)"](attestationMaintainer, dataMaintainer)) + .to.emit(abnftContract, "Transfer") + .withArgs(alice.address, maintainer.address, tokenId) + + // Now maintainer owns the token, hence he is owner and can indeed change floating + await expect(abnftContract.connect(maintainer).float(anchor, FloatState.Floating)) + .to.emit(abnftContract, "FloatingStateChange") + .withArgs(anchor, tokenId, FloatState.Floating, maintainer.address); + + expect(await abnftContract.floating(anchor)) + .to.be.equal(true); // one was used to mint + }); + + it("SHOULD allow approveAnchor followed by safeTransfer when anchor IS floating", async function() { + const { abnftContract, anchor, maintainer, oracle, merkleTree, alice, bob, gasProvider, mallory,carl} = await loadFixture(deployAbNftAndMintTokenToAliceFixture); + const tokenId = await abnftContract.tokenByAnchor(anchor); + const [attestationBob, dataBob] = await createAttestationWithData(bob.address, anchor, oracle, merkleTree); // Transfer to bob + + await expect(abnftContract.connect(maintainer).updateFloatingAuthorization(ERC6956Authorization.OWNER, ERC6956Authorization.OWNER)) + .to.emit(abnftContract, "FloatingAuthorizationChange") + .withArgs(ERC6956Authorization.OWNER, ERC6956Authorization.OWNER, maintainer.address); + + // somebody approves himself via attestation approves bob to act on her behalf + await expect(abnftContract.connect(gasProvider)["approveAnchor(bytes,bytes)"](attestationBob,dataBob)) + .to.emit(abnftContract, "Approval") // Standard ERC721 event + .withArgs(await abnftContract.ownerOf(tokenId), bob.address, tokenId); + + // Should not allow mallory to transfer, since only bob is approved + await expect(abnftContract.connect(mallory).transferFrom(alice.address, bob.address, 1)) + .to.revertedWith("ERC721: caller is not token owner or approved"); + + // Bob makes it floatable (which is possible, because he is approved) + await expect(abnftContract.connect(bob).float(anchor, FloatState.Floating)) + .to.emit(abnftContract, "FloatingStateChange") + .withArgs(anchor, tokenId, FloatState.Floating, bob.address); + + // Bob transfers it... + await expect(abnftContract.connect(bob).transferFrom(alice.address, carl.address, tokenId)) + .to.emit(abnftContract, "Transfer") + .withArgs(alice.address,carl.address, tokenId); + }) +}); + +describe("Attested Transfer Limits", function () { + it("SHOULD count attested transfers (transfer, burn, approve)", async function () { + const { abnftContract, anchor, maintainer, oracle, merkleTree, alice, bob, gasProvider, mallory,carl} = await loadFixture(deployAbNftAndMintTokenToAliceFixture); + const tokenId = await abnftContract.tokenByAnchor(anchor); + const [attestationBob, dataBob] = await createAttestationWithData(bob.address, anchor, oracle, merkleTree); // Mint to alice + const [attestationCarl, dataCarl] = await createAttestationWithData(carl.address, anchor, oracle, merkleTree); // Mint to alice + + + // Transfers shall be counted - also the one from the fixture + expect(await abnftContract.attestationsUsedByAnchor(anchor)) + .to.be.equal(1); + + // Should increase count by 1 + await expect(abnftContract["approveAnchor(bytes,bytes)"](attestationBob, dataBob)) + .to.emit(abnftContract, "Approval") // Standard ERC721 event + .withArgs(await abnftContract.ownerOf(tokenId), bob.address, tokenId); + + // Should increase count by 1 + await expect(abnftContract["burnAnchor(bytes,bytes)"](attestationCarl, dataCarl)) + .to.emit(abnftContract, "Transfer") + .withArgs(alice.address, NULLADDR, tokenId); + + // InitialMint + Approve + Burns shall also be counted - also the one from the fixture + expect(await abnftContract.attestationsUsedByAnchor(anchor)) + .to.be.equal(3); + + // Should return 0 for invalid anchors + expect(await abnftContract.attestationsUsedByAnchor(invalidAnchor)) + .to.be.equal(0); + }); + + it("SHOULD allow maintainer to update global attestation limit", async function () { + const { abnftContract, maintainer, oracle, merkleTree, alice, bob, gasProvider, mallory,carl} = await deployForAttestationLimit(10, AttestedTransferLimitUpdatePolicy.FLEXIBLE); + + await expect(abnftContract.connect(mallory).updateGlobalAttestationLimit(5)) + .to.revertedWith("ERC6956-E1"); + + // Should be able to update + await expect(abnftContract.connect(maintainer).updateGlobalAttestationLimit(5)) + .to.emit(abnftContract, "GlobalAttestationLimitUpdate") // Standard ERC721 event + .withArgs(5, maintainer.address); + + // Check effect, but requesting transfers left from a non-existent anchor + expect(await abnftContract.attestationUsagesLeft(invalidAnchor)) + .to.be.equal(5); + }); + + it("Should allow maintainer to update anchor-based attestation limit w/o changing global limits", async function () { + const globalLimit = 10; + const specificAnchorLimit = 5; + const { abnftContract, maintainer, oracle, merkleTree, alice, bob, gasProvider, mallory,carl} = await deployForAttestationLimit(globalLimit, AttestedTransferLimitUpdatePolicy.FLEXIBLE); + + const anchor = merkleTestAnchors[0][0]; + const [mintAttestationAlice, mintDataAlice] = await createAttestationWithData(alice.address, anchor, oracle, merkleTree); // Mint to alice + const tokenId = 1; + + await expect(abnftContract.connect(gasProvider)["transferAnchor(bytes,bytes)"](mintAttestationAlice, mintDataAlice)) + .to.emit(abnftContract, "Transfer") // Standard ERC721 event + .withArgs(NULLADDR, alice.address, tokenId); + + + // Note that an anchor does not need to exist yet for playing with the limits + // Check effect, but requesting transfers left from a non-existent anchor + expect(await abnftContract.attestationUsagesLeft(invalidAnchor)) + .to.be.equal(globalLimit); + + // Should be able to update + await expect(abnftContract.connect(maintainer).updateAttestationLimit(anchor, specificAnchorLimit)) + .to.emit(abnftContract, "AttestationLimitUpdate") // Standard ERC721 event + .withArgs(anchor, tokenId, specificAnchorLimit, maintainer.address); + + // Check unchanged global effect, but requesting transfers left from a non-existent anchor + expect(await abnftContract.attestationUsagesLeft(invalidAnchor)) + .to.be.equal(globalLimit); + + // Check verify effect + expect(await abnftContract.attestationUsagesLeft(anchor)) + .to.be.equal(specificAnchorLimit-1); // 1 has been used to mint + }); + + it("Should enforce anchor limits (global + local)", async function () { + const globalLimit = 2; + const specificAnchorLimit = 1; + const { abnftContract, maintainer, oracle, merkleTree, alice, bob, gasProvider, mallory,carl, hacker} = await deployForAttestationLimit(globalLimit, AttestedTransferLimitUpdatePolicy.FLEXIBLE); + const anchor = merkleTestAnchors[0][0]; // can be transferred twice + const limitedAnchor = merkleTestAnchors[1][0]; // can be transferred once + + const [anchorToAlice, anchorToAliceData] = await createAttestationWithData(alice.address, anchor, oracle, merkleTree); // Mint to alice + const [anchorToBob, anchorToBobData] = await createAttestationWithData(bob.address, anchor, oracle, merkleTree); // Transfer to bob + const [anchorToHacker, anchorToHackerData] = await createAttestationWithData(hacker.address, anchor, oracle, merkleTree); // Limit reached! + + const [limitedAnchorToCarl, limitedAnchorToCarlData] = await createAttestationWithData(carl.address, limitedAnchor, oracle, merkleTree); // Mint to carl + const [limitedAnchorToMallory, limitedAnchorToMalloryData] = await createAttestationWithData(mallory.address, limitedAnchor, oracle, merkleTree); // Limit reached! + + expect(await abnftContract.attestationUsagesLeft(anchor)) + .to.be.equal(globalLimit); + + // ####################################### FIRST ANCHOR + await expect(abnftContract.connect(gasProvider)["transferAnchor(bytes,bytes)"](anchorToAlice, anchorToAliceData)) + .to.emit(abnftContract, "Transfer"); + + await expect(abnftContract.connect(gasProvider)["transferAnchor(bytes,bytes)"](anchorToBob, anchorToBobData)) + .to.emit(abnftContract, "Transfer"); + + await expect(abnftContract.connect(gasProvider)["transferAnchor(bytes,bytes)"](anchorToHacker, anchorToHackerData)) + .to.revertedWith("ERC6956-E24"); + + // ###################################### SECOND ANCHOR + await expect(abnftContract.connect(gasProvider)["transferAnchor(bytes,bytes)"](limitedAnchorToCarl, limitedAnchorToCarlData)) + .to.emit(abnftContract, "Transfer"); + + // Update anchor based limit + await expect(abnftContract.connect(maintainer).updateAttestationLimit(limitedAnchor, specificAnchorLimit)) + .to.emit(abnftContract, "AttestationLimitUpdate") + .withArgs(limitedAnchor, 2, specificAnchorLimit, maintainer.address); + + expect(await abnftContract.attestationUsagesLeft(limitedAnchor)) + .to.be.equal(specificAnchorLimit-1); // one was used to mint + + await expect(abnftContract.connect(gasProvider)["transferAnchor(bytes,bytes)"](limitedAnchorToMallory, limitedAnchorToMalloryData)) + .to.revertedWith("ERC6956-E24"); + }); +}); + +}); diff --git a/assets/eip-6956/test/commons.ts b/assets/eip-6956/test/commons.ts new file mode 100644 index 0000000000000..9b411c3e970be --- /dev/null +++ b/assets/eip-6956/test/commons.ts @@ -0,0 +1,77 @@ +import { ethers } from "hardhat"; +import { createHash } from 'node:crypto'; +import { StandardMerkleTree } from "@openzeppelin/merkle-tree"; +import { float } from "hardhat/internal/core/params/argumentTypes"; + + +export enum ERC6956Authorization { + NONE,// = 0, // None of the above - a 1:1 relationship is maintained + OWNER,// = (1 << 1), // The owner of the token, i.e. the digital representation + ISSUER,// = (1 << 2), // The issuer of the tokens, i.e. this smart contract + ASSET,// = (1<< 3), // The asset, i.e. via attestation + OWNER_AND_ISSUER,// = (1<<1) | (1<<2), + OWNER_AND_ASSET,// = (1<<1) | (1<<3), + ASSET_AND_ISSUER,// = (1<<3) | (1<<2), + ALL// = (1<<1) | (1<<2) | (1<<3) // Owner + Issuer + Asset + } + +export enum ERC6956Role { + OWNER, + ISSUER, + ASSET + } + +export enum AttestedTransferLimitUpdatePolicy { + IMMUTABLE, + INCREASE_ONLY, + DECREASE_ONLY, + FLEXIBLE + } + +export const invalidAnchor = '0x' + createHash('sha256').update('TestAnchor1239').digest('hex'); +export const NULLADDR = ethers.utils.getAddress('0x0000000000000000000000000000000000000000'); + + // Needs to be an odd number of anchors to test the edge case of the merkle- + // tree: Nodes with only one leaf. + // Also: When building the tree (see buildMerkleTree fixture) those hashes are + // hashed again. This is intended because of the way Merkle-Proof and our + // smart contract works: + // Proof = H(leave) + H(L1) + H(L0) + // Our contract uses hashed anchor numbers as identifiers. + // Hence if we use direct anchor number checksums, H(leave) would + // be an actually valid anchor number on the smart contract. + export const merkleTestAnchors = [ + ['0x' + createHash('sha256').update('TestAnchor123').digest('hex')], + ['0x' + createHash('sha256').update('TestAnchor124').digest('hex')], + ['0x' + createHash('sha256').update('TestAnchor125').digest('hex')], + ['0x' + createHash('sha256').update('TestAnchor126').digest('hex')], + ['0x' + createHash('sha256').update('TestAnchor127').digest('hex')] + ] + + +export async function createAttestation(to, anchor, signer, validStartTime= 0) { + const attestationTime = Math.floor(Date.now() / 1000.0); // Now in seconds + const expiryTime = attestationTime + 5 * 60; // 5min valid + + const messageHash = ethers.utils.solidityKeccak256(["address", "bytes32", "uint256", 'uint256', "uint256"], [to, anchor, attestationTime, validStartTime, expiryTime]); + const sig = await signer.signMessage(ethers.utils.arrayify(messageHash)); + + return ethers.utils.defaultAbiCoder.encode(['address', 'bytes32', 'uint256', 'uint256', 'uint256', 'bytes'], [to, anchor, attestationTime, validStartTime, expiryTime, sig]); +} + + +export async function createAttestationWithData(to, anchor, signer, merkleTree, validStartTime= 0) { + + const attestation = await createAttestation(to, anchor, signer, validStartTime); // Now in seconds + + const proof = merkleTree.getProof([anchor]); + const data = ethers.utils.defaultAbiCoder.encode(['bytes32[]'], [proof]) + + return [attestation, data]; +} + + +export const IERC6956InterfaceId = '0xa9cf7635'; +export const IERC6956AttestationLimitedInterfaceId ='0x75a2e933' +export const IERC6956FloatableInterfaceId = '0xf82773f7'; +export const IERC6956ValidAnchorsInterfaceId = '0x051c9bd8'; diff --git a/assets/eip-6960/eip-6960-dual-layer-token-dlt.png b/assets/eip-6960/eip-6960-dual-layer-token-dlt.png new file mode 100644 index 0000000000000..d4db3c29e9b2e Binary files /dev/null and b/assets/eip-6960/eip-6960-dual-layer-token-dlt.png differ diff --git a/assets/eip-6982/.gitignore b/assets/eip-6982/.gitignore new file mode 100644 index 0000000000000..b102f6f5f59eb --- /dev/null +++ b/assets/eip-6982/.gitignore @@ -0,0 +1,68 @@ +*.swp +*.swo + +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed +allFiredEvents +scTopics + +# Coverage directory used by tools like istanbul +coverage +coverage.json +coverageEnv + +# node-waf configuration +.lock-wscript + +# Dependency directory +node_modules + +# Debug log from npm +npm-debug.log + +# local env variables +.env +.env.* +env.* + +# truffle build directory +build/ + +# macOS +.DS_Store + +# truffle +.node-xmlhttprequest-* + +# IntelliJ IDE +.idea + +# docs artifacts +docs/modules/api + +# only used to package @openzeppelin/contracts +contracts/build/ +contracts/README.md + +# temporary artifact from solidity-coverage +.coverage_artifacts +.coverage_cache +.coverage_contracts + +# hardhat +cache +artifacts + +#local data +db +/etherscan +.openzeppelin +/test/fixtures/csv +/export +pnpm-lock.yaml diff --git a/assets/eip-6982/README.md b/assets/eip-6982/README.md new file mode 100644 index 0000000000000..abec2293f500d --- /dev/null +++ b/assets/eip-6982/README.md @@ -0,0 +1,11 @@ +# EIP 6982 implementation + +As a reference implementation of EIP-6982 we use the Nduja Labs ERC721Lockable contract. + +To run the tests, run the following commands: + +```shell +npm i -g pnpm +pnpm i +pnpm test +``` diff --git a/assets/eip-6982/contracts/ERC721Lockable.sol b/assets/eip-6982/contracts/ERC721Lockable.sol new file mode 100644 index 0000000000000..c6a02c47fab2d --- /dev/null +++ b/assets/eip-6982/contracts/ERC721Lockable.sol @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +// Authors: Francesco Sullo + +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; +import "@openzeppelin/contracts/utils/Address.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; +import "./IERC721Lockable.sol"; +import "./IERC6982.sol"; + +// This is an example of lockable ERC721 using IERC6982 as basic interface + +contract ERC721Lockable is IERC6982, IERC721Lockable, Ownable, ERC721, ERC721Enumerable { + using Address for address; + + mapping(address => bool) private _locker; + mapping(uint256 => address) private _lockedBy; + + bool internal _defaultLocked; + + modifier onlyLocker() { + require(_locker[_msgSender()], "Not a locker"); + _; + } + + constructor( + string memory name, + string memory symbol, + bool defaultLocked_ + ) ERC721(name, symbol) { + updateDefaultLocked(defaultLocked_); + } + + function defaultLocked() external view override returns (bool) { + return _defaultLocked; + } + + function updateDefaultLocked(bool defaultLocked_) public onlyOwner { + _defaultLocked = defaultLocked_; + emit DefaultLocked(defaultLocked_); + } + + function _beforeTokenTransfer( + address from, + address to, + uint256 tokenId, + uint256 batchSize + ) internal override(ERC721, ERC721Enumerable) { + require( + // during minting + from == address(0) || + // later + !locked(tokenId), + "Token is locked" + ); + super._beforeTokenTransfer(from, to, tokenId, batchSize); + } + + function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC721Enumerable) returns (bool) { + return + interfaceId == type(IERC6982).interfaceId || + interfaceId == type(IERC721Lockable).interfaceId || + super.supportsInterface(interfaceId); + } + + function locked(uint256 tokenId) public view virtual override returns (bool) { + require(_exists(tokenId), "Token does not exist"); + return _lockedBy[tokenId] != address(0); + } + + function lockerOf(uint256 tokenId) public view virtual override returns (address) { + return _lockedBy[tokenId]; + } + + function isLocker(address locker) public view virtual override returns (bool) { + return _locker[locker]; + } + + function setLocker(address locker) external virtual override onlyOwner { + require(locker.isContract(), "Locker not a contract"); + _locker[locker] = true; + emit LockerSet(locker); + } + + function removeLocker(address locker) external virtual override onlyOwner { + require(_locker[locker], "Not an active locker"); + delete _locker[locker]; + emit LockerRemoved(locker); + } + + function hasLocks(address owner) public view virtual override returns (bool) { + uint256 balance = balanceOf(owner); + for (uint256 i = 0; i < balance; i++) { + uint256 id = tokenOfOwnerByIndex(owner, i); + if (locked(id)) { + return true; + } + } + return false; + } + + function lock(uint256 tokenId) external virtual override onlyLocker { + // locker must be approved to mark the token as locked + require(isLocker(_msgSender()), "Not an authorized locker"); + require(getApproved(tokenId) == _msgSender() || isApprovedForAll(ownerOf(tokenId), _msgSender()), "Locker not approved"); + _lockedBy[tokenId] = _msgSender(); + emit Locked(tokenId, true); + } + + function unlock(uint256 tokenId) external virtual override onlyLocker { + // will revert if token does not exist + require(_lockedBy[tokenId] == _msgSender(), "Wrong locker"); + delete _lockedBy[tokenId]; + emit Locked(tokenId, false); + } + + // emergency function in case a compromised locker is removed + function unlockIfRemovedLocker(uint256 tokenId) external virtual override { + require(locked(tokenId), "Not a locked tokenId"); + require(!_locker[_lockedBy[tokenId]], "Locker is still active"); + require(ownerOf(tokenId) == _msgSender(), "Not the asset owner"); + delete _lockedBy[tokenId]; + emit ForcefullyUnlocked(tokenId); + } + + // manage approval + + function approve(address to, uint256 tokenId) public virtual override(IERC721, ERC721) { + require(!locked(tokenId), "Locked asset"); + super.approve(to, tokenId); + } + + function getApproved(uint256 tokenId) public view virtual override(IERC721, ERC721) returns (address) { + if (locked(tokenId) && lockerOf(tokenId) != _msgSender()) { + return address(0); + } + return super.getApproved(tokenId); + } + + function setApprovalForAll(address operator, bool approved) public virtual override(IERC721, ERC721) { + require(!approved || !hasLocks(_msgSender()), "At least one asset is locked"); + super.setApprovalForAll(operator, approved); + } + + function isApprovedForAll(address owner, address operator) public view virtual override(IERC721, ERC721) returns (bool) { + if (hasLocks(owner)) { + return false; + } + return super.isApprovedForAll(owner, operator); + } +} diff --git a/assets/eip-6982/contracts/IERC6982.sol b/assets/eip-6982/contracts/IERC6982.sol new file mode 100644 index 0000000000000..06ac78132b978 --- /dev/null +++ b/assets/eip-6982/contracts/IERC6982.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.9; + +// ERC165 interfaceId 0x6b61a747 +interface IERC6982 { + // This event MUST be emitted upon deployment of the contract, establishing + // the default lock status for any tokens that will be minted in the future. + // If the default lock status changes for any reason, this event + // MUST be re-emitted to update the default status for all tokens. + // Note that emitting a new DefaultLocked event does not affect the lock + // status of any tokens for which a Locked event has previously been emitted. + event DefaultLocked(bool locked); + + // This event MUST be emitted whenever the lock status of a specific token + // changes, effectively overriding the default lock status for this token. + event Locked(uint256 indexed tokenId, bool locked); + + // This function returns the current default lock status for tokens. + // It reflects the value set by the latest DefaultLocked event. + function defaultLocked() external view returns (bool); + + // This function returns the lock status of a specific token. + // If no Locked event has been emitted for a given tokenId, it MUST return + // the value that defaultLocked() returns, which represents the default + // lock status. + // This function MUST revert if the token does not exist. + function locked(uint256 tokenId) external view returns (bool); +} diff --git a/assets/eip-6982/contracts/IERC721Lockable.sol b/assets/eip-6982/contracts/IERC721Lockable.sol new file mode 100644 index 0000000000000..77b2ff89e092f --- /dev/null +++ b/assets/eip-6982/contracts/IERC721Lockable.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +// Author: +// Francesco Sullo + +interface IERC721Lockable { + event LockerSet(address locker); + event LockerRemoved(address locker); + event ForcefullyUnlocked(uint256 tokenId); + + // tells if a token is locked. Removed to extend IERC5192 + // function locked(uint256 tokenID) external view returns (bool); + + // tells the address of the contract which is locking a token + function lockerOf(uint256 tokenID) external view returns (address); + + // tells if a contract is a locker + function isLocker(address _locker) external view returns (bool); + + // set a locker, if the actor that is locking it is a contract, it + // should be approved + // It should emit a LockerSet event + function setLocker(address pool) external; + + // remove a locker + // It should emit a LockerRemoved event + function removeLocker(address pool) external; + + // tells if an NFT has any locks on it + // The function is called internally and externally + function hasLocks(address owner) external view returns (bool); + + // locks an NFT + // It should emit a Locked event + function lock(uint256 tokenID) external; + + // unlocks an NFT + // It should emit a Unlocked event + function unlock(uint256 tokenID) external; + + // unlock an NFT if the locker is removed + // This is an emergency function called by the token owner or a DAO + // It should emit a ForcefullyUnlocked event + function unlockIfRemovedLocker(uint256 tokenID) external; +} diff --git a/assets/eip-6982/contracts/mocks/ERC721LockableMock.sol b/assets/eip-6982/contracts/mocks/ERC721LockableMock.sol new file mode 100644 index 0000000000000..94b62167c20f4 --- /dev/null +++ b/assets/eip-6982/contracts/mocks/ERC721LockableMock.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +// Authors: Francesco Sullo + +import "../ERC721Lockable.sol"; + +contract ERC721LockableMock is ERC721Lockable { + + uint public latestTokenId; + + constructor(string memory name, string memory symbol) ERC721Lockable(name, symbol, false) {} + + function mint (address to, uint256 amount) public { + for (uint256 i = 0; i < amount; i++) { + // inefficient, but this is a mock :-) + _safeMint(to, ++latestTokenId); + } + } +} diff --git a/assets/eip-6982/contracts/mocks/MyLocker.sol b/assets/eip-6982/contracts/mocks/MyLocker.sol new file mode 100644 index 0000000000000..5ceff78ac7359 --- /dev/null +++ b/assets/eip-6982/contracts/mocks/MyLocker.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +// Authors: Francesco Sullo + +import "../IERC721Lockable.sol"; + +contract MyLocker { + function lock(address asset, uint256 id) public { + IERC721Lockable(asset).lock(id); + } + + function unlock(address asset, uint256 id) public { + IERC721Lockable(asset).unlock(id); + } +} diff --git a/assets/eip-6982/hardhat.config.js b/assets/eip-6982/hardhat.config.js new file mode 100644 index 0000000000000..0d430b5335f8c --- /dev/null +++ b/assets/eip-6982/hardhat.config.js @@ -0,0 +1,24 @@ +require("@nomiclabs/hardhat-waffle"); + +// You need to export an object to set up your config +// Go to https://hardhat.org/config/ to learn more + +/** + * @type import('hardhat/config').HardhatUserConfig + */ +module.exports = { + solidity: { + version: "0.8.19", + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + networks: { + hardhat: { + blockGasLimit: 10000000, + } + }, +}; diff --git a/assets/eip-6982/package.json b/assets/eip-6982/package.json new file mode 100644 index 0000000000000..b7fd956dc41b0 --- /dev/null +++ b/assets/eip-6982/package.json @@ -0,0 +1,27 @@ +{ + "name": "erc6982-example", + "version": "0.1.0", + "scripts": { + "test": "npx hardhat test", + "compile": "npx hardhat compile" + }, + "author": { + "name": "Francesco Sullo", + "email": "francesco@sullo.co" + }, + "license": "MIT", + "devDependencies": { + "@nomiclabs/hardhat-ethers": "^2.2.3", + "@nomiclabs/hardhat-waffle": "^2.0.5", + "@openzeppelin/hardhat-upgrades": "^1.25.3", + "chai": "^4.3.7", + "ethereum-waffle": "^3.4.4", + "ethers": "^5.7.2", + "hardhat": "^2.14.0", + "typescript": "^4.9.5" + }, + "dependencies": { + "@openzeppelin/contracts": "^4.8.3", + "@openzeppelin/contracts-upgradeable": "^4.8.3" + } +} diff --git a/assets/eip-6982/test/Lockable.test.js b/assets/eip-6982/test/Lockable.test.js new file mode 100644 index 0000000000000..279f13839b93e --- /dev/null +++ b/assets/eip-6982/test/Lockable.test.js @@ -0,0 +1,42 @@ +const {expect} = require("chai"); +const { deployContractUpgradeable, deployContract} = require("./helpers"); + +describe("ERC721Lockable", function () { + let myToken; + let myLocker; + + let owner, holder, holder2; + + before(async function () { + [owner, holder, holder2] = await ethers.getSigners(); + }); + + beforeEach(async function () { + // myPool = await deployContract("MyPlayer"); + myToken = await deployContract("ERC721LockableMock", "My token", "NFT"); + myLocker = await deployContract("MyLocker") + }); + + it("should verify the flow", async function () { + + expect(await myToken.supportsInterface("0x2e4e0d27")).equal(true); + + await myToken.mint(holder.address, 5); + + await myToken.setLocker(myLocker.address); + expect(await myToken.isLocker(myLocker.address)).equal(true); + + await expect(myLocker.lock(myToken.address, 2)).revertedWith("Locker not approved"); + + await myToken.connect(holder).approve(myLocker.address, 2); + await myLocker.lock(myToken.address, 2); + + expect(await myToken.locked(2)).equal(true); + + await expect(myToken.connect(holder).transferFrom(holder.address, holder2.address, 2)).revertedWith("Token is locked"); + + await expect(myToken.connect(holder).transferFrom(holder.address, holder2.address, 3)).emit(myToken, "Transfer").withArgs(holder.address, holder2.address, 3); + + }); + +}); diff --git a/assets/eip-6982/test/helpers.js b/assets/eip-6982/test/helpers.js new file mode 100644 index 0000000000000..8aab232fdeec1 --- /dev/null +++ b/assets/eip-6982/test/helpers.js @@ -0,0 +1,67 @@ +const {assert} = require("chai"); + +const Helpers = { + initEthers(ethers) { + this.ethers = ethers; + }, + + async assertThrowsMessage(promise, message) { + try { + await promise; + console.log("It did not throw :-("); + assert.isTrue(false); + } catch (e) { + const shouldBeTrue = e.message.indexOf(message) > -1; + if (!shouldBeTrue) { + console.error("Expected:", message); + console.error("Returned:", e.message); + // console.log(e) + } + assert.isTrue(shouldBeTrue); + } + }, + + async deployContractBy(contractName, owner, ...args) { + const Contract = await this.ethers.getContractFactory(contractName); + const contract = await Contract.connect(owner).deploy(...args); + await contract.deployed(); + return contract; + }, + + async deployContract(contractName, ...args) { + const Contract = await this.ethers.getContractFactory(contractName); + const contract = await Contract.deploy(...args); + await contract.deployed(); + return contract; + }, + + async deployContractUpgradeable(contractName, args = []) { + const Contract = await this.ethers.getContractFactory(contractName); + const contract = await upgrades.deployProxy(Contract, args); + await contract.deployed(); + return contract; + }, + + async signPackedData( + hash, + // hardhat account #4, starting from #0 + privateKey = "0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a" + ) { + const signingKey = new this.ethers.utils.SigningKey(privateKey); + const signedDigest = signingKey.signDigest(hash); + return this.ethers.utils.joinSignature(signedDigest); + }, + + async getTimestamp() { + return (await this.ethers.provider.getBlock()).timestamp; + }, + + addr0: "0x0000000000000000000000000000000000000000", + + async increaseBlockTimestampBy(offset) { + await this.ethers.provider.send("evm_increaseTime", [offset]); + await this.ethers.provider.send("evm_mine"); + }, +}; + +module.exports = Helpers; diff --git a/assets/eip-7007/.gitignore b/assets/eip-7007/.gitignore new file mode 100644 index 0000000000000..00dad773492c8 --- /dev/null +++ b/assets/eip-7007/.gitignore @@ -0,0 +1,11 @@ +node_modules +.env +coverage +coverage.json +typechain +typechain-types + +# Hardhat files +cache +artifacts + diff --git a/assets/eip-7007/README.md b/assets/eip-7007/README.md new file mode 100644 index 0000000000000..cc8e3a0f2fb7c --- /dev/null +++ b/assets/eip-7007/README.md @@ -0,0 +1,55 @@ +# ERC-7007 Reference Implementation + +This is a WIP implementation of ERC-7007 based on the discussions in the [EIP-7007 issue thread](https://github.com/ethereum/EIPs/issues/7007). + +## Setup +Run `npm install` in the root directory. + +## Testing +Try running some of the following tasks: + +```shell +npx hardhat help +npx hardhat test +REPORT_GAS=true npx hardhat test +``` + +## Metadata Standard + +```json +{ + "title": "AIGC Metadata", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Identifies the asset to which this NFT represents" + }, + "description": { + "type": "string", + "description": "Describes the asset to which this NFT represents" + }, + "image": { + "type": "string", + "description": "A URI pointing to a resource with mime type image/* representing the asset to which this NFT represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive." + }, + + "prompt": { + "type": "string", + "description": "Identifies the prompt from which this AIGC NFT generated" + }, + "seed": { + "type": "uint256", + "description": "Identifies the seed from which this AIGC NFT generated" + }, + "aigc_type": { + "type": "string", + "description": "image/video/audio..." + }, + "aigc_data": { + "type": "string", + "description": "A URI pointing to a resource with mime type image/* representing the asset to which this AIGC NFT represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive." + } + } +} +``` \ No newline at end of file diff --git a/assets/eip-7007/contracts/ERC7007.sol b/assets/eip-7007/contracts/ERC7007.sol new file mode 100644 index 0000000000000..5610225acc64b --- /dev/null +++ b/assets/eip-7007/contracts/ERC7007.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.18; + +import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; +import "./IERC7007.sol"; +import "./IVerifier.sol"; + +/** + * @dev Implementation of the {IERC7007} interface. + */ +contract ERC7007 is ERC165, IERC7007, ERC721URIStorage { + address public immutable verifier; + + /** + * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. + */ + constructor( + string memory name_, + string memory symbol_, + address verifier_ + ) ERC721(name_, symbol_) { + verifier = verifier_; + } + + /** + * @dev See {IERC7007-mint}. + */ + function mint( + bytes calldata prompt, + bytes calldata aigcData, + string calldata uri, + bytes calldata proof + ) public virtual override returns (uint256 tokenId) { + require(verify(prompt, aigcData, proof), "ERC7007: invalid proof"); + tokenId = uint256(keccak256(prompt)); + _safeMint(msg.sender, tokenId); + string memory tokenUri = string( + abi.encodePacked( + "{", + uri, + ', "prompt": "', + string(prompt), + '", "aigc_data": "', + string(aigcData), + '"}' + ) + ); + _setTokenURI(tokenId, tokenUri); + emit Mint(tokenId, prompt, aigcData, uri, proof); + } + + /** + * @dev See {IERC7007-verify}. + */ + function verify( + bytes calldata prompt, + bytes calldata aigcData, + bytes calldata proof + ) public view virtual override returns (bool success) { + return + IVerifier(verifier).verifyProof( + proof, + abi.encodePacked(prompt, aigcData) + ); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface( + bytes4 interfaceId + ) public view virtual override(ERC165, ERC721, IERC165) returns (bool) { + return + interfaceId == type(IERC721).interfaceId || + interfaceId == type(IERC721Metadata).interfaceId || + super.supportsInterface(interfaceId); + } +} diff --git a/assets/eip-7007/contracts/ERC7007Enumerable.sol b/assets/eip-7007/contracts/ERC7007Enumerable.sol new file mode 100644 index 0000000000000..d8baed3210bb5 --- /dev/null +++ b/assets/eip-7007/contracts/ERC7007Enumerable.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.18; + +import "./ERC7007.sol"; +import "./IERC7007Enumerable.sol"; + +/** + * @dev Implementation of the {IERC7007Enumerable} interface. + */ +abstract contract ERC7007Enumerable is ERC7007, IERC7007Enumerable { + /** + * @dev See {IERC7007Enumerable-tokenId}. + */ + mapping(uint256 => string) public prompt; + + + /** + * @dev See {IERC7007Enumerable-prompt}. + */ + mapping(bytes => uint256) public tokenId; + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface( + bytes4 interfaceId + ) public view virtual override(IERC165, ERC7007) returns (bool) { + return + interfaceId == type(IERC7007Enumerable).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC7007-mint}. + */ + function mint( + bytes calldata prompt_, + bytes calldata aigcData, + string calldata uri, + bytes calldata proof + ) public virtual override(ERC7007, IERC7007) returns (uint256 tokenId_) { + tokenId_ = ERC7007.mint(prompt_, aigcData, uri, proof); + prompt[tokenId_] = string(prompt_); + tokenId[prompt_] = tokenId_; + } +} + +contract MockERC7007Enumerable is ERC7007Enumerable { + constructor( + string memory name_, + string memory symbol_, + address verifier_ + ) ERC7007(name_, symbol_, verifier_) {} +} \ No newline at end of file diff --git a/assets/eip-7007/contracts/IERC7007.sol b/assets/eip-7007/contracts/IERC7007.sol new file mode 100644 index 0000000000000..359b6b626d631 --- /dev/null +++ b/assets/eip-7007/contracts/IERC7007.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.18; + +import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; + +/** + * @dev Required interface of an ERC7007 compliant contract. + * Note: the ERC-165 identifier for this interface is 0x7e52e423. + */ +interface IERC7007 is IERC165, IERC721 { + /** + * @dev Emitted when `tokenId` token is minted. + */ + event Mint( + uint256 indexed tokenId, + bytes indexed prompt, + bytes indexed aigcData, + string uri, + bytes proof + ); + + /** + * @dev Mint token at `tokenId` given `prompt`, `aigcData`, `uri` and `proof`. + * + * Requirements: + * - `tokenId` must not exist.' + * - verify(`prompt`, `aigcData`, `proof`) must return true. + * + * Optional: + * - `proof` should not include `aigcData` to save gas. + */ + function mint( + bytes calldata prompt, + bytes calldata aigcData, + string calldata uri, + bytes calldata proof + ) external returns (uint256 tokenId); + + /** + * @dev Verify the `prompt`, `aigcData` and `proof`. + */ + function verify( + bytes calldata prompt, + bytes calldata aigcData, + bytes calldata proof + ) external view returns (bool success); +} diff --git a/assets/eip-7007/contracts/IERC7007Enumerable.sol b/assets/eip-7007/contracts/IERC7007Enumerable.sol new file mode 100644 index 0000000000000..6055402b80ef5 --- /dev/null +++ b/assets/eip-7007/contracts/IERC7007Enumerable.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.18; + +import "./IERC7007.sol"; + +/** + * @title ERC7007 Token Standard, optional enumeration extension + * Note: the ERC-165 identifier for this interface is 0xfa1a557a. + */ +interface IERC7007Enumerable is IERC7007 { + /** + * @dev Returns the token ID given `prompt`. + */ + function tokenId(bytes calldata prompt) external view returns (uint256); + + /** + * @dev Returns the prompt given `tokenId`. + */ + function prompt(uint256 tokenId) external view returns (string calldata); +} diff --git a/assets/eip-7007/contracts/IVerifier.sol b/assets/eip-7007/contracts/IVerifier.sol new file mode 100644 index 0000000000000..3d918c70ba0c3 --- /dev/null +++ b/assets/eip-7007/contracts/IVerifier.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.18; + +interface IVerifier { + function verifyProof( + bytes calldata proof, + bytes calldata public_inputs + ) external view returns (bool valid); +} diff --git a/assets/eip-7007/contracts/MockVerifier.sol b/assets/eip-7007/contracts/MockVerifier.sol new file mode 100644 index 0000000000000..4c1a771272990 --- /dev/null +++ b/assets/eip-7007/contracts/MockVerifier.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.18; + +import "./IVerifier.sol"; + +contract MockVerifier is IVerifier { + function verifyProof( + bytes calldata proof, + bytes calldata public_inputs + ) external pure override returns (bool valid) { + return + public_inputs.length > 0 && keccak256(proof) == keccak256("valid"); + } +} diff --git a/assets/eip-7007/hardhat.config.js b/assets/eip-7007/hardhat.config.js new file mode 100644 index 0000000000000..d5dd5f4e8ddd4 --- /dev/null +++ b/assets/eip-7007/hardhat.config.js @@ -0,0 +1,6 @@ +require("@nomicfoundation/hardhat-toolbox"); + +/** @type import('hardhat/config').HardhatUserConfig */ +module.exports = { + solidity: "0.8.18", +}; diff --git a/assets/eip-7007/package-lock.json b/assets/eip-7007/package-lock.json new file mode 100644 index 0000000000000..db6776ab74230 --- /dev/null +++ b/assets/eip-7007/package-lock.json @@ -0,0 +1,16534 @@ +{ + "name": "erc7007", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "erc7007", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@nomicfoundation/hardhat-toolbox": "^2.0.2", + "@openzeppelin/contracts": "^4.8.3", + "hardhat": "^2.14.0" + } + }, + "node_modules/@chainsafe/as-sha256": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@chainsafe/as-sha256/-/as-sha256-0.3.1.tgz", + "integrity": "sha512-hldFFYuf49ed7DAakWVXSJODuq3pzJEguD8tQ7h+sGkM18vja+OFoJI9krnGmgzyuZC2ETX0NOIcCTy31v2Mtg==", + "dev": true + }, + "node_modules/@chainsafe/persistent-merkle-tree": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.4.2.tgz", + "integrity": "sha512-lLO3ihKPngXLTus/L7WHKaw9PnNJWizlOF1H9NNzHP6Xvh82vzg9F2bzkXhYIFshMZ2gTCEz8tq6STe7r5NDfQ==", + "dev": true, + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "node_modules/@chainsafe/ssz": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.9.4.tgz", + "integrity": "sha512-77Qtg2N1ayqs4Bg/wvnWfg5Bta7iy7IRh8XqXh7oNMeP2HBbBwx8m6yTpA8p0EHItWPEBkgZd5S5/LSlp3GXuQ==", + "dev": true, + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.4.2", + "case": "^1.6.3" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0" + } + }, + "node_modules/@ethersproject/basex": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", + "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0" + } + }, + "node_modules/@ethersproject/contracts": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", + "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abi": "^5.7.0", + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/hdnode": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", + "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/json-wallets": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", + "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ] + }, + "node_modules/@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/pbkdf2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", + "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/sha2": "^5.7.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, + "node_modules/@ethersproject/providers/node_modules/ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@ethersproject/random": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", + "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/sha2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", + "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/solidity": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", + "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "node_modules/@ethersproject/units": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", + "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/wallet": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/json-wallets": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/wordlists": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", + "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true, + "peer": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@metamask/eth-sig-util": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz", + "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", + "dev": true, + "dependencies": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^6.2.1", + "ethjs-util": "^0.1.6", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@morgan-stanley/ts-mocking-bird": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@morgan-stanley/ts-mocking-bird/-/ts-mocking-bird-0.6.4.tgz", + "integrity": "sha512-57VJIflP8eR2xXa9cD1LUawh+Gh+BVQfVu0n6GALyg/AqV/Nz25kDRvws3i9kIe1PTrbsZZOYpsYp6bXPd6nVA==", + "dev": true, + "peer": true, + "dependencies": { + "lodash": "^4.17.16", + "uuid": "^7.0.3" + }, + "peerDependencies": { + "jasmine": "2.x || 3.x || 4.x", + "jest": "26.x || 27.x || 28.x", + "typescript": ">=4.2" + }, + "peerDependenciesMeta": { + "jasmine": { + "optional": true + }, + "jest": { + "optional": true + } + } + }, + "node_modules/@morgan-stanley/ts-mocking-bird/node_modules/uuid": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", + "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==", + "dev": true, + "peer": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@noble/hashes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "peer": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "peer": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nomicfoundation/ethereumjs-block": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.1.tgz", + "integrity": "sha512-u1Yioemi6Ckj3xspygu/SfFvm8vZEO8/Yx5a1QLzi6nVU0jz3Pg2OmHKJ5w+D9Ogk1vhwRiqEBAqcb0GVhCyHw==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-trie": "6.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "ethereum-cryptography": "0.1.3", + "ethers": "^5.7.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-block/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@nomicfoundation/ethereumjs-blockchain": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.1.tgz", + "integrity": "sha512-NhzndlGg829XXbqJEYrF1VeZhAwSPgsK/OB7TVrdzft3y918hW5KNd7gIZ85sn6peDZOdjBsAXIpXZ38oBYE5A==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-block": "5.0.1", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-ethash": "3.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-trie": "6.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "abstract-level": "^1.0.3", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "level": "^8.0.0", + "lru-cache": "^5.1.1", + "memory-level": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-blockchain/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@nomicfoundation/ethereumjs-common": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.1.tgz", + "integrity": "sha512-OBErlkfp54GpeiE06brBW/TTbtbuBJV5YI5Nz/aB2evTDo+KawyEzPjBlSr84z/8MFfj8wS2wxzQX1o32cev5g==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-util": "9.0.1", + "crc-32": "^1.2.0" + } + }, + "node_modules/@nomicfoundation/ethereumjs-ethash": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.1.tgz", + "integrity": "sha512-KDjGIB5igzWOp8Ik5I6QiRH5DH+XgILlplsHR7TEuWANZA759G6krQ6o8bvj+tRUz08YygMQu/sGd9mJ1DYT8w==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-block": "5.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "abstract-level": "^1.0.3", + "bigint-crypto-utils": "^3.0.23", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-ethash/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@nomicfoundation/ethereumjs-evm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.1.tgz", + "integrity": "sha512-oL8vJcnk0Bx/onl+TgQOQ1t/534GKFaEG17fZmwtPFeH8S5soiBYPCLUrvANOl4sCp9elYxIMzIiTtMtNNN8EQ==", + "dev": true, + "dependencies": { + "@ethersproject/providers": "^5.7.1", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "mcl-wasm": "^0.7.1", + "rustbn.js": "~0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-evm/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", + "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==", + "dev": true, + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-statemanager": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.1.tgz", + "integrity": "sha512-B5ApMOnlruVOR7gisBaYwFX+L/AP7i/2oAahatssjPIBVDF6wTX1K7Qpa39E/nzsH8iYuL3krkYeUFIdO3EMUQ==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "ethers": "^5.7.1", + "js-sdsl": "^4.1.4" + } + }, + "node_modules/@nomicfoundation/ethereumjs-statemanager/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@nomicfoundation/ethereumjs-trie": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.1.tgz", + "integrity": "sha512-A64It/IMpDVODzCgxDgAAla8jNjNtsoQZIzZUfIV5AY6Coi4nvn7+VReBn5itlxMiL2yaTlQr9TRWp3CSI6VoA==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "@types/readable-stream": "^2.3.13", + "ethereum-cryptography": "0.1.3", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-trie/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@nomicfoundation/ethereumjs-tx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.1.tgz", + "integrity": "sha512-0HwxUF2u2hrsIM1fsasjXvlbDOq1ZHFV2dd1yGq8CA+MEYhaxZr8OTScpVkkxqMwBcc5y83FyPl0J9MZn3kY0w==", + "dev": true, + "dependencies": { + "@chainsafe/ssz": "^0.9.2", + "@ethersproject/providers": "^5.7.2", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-tx/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@nomicfoundation/ethereumjs-util": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", + "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", + "dev": true, + "dependencies": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-util/node_modules/@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", + "dev": true, + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "node_modules/@nomicfoundation/ethereumjs-util/node_modules/@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "dev": true, + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + }, + "node_modules/@nomicfoundation/ethereumjs-util/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@nomicfoundation/ethereumjs-vm": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.1.tgz", + "integrity": "sha512-rArhyn0jPsS/D+ApFsz3yVJMQ29+pVzNZ0VJgkzAZ+7FqXSRtThl1C1prhmlVr3YNUlfpZ69Ak+RUT4g7VoOuQ==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-block": "5.0.1", + "@nomicfoundation/ethereumjs-blockchain": "7.0.1", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-evm": "2.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-statemanager": "2.0.1", + "@nomicfoundation/ethereumjs-trie": "6.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "mcl-wasm": "^0.7.1", + "rustbn.js": "~0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-vm/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@nomicfoundation/hardhat-chai-matchers": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-1.0.6.tgz", + "integrity": "sha512-f5ZMNmabZeZegEfuxn/0kW+mm7+yV7VNDxLpMOMGXWFJ2l/Ct3QShujzDRF9cOkK9Ui/hbDeOWGZqyQALDXVCQ==", + "dev": true, + "peer": true, + "dependencies": { + "@ethersproject/abi": "^5.1.2", + "@types/chai-as-promised": "^7.1.3", + "chai-as-promised": "^7.1.1", + "deep-eql": "^4.0.1", + "ordinal": "^1.0.3" + }, + "peerDependencies": { + "@nomiclabs/hardhat-ethers": "^2.0.0", + "chai": "^4.2.0", + "ethers": "^5.0.0", + "hardhat": "^2.9.4" + } + }, + "node_modules/@nomicfoundation/hardhat-network-helpers": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.8.tgz", + "integrity": "sha512-MNqQbzUJZnCMIYvlniC3U+kcavz/PhhQSsY90tbEtUyMj/IQqsLwIRZa4ctjABh3Bz0KCh9OXUZ7Yk/d9hr45Q==", + "dev": true, + "peer": true, + "dependencies": { + "ethereumjs-util": "^7.1.4" + }, + "peerDependencies": { + "hardhat": "^2.9.5" + } + }, + "node_modules/@nomicfoundation/hardhat-network-helpers/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "peer": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@nomicfoundation/hardhat-network-helpers/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "peer": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@nomicfoundation/hardhat-toolbox": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-toolbox/-/hardhat-toolbox-2.0.2.tgz", + "integrity": "sha512-vnN1AzxbvpSx9pfdRHbUzTRIXpMLPXnUlkW855VaDk6N1pwRaQ2gNzEmFAABk4lWf11E00PKwFd/q27HuwYrYg==", + "dev": true, + "peerDependencies": { + "@ethersproject/abi": "^5.4.7", + "@ethersproject/providers": "^5.4.7", + "@nomicfoundation/hardhat-chai-matchers": "^1.0.0", + "@nomicfoundation/hardhat-network-helpers": "^1.0.0", + "@nomiclabs/hardhat-ethers": "^2.0.0", + "@nomiclabs/hardhat-etherscan": "^3.0.0", + "@typechain/ethers-v5": "^10.1.0", + "@typechain/hardhat": "^6.1.2", + "@types/chai": "^4.2.0", + "@types/mocha": ">=9.1.0", + "@types/node": ">=12.0.0", + "chai": "^4.2.0", + "ethers": "^5.4.7", + "hardhat": "^2.11.0", + "hardhat-gas-reporter": "^1.0.8", + "solidity-coverage": "^0.8.1", + "ts-node": ">=8.0.0", + "typechain": "^8.1.0", + "typescript": ">=4.5.0" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.1.tgz", + "integrity": "sha512-1LMtXj1puAxyFusBgUIy5pZk3073cNXYnXUpuNKFghHbIit/xZgbk0AokpUADbNm3gyD6bFWl3LRFh3dhVdREg==", + "dev": true, + "engines": { + "node": ">= 12" + }, + "optionalDependencies": { + "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.1", + "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.1", + "@nomicfoundation/solidity-analyzer-freebsd-x64": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-arm64-msvc": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-ia32-msvc": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.1" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-arm64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.1.tgz", + "integrity": "sha512-KcTodaQw8ivDZyF+D76FokN/HdpgGpfjc/gFCImdLUyqB6eSWVaZPazMbeAjmfhx3R0zm/NYVzxwAokFKgrc0w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.1.tgz", + "integrity": "sha512-XhQG4BaJE6cIbjAVtzGOGbK3sn1BO9W29uhk9J8y8fZF1DYz0Doj8QDMfpMu+A6TjPDs61lbsmeYodIDnfveSA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-freebsd-x64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-freebsd-x64/-/solidity-analyzer-freebsd-x64-0.1.1.tgz", + "integrity": "sha512-GHF1VKRdHW3G8CndkwdaeLkVBi5A9u2jwtlS7SLhBc8b5U/GcoL39Q+1CSO3hYqePNP+eV5YI7Zgm0ea6kMHoA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.1.tgz", + "integrity": "sha512-g4Cv2fO37ZsUENQ2vwPnZc2zRenHyAxHcyBjKcjaSmmkKrFr64yvzeNO8S3GBFCo90rfochLs99wFVGT/0owpg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.1.tgz", + "integrity": "sha512-WJ3CE5Oek25OGE3WwzK7oaopY8xMw9Lhb0mlYuJl/maZVo+WtP36XoQTb7bW/i8aAdHW5Z+BqrHMux23pvxG3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.1.tgz", + "integrity": "sha512-5WN7leSr5fkUBBjE4f3wKENUy9HQStu7HmWqbtknfXkkil+eNWiBV275IOlpXku7v3uLsXTOKpnnGHJYI2qsdA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.1.tgz", + "integrity": "sha512-KdYMkJOq0SYPQMmErv/63CwGwMm5XHenEna9X9aB8mQmhDBrYrlAOSsIPgFCUSL0hjxE3xHP65/EPXR/InD2+w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-arm64-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.1.tgz", + "integrity": "sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-ia32-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.1.tgz", + "integrity": "sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.1.tgz", + "integrity": "sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomiclabs/hardhat-ethers": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.2.3.tgz", + "integrity": "sha512-YhzPdzb612X591FOe68q+qXVXGG2ANZRvDo0RRUtimev85rCrAlv/TLMEZw5c+kq9AbzocLTVX/h2jVIFPL9Xg==", + "dev": true, + "peer": true, + "peerDependencies": { + "ethers": "^5.0.0", + "hardhat": "^2.0.0" + } + }, + "node_modules/@nomiclabs/hardhat-etherscan": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-3.1.7.tgz", + "integrity": "sha512-tZ3TvSgpvsQ6B6OGmo1/Au6u8BrAkvs1mIC/eURA3xgIfznUZBhmpne8hv7BXUzw9xNL3fXdpOYgOQlVMTcoHQ==", + "dev": true, + "peer": true, + "dependencies": { + "@ethersproject/abi": "^5.1.2", + "@ethersproject/address": "^5.0.2", + "cbor": "^8.1.0", + "chalk": "^2.4.2", + "debug": "^4.1.1", + "fs-extra": "^7.0.1", + "lodash": "^4.17.11", + "semver": "^6.3.0", + "table": "^6.8.0", + "undici": "^5.14.0" + }, + "peerDependencies": { + "hardhat": "^2.0.4" + } + }, + "node_modules/@openzeppelin/contracts": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.8.3.tgz", + "integrity": "sha512-bQHV8R9Me8IaJoJ2vPG4rXcL7seB7YVuskr4f+f5RyOStSZetwzkWtoqDMl5erkBJy0lDRUnIR2WIkPiC0GJlg==", + "dev": true + }, + "node_modules/@scure/base": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", + "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@scure/bip32": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/@scure/bip39": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/@sentry/core": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", + "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/hub": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", + "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", + "dev": true, + "dependencies": { + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/minimal": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", + "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/node": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.30.0.tgz", + "integrity": "sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==", + "dev": true, + "dependencies": { + "@sentry/core": "5.30.0", + "@sentry/hub": "5.30.0", + "@sentry/tracing": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/tracing": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.30.0.tgz", + "integrity": "sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", + "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", + "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", + "dev": true, + "dependencies": { + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@solidity-parser/parser": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.5.tgz", + "integrity": "sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==", + "dev": true, + "peer": true, + "dependencies": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true, + "peer": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "peer": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "peer": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true, + "peer": true + }, + "node_modules/@typechain/ethers-v5": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@typechain/ethers-v5/-/ethers-v5-10.2.0.tgz", + "integrity": "sha512-ikaq0N/w9fABM+G01OFmU3U3dNnyRwEahkdvi9mqy1a3XwKiPZaF/lu54OcNaEWnpvEYyhhS0N7buCtLQqC92w==", + "dev": true, + "peer": true, + "dependencies": { + "lodash": "^4.17.15", + "ts-essentials": "^7.0.1" + }, + "peerDependencies": { + "@ethersproject/abi": "^5.0.0", + "@ethersproject/bytes": "^5.0.0", + "@ethersproject/providers": "^5.0.0", + "ethers": "^5.1.3", + "typechain": "^8.1.1", + "typescript": ">=4.3.0" + } + }, + "node_modules/@typechain/hardhat": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/@typechain/hardhat/-/hardhat-6.1.5.tgz", + "integrity": "sha512-lg7LW4qDZpxFMknp3Xool61Fg6Lays8F8TXdFGBG+MxyYcYU5795P1U2XdStuzGq9S2Dzdgh+1jGww9wvZ6r4Q==", + "dev": true, + "peer": true, + "dependencies": { + "fs-extra": "^9.1.0" + }, + "peerDependencies": { + "@ethersproject/abi": "^5.4.7", + "@ethersproject/providers": "^5.4.7", + "@typechain/ethers-v5": "^10.2.0", + "ethers": "^5.4.7", + "hardhat": "^2.9.9", + "typechain": "^8.1.1" + } + }, + "node_modules/@typechain/hardhat/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "peer": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typechain/hardhat/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "peer": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@typechain/hardhat/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@types/bn.js": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz", + "integrity": "sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/chai": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", + "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==", + "dev": true, + "peer": true + }, + "node_modules/@types/chai-as-promised": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.5.tgz", + "integrity": "sha512-jStwss93SITGBwt/niYrkf2C+/1KTeZCZl1LaeezTlqppAKeoQC7jxyqYuP72sxBGKCIbw7oHgbYssIRzT5FCQ==", + "dev": true, + "peer": true, + "dependencies": { + "@types/chai": "*" + } + }, + "node_modules/@types/concat-stream": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", + "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/form-data": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", + "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "peer": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", + "dev": true + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true, + "peer": true + }, + "node_modules/@types/mocha": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", + "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", + "dev": true, + "peer": true + }, + "node_modules/@types/node": { + "version": "18.16.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz", + "integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q==", + "dev": true + }, + "node_modules/@types/pbkdf2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", + "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/prettier": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", + "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", + "dev": true, + "peer": true + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true, + "peer": true + }, + "node_modules/@types/readable-stream": { + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.15.tgz", + "integrity": "sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "safe-buffer": "~5.1.1" + } + }, + "node_modules/@types/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==", + "dev": true, + "peer": true + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/abstract-level": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-1.0.3.tgz", + "integrity": "sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "catering": "^2.1.0", + "is-buffer": "^2.0.5", + "level-supports": "^4.0.0", + "level-transcoder": "^1.0.1", + "module-error": "^1.0.1", + "queue-microtask": "^1.2.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true, + "engines": { + "node": ">=0.3.0" + } + }, + "node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.4.2" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/antlr4ts": { + "version": "0.5.0-alpha.4", + "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", + "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", + "dev": true, + "peer": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "peer": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array.prototype.reduce": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz", + "integrity": "sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "peer": true + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "peer": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", + "dev": true, + "peer": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "peer": true + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", + "dev": true, + "peer": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "peer": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bcrypt-pbkdf/node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true, + "peer": true + }, + "node_modules/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", + "dev": true + }, + "node_modules/bigint-crypto-utils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/bigint-crypto-utils/-/bigint-crypto-utils-3.2.2.tgz", + "integrity": "sha512-U1RbE3aX9ayCUVcIPHuPDPKcK3SFOXf93J1UK/iHlJuQB7bhagPIX06/CLpLEsDThJ7KA4Dhrnzynl+d2weTiw==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", + "dev": true + }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true + }, + "node_modules/browser-level": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browser-level/-/browser-level-1.0.1.tgz", + "integrity": "sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ==", + "dev": true, + "dependencies": { + "abstract-level": "^1.0.2", + "catering": "^2.1.1", + "module-error": "^1.0.2", + "run-parallel-limit": "^1.1.0" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "dev": true, + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dev": true, + "dependencies": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/case": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/case/-/case-1.6.3.tgz", + "integrity": "sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true, + "peer": true + }, + "node_modules/catering": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", + "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cbor": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", + "integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==", + "dev": true, + "peer": true, + "dependencies": { + "nofilter": "^3.1.0" + }, + "engines": { + "node": ">=12.19" + } + }, + "node_modules/chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "peer": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chai-as-promised": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", + "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", + "dev": true, + "peer": true, + "dependencies": { + "check-error": "^1.0.2" + }, + "peerDependencies": { + "chai": ">= 2.1.2 < 5" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "dev": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/classic-level": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/classic-level/-/classic-level-1.3.0.tgz", + "integrity": "sha512-iwFAJQYtqRTRM0F6L8h4JCt00ZSGdOyqh7yVrhhjrOpFhmBjNlRUey64MCiyo6UmQHMJ+No3c81nujPv+n9yrg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "abstract-level": "^1.0.2", + "catering": "^2.1.0", + "module-error": "^1.0.1", + "napi-macros": "^2.2.2", + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-table3": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", + "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "dev": true, + "peer": true, + "dependencies": { + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "colors": "^1.1.2" + } + }, + "node_modules/cli-table3/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-table3/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-table3/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "peer": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-table3/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "peer": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "dev": true + }, + "node_modules/command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "dev": true, + "peer": true, + "dependencies": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/command-line-usage": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", + "integrity": "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==", + "dev": true, + "peer": true, + "dependencies": { + "array-back": "^4.0.2", + "chalk": "^2.4.2", + "table-layout": "^1.0.2", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/command-line-usage/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/command-line-usage/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "peer": true, + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "peer": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "peer": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true, + "peer": true + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "peer": true + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "dev": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "peer": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/death": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/death/-/death-1.1.0.tgz", + "integrity": "sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==", + "dev": true, + "peer": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "peer": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "peer": true + }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, + "peer": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/detect-port": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", + "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", + "dev": true, + "peer": true, + "dependencies": { + "address": "^1.0.1", + "debug": "4" + }, + "bin": { + "detect": "bin/detect-port.js", + "detect-port": "bin/detect-port.js" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/difflib": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz", + "integrity": "sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==", + "dev": true, + "peer": true, + "dependencies": { + "heap": ">= 0.2.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "peer": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "peer": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/es-abstract": { + "version": "1.21.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", + "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", + "dev": true, + "peer": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.0", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-abstract/node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", + "dev": true, + "peer": true + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "peer": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "peer": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==", + "dev": true, + "peer": true, + "dependencies": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=0.12.0" + }, + "optionalDependencies": { + "source-map": "~0.2.0" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", + "dev": true, + "peer": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eth-gas-reporter": { + "version": "0.2.25", + "resolved": "https://registry.npmjs.org/eth-gas-reporter/-/eth-gas-reporter-0.2.25.tgz", + "integrity": "sha512-1fRgyE4xUB8SoqLgN3eDfpDfwEfRxh2Sz1b7wzFbyQA+9TekMmvSjjoRu9SKcSVyK+vLkLIsVbJDsTWjw195OQ==", + "dev": true, + "peer": true, + "dependencies": { + "@ethersproject/abi": "^5.0.0-beta.146", + "@solidity-parser/parser": "^0.14.0", + "cli-table3": "^0.5.0", + "colors": "1.4.0", + "ethereum-cryptography": "^1.0.3", + "ethers": "^4.0.40", + "fs-readdir-recursive": "^1.1.0", + "lodash": "^4.17.14", + "markdown-table": "^1.1.3", + "mocha": "^7.1.1", + "req-cwd": "^2.0.0", + "request": "^2.88.0", + "request-promise-native": "^1.0.5", + "sha1": "^1.1.1", + "sync-request": "^6.0.0" + }, + "peerDependencies": { + "@codechecks/client": "^0.1.0" + }, + "peerDependenciesMeta": { + "@codechecks/client": { + "optional": true + } + } + }, + "node_modules/eth-gas-reporter/node_modules/ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "peer": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/eth-gas-reporter/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true, + "peer": true + }, + "node_modules/eth-gas-reporter/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/node_modules/chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "peer": true, + "dependencies": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.1.1" + } + }, + "node_modules/eth-gas-reporter/node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "peer": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "peer": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eth-gas-reporter/node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/eth-gas-reporter/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true, + "peer": true + }, + "node_modules/eth-gas-reporter/node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "peer": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eth-gas-reporter/node_modules/ethers": { + "version": "4.0.49", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.49.tgz", + "integrity": "sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg==", + "dev": true, + "peer": true, + "dependencies": { + "aes-js": "3.0.0", + "bn.js": "^4.11.9", + "elliptic": "6.5.4", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.4", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "peer": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/node_modules/flat": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", + "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", + "dev": true, + "peer": true, + "dependencies": { + "is-buffer": "~2.0.3" + }, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/eth-gas-reporter/node_modules/fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "deprecated": "\"Please update to latest v2.3 or v2.2\"", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "peer": true, + "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" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eth-gas-reporter/node_modules/hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eth-gas-reporter/node_modules/js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true, + "peer": true + }, + "node_modules/eth-gas-reporter/node_modules/js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "peer": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eth-gas-reporter/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "peer": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/node_modules/log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "peer": true, + "dependencies": { + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eth-gas-reporter/node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eth-gas-reporter/node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "peer": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/eth-gas-reporter/node_modules/mocha": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz", + "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.5", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/eth-gas-reporter/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true, + "peer": true + }, + "node_modules/eth-gas-reporter/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "peer": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eth-gas-reporter/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "peer": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/node_modules/readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "peer": true, + "dependencies": { + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/eth-gas-reporter/node_modules/scrypt-js": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", + "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==", + "dev": true, + "peer": true + }, + "node_modules/eth-gas-reporter/node_modules/setimmediate": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", + "integrity": "sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==", + "dev": true, + "peer": true + }, + "node_modules/eth-gas-reporter/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "peer": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/node_modules/uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "peer": true + }, + "node_modules/eth-gas-reporter/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true, + "peer": true + }, + "node_modules/eth-gas-reporter/node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "peer": true, + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "node_modules/eth-gas-reporter/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "peer": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "peer": true, + "dependencies": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ethereum-bloom-filters": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz", + "integrity": "sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==", + "dev": true, + "peer": true, + "dependencies": { + "js-sha3": "^0.8.0" + } + }, + "node_modules/ethereum-cryptography": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", + "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" + } + }, + "node_modules/ethereumjs-abi": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", + "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + } + }, + "node_modules/ethereumjs-abi/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "dependencies": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + }, + "node_modules/ethereumjs-util/node_modules/@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/ethereumjs-util/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/ethereumjs-util/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/ethers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" + } + }, + "node_modules/ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==", + "dev": true, + "peer": true, + "dependencies": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/ethjs-unit/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true, + "peer": true + }, + "node_modules/ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "dev": true, + "dependencies": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true, + "peer": true + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "peer": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "peer": true + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "peer": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "peer": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "peer": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "peer": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "dev": true, + "peer": true, + "dependencies": { + "array-back": "^3.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "peer": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "peer": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/fp-ts": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", + "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==", + "dev": true + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true, + "peer": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "peer": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/ghost-testrpc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/ghost-testrpc/-/ghost-testrpc-0.0.2.tgz", + "integrity": "sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==", + "dev": true, + "peer": true, + "dependencies": { + "chalk": "^2.4.2", + "node-emoji": "^1.10.0" + }, + "bin": { + "testrpc-sc": "index.js" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "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" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "peer": true, + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "peer": true, + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "peer": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", + "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", + "dev": true, + "peer": true, + "dependencies": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "peer": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4.x" + } + }, + "node_modules/handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dev": true, + "peer": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dev": true, + "peer": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/hardhat": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.14.0.tgz", + "integrity": "sha512-73jsInY4zZahMSVFurSK+5TNCJTXMv+vemvGia0Ac34Mm19fYp6vEPVGF3sucbumszsYxiTT2TbS8Ii2dsDSoQ==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.1.2", + "@metamask/eth-sig-util": "^4.0.0", + "@nomicfoundation/ethereumjs-block": "5.0.1", + "@nomicfoundation/ethereumjs-blockchain": "7.0.1", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-evm": "2.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-statemanager": "2.0.1", + "@nomicfoundation/ethereumjs-trie": "6.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "@nomicfoundation/ethereumjs-vm": "7.0.1", + "@nomicfoundation/solidity-analyzer": "^0.1.0", + "@sentry/node": "^5.18.1", + "@types/bn.js": "^5.1.0", + "@types/lru-cache": "^5.1.0", + "abort-controller": "^3.0.0", + "adm-zip": "^0.4.16", + "aggregate-error": "^3.0.0", + "ansi-escapes": "^4.3.0", + "chalk": "^2.4.2", + "chokidar": "^3.4.0", + "ci-info": "^2.0.0", + "debug": "^4.1.1", + "enquirer": "^2.3.0", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^1.0.3", + "ethereumjs-abi": "^0.6.8", + "find-up": "^2.1.0", + "fp-ts": "1.19.3", + "fs-extra": "^7.0.1", + "glob": "7.2.0", + "immutable": "^4.0.0-rc.12", + "io-ts": "1.10.4", + "keccak": "^3.0.2", + "lodash": "^4.17.11", + "mnemonist": "^0.38.0", + "mocha": "^10.0.0", + "p-map": "^4.0.0", + "qs": "^6.7.0", + "raw-body": "^2.4.1", + "resolve": "1.17.0", + "semver": "^6.3.0", + "solc": "0.7.3", + "source-map-support": "^0.5.13", + "stacktrace-parser": "^0.1.10", + "tsort": "0.0.1", + "undici": "^5.14.0", + "uuid": "^8.3.2", + "ws": "^7.4.6" + }, + "bin": { + "hardhat": "internal/cli/bootstrap.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "ts-node": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/hardhat-gas-reporter": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.9.tgz", + "integrity": "sha512-INN26G3EW43adGKBNzYWOlI3+rlLnasXTwW79YNnUhXPDa+yHESgt639dJEs37gCjhkbNKcRRJnomXEuMFBXJg==", + "dev": true, + "peer": true, + "dependencies": { + "array-uniq": "1.0.3", + "eth-gas-reporter": "^0.2.25", + "sha1": "^1.1.1" + }, + "peerDependencies": { + "hardhat": "^2.0.2" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "peer": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "peer": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash-base/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", + "dev": true, + "peer": true + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/http-basic": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", + "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", + "dev": true, + "peer": true, + "dependencies": { + "caseless": "^0.12.0", + "concat-stream": "^1.6.2", + "http-response-object": "^3.0.1", + "parse-cache-control": "^1.0.1" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-response-object": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", + "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "^10.0.3" + } + }, + "node_modules/http-response-object/node_modules/@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "dev": true, + "peer": true + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dev": true, + "peer": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz", + "integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==", + "dev": true + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "peer": true + }, + "node_modules/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "peer": true, + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/io-ts": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", + "integrity": "sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==", + "dev": true, + "dependencies": { + "fp-ts": "^1.0.0" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "peer": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "peer": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", + "dev": true, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "peer": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "peer": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "peer": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "peer": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true, + "peer": true + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "peer": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "peer": true + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true, + "peer": true + }, + "node_modules/js-sdsl": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", + "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true, + "peer": true + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true, + "peer": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "peer": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "peer": true + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonschema": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", + "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", + "dev": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "peer": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/keccak": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.3.tgz", + "integrity": "sha512-JZrLIAJWuZxKbCilMpNz5Vj7Vtb4scDG3dMXLOsbzBmQGyjwE61BbW7bJkfKKCShXiQZt3T6sBgALRtmd+nZaQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/level": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/level/-/level-8.0.0.tgz", + "integrity": "sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ==", + "dev": true, + "dependencies": { + "browser-level": "^1.0.1", + "classic-level": "^1.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/level" + } + }, + "node_modules/level-supports": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-4.0.1.tgz", + "integrity": "sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/level-transcoder": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/level-transcoder/-/level-transcoder-1.0.1.tgz", + "integrity": "sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "module-error": "^1.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "peer": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true, + "peer": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true, + "peer": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/loupe": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "peer": true, + "dependencies": { + "get-func-name": "^2.0.0" + } + }, + "node_modules/lru_map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "peer": true + }, + "node_modules/markdown-table": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", + "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", + "dev": true, + "peer": true + }, + "node_modules/mcl-wasm": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz", + "integrity": "sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ==", + "dev": true, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/memory-level": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/memory-level/-/memory-level-1.0.0.tgz", + "integrity": "sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og==", + "dev": true, + "dependencies": { + "abstract-level": "^1.0.0", + "functional-red-black-tree": "^1.0.1", + "module-error": "^1.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "peer": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "peer": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "peer": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mnemonist": { + "version": "0.38.5", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", + "integrity": "sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==", + "dev": true, + "dependencies": { + "obliterator": "^2.0.0" + } + }, + "node_modules/mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/module-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/module-error/-/module-error-1.0.2.tgz", + "integrity": "sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-macros": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.2.2.tgz", + "integrity": "sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g==", + "dev": true + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "peer": true + }, + "node_modules/node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "dev": true + }, + "node_modules/node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dev": true, + "peer": true, + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, + "peer": true, + "dependencies": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + } + }, + "node_modules/node-environment-flags/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/node-gyp-build": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", + "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", + "dev": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/nofilter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", + "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12.19" + } + }, + "node_modules/nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", + "dev": true, + "peer": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/number-to-bn": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", + "integrity": "sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==", + "dev": true, + "peer": true, + "dependencies": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/number-to-bn/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true, + "peer": true + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "peer": true, + "dependencies": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.6.tgz", + "integrity": "sha512-lq+61g26E/BgHv0ZTFgRvi7NMEPuAxLkFU7rukXjc/AlwH4Am5xXVnIXy3un1bg/JPbXHrixRkK1itUzzPiIjQ==", + "dev": true, + "peer": true, + "dependencies": { + "array.prototype.reduce": "^1.0.5", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.21.2", + "safe-array-concat": "^1.0.0" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obliterator": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", + "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==", + "dev": true + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "peer": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ordinal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ordinal/-/ordinal-1.0.3.tgz", + "integrity": "sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ==", + "dev": true, + "peer": true + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==", + "dev": true, + "peer": true + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true, + "peer": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "peer": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "peer": true + }, + "node_modules/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "dev": true, + "peer": true, + "dependencies": { + "asap": "~2.0.6" + } + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true, + "peer": true + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.1.tgz", + "integrity": "sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "peer": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dev": true, + "peer": true, + "dependencies": { + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/req-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz", + "integrity": "sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ==", + "dev": true, + "peer": true, + "dependencies": { + "req-from": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/req-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-from/-/req-from-2.0.0.tgz", + "integrity": "sha512-LzTfEVDVQHBRfjOUMgNBA+V6DWsSnoeKzf42J7l0xa/B4jyPOuuF5MlNSmomLNGemWTnV2TIdjSSLnEn95fOQA==", + "dev": true, + "peer": true, + "dependencies": { + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "peer": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "dev": true, + "peer": true, + "dependencies": { + "lodash": "^4.17.19" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "request": "^2.34" + } + }, + "node_modules/request-promise-native": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", + "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", + "deprecated": "request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142", + "dev": true, + "peer": true, + "dependencies": { + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + }, + "engines": { + "node": ">=0.12.0" + }, + "peerDependencies": { + "request": "^2.34" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "peer": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true, + "peer": true + }, + "node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "peer": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.0" + }, + "bin": { + "rlp": "bin/rlp" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "peer": true, + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/run-parallel-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", + "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rustbn.js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz", + "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==", + "dev": true + }, + "node_modules/safe-array-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "peer": true + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/sc-istanbul": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/sc-istanbul/-/sc-istanbul-0.4.6.tgz", + "integrity": "sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==", + "dev": true, + "peer": true, + "dependencies": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "istanbul": "lib/cli.js" + } + }, + "node_modules/sc-istanbul/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "peer": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/sc-istanbul/node_modules/glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "dev": true, + "peer": true, + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/sc-istanbul/node_modules/has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sc-istanbul/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "peer": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/sc-istanbul/node_modules/js-yaml/node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "peer": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sc-istanbul/node_modules/resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", + "dev": true, + "peer": true + }, + "node_modules/sc-istanbul/node_modules/supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^1.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, + "node_modules/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "peer": true + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/sha1": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", + "integrity": "sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==", + "dev": true, + "peer": true, + "dependencies": { + "charenc": ">= 0.0.1", + "crypt": ">= 0.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "peer": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "peer": true + }, + "node_modules/solc": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", + "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", + "dev": true, + "dependencies": { + "command-exists": "^1.2.8", + "commander": "3.0.2", + "follow-redirects": "^1.12.1", + "fs-extra": "^0.30.0", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "require-from-string": "^2.0.0", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "bin": { + "solcjs": "solcjs" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/solc/node_modules/fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "node_modules/solc/node_modules/jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/solc/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/solidity-coverage": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.2.tgz", + "integrity": "sha512-cv2bWb7lOXPE9/SSleDO6czkFiMHgP4NXPj+iW9W7iEKLBk7Cj0AGBiNmGX3V1totl9wjPrT0gHmABZKZt65rQ==", + "dev": true, + "peer": true, + "dependencies": { + "@ethersproject/abi": "^5.0.9", + "@solidity-parser/parser": "^0.14.1", + "chalk": "^2.4.2", + "death": "^1.1.0", + "detect-port": "^1.3.0", + "difflib": "^0.2.4", + "fs-extra": "^8.1.0", + "ghost-testrpc": "^0.0.2", + "global-modules": "^2.0.0", + "globby": "^10.0.1", + "jsonschema": "^1.2.4", + "lodash": "^4.17.15", + "mocha": "7.1.2", + "node-emoji": "^1.10.0", + "pify": "^4.0.1", + "recursive-readdir": "^2.2.2", + "sc-istanbul": "^0.4.5", + "semver": "^7.3.4", + "shelljs": "^0.8.3", + "web3-utils": "^1.3.6" + }, + "bin": { + "solidity-coverage": "plugins/bin.js" + }, + "peerDependencies": { + "hardhat": "^2.11.0" + } + }, + "node_modules/solidity-coverage/node_modules/ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "peer": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/solidity-coverage/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/node_modules/chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "peer": true, + "dependencies": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.1.1" + } + }, + "node_modules/solidity-coverage/node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "peer": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/solidity-coverage/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "peer": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/solidity-coverage/node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solidity-coverage/node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/solidity-coverage/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true, + "peer": true + }, + "node_modules/solidity-coverage/node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "peer": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/solidity-coverage/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "peer": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/node_modules/flat": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", + "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", + "dev": true, + "peer": true, + "dependencies": { + "is-buffer": "~2.0.3" + }, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/solidity-coverage/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/solidity-coverage/node_modules/fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "deprecated": "\"Please update to latest v2.3 or v2.2\"", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/solidity-coverage/node_modules/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "peer": true, + "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" + }, + "engines": { + "node": "*" + } + }, + "node_modules/solidity-coverage/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/solidity-coverage/node_modules/js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "peer": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/solidity-coverage/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "peer": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/node_modules/log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "peer": true, + "dependencies": { + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/solidity-coverage/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/solidity-coverage/node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/solidity-coverage/node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "peer": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/solidity-coverage/node_modules/mocha": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.2.tgz", + "integrity": "sha512-o96kdRKMKI3E8U0bjnfqW4QMk12MwZ4mhdBTf+B5a1q9+aq2HRnj+3ZdJu0B/ZhJeK78MgYuv6L8d/rA5AeBJA==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.5", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/solidity-coverage/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true, + "peer": true + }, + "node_modules/solidity-coverage/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "peer": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/solidity-coverage/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "peer": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/node_modules/readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "peer": true, + "dependencies": { + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/solidity-coverage/node_modules/semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", + "dev": true, + "peer": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/solidity-coverage/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "peer": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solidity-coverage/node_modules/supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true, + "peer": true + }, + "node_modules/solidity-coverage/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "peer": true + }, + "node_modules/solidity-coverage/node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "peer": true, + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "node_modules/solidity-coverage/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "peer": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/solidity-coverage/node_modules/yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "peer": true, + "dependencies": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "peer": true + }, + "node_modules/sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dev": true, + "peer": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sshpk/node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true, + "peer": true + }, + "node_modules/stacktrace-parser": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", + "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==", + "dev": true, + "dependencies": { + "type-fest": "^0.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stacktrace-parser/node_modules/type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/string-format": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-format/-/string-format-2.0.0.tgz", + "integrity": "sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==", + "dev": true, + "peer": true + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", + "dev": true, + "dependencies": { + "is-hex-prefixed": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sync-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", + "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", + "dev": true, + "peer": true, + "dependencies": { + "http-response-object": "^3.0.1", + "sync-rpc": "^1.2.1", + "then-request": "^6.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/sync-rpc": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz", + "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==", + "dev": true, + "peer": true, + "dependencies": { + "get-port": "^3.1.0" + } + }, + "node_modules/table": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", + "dev": true, + "peer": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "dev": true, + "peer": true, + "dependencies": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/table-layout/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/table-layout/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "peer": true + }, + "node_modules/then-request": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", + "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", + "dev": true, + "peer": true, + "dependencies": { + "@types/concat-stream": "^1.6.0", + "@types/form-data": "0.0.33", + "@types/node": "^8.0.0", + "@types/qs": "^6.2.31", + "caseless": "~0.12.0", + "concat-stream": "^1.6.0", + "form-data": "^2.2.0", + "http-basic": "^8.1.1", + "http-response-object": "^3.0.1", + "promise": "^8.0.0", + "qs": "^6.4.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/then-request/node_modules/@types/node": { + "version": "8.10.66", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", + "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", + "dev": true, + "peer": true + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "peer": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/ts-command-line-args": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-command-line-args/-/ts-command-line-args-2.5.0.tgz", + "integrity": "sha512-Ff7Xt04WWCjj/cmPO9eWTJX3qpBZWuPWyQYG1vnxJao+alWWYjwJBc5aYz3h5p5dE08A6AnpkgiCtP/0KXXBYw==", + "dev": true, + "peer": true, + "dependencies": { + "@morgan-stanley/ts-mocking-bird": "^0.6.2", + "chalk": "^4.1.0", + "command-line-args": "^5.1.1", + "command-line-usage": "^6.1.0", + "string-format": "^2.0.0" + }, + "bin": { + "write-markdown": "dist/write-markdown.js" + } + }, + "node_modules/ts-command-line-args/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ts-command-line-args/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ts-command-line-args/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ts-command-line-args/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "peer": true + }, + "node_modules/ts-command-line-args/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-command-line-args/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-essentials": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz", + "integrity": "sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==", + "dev": true, + "peer": true, + "peerDependencies": { + "typescript": ">=3.7.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "peer": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsort": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", + "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==", + "dev": true + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "peer": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "dev": true + }, + "node_modules/tweetnacl-util": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", + "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "peer": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typechain": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/typechain/-/typechain-8.1.1.tgz", + "integrity": "sha512-uF/sUvnXTOVF2FHKhQYnxHk4su4JjZR8vr4mA2mBaRwHTbwh0jIlqARz9XJr1tA0l7afJGvEa1dTSi4zt039LQ==", + "dev": true, + "peer": true, + "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" + }, + "bin": { + "typechain": "dist/cli/cli.js" + }, + "peerDependencies": { + "typescript": ">=4.3.0" + } + }, + "node_modules/typechain/node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "peer": true, + "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" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typechain/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "peer": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true, + "peer": true + }, + "node_modules/typescript": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "optional": true, + "peer": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici": { + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.0.tgz", + "integrity": "sha512-fR9RXCc+6Dxav4P9VV/sp5w3eFiSdOjJYsbtWfd4s5L5C4ogyuVpdKIVHeW0vV1MloM65/f7W45nR9ZxwVdyiA==", + "dev": true, + "dependencies": { + "busboy": "^1.6.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "peer": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==", + "dev": true, + "peer": true + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "peer": true + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "peer": true, + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/web3-utils": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.9.0.tgz", + "integrity": "sha512-p++69rCNNfu2jM9n5+VD/g26l+qkEOQ1m6cfRQCbH8ZRrtquTmrirJMgTmyOoax5a5XRYOuws14aypCOs51pdQ==", + "dev": true, + "peer": true, + "dependencies": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-utils/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "peer": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/web3-utils/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "peer": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "peer": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "peer": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true, + "peer": true + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "peer": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "peer": true, + "dependencies": { + "string-width": "^1.0.2 || 2" + } + }, + "node_modules/wide-align/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "peer": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "peer": true + }, + "node_modules/wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "dev": true, + "peer": true, + "dependencies": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/wordwrapjs/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@chainsafe/as-sha256": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@chainsafe/as-sha256/-/as-sha256-0.3.1.tgz", + "integrity": "sha512-hldFFYuf49ed7DAakWVXSJODuq3pzJEguD8tQ7h+sGkM18vja+OFoJI9krnGmgzyuZC2ETX0NOIcCTy31v2Mtg==", + "dev": true + }, + "@chainsafe/persistent-merkle-tree": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.4.2.tgz", + "integrity": "sha512-lLO3ihKPngXLTus/L7WHKaw9PnNJWizlOF1H9NNzHP6Xvh82vzg9F2bzkXhYIFshMZ2gTCEz8tq6STe7r5NDfQ==", + "dev": true, + "requires": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "@chainsafe/ssz": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.9.4.tgz", + "integrity": "sha512-77Qtg2N1ayqs4Bg/wvnWfg5Bta7iy7IRh8XqXh7oNMeP2HBbBwx8m6yTpA8p0EHItWPEBkgZd5S5/LSlp3GXuQ==", + "dev": true, + "requires": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.4.2", + "case": "^1.6.3" + } + }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "peer": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + } + }, + "@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "dev": true, + "requires": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "dev": true, + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0" + } + }, + "@ethersproject/basex": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", + "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0" + } + }, + "@ethersproject/contracts": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", + "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "dev": true, + "requires": { + "@ethersproject/abi": "^5.7.0", + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0" + } + }, + "@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "dev": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/hdnode": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", + "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "dev": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "@ethersproject/json-wallets": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", + "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "dev": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "dev": true + }, + "@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/pbkdf2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", + "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/sha2": "^5.7.0" + } + }, + "@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "dev": true, + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + }, + "dependencies": { + "ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "dev": true, + "requires": {} + } + } + }, + "@ethersproject/random": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", + "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/sha2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", + "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "hash.js": "1.1.7" + } + }, + "@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "@ethersproject/solidity": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", + "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "dev": true, + "requires": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "@ethersproject/units": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", + "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/wallet": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "dev": true, + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/json-wallets": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "dev": true, + "requires": { + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/wordlists": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", + "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "peer": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true, + "peer": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "peer": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@metamask/eth-sig-util": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz", + "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", + "dev": true, + "requires": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^6.2.1", + "ethjs-util": "^0.1.6", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.1" + } + }, + "@morgan-stanley/ts-mocking-bird": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@morgan-stanley/ts-mocking-bird/-/ts-mocking-bird-0.6.4.tgz", + "integrity": "sha512-57VJIflP8eR2xXa9cD1LUawh+Gh+BVQfVu0n6GALyg/AqV/Nz25kDRvws3i9kIe1PTrbsZZOYpsYp6bXPd6nVA==", + "dev": true, + "peer": true, + "requires": { + "lodash": "^4.17.16", + "uuid": "^7.0.3" + }, + "dependencies": { + "uuid": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", + "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==", + "dev": true, + "peer": true + } + } + }, + "@noble/hashes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", + "dev": true + }, + "@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "dev": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "peer": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "peer": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "peer": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@nomicfoundation/ethereumjs-block": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.1.tgz", + "integrity": "sha512-u1Yioemi6Ckj3xspygu/SfFvm8vZEO8/Yx5a1QLzi6nVU0jz3Pg2OmHKJ5w+D9Ogk1vhwRiqEBAqcb0GVhCyHw==", + "dev": true, + "requires": { + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-trie": "6.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "ethereum-cryptography": "0.1.3", + "ethers": "^5.7.1" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "@nomicfoundation/ethereumjs-blockchain": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.1.tgz", + "integrity": "sha512-NhzndlGg829XXbqJEYrF1VeZhAwSPgsK/OB7TVrdzft3y918hW5KNd7gIZ85sn6peDZOdjBsAXIpXZ38oBYE5A==", + "dev": true, + "requires": { + "@nomicfoundation/ethereumjs-block": "5.0.1", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-ethash": "3.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-trie": "6.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "abstract-level": "^1.0.3", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "level": "^8.0.0", + "lru-cache": "^5.1.1", + "memory-level": "^1.0.0" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "@nomicfoundation/ethereumjs-common": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.1.tgz", + "integrity": "sha512-OBErlkfp54GpeiE06brBW/TTbtbuBJV5YI5Nz/aB2evTDo+KawyEzPjBlSr84z/8MFfj8wS2wxzQX1o32cev5g==", + "dev": true, + "requires": { + "@nomicfoundation/ethereumjs-util": "9.0.1", + "crc-32": "^1.2.0" + } + }, + "@nomicfoundation/ethereumjs-ethash": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.1.tgz", + "integrity": "sha512-KDjGIB5igzWOp8Ik5I6QiRH5DH+XgILlplsHR7TEuWANZA759G6krQ6o8bvj+tRUz08YygMQu/sGd9mJ1DYT8w==", + "dev": true, + "requires": { + "@nomicfoundation/ethereumjs-block": "5.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "abstract-level": "^1.0.3", + "bigint-crypto-utils": "^3.0.23", + "ethereum-cryptography": "0.1.3" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "@nomicfoundation/ethereumjs-evm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.1.tgz", + "integrity": "sha512-oL8vJcnk0Bx/onl+TgQOQ1t/534GKFaEG17fZmwtPFeH8S5soiBYPCLUrvANOl4sCp9elYxIMzIiTtMtNNN8EQ==", + "dev": true, + "requires": { + "@ethersproject/providers": "^5.7.1", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "mcl-wasm": "^0.7.1", + "rustbn.js": "~0.2.0" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", + "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==", + "dev": true + }, + "@nomicfoundation/ethereumjs-statemanager": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.1.tgz", + "integrity": "sha512-B5ApMOnlruVOR7gisBaYwFX+L/AP7i/2oAahatssjPIBVDF6wTX1K7Qpa39E/nzsH8iYuL3krkYeUFIdO3EMUQ==", + "dev": true, + "requires": { + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "ethers": "^5.7.1", + "js-sdsl": "^4.1.4" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "@nomicfoundation/ethereumjs-trie": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.1.tgz", + "integrity": "sha512-A64It/IMpDVODzCgxDgAAla8jNjNtsoQZIzZUfIV5AY6Coi4nvn7+VReBn5itlxMiL2yaTlQr9TRWp3CSI6VoA==", + "dev": true, + "requires": { + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "@types/readable-stream": "^2.3.13", + "ethereum-cryptography": "0.1.3", + "readable-stream": "^3.6.0" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "@nomicfoundation/ethereumjs-tx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.1.tgz", + "integrity": "sha512-0HwxUF2u2hrsIM1fsasjXvlbDOq1ZHFV2dd1yGq8CA+MEYhaxZr8OTScpVkkxqMwBcc5y83FyPl0J9MZn3kY0w==", + "dev": true, + "requires": { + "@chainsafe/ssz": "^0.9.2", + "@ethersproject/providers": "^5.7.2", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "ethereum-cryptography": "0.1.3" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "@nomicfoundation/ethereumjs-util": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", + "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", + "dev": true, + "requires": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "ethereum-cryptography": "0.1.3" + }, + "dependencies": { + "@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", + "dev": true, + "requires": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "dev": true, + "requires": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + }, + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "@nomicfoundation/ethereumjs-vm": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.1.tgz", + "integrity": "sha512-rArhyn0jPsS/D+ApFsz3yVJMQ29+pVzNZ0VJgkzAZ+7FqXSRtThl1C1prhmlVr3YNUlfpZ69Ak+RUT4g7VoOuQ==", + "dev": true, + "requires": { + "@nomicfoundation/ethereumjs-block": "5.0.1", + "@nomicfoundation/ethereumjs-blockchain": "7.0.1", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-evm": "2.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-statemanager": "2.0.1", + "@nomicfoundation/ethereumjs-trie": "6.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "mcl-wasm": "^0.7.1", + "rustbn.js": "~0.2.0" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "@nomicfoundation/hardhat-chai-matchers": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-1.0.6.tgz", + "integrity": "sha512-f5ZMNmabZeZegEfuxn/0kW+mm7+yV7VNDxLpMOMGXWFJ2l/Ct3QShujzDRF9cOkK9Ui/hbDeOWGZqyQALDXVCQ==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/abi": "^5.1.2", + "@types/chai-as-promised": "^7.1.3", + "chai-as-promised": "^7.1.1", + "deep-eql": "^4.0.1", + "ordinal": "^1.0.3" + } + }, + "@nomicfoundation/hardhat-network-helpers": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.8.tgz", + "integrity": "sha512-MNqQbzUJZnCMIYvlniC3U+kcavz/PhhQSsY90tbEtUyMj/IQqsLwIRZa4ctjABh3Bz0KCh9OXUZ7Yk/d9hr45Q==", + "dev": true, + "peer": true, + "requires": { + "ethereumjs-util": "^7.1.4" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "peer": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "peer": true, + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + } + } + } + }, + "@nomicfoundation/hardhat-toolbox": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-toolbox/-/hardhat-toolbox-2.0.2.tgz", + "integrity": "sha512-vnN1AzxbvpSx9pfdRHbUzTRIXpMLPXnUlkW855VaDk6N1pwRaQ2gNzEmFAABk4lWf11E00PKwFd/q27HuwYrYg==", + "dev": true, + "requires": {} + }, + "@nomicfoundation/solidity-analyzer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.1.tgz", + "integrity": "sha512-1LMtXj1puAxyFusBgUIy5pZk3073cNXYnXUpuNKFghHbIit/xZgbk0AokpUADbNm3gyD6bFWl3LRFh3dhVdREg==", + "dev": true, + "requires": { + "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.1", + "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.1", + "@nomicfoundation/solidity-analyzer-freebsd-x64": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-arm64-msvc": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-ia32-msvc": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.1" + } + }, + "@nomicfoundation/solidity-analyzer-darwin-arm64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.1.tgz", + "integrity": "sha512-KcTodaQw8ivDZyF+D76FokN/HdpgGpfjc/gFCImdLUyqB6eSWVaZPazMbeAjmfhx3R0zm/NYVzxwAokFKgrc0w==", + "dev": true, + "optional": true + }, + "@nomicfoundation/solidity-analyzer-darwin-x64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.1.tgz", + "integrity": "sha512-XhQG4BaJE6cIbjAVtzGOGbK3sn1BO9W29uhk9J8y8fZF1DYz0Doj8QDMfpMu+A6TjPDs61lbsmeYodIDnfveSA==", + "dev": true, + "optional": true + }, + "@nomicfoundation/solidity-analyzer-freebsd-x64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-freebsd-x64/-/solidity-analyzer-freebsd-x64-0.1.1.tgz", + "integrity": "sha512-GHF1VKRdHW3G8CndkwdaeLkVBi5A9u2jwtlS7SLhBc8b5U/GcoL39Q+1CSO3hYqePNP+eV5YI7Zgm0ea6kMHoA==", + "dev": true, + "optional": true + }, + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.1.tgz", + "integrity": "sha512-g4Cv2fO37ZsUENQ2vwPnZc2zRenHyAxHcyBjKcjaSmmkKrFr64yvzeNO8S3GBFCo90rfochLs99wFVGT/0owpg==", + "dev": true, + "optional": true + }, + "@nomicfoundation/solidity-analyzer-linux-arm64-musl": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.1.tgz", + "integrity": "sha512-WJ3CE5Oek25OGE3WwzK7oaopY8xMw9Lhb0mlYuJl/maZVo+WtP36XoQTb7bW/i8aAdHW5Z+BqrHMux23pvxG3w==", + "dev": true, + "optional": true + }, + "@nomicfoundation/solidity-analyzer-linux-x64-gnu": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.1.tgz", + "integrity": "sha512-5WN7leSr5fkUBBjE4f3wKENUy9HQStu7HmWqbtknfXkkil+eNWiBV275IOlpXku7v3uLsXTOKpnnGHJYI2qsdA==", + "dev": true, + "optional": true + }, + "@nomicfoundation/solidity-analyzer-linux-x64-musl": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.1.tgz", + "integrity": "sha512-KdYMkJOq0SYPQMmErv/63CwGwMm5XHenEna9X9aB8mQmhDBrYrlAOSsIPgFCUSL0hjxE3xHP65/EPXR/InD2+w==", + "dev": true, + "optional": true + }, + "@nomicfoundation/solidity-analyzer-win32-arm64-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.1.tgz", + "integrity": "sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg==", + "dev": true, + "optional": true + }, + "@nomicfoundation/solidity-analyzer-win32-ia32-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.1.tgz", + "integrity": "sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ==", + "dev": true, + "optional": true + }, + "@nomicfoundation/solidity-analyzer-win32-x64-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.1.tgz", + "integrity": "sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw==", + "dev": true, + "optional": true + }, + "@nomiclabs/hardhat-ethers": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.2.3.tgz", + "integrity": "sha512-YhzPdzb612X591FOe68q+qXVXGG2ANZRvDo0RRUtimev85rCrAlv/TLMEZw5c+kq9AbzocLTVX/h2jVIFPL9Xg==", + "dev": true, + "peer": true, + "requires": {} + }, + "@nomiclabs/hardhat-etherscan": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-3.1.7.tgz", + "integrity": "sha512-tZ3TvSgpvsQ6B6OGmo1/Au6u8BrAkvs1mIC/eURA3xgIfznUZBhmpne8hv7BXUzw9xNL3fXdpOYgOQlVMTcoHQ==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/abi": "^5.1.2", + "@ethersproject/address": "^5.0.2", + "cbor": "^8.1.0", + "chalk": "^2.4.2", + "debug": "^4.1.1", + "fs-extra": "^7.0.1", + "lodash": "^4.17.11", + "semver": "^6.3.0", + "table": "^6.8.0", + "undici": "^5.14.0" + } + }, + "@openzeppelin/contracts": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.8.3.tgz", + "integrity": "sha512-bQHV8R9Me8IaJoJ2vPG4rXcL7seB7YVuskr4f+f5RyOStSZetwzkWtoqDMl5erkBJy0lDRUnIR2WIkPiC0GJlg==", + "dev": true + }, + "@scure/base": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", + "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", + "dev": true + }, + "@scure/bip32": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", + "dev": true, + "requires": { + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", + "@scure/base": "~1.1.0" + } + }, + "@scure/bip39": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", + "dev": true, + "requires": { + "@noble/hashes": "~1.2.0", + "@scure/base": "~1.1.0" + } + }, + "@sentry/core": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", + "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", + "dev": true, + "requires": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/hub": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", + "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", + "dev": true, + "requires": { + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/minimal": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", + "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", + "dev": true, + "requires": { + "@sentry/hub": "5.30.0", + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/node": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.30.0.tgz", + "integrity": "sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==", + "dev": true, + "requires": { + "@sentry/core": "5.30.0", + "@sentry/hub": "5.30.0", + "@sentry/tracing": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + } + }, + "@sentry/tracing": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.30.0.tgz", + "integrity": "sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==", + "dev": true, + "requires": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", + "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==", + "dev": true + }, + "@sentry/utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", + "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", + "dev": true, + "requires": { + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@solidity-parser/parser": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.5.tgz", + "integrity": "sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==", + "dev": true, + "peer": true, + "requires": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true, + "peer": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "peer": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "peer": true + }, + "@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true, + "peer": true + }, + "@typechain/ethers-v5": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@typechain/ethers-v5/-/ethers-v5-10.2.0.tgz", + "integrity": "sha512-ikaq0N/w9fABM+G01OFmU3U3dNnyRwEahkdvi9mqy1a3XwKiPZaF/lu54OcNaEWnpvEYyhhS0N7buCtLQqC92w==", + "dev": true, + "peer": true, + "requires": { + "lodash": "^4.17.15", + "ts-essentials": "^7.0.1" + } + }, + "@typechain/hardhat": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/@typechain/hardhat/-/hardhat-6.1.5.tgz", + "integrity": "sha512-lg7LW4qDZpxFMknp3Xool61Fg6Lays8F8TXdFGBG+MxyYcYU5795P1U2XdStuzGq9S2Dzdgh+1jGww9wvZ6r4Q==", + "dev": true, + "peer": true, + "requires": { + "fs-extra": "^9.1.0" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "peer": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "peer": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "peer": true + } + } + }, + "@types/bn.js": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz", + "integrity": "sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/chai": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", + "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==", + "dev": true, + "peer": true + }, + "@types/chai-as-promised": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.5.tgz", + "integrity": "sha512-jStwss93SITGBwt/niYrkf2C+/1KTeZCZl1LaeezTlqppAKeoQC7jxyqYuP72sxBGKCIbw7oHgbYssIRzT5FCQ==", + "dev": true, + "peer": true, + "requires": { + "@types/chai": "*" + } + }, + "@types/concat-stream": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", + "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", + "dev": true, + "peer": true, + "requires": { + "@types/node": "*" + } + }, + "@types/form-data": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", + "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==", + "dev": true, + "peer": true, + "requires": { + "@types/node": "*" + } + }, + "@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "peer": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", + "dev": true + }, + "@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true, + "peer": true + }, + "@types/mocha": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", + "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", + "dev": true, + "peer": true + }, + "@types/node": { + "version": "18.16.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz", + "integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q==", + "dev": true + }, + "@types/pbkdf2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", + "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/prettier": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", + "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", + "dev": true, + "peer": true + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true, + "peer": true + }, + "@types/readable-stream": { + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.15.tgz", + "integrity": "sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ==", + "dev": true, + "requires": { + "@types/node": "*", + "safe-buffer": "~5.1.1" + } + }, + "@types/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==", + "dev": true, + "peer": true + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "abstract-level": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-1.0.3.tgz", + "integrity": "sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA==", + "dev": true, + "requires": { + "buffer": "^6.0.3", + "catering": "^2.1.0", + "is-buffer": "^2.0.5", + "level-supports": "^4.0.0", + "level-transcoder": "^1.0.1", + "module-error": "^1.0.1", + "queue-microtask": "^1.2.3" + } + }, + "acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "peer": true + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "peer": true + }, + "address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "dev": true, + "peer": true + }, + "adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true + }, + "aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "peer": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", + "dev": true, + "optional": true, + "peer": true + }, + "ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "antlr4ts": { + "version": "0.5.0-alpha.4", + "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", + "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", + "dev": true, + "peer": true + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "peer": true + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "dev": true, + "peer": true + }, + "array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "peer": true + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "dev": true, + "peer": true + }, + "array.prototype.reduce": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz", + "integrity": "sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q==", + "dev": true, + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + } + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "peer": true + }, + "asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "peer": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "peer": true + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "peer": true + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "peer": true + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", + "dev": true, + "peer": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "peer": true + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "peer": true + }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "peer": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true, + "peer": true + }, + "aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", + "dev": true, + "peer": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "peer": true, + "requires": { + "tweetnacl": "^0.14.3" + }, + "dependencies": { + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true, + "peer": true + } + } + }, + "bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", + "dev": true + }, + "bigint-crypto-utils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/bigint-crypto-utils/-/bigint-crypto-utils-3.2.2.tgz", + "integrity": "sha512-U1RbE3aX9ayCUVcIPHuPDPKcK3SFOXf93J1UK/iHlJuQB7bhagPIX06/CLpLEsDThJ7KA4Dhrnzynl+d2weTiw==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", + "dev": true + }, + "bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true + }, + "browser-level": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browser-level/-/browser-level-1.0.1.tgz", + "integrity": "sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ==", + "dev": true, + "requires": { + "abstract-level": "^1.0.2", + "catering": "^2.1.1", + "module-error": "^1.0.2", + "run-parallel-limit": "^1.1.0" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "dev": true, + "requires": { + "base-x": "^3.0.2" + } + }, + "bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dev": true, + "requires": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true + }, + "busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, + "requires": { + "streamsearch": "^1.1.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "case": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/case/-/case-1.6.3.tgz", + "integrity": "sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true, + "peer": true + }, + "catering": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", + "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", + "dev": true + }, + "cbor": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", + "integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==", + "dev": true, + "peer": true, + "requires": { + "nofilter": "^3.1.0" + } + }, + "chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "peer": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + } + }, + "chai-as-promised": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", + "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", + "dev": true, + "peer": true, + "requires": { + "check-error": "^1.0.2" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "dev": true, + "peer": true + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true, + "peer": true + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "classic-level": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/classic-level/-/classic-level-1.3.0.tgz", + "integrity": "sha512-iwFAJQYtqRTRM0F6L8h4JCt00ZSGdOyqh7yVrhhjrOpFhmBjNlRUey64MCiyo6UmQHMJ+No3c81nujPv+n9yrg==", + "dev": true, + "requires": { + "abstract-level": "^1.0.2", + "catering": "^2.1.0", + "module-error": "^1.0.1", + "napi-macros": "^2.2.2", + "node-gyp-build": "^4.3.0" + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-table3": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", + "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "dev": true, + "peer": true, + "requires": { + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "peer": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "peer": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "peer": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "peer": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "peer": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "peer": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "dev": true + }, + "command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "dev": true, + "peer": true, + "requires": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + } + }, + "command-line-usage": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", + "integrity": "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==", + "dev": true, + "peer": true, + "requires": { + "array-back": "^4.0.2", + "chalk": "^2.4.2", + "table-layout": "^1.0.2", + "typical": "^5.2.0" + }, + "dependencies": { + "array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true, + "peer": true + }, + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "peer": true + } + } + }, + "commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "peer": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "peer": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "peer": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true, + "peer": true + }, + "crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "peer": true + }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "dev": true, + "peer": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "peer": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "death": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/death/-/death-1.1.0.tgz", + "integrity": "sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==", + "dev": true, + "peer": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, + "deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "peer": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "peer": true + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "peer": true + }, + "define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, + "peer": true, + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "peer": true + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "detect-port": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", + "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", + "dev": true, + "peer": true, + "requires": { + "address": "^1.0.1", + "debug": "4" + } + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, + "difflib": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz", + "integrity": "sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==", + "dev": true, + "peer": true, + "requires": { + "heap": ">= 0.2.0" + } + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "peer": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "peer": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true + }, + "es-abstract": { + "version": "1.21.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", + "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", + "dev": true, + "peer": true, + "requires": { + "array-buffer-byte-length": "^1.0.0", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.0", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + }, + "dependencies": { + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + } + } + }, + "es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", + "dev": true, + "peer": true + }, + "es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "peer": true, + "requires": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "peer": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==", + "dev": true, + "peer": true, + "requires": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.2.0" + }, + "dependencies": { + "source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", + "dev": true, + "peer": true + }, + "estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", + "dev": true, + "peer": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "peer": true + }, + "eth-gas-reporter": { + "version": "0.2.25", + "resolved": "https://registry.npmjs.org/eth-gas-reporter/-/eth-gas-reporter-0.2.25.tgz", + "integrity": "sha512-1fRgyE4xUB8SoqLgN3eDfpDfwEfRxh2Sz1b7wzFbyQA+9TekMmvSjjoRu9SKcSVyK+vLkLIsVbJDsTWjw195OQ==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/abi": "^5.0.0-beta.146", + "@solidity-parser/parser": "^0.14.0", + "cli-table3": "^0.5.0", + "colors": "1.4.0", + "ethereum-cryptography": "^1.0.3", + "ethers": "^4.0.40", + "fs-readdir-recursive": "^1.1.0", + "lodash": "^4.17.14", + "markdown-table": "^1.1.3", + "mocha": "^7.1.1", + "req-cwd": "^2.0.0", + "request": "^2.88.0", + "request-promise-native": "^1.0.5", + "sha1": "^1.1.1", + "sync-request": "^6.0.0" + }, + "dependencies": { + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true, + "peer": true + }, + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "peer": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "peer": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true, + "peer": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "peer": true + }, + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "peer": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "peer": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "peer": true, + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "peer": true + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "peer": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true, + "peer": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "peer": true + }, + "ethers": { + "version": "4.0.49", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.49.tgz", + "integrity": "sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg==", + "dev": true, + "peer": true, + "requires": { + "aes-js": "3.0.0", + "bn.js": "^4.11.9", + "elliptic": "6.5.4", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.4", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "peer": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", + "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", + "dev": true, + "peer": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true, + "peer": true + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "peer": true, + "requires": { + "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" + } + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "peer": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "peer": true + }, + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true, + "peer": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "peer": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "peer": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "peer": true, + "requires": { + "chalk": "^2.4.2" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "peer": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "peer": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz", + "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==", + "dev": true, + "peer": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.5", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true, + "peer": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "peer": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "peer": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "peer": true + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "peer": true, + "requires": { + "picomatch": "^2.0.4" + } + }, + "scrypt-js": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", + "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==", + "dev": true, + "peer": true + }, + "setimmediate": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", + "integrity": "sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==", + "dev": true, + "peer": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "peer": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "peer": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "peer": true + }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "peer": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg==", + "dev": true, + "peer": true + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "peer": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true, + "peer": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "peer": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "peer": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "peer": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + } + } + } + }, + "ethereum-bloom-filters": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz", + "integrity": "sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==", + "dev": true, + "peer": true, + "requires": { + "js-sha3": "^0.8.0" + } + }, + "ethereum-cryptography": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", + "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", + "dev": true, + "requires": { + "@noble/hashes": "1.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" + } + }, + "ethereumjs-abi": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", + "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", + "dev": true, + "requires": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + }, + "dependencies": { + "@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "ethers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", + "dev": true, + "requires": { + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" + } + }, + "ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==", + "dev": true, + "peer": true, + "requires": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true, + "peer": true + } + } + }, + "ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true, + "peer": true + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true, + "peer": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "peer": true + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "peer": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "peer": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "peer": true + }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "peer": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "dev": true, + "peer": true, + "requires": { + "array-back": "^3.0.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "peer": true, + "requires": { + "is-callable": "^1.1.3" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true, + "peer": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "peer": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "fp-ts": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", + "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==", + "dev": true + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true, + "peer": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "peer": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true, + "peer": true + }, + "get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==", + "dev": true, + "peer": true + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "peer": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "ghost-testrpc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/ghost-testrpc/-/ghost-testrpc-0.0.2.tgz", + "integrity": "sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==", + "dev": true, + "peer": true, + "requires": { + "chalk": "^2.4.2", + "node-emoji": "^1.10.0" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "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-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "peer": true, + "requires": { + "global-prefix": "^3.0.0" + } + }, + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "peer": true, + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + } + }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "peer": true, + "requires": { + "define-properties": "^1.1.3" + } + }, + "globby": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", + "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", + "dev": true, + "peer": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "peer": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "peer": true + }, + "handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dev": true, + "peer": true, + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "dev": true, + "peer": true + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "dev": true, + "peer": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "hardhat": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.14.0.tgz", + "integrity": "sha512-73jsInY4zZahMSVFurSK+5TNCJTXMv+vemvGia0Ac34Mm19fYp6vEPVGF3sucbumszsYxiTT2TbS8Ii2dsDSoQ==", + "dev": true, + "requires": { + "@ethersproject/abi": "^5.1.2", + "@metamask/eth-sig-util": "^4.0.0", + "@nomicfoundation/ethereumjs-block": "5.0.1", + "@nomicfoundation/ethereumjs-blockchain": "7.0.1", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-evm": "2.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-statemanager": "2.0.1", + "@nomicfoundation/ethereumjs-trie": "6.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "@nomicfoundation/ethereumjs-vm": "7.0.1", + "@nomicfoundation/solidity-analyzer": "^0.1.0", + "@sentry/node": "^5.18.1", + "@types/bn.js": "^5.1.0", + "@types/lru-cache": "^5.1.0", + "abort-controller": "^3.0.0", + "adm-zip": "^0.4.16", + "aggregate-error": "^3.0.0", + "ansi-escapes": "^4.3.0", + "chalk": "^2.4.2", + "chokidar": "^3.4.0", + "ci-info": "^2.0.0", + "debug": "^4.1.1", + "enquirer": "^2.3.0", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^1.0.3", + "ethereumjs-abi": "^0.6.8", + "find-up": "^2.1.0", + "fp-ts": "1.19.3", + "fs-extra": "^7.0.1", + "glob": "7.2.0", + "immutable": "^4.0.0-rc.12", + "io-ts": "1.10.4", + "keccak": "^3.0.2", + "lodash": "^4.17.11", + "mnemonist": "^0.38.0", + "mocha": "^10.0.0", + "p-map": "^4.0.0", + "qs": "^6.7.0", + "raw-body": "^2.4.1", + "resolve": "1.17.0", + "semver": "^6.3.0", + "solc": "0.7.3", + "source-map-support": "^0.5.13", + "stacktrace-parser": "^0.1.10", + "tsort": "0.0.1", + "undici": "^5.14.0", + "uuid": "^8.3.2", + "ws": "^7.4.6" + } + }, + "hardhat-gas-reporter": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.9.tgz", + "integrity": "sha512-INN26G3EW43adGKBNzYWOlI3+rlLnasXTwW79YNnUhXPDa+yHESgt639dJEs37gCjhkbNKcRRJnomXEuMFBXJg==", + "dev": true, + "peer": true, + "requires": { + "array-uniq": "1.0.3", + "eth-gas-reporter": "^0.2.25", + "sha1": "^1.1.1" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "peer": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "peer": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "peer": true + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "peer": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", + "dev": true, + "peer": true + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "http-basic": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", + "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", + "dev": true, + "peer": true, + "requires": { + "caseless": "^0.12.0", + "concat-stream": "^1.6.2", + "http-response-object": "^3.0.1", + "parse-cache-control": "^1.0.1" + } + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "http-response-object": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", + "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", + "dev": true, + "peer": true, + "requires": { + "@types/node": "^10.0.3" + }, + "dependencies": { + "@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "dev": true, + "peer": true + } + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dev": true, + "peer": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "peer": true + }, + "immutable": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz", + "integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "peer": true + }, + "internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "peer": true, + "requires": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "peer": true + }, + "io-ts": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", + "integrity": "sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==", + "dev": true, + "requires": { + "fp-ts": "^1.0.0" + } + }, + "is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + } + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "peer": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "peer": true + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "peer": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", + "dev": true + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "peer": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "peer": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "peer": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "peer": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "peer": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "peer": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true, + "peer": true + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "peer": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "peer": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "peer": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true, + "peer": true + }, + "js-sdsl": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", + "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", + "dev": true + }, + "js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true, + "peer": true + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true, + "peer": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "peer": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "peer": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonschema": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", + "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", + "dev": true, + "peer": true + }, + "jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "peer": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "keccak": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.3.tgz", + "integrity": "sha512-JZrLIAJWuZxKbCilMpNz5Vj7Vtb4scDG3dMXLOsbzBmQGyjwE61BbW7bJkfKKCShXiQZt3T6sBgALRtmd+nZaQ==", + "dev": true, + "requires": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "peer": true + }, + "klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.9" + } + }, + "level": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/level/-/level-8.0.0.tgz", + "integrity": "sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ==", + "dev": true, + "requires": { + "browser-level": "^1.0.1", + "classic-level": "^1.2.0" + } + }, + "level-supports": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-4.0.1.tgz", + "integrity": "sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA==", + "dev": true + }, + "level-transcoder": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/level-transcoder/-/level-transcoder-1.0.1.tgz", + "integrity": "sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==", + "dev": true, + "requires": { + "buffer": "^6.0.3", + "module-error": "^1.0.1" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "peer": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true, + "peer": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true, + "peer": true + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "loupe": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "peer": true, + "requires": { + "get-func-name": "^2.0.0" + } + }, + "lru_map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "peer": true + }, + "markdown-table": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", + "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", + "dev": true, + "peer": true + }, + "mcl-wasm": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz", + "integrity": "sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ==", + "dev": true + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "memory-level": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/memory-level/-/memory-level-1.0.0.tgz", + "integrity": "sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og==", + "dev": true, + "requires": { + "abstract-level": "^1.0.0", + "functional-red-black-tree": "^1.0.1", + "module-error": "^1.0.1" + } + }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "peer": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "peer": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "peer": true + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "peer": true, + "requires": { + "mime-db": "1.52.0" + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "peer": true + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "peer": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "mnemonist": { + "version": "0.38.5", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", + "integrity": "sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==", + "dev": true, + "requires": { + "obliterator": "^2.0.0" + } + }, + "mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "requires": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "module-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/module-error/-/module-error-1.0.2.tgz", + "integrity": "sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true + }, + "napi-macros": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.2.2.tgz", + "integrity": "sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "peer": true + }, + "node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "dev": true + }, + "node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dev": true, + "peer": true, + "requires": { + "lodash": "^4.17.21" + } + }, + "node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, + "peer": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "peer": true + } + } + }, + "node-gyp-build": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", + "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", + "dev": true + }, + "nofilter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", + "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", + "dev": true, + "peer": true + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", + "dev": true, + "peer": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "number-to-bn": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", + "integrity": "sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==", + "dev": true, + "peer": true, + "requires": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true, + "peer": true + } + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "peer": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "peer": true + }, + "object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "peer": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "peer": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.6.tgz", + "integrity": "sha512-lq+61g26E/BgHv0ZTFgRvi7NMEPuAxLkFU7rukXjc/AlwH4Am5xXVnIXy3un1bg/JPbXHrixRkK1itUzzPiIjQ==", + "dev": true, + "peer": true, + "requires": { + "array.prototype.reduce": "^1.0.5", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.21.2", + "safe-array-concat": "^1.0.0" + } + }, + "obliterator": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", + "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "peer": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "ordinal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ordinal/-/ordinal-1.0.3.tgz", + "integrity": "sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ==", + "dev": true, + "peer": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true + }, + "parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==", + "dev": true, + "peer": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "peer": true + }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "peer": true + }, + "pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true, + "peer": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "peer": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true, + "peer": true + }, + "prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "peer": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "peer": true + }, + "promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "dev": true, + "peer": true, + "requires": { + "asap": "~2.0.6" + } + }, + "psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true, + "peer": true + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "peer": true + }, + "qs": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.1.tgz", + "integrity": "sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "peer": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dev": true, + "peer": true, + "requires": { + "minimatch": "^3.0.5" + } + }, + "reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", + "dev": true, + "peer": true + }, + "regexp.prototype.flags": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dev": true, + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" + } + }, + "req-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz", + "integrity": "sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ==", + "dev": true, + "peer": true, + "requires": { + "req-from": "^2.0.0" + } + }, + "req-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-from/-/req-from-2.0.0.tgz", + "integrity": "sha512-LzTfEVDVQHBRfjOUMgNBA+V6DWsSnoeKzf42J7l0xa/B4jyPOuuF5MlNSmomLNGemWTnV2TIdjSSLnEn95fOQA==", + "dev": true, + "peer": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, + "peer": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true, + "peer": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true, + "peer": true + } + } + }, + "request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "dev": true, + "peer": true, + "requires": { + "lodash": "^4.17.19" + } + }, + "request-promise-native": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", + "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", + "dev": true, + "peer": true, + "requires": { + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true, + "peer": true + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", + "dev": true, + "peer": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "peer": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "dev": true, + "requires": { + "bn.js": "^5.2.0" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "peer": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "run-parallel-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", + "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rustbn.js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz", + "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==", + "dev": true + }, + "safe-array-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "dev": true, + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "peer": true + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sc-istanbul": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/sc-istanbul/-/sc-istanbul-0.4.6.tgz", + "integrity": "sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==", + "dev": true, + "peer": true, + "requires": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "peer": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "dev": true, + "peer": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", + "dev": true, + "peer": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "peer": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "peer": true + } + } + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", + "dev": true, + "peer": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", + "dev": true, + "peer": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, + "secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "dev": true, + "requires": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "peer": true + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "sha1": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", + "integrity": "sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==", + "dev": true, + "peer": true, + "requires": { + "charenc": ">= 0.0.1", + "crypt": ">= 0.0.1" + } + }, + "shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "peer": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "peer": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "peer": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "peer": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "peer": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "peer": true + } + } + }, + "solc": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", + "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", + "dev": true, + "requires": { + "command-exists": "^1.2.8", + "commander": "3.0.2", + "follow-redirects": "^1.12.1", + "fs-extra": "^0.30.0", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "require-from-string": "^2.0.0", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "dependencies": { + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "solidity-coverage": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.2.tgz", + "integrity": "sha512-cv2bWb7lOXPE9/SSleDO6czkFiMHgP4NXPj+iW9W7iEKLBk7Cj0AGBiNmGX3V1totl9wjPrT0gHmABZKZt65rQ==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/abi": "^5.0.9", + "@solidity-parser/parser": "^0.14.1", + "chalk": "^2.4.2", + "death": "^1.1.0", + "detect-port": "^1.3.0", + "difflib": "^0.2.4", + "fs-extra": "^8.1.0", + "ghost-testrpc": "^0.0.2", + "global-modules": "^2.0.0", + "globby": "^10.0.1", + "jsonschema": "^1.2.4", + "lodash": "^4.17.15", + "mocha": "7.1.2", + "node-emoji": "^1.10.0", + "pify": "^4.0.1", + "recursive-readdir": "^2.2.2", + "sc-istanbul": "^0.4.5", + "semver": "^7.3.4", + "shelljs": "^0.8.3", + "web3-utils": "^1.3.6" + }, + "dependencies": { + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true, + "peer": true + }, + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "peer": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "peer": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "peer": true + }, + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "peer": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "peer": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "peer": true, + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "peer": true + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "peer": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true, + "peer": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "peer": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "peer": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", + "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", + "dev": true, + "peer": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "peer": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true, + "peer": true + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "peer": true, + "requires": { + "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" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "peer": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "peer": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "peer": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "peer": true, + "requires": { + "chalk": "^2.4.2" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "peer": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "peer": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "peer": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.2.tgz", + "integrity": "sha512-o96kdRKMKI3E8U0bjnfqW4QMk12MwZ4mhdBTf+B5a1q9+aq2HRnj+3ZdJu0B/ZhJeK78MgYuv6L8d/rA5AeBJA==", + "dev": true, + "peer": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.5", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true, + "peer": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "peer": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "peer": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "peer": true + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "peer": true, + "requires": { + "picomatch": "^2.0.4" + } + }, + "semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", + "dev": true, + "peer": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "peer": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "peer": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "peer": true + }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "peer": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "peer": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true, + "peer": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "peer": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "peer": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "peer": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "peer": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + } + } + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "peer": true + }, + "sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dev": true, + "peer": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "dependencies": { + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true, + "peer": true + } + } + }, + "stacktrace-parser": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", + "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==", + "dev": true, + "requires": { + "type-fest": "^0.7.1" + }, + "dependencies": { + "type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "dev": true + } + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==", + "dev": true, + "peer": true + }, + "streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "string-format": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-format/-/string-format-2.0.0.tgz", + "integrity": "sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==", + "dev": true, + "peer": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "sync-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", + "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", + "dev": true, + "peer": true, + "requires": { + "http-response-object": "^3.0.1", + "sync-rpc": "^1.2.1", + "then-request": "^6.0.0" + } + }, + "sync-rpc": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz", + "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==", + "dev": true, + "peer": true, + "requires": { + "get-port": "^3.1.0" + } + }, + "table": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", + "dev": true, + "peer": true, + "requires": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "peer": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "peer": true + } + } + }, + "table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "dev": true, + "peer": true, + "requires": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "dependencies": { + "array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true, + "peer": true + }, + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "peer": true + } + } + }, + "then-request": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", + "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", + "dev": true, + "peer": true, + "requires": { + "@types/concat-stream": "^1.6.0", + "@types/form-data": "0.0.33", + "@types/node": "^8.0.0", + "@types/qs": "^6.2.31", + "caseless": "~0.12.0", + "concat-stream": "^1.6.0", + "form-data": "^2.2.0", + "http-basic": "^8.1.1", + "http-response-object": "^3.0.1", + "promise": "^8.0.0", + "qs": "^6.4.0" + }, + "dependencies": { + "@types/node": { + "version": "8.10.66", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", + "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", + "dev": true, + "peer": true + } + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "peer": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "ts-command-line-args": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-command-line-args/-/ts-command-line-args-2.5.0.tgz", + "integrity": "sha512-Ff7Xt04WWCjj/cmPO9eWTJX3qpBZWuPWyQYG1vnxJao+alWWYjwJBc5aYz3h5p5dE08A6AnpkgiCtP/0KXXBYw==", + "dev": true, + "peer": true, + "requires": { + "@morgan-stanley/ts-mocking-bird": "^0.6.2", + "chalk": "^4.1.0", + "command-line-args": "^5.1.1", + "command-line-usage": "^6.1.0", + "string-format": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "peer": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "peer": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "peer": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "peer": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "peer": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "ts-essentials": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz", + "integrity": "sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==", + "dev": true, + "peer": true, + "requires": {} + }, + "ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "peer": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "peer": true + } + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tsort": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", + "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "peer": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "dev": true + }, + "tweetnacl-util": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", + "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "peer": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "peer": true + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + }, + "typechain": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/typechain/-/typechain-8.1.1.tgz", + "integrity": "sha512-uF/sUvnXTOVF2FHKhQYnxHk4su4JjZR8vr4mA2mBaRwHTbwh0jIlqARz9XJr1tA0l7afJGvEa1dTSi4zt039LQ==", + "dev": true, + "peer": true, + "requires": { + "@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" + }, + "dependencies": { + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "peer": true, + "requires": { + "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" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "peer": true + } + } + }, + "typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true, + "peer": true + }, + "typescript": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "dev": true, + "peer": true + }, + "typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "dev": true, + "peer": true + }, + "uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "optional": true, + "peer": true + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "undici": { + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.0.tgz", + "integrity": "sha512-fR9RXCc+6Dxav4P9VV/sp5w3eFiSdOjJYsbtWfd4s5L5C4ogyuVpdKIVHeW0vV1MloM65/f7W45nR9ZxwVdyiA==", + "dev": true, + "requires": { + "busboy": "^1.6.0" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "peer": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==", + "dev": true, + "peer": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "peer": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "peer": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "web3-utils": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.9.0.tgz", + "integrity": "sha512-p++69rCNNfu2jM9n5+VD/g26l+qkEOQ1m6cfRQCbH8ZRrtquTmrirJMgTmyOoax5a5XRYOuws14aypCOs51pdQ==", + "dev": true, + "peer": true, + "requires": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "peer": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "peer": true, + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + } + } + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "peer": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "peer": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true, + "peer": true + }, + "which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "peer": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + } + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "peer": true, + "requires": { + "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "peer": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "peer": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "peer": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "peer": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "peer": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "peer": true + }, + "wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "dev": true, + "peer": true, + "requires": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + }, + "dependencies": { + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "peer": true + } + } + }, + "workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "requires": {} + }, + "xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==", + "dev": true, + "peer": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "peer": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/assets/eip-7007/package.json b/assets/eip-7007/package.json new file mode 100644 index 0000000000000..0c5b28f233e4f --- /dev/null +++ b/assets/eip-7007/package.json @@ -0,0 +1,17 @@ +{ + "name": "erc7007", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@nomicfoundation/hardhat-toolbox": "^2.0.2", + "@openzeppelin/contracts": "^4.8.3", + "hardhat": "^2.14.0" + } +} diff --git a/assets/eip-7007/test/test.js b/assets/eip-7007/test/test.js new file mode 100644 index 0000000000000..31777ecb3ec2f --- /dev/null +++ b/assets/eip-7007/test/test.js @@ -0,0 +1,90 @@ +const { + time, + loadFixture, +} = require("@nomicfoundation/hardhat-network-helpers"); +const { anyValue } = require("@nomicfoundation/hardhat-chai-matchers/withArgs"); +const { expect } = require("chai"); +const { BigNumber } = require("ethers"); + +async function deployVerifierFixture() { + const Verifier = await ethers.getContractFactory("MockVerifier"); + const verifier = await Verifier.deploy(); + await verifier.deployed(); + return verifier; +} +const prompt = ethers.utils.toUtf8Bytes("test"); +const aigcData = ethers.utils.toUtf8Bytes("test"); +const uri = '"name": "test", "description": "test", "image": "test", "aigc_type": "test"'; +const validProof = ethers.utils.toUtf8Bytes("valid"); +const invalidProof = ethers.utils.toUtf8Bytes("invalid"); +const tokenId = BigNumber.from("70622639689279718371527342103894932928233838121221666359043189029713682937432"); + +describe("ERC7007.sol", function () { + + async function deployERC7007Fixture() { + const verifier = await deployVerifierFixture(); + + const ERC7007 = await ethers.getContractFactory("ERC7007"); + const erc7007 = await ERC7007.deploy("testing", "TEST", verifier.address); + await erc7007.deployed(); + return erc7007; + } + + describe("mint", function () { + it("should mint a token", async function () { + const erc7007 = await deployERC7007Fixture(); + const [owner] = await ethers.getSigners(); + await erc7007.mint(prompt, aigcData, uri, validProof); + expect(await erc7007.balanceOf(owner.address)).to.equal(1); + }); + + it("should not mint a token with invalid proof", async function () { + const erc7007 = await deployERC7007Fixture(); + await expect(erc7007.mint(prompt, aigcData, uri, invalidProof)).to.be.revertedWith("ERC7007: invalid proof"); + }); + + it("should not mint a token with same data twice", async function () { + const erc7007 = await deployERC7007Fixture(); + await erc7007.mint(prompt, aigcData, uri, validProof); + await expect(erc7007.mint(prompt, aigcData, uri, validProof)).to.be.revertedWith("ERC721: token already minted"); + }); + + it("should emit a Mint event", async function () { + const erc7007 = await deployERC7007Fixture(); + await expect(erc7007.mint(prompt, aigcData, uri, validProof)) + .to.emit(erc7007, "Mint") + }); + }); + + describe("metadata", function () { + it("should return token metadata", async function () { + const erc7007 = await deployERC7007Fixture(); + await erc7007.mint(prompt, aigcData, uri, validProof); + expect(await erc7007.tokenURI(tokenId)).to.equal('{"name": "test", "description": "test", "image": "test", "aigc_type": "test", "prompt": "test", "aigc_data": "test"}'); + }); + }); +}); + +describe("ERC7007Enumerable.sol", function () { + + async function deployERC7007EnumerableFixture() { + const verifier = await deployVerifierFixture(); + + const ERC7007Enumerable = await ethers.getContractFactory("MockERC7007Enumerable"); + const erc7007Enumerable = await ERC7007Enumerable.deploy("testing", "TEST", verifier.address); + await erc7007Enumerable.deployed(); + await erc7007Enumerable.mint(prompt, aigcData, uri, validProof); + return erc7007Enumerable; + } + + it("should return token id by prompt", async function () { + const erc7007Enumerable = await deployERC7007EnumerableFixture(); + expect(await erc7007Enumerable.tokenId(prompt)).to.equal(tokenId); + }); + + it("should return token prompt by id", async function () { + const erc7007Enumerable = await deployERC7007EnumerableFixture(); + expect(await erc7007Enumerable.prompt(tokenId)).to.equal("test"); + }); + +}); \ No newline at end of file diff --git a/assets/eip-7053/digital-media-indexing-system-and-metadata-lookup.jpg b/assets/eip-7053/digital-media-indexing-system-and-metadata-lookup.jpg new file mode 100644 index 0000000000000..8afd23d2c4d9e Binary files /dev/null and b/assets/eip-7053/digital-media-indexing-system-and-metadata-lookup.jpg differ diff --git a/assets/eip-modular-smart-contract-accounts-and-plugins/MSCA_Two_Call_Paths_Diagram.svg b/assets/eip-modular-smart-contract-accounts-and-plugins/MSCA_Two_Call_Paths_Diagram.svg deleted file mode 100644 index 729ecb99bff62..0000000000000 --- a/assets/eip-modular-smart-contract-accounts-and-plugins/MSCA_Two_Call_Paths_Diagram.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - SCAEntryPointEOA/SC callA.0B.1Execution FunctionA.1runtimeValidatorPre Execution Hook(s)Post Execution Hook(s)A.2Step 1Step 2Step 3Step 4ACalls from Entrypoint (ERC-4337)BCalls from EOAs and other contractsA.3 B.3A.4 B.4B.2userOpValidatorvalidateUserOp \ No newline at end of file