From 5980084ebe942bf0719619920a6f397f0658df58 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Mon, 11 Sep 2023 11:11:42 +0100 Subject: [PATCH 01/55] docs: add Code4Rena bug fixes + missing details in CHANGELOG for v0.11.1 --- CHANGELOG.md | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7739d4f1e..32f4b0ca8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,11 @@ All notable changes to this project will be documented in this file. See [standa ### ⚠ BREAKING CHANGES -- Include LSP20 in interfaceId calculation ([#668](https://github.com/lukso-network/lsp-smart-contracts/pull/668)), from: `0x3e89ad98` to `0x24871b3d` +- change visibility of `_reentrancyStatus` state variable from `private` to `internal` in `LSP6KeyManagerCore` ([#651](https://github.com/lukso-network/lsp-smart-contracts/pull/651)) + +- change data key for `SupportedStandards` from `LSP3UniversalProfile` to `LSP3Profile` in `LSP3Constants.sol` and `constants.ts` ([#664](https://github.com/lukso-network/lsp-smart-contracts/pull/664)) + +- Include LSP20 in interfaceId calculation ([#668](https://github.com/lukso-network/lsp-smart-contracts/pull/668)), from: `0x3e89ad98` to `0x24871b3d`. - Return instead of revert when the `LSP1UniversalReceiverDelegateUP` is not able to register LSP5-LSP10 data keys. ([#672](https://github.com/lukso-network/lsp-smart-contracts/pull/672)) @@ -22,20 +26,54 @@ All notable changes to this project will be documented in this file. See [standa - Remove `LSP0Utils.sol`. ([#683](https://github.com/lukso-network/lsp-smart-contracts/pull/683)) -- Change token LSP1 notification data format from `abi.encodepacked` to `abi.encode`. ([#699](https://github.com/lukso-network/lsp-smart-contracts/pull/699)) +- Add LSP17 in inheritance of LSP7 and LSP8 ([#697](https://github.com/lukso-network/lsp-smart-contracts/pull/697)) + +- Change token LSP1 notification data format from `abi.encodePacked` to `abi.encode`. ([#699](https://github.com/lukso-network/lsp-smart-contracts/pull/699)) - Notify Operator via LSP1 in `authorizeOperator` in LSP7 and LSP8. ([#700](https://github.com/lukso-network/lsp-smart-contracts/pull/700)) ### Features -- Add LSP25ExecuteRelayCall as its seperate standard. ([#678](https://github.com/lukso-network/lsp-smart-contracts/pull/678)) +- Mark multiple functions as `virtual` across the smart contracts, so that their behaviour can be overriden through inheritance [#644](https://github.com/lukso-network/lsp-smart-contracts/pull/644). + +- Change visibility of `_reentrancyStatus` state variable from `private` to `internal` in `LSP6KeyManagerCore` ([#651](https://github.com/lukso-network/lsp-smart-contracts/pull/651)) + +- Create implementation of `LSP23LinkedContractsFactory` ([#658](https://github.com/lukso-network/lsp-smart-contracts/pull/658)) + +- Add external call (= hook) to LSP1 in LSP14 `renounceOwnership` function ([#663](https://github.com/lukso-network/lsp-smart-contracts/pull/663)) + +- Add `LSP25ExecuteRelayCall` as its separate standard. ([#678](https://github.com/lukso-network/lsp-smart-contracts/pull/678)) + +- Add `getOperatorsOf(address)` function to LSP7 ([#698](https://github.com/lukso-network/lsp-smart-contracts/pull/698)) + +- Add LSP17 in inheritance of LSP7 and LSP8 ([#697](https://github.com/lukso-network/lsp-smart-contracts/pull/697)) + +- Notify Operator via LSP1 in authorizeOperator in LSP7 and LSP8. (https://github.com/lukso-network/lsp-smart-contracts/pull/700) + +### Perfs + +- Improve deployment + runtime cost of LSP6 Key Manager by replacing calldata slices with `abi.decode` when verifying `ERC725X.execute(uint256,address,uint256,bytes)` calldata payloads ([#682](https://github.com/lukso-network/lsp-smart-contracts/pull/682)) ### Bug Fixes +- Add lock guard when transferring ownership in LSP14 ([#645](https://github.com/lukso-network/lsp-smart-contracts/pull/645)) + +- Delete pending when confirming renounce ownership the second time ([#646](https://github.com/lukso-network/lsp-smart-contracts/pull/646)) + +- Disallowing setting LSP6 Key Manager as a LSP17 extension in setData paths in Key Manager ([#648](https://github.com/lukso-network/lsp-smart-contracts/pull/648)) + +- Add check for `length == 0` when checking for Allowed ERC725Y Data Keys in Key Manager to prevent mask from allowing any data keys ([#659](https://github.com/lukso-network/lsp-smart-contracts/pull/659)) + +- Use bitwise OR `|` operator in `LSP6Utils` function `combinePermissions(...)` to prevent from adding same permission twice and generate incorrect `bytes32` permission value ([#660](https://github.com/lukso-network/lsp-smart-contracts/pull/660)) + +- Resolve inheritance of `LSP8Burnable` to include LSP4 ([#661](https://github.com/lukso-network/lsp-smart-contracts/pull/661)) + - Refactor `_fallbackLSP17Extendable` function to enable to run code after it is called + prevent potential solc bug "storage write removal". ([#674](https://github.com/lukso-network/lsp-smart-contracts/pull/674)) - Update lsp8 compatible approve() logic to allow operators themselves to authorize operators. ([#681](https://github.com/lukso-network/lsp-smart-contracts/pull/681)) +- Add input validations for LSP6, LSP1 and LSP17 data keys when setting data in `LSP6SetDataModule` ([#679](https://github.com/lukso-network/lsp-smart-contracts/pull/679)) + ### Build - upgrade `@erc725/smart-contracts` version to 5.2.0 ([#696](https://github.com/lukso-network/lsp-smart-contracts/pull/696)) From 22bd82bc998e8541bc4256251428e013b05f3b61 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Mon, 11 Sep 2023 12:41:36 +0100 Subject: [PATCH 02/55] docs: fix name of folder for LSP23 --- .../ILSP23LinkedContractsFactory.sol | 0 .../IPostDeploymentModule.sol | 0 .../LSP23Errors.sol | 0 .../LSP23LinkedContractsFactory.sol | 0 .../modules/UniversalProfileInitPostDeploymentModule.sol | 0 .../modules/UniversalProfilePostDeploymentModule.sol | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename contracts/{LSP23LinkedContractsDeployment => LSP23LinkedContractsFactory}/ILSP23LinkedContractsFactory.sol (100%) rename contracts/{LSP23LinkedContractsDeployment => LSP23LinkedContractsFactory}/IPostDeploymentModule.sol (100%) rename contracts/{LSP23LinkedContractsDeployment => LSP23LinkedContractsFactory}/LSP23Errors.sol (100%) rename contracts/{LSP23LinkedContractsDeployment => LSP23LinkedContractsFactory}/LSP23LinkedContractsFactory.sol (100%) rename contracts/{LSP23LinkedContractsDeployment => LSP23LinkedContractsFactory}/modules/UniversalProfileInitPostDeploymentModule.sol (100%) rename contracts/{LSP23LinkedContractsDeployment => LSP23LinkedContractsFactory}/modules/UniversalProfilePostDeploymentModule.sol (100%) diff --git a/contracts/LSP23LinkedContractsDeployment/ILSP23LinkedContractsFactory.sol b/contracts/LSP23LinkedContractsFactory/ILSP23LinkedContractsFactory.sol similarity index 100% rename from contracts/LSP23LinkedContractsDeployment/ILSP23LinkedContractsFactory.sol rename to contracts/LSP23LinkedContractsFactory/ILSP23LinkedContractsFactory.sol diff --git a/contracts/LSP23LinkedContractsDeployment/IPostDeploymentModule.sol b/contracts/LSP23LinkedContractsFactory/IPostDeploymentModule.sol similarity index 100% rename from contracts/LSP23LinkedContractsDeployment/IPostDeploymentModule.sol rename to contracts/LSP23LinkedContractsFactory/IPostDeploymentModule.sol diff --git a/contracts/LSP23LinkedContractsDeployment/LSP23Errors.sol b/contracts/LSP23LinkedContractsFactory/LSP23Errors.sol similarity index 100% rename from contracts/LSP23LinkedContractsDeployment/LSP23Errors.sol rename to contracts/LSP23LinkedContractsFactory/LSP23Errors.sol diff --git a/contracts/LSP23LinkedContractsDeployment/LSP23LinkedContractsFactory.sol b/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol similarity index 100% rename from contracts/LSP23LinkedContractsDeployment/LSP23LinkedContractsFactory.sol rename to contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol diff --git a/contracts/LSP23LinkedContractsDeployment/modules/UniversalProfileInitPostDeploymentModule.sol b/contracts/LSP23LinkedContractsFactory/modules/UniversalProfileInitPostDeploymentModule.sol similarity index 100% rename from contracts/LSP23LinkedContractsDeployment/modules/UniversalProfileInitPostDeploymentModule.sol rename to contracts/LSP23LinkedContractsFactory/modules/UniversalProfileInitPostDeploymentModule.sol diff --git a/contracts/LSP23LinkedContractsDeployment/modules/UniversalProfilePostDeploymentModule.sol b/contracts/LSP23LinkedContractsFactory/modules/UniversalProfilePostDeploymentModule.sol similarity index 100% rename from contracts/LSP23LinkedContractsDeployment/modules/UniversalProfilePostDeploymentModule.sol rename to contracts/LSP23LinkedContractsFactory/modules/UniversalProfilePostDeploymentModule.sol From bc60156df696f06721df1ed7b1daa77c9836e559 Mon Sep 17 00:00:00 2001 From: Skima Harvey <64636974+skimaharvey@users.noreply.github.com> Date: Tue, 12 Sep 2023 14:39:02 +0100 Subject: [PATCH 03/55] docs: add deployment info for post deployment module (#708) * docs: add deployment info for post deployment module * docs: create ReadMe for post-deployment modules --- .../modules/README.md | 23 +++++ .../modules/deployment-UP-init-module.md | 92 +++++++++++++++++++ .../modules/deployment-UP-module.md | 90 ++++++++++++++++++ 3 files changed, 205 insertions(+) create mode 100644 contracts/LSP23LinkedContractsFactory/modules/README.md create mode 100644 contracts/LSP23LinkedContractsFactory/modules/deployment-UP-init-module.md create mode 100644 contracts/LSP23LinkedContractsFactory/modules/deployment-UP-module.md diff --git a/contracts/LSP23LinkedContractsFactory/modules/README.md b/contracts/LSP23LinkedContractsFactory/modules/README.md new file mode 100644 index 000000000..e02d730cd --- /dev/null +++ b/contracts/LSP23LinkedContractsFactory/modules/README.md @@ -0,0 +1,23 @@ +# LSP23 Linked Contracts Deployment Module + +This folder contains modules related to the deployment of LSP23 Linked Contracts. The modules are essential for initializing and post-deploying actions for Universal Profiles. + +## Modules + +- **UniversalProfileInitPostDeploymentModule**: This module is responsible for the initial setup after the deployment of a Universal Profile Init contract. + + - **Standardized Address**: `0x000000000066093407b6704B89793beFfD0D8F00` + - **Standardized Salt**: `0x12a6712f113536d8b01d99f72ce168c7e10901240d73e80eeb821d01aa4c2b1a` + - [More Details](./deployment-UP-init-module.md) + +- **UniversalProfilePostDeploymentModule**: This module is responsible for the initial setup after the deployment of a Universal Profile contract. + - **Standardized Address**: `0x0000005aD606bcFEF9Ea6D0BbE5b79847054BcD7` + - **Standardized Salt**: `0x42ff55d7957589c62da54a4368b10a2bc549f2038bbb6880ec6b3e0ecae2ba58` + - [More Details](./deployment-UP-module.md) + +## Setup + +Before deploying any of these modules, make sure that the following contracts are already deployed on the same network: + +- [Nick's Factory contract](https://github.com/Arachnid/deterministic-deployment-proxy/tree/master) +- [LSP23 Linked Contracts Factory](https://github.com/lukso-network/LIPs/LSPs/LSP-23-LinkedContractsFactory.md#lsp23linkedcontractsfactory-deployment) diff --git a/contracts/LSP23LinkedContractsFactory/modules/deployment-UP-init-module.md b/contracts/LSP23LinkedContractsFactory/modules/deployment-UP-init-module.md new file mode 100644 index 000000000..13c2fc307 --- /dev/null +++ b/contracts/LSP23LinkedContractsFactory/modules/deployment-UP-init-module.md @@ -0,0 +1,92 @@ +# Setup + +Before the deployment of the `UniversalProfileInitPostDeploymentModule` on any network, people should make sure that the [Nick's Factory contract](https://github.com/Arachnid/deterministic-deployment-proxy/tree/master) is deployed on the same network. +You also need to make sure that the LSP23 Linked Contracts Factory is deployed on the same network. Please refer to [LSP23 Linked Contracts Deployment Factory LIP](https://github.com/lukso-network/LIPs/LSPs/LSP-23-LinkedContractsFactory.md#lsp23linkedcontractsfactory-deployment) in order to deploy it. + +# Deployment of the Universal Profile Init Post Deployment Module + +## Standardized Address + +`0x000000000066093407b6704B89793beFfD0D8F00` + +## Standardized Salt + +`0x12a6712f113536d8b01d99f72ce168c7e10901240d73e80eeb821d01aa4c2b1a` + +## Standardized Bytecode + +```solidity +0x60806040523480156200001157600080fd5b506200001c6200002c565b620000266200002c565b620000ed565b600054610100900460ff1615620000995760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614620000eb576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b61497980620000fd6000396000f3fe6080604052600436106101635760003560e01c8063715018a6116100c0578063c4d66de811610074578063e30c397811610059578063e30c397814610451578063ead3fbdf1461020d578063f2fde38b1461047c5761019e565b8063c4d66de81461041e578063dedff9c6146104315761019e565b80637f23690c116100a55780637f23690c146103a65780638da5cb5b146103b9578063979024211461040b5761019e565b8063715018a61461037c57806379ba5097146103915761019e565b806344c028fe1161011757806354f6127f116100fc57806354f6127f146103295780636963d438146103495780636bb56a14146103695761019e565b806344c028fe146102f65780634f04d60a146103165761019e565b80631626ba7e116101485780631626ba7e1461026557806328c4d14e146102b657806331858452146102d65761019e565b806301bfba611461020d57806301ffc9a7146102355761019e565b3661019e57341561019c57604051349033907f7e71433ddf847725166244795048ecf3e3f9f35628254ecbf73605666423349390600090a35b005b600036606034156101d757604051349033907f7e71433ddf847725166244795048ecf3e3f9f35628254ecbf73605666423349390600090a35b60043610156101f55750604080516020810190915260008152610202565b6101ff838361049c565b90505b915050805190602001f35b34801561021957600080fd5b5061022260c881565b6040519081526020015b60405180910390f35b34801561024157600080fd5b50610255610250366004613a93565b610677565b604051901515815260200161022c565b34801561027157600080fd5b50610285610280366004613bca565b61080c565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200161022c565b3480156102c257600080fd5b5061019c6102d1366004613c7c565b610ac3565b6102e96102e4366004613de7565b610c2a565b60405161022c9190613fb2565b610309610304366004613fc5565b610cf4565b60405161022c919061401a565b61019c61032436600461402d565b610d95565b34801561033557600080fd5b506103096103443660046140a1565b610f19565b34801561035557600080fd5b506102e96103643660046140ba565b610f24565b61030961037736600461412f565b61109a565b34801561038857600080fd5b5061019c6112a2565b34801561039d57600080fd5b5061019c6113a7565b61019c6103b4366004613bca565b6114b1565b3480156103c557600080fd5b5060005462010000900473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161022c565b61019c61041936600461417b565b611552565b61019c61042c3660046141d5565b611681565b34801561043d57600080fd5b506102e961044c3660046141f0565b611815565b34801561045d57600080fd5b5060035473ffffffffffffffffffffffffffffffffffffffff166103e6565b34801561048857600080fd5b5061019c6104973660046141d5565b6118c0565b606060006104cd6000357fffffffff0000000000000000000000000000000000000000000000000000000016611b4f565b90506000357fffffffff0000000000000000000000000000000000000000000000000000000016158015610515575073ffffffffffffffffffffffffffffffffffffffff8116155b15610530575050604080516020810190915260008152610671565b73ffffffffffffffffffffffffffffffffffffffff81166105a8576040517fbb370b2b0000000000000000000000000000000000000000000000000000000081527fffffffff000000000000000000000000000000000000000000000000000000006000351660048201526024015b60405180910390fd5b6000808273ffffffffffffffffffffffffffffffffffffffff16868633346040516020016105d99493929190614225565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261061191614268565b6000604051808303816000865af19150503d806000811461064e576040519150601f19603f3d011682016040523d82523d6000602084013e610653565b606091505b50915091508115610668579250610671915050565b80518060208301fd5b92915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f1626ba7e00000000000000000000000000000000000000000000000000000000148061070a57507fffffffff0000000000000000000000000000000000000000000000000000000082167f24871b3d00000000000000000000000000000000000000000000000000000000145b8061075657507fffffffff0000000000000000000000000000000000000000000000000000000082167f6bb56a1400000000000000000000000000000000000000000000000000000000145b806107a257507fffffffff0000000000000000000000000000000000000000000000000000000082167f94be599900000000000000000000000000000000000000000000000000000000145b806107ee57507fffffffff0000000000000000000000000000000000000000000000000000000082167f1a0eb6a500000000000000000000000000000000000000000000000000000000145b806107fd57506107fd82611bbf565b80610671575061067182611c15565b6000805462010000900473ffffffffffffffffffffffffffffffffffffffff16803b156109e0576000808273ffffffffffffffffffffffffffffffffffffffff16631626ba7e60e01b8787604051602401610868929190614284565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516108f19190614268565b600060405180830381855afa9150503d806000811461092c576040519150601f19603f3d011682016040523d82523d6000602084013e610931565b606091505b50915091506000828015610946575081516020145b8015610986575081517f1626ba7e0000000000000000000000000000000000000000000000000000000090610984908401602090810190850161429d565b145b9050806109b3577fffffffff000000000000000000000000000000000000000000000000000000006109d5565b7f1626ba7e000000000000000000000000000000000000000000000000000000005b945050505050610671565b6000806109ed8686611c78565b90925090506000816004811115610a0657610a066142b6565b14610a3757507fffffffff000000000000000000000000000000000000000000000000000000009250610671915050565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614610a90577fffffffff00000000000000000000000000000000000000000000000000000000610ab2565b7f1626ba7e000000000000000000000000000000000000000000000000000000005b9350505050610671565b5092915050565b600080610ad28385018561417b565b915091508573ffffffffffffffffffffffffffffffffffffffff166344c028fe600430600086868b604051602401610b0c939291906142e5565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f4f04d60a000000000000000000000000000000000000000000000000000000001790525160e086901b7fffffffff00000000000000000000000000000000000000000000000000000000168152610bbc949392919060040161435a565b6000604051808303816000875af1158015610bdb573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610c219190810190614395565b50505050505050565b60603415610c6057604051349033907f7e71433ddf847725166244795048ecf3e3f9f35628254ecbf73605666423349390600090a35b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1633819003610c9b57610c9386868686611cbd565b915050610cec565b6000610ca682611e4d565b90506000610cb688888888611cbd565b90508115610ce757610ce78382604051602001610cd39190613fb2565b604051602081830303815290604052612060565b925050505b949350505050565b60603415610d2a57604051349033907f7e71433ddf847725166244795048ecf3e3f9f35628254ecbf73605666423349390600090a35b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1633819003610d5d57610c9386868686612233565b6000610d6882611e4d565b90506000610d7888888888612233565b90508115610ce757610ce78382604051602001610cd3919061401a565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610eba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152606860248201527f556e6976657273616c50726f66696c65496e6974506f73744465706c6f796d6560448201527f6e744d6f64756c653a2073657444617461416e645472616e736665724f776e6560648201527f7273686970206f6e6c7920616c6c6f776564207468726f7567682064656c656760848201527f6174652063616c6c00000000000000000000000000000000000000000000000060a482015260c40161059f565b60005b8351811015610f0a57610f02848281518110610edb57610edb614403565b6020026020010151848381518110610ef557610ef5614403565b60200260200101516123d5565b600101610ebd565b50610f1481612449565b505050565b6060610671826124ef565b60608167ffffffffffffffff811115610f3f57610f3f613ab0565b604051908082528060200260200182016040528015610f7257816020015b6060815260200190600190039081610f5d5790505b50905060005b82811015610abc5760008030868685818110610f9657610f96614403565b9050602002810190610fa89190614432565b604051610fb6929190614497565b600060405180830381855af49150503d8060008114610ff1576040519150601f19603f3d011682016040523d82523d6000602084013e610ff6565b606091505b509150915081611072578051156110105780518082602001fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4c5350303a20626174636843616c6c7320726576657274656400000000000000604482015260640161059f565b8084848151811061108557611085614403565b60209081029190910101525050600101610f78565b606034156110d057604051349033907f7e71433ddf847725166244795048ecf3e3f9f35628254ecbf73605666423349390600090a35b60006110fb7f0cfc51aec37c55a4d0b1a65c6255c4bf2fbdf6277f3cc0730c45b828b6db8b476124ef565b905060606014825110611170576000611113836144a7565b60601c9050611142817f6bb56a1400000000000000000000000000000000000000000000000000000000612591565b1561116e5761116b73ffffffffffffffffffffffffffffffffffffffff82168888883334612660565b91505b505b600061119c7f0cfc51aec37c55a4d0b10000000000000000000000000000000000000000000088612800565b905060006111a9826124ef565b90506060601482511061121e5760006111c1836144a7565b60601c90506111f0817f6bb56a1400000000000000000000000000000000000000000000000000000000612591565b1561121c5761121973ffffffffffffffffffffffffffffffffffffffff82168b8b8b3334612660565b91505b505b83816040516020016112319291906144f7565b604051602081830303815290604052955088343373ffffffffffffffffffffffffffffffffffffffff167f9c3ba68eb5742b8e3961aea0afc7371a71bf433c8a67a831803b64c064a178c28b8b8b60405161128e93929190614565565b60405180910390a450505050509392505050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff16338190036112d4576112d161287c565b50565b60006112df82611e4d565b9050600061130960005473ffffffffffffffffffffffffffffffffffffffff620100009091041690565b905061131361287c565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff16611388576040805160208101909152600081526113889073ffffffffffffffffffffffffffffffffffffffff8316907fa4e59c931d14f7c8a7a35027f92ee40b5f2886b9fdcdb78f30bc5ecce5a2f814906129b8565b8115610f1457610f148360405180602001604052806000815250612060565b60035474010000000000000000000000000000000000000000900460ff16156113fc576040517f5758dd0700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005462010000900473ffffffffffffffffffffffffffffffffffffffff16611423612aa0565b6040805160208101909152600081526114759073ffffffffffffffffffffffffffffffffffffffff8316907fa4e59c931d14f7c8a7a35027f92ee40b5f2886b9fdcdb78f30bc5ecce5a2f814906129b8565b6040805160208101909152600081526112d19033907fceca317f109c43507871523e82dc2a3cc64dfa18f12da0b6db14f6e23f995538906129b8565b34156114e557604051349033907f7e71433ddf847725166244795048ecf3e3f9f35628254ecbf73605666423349390600090a35b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163381900361151657610f1483836123d5565b600061152182611e4d565b905061152d84846123d5565b801561154c5761154c8260405180602001604052806000815250612060565b50505050565b341561158657604051349033907f7e71433ddf847725166244795048ecf3e3f9f35628254ecbf73605666423349390600090a35b80518251146115c1576040517f3bcc897900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005462010000900473ffffffffffffffffffffffffffffffffffffffff16338190036116115760005b835181101561154c57611609848281518110610edb57610edb614403565b6001016115eb565b600061161c82611e4d565b905060005b84518110156116615761165985828151811061163f5761163f614403565b6020026020010151858381518110610ef557610ef5614403565b600101611621565b50801561154c5761154c8260405180602001604052806000815250612060565b600054610100900460ff16158080156116a15750600054600160ff909116105b806116bb5750303b1580156116bb575060005460ff166001145b611747576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161059f565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156117a557600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6117ae82612b7a565b801561181157600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b6060815167ffffffffffffffff81111561183157611831613ab0565b60405190808252806020026020018201604052801561186457816020015b606081526020019060019003908161184f5790505b50905060005b82518110156118ba5761189583828151811061188857611888614403565b60200260200101516124ef565b8282815181106118a7576118a7614403565b602090810291909101015260010161186a565b50919050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1633819003611a0757600380547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000017905561192f82612c7c565b8173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a36040805160208101909152600081526119db9073ffffffffffffffffffffffffffffffffffffffff8416907fe17117c9d2665d1dbeb479ed8058bbebde3c50ac50e2e65619f60006caac6926906129b8565b600380547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690555050565b6000611a1282611e4d565b600380547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790559050611a5c83612c7c565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a3604080516020810190915260008152611b089073ffffffffffffffffffffffffffffffffffffffff8516907fe17117c9d2665d1dbeb479ed8058bbebde3c50ac50e2e65619f60006caac6926906129b8565b600380547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690558015610f1457610f148260405180602001604052806000815250612060565b600080611b9e7fcee78b4094da86011096000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008516612800565b90506000611bab826124ef565b611bb4906144a7565b60601c949350505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167fa918fa6b000000000000000000000000000000000000000000000000000000001480610671575061067182612d17565b600080611c417f01ffc9a700000000000000000000000000000000000000000000000000000000611b4f565b905073ffffffffffffffffffffffffffffffffffffffff8116611c675750600092915050565b611c718184612591565b9392505050565b6000808251604103611cae5760208301516040840151606085015160001a611ca287828585612d6d565b94509450505050611cb6565b506000905060025b9250929050565b606083518551141580611cde575082518451141580611cde57508151835114155b15611d15576040517f3ff55f4d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8451600003611d50576040517fe9ad2b5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000855167ffffffffffffffff811115611d6c57611d6c613ab0565b604051908082528060200260200182016040528015611d9f57816020015b6060815260200190600190039081611d8a5790505b50905060005b8651811015611e4357611e1e878281518110611dc357611dc3614403565b6020026020010151878381518110611ddd57611ddd614403565b6020026020010151878481518110611df757611df7614403565b6020026020010151878581518110611e1157611e11614403565b6020026020010151612233565b828281518110611e3057611e30614403565b6020908102919091010152600101611da5565b5095945050505050565b60008060008373ffffffffffffffffffffffffffffffffffffffff16639bf04b1160e01b3334600036604051602401611e89949392919061458b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051611f129190614268565b6000604051808303816000865af19150503d8060008114611f4f576040519150601f19603f3d011682016040523d82523d6000602084013e611f54565b606091505b5091509150611f6560008383612e5c565b600081806020019051810190611f7b91906145c1565b90507fffffff000000000000000000000000000000000000000000000000000000000081167f9bf04b000000000000000000000000000000000000000000000000000000000014611ffd576000826040517fd088ec4000000000000000000000000000000000000000000000000000000000815260040161059f9291906145de565b7f01000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600383901a60f81b1614612054576000612057565b60015b95945050505050565b6000808373ffffffffffffffffffffffffffffffffffffffff1663d3fc45d360e01b333460003660405160200161209a94939291906145f9565b60405160208183030381529060405280519060200120856040516024016120c2929190614284565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161214b9190614268565b6000604051808303816000865af19150503d8060008114612188576040519150601f19603f3d011682016040523d82523d6000602084013e61218d565b606091505b509150915061219e60018383612e5c565b80517fd3fc45d300000000000000000000000000000000000000000000000000000000906121d590830160209081019084016145c1565b7fffffffff00000000000000000000000000000000000000000000000000000000161461154c576001816040517fd088ec4000000000000000000000000000000000000000000000000000000000815260040161059f9291906145de565b60608461224c57612245848484612ee5565b9050610cec565b600185036122ac5773ffffffffffffffffffffffffffffffffffffffff8416156122a2576040517f3041824a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612245838361305c565b6002850361230c5773ffffffffffffffffffffffffffffffffffffffff841615612302576040517f3041824a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61224583836131d5565b6003850361235657821561234c576040517f72f2bc6a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61224584836132f8565b600485036123a0578215612396576040517f5ac8313500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6122458483613420565b6040517f7583b3bc0000000000000000000000000000000000000000000000000000000081526004810186905260240161059f565b60008281526001602052604090206123ed82826146da565b50817fece574603820d07bc9b91f2a932baadf4628aabcb8afba49776529c14a6104b26101008351111561242e576124298360006101006134fe565b612430565b825b60405161243d919061401a565b60405180910390a25050565b60005473ffffffffffffffffffffffffffffffffffffffff8281166201000090920416146112d1576000805473ffffffffffffffffffffffffffffffffffffffff838116620100008181027fffffffffffffffffffff0000000000000000000000000000000000000000ffff851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b600081815260016020526040902080546060919061250c9061463f565b80601f01602080910402602001604051908101604052809291908181526020018280546125389061463f565b80156125855780601f1061255a57610100808354040283529160200191612585565b820191906000526020600020905b81548152906001019060200180831161256857829003601f168201915b50505050509050919050565b604080517fffffffff000000000000000000000000000000000000000000000000000000008316602480830191909152825180830390910181526044909101909152602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825160009392849283928392918391908a617530fa92503d91506000519050828015612649575060208210155b80156126555750600081115b979650505050505050565b60606000636bb56a1460e01b878787604051602401612681939291906147f4565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909516949094179093525161270e92879187910161480e565b60405160208183030381529060405290506000808973ffffffffffffffffffffffffffffffffffffffff16836040516127479190614268565b6000604051808303816000865af19150503d8060008114612784576040519150601f19603f3d011682016040523d82523d6000602084013e612789565b606091505b50915091506127ce82826040518060400160405280602081526020017f43616c6c20746f20756e6976657273616c5265636569766572206661696c6564815250613678565b5080516000036127de57806127f2565b808060200190518101906127f29190614395565b9a9950505050505050505050565b604080517fffffffffffffffffffff00000000000000000000000000000000000000000000841660208201526000602a82018190527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008416602c83015291829101604051602081830303815290604052905080610cec90614860565b60025443906000906128909060c8906148d1565b9050600061289f60c8836148d1565b9050808311806128af5750600254155b1561290f576002839055600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556040517f81b7f830f1f0084db6497c486cbe6974c86488dcc4e3738eab94ab6d6b1653e790600090a1505050565b81831015612953576040517f8b9bf507000000000000000000000000000000000000000000000000000000008152600481018390526024810182905260440161059f565b61295d6000612449565b60006002819055600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556040517fd1f66c3d2bc1993a86be5e3d33709d98f0442381befcedd29f578b9b2506b1ce9190a1505050565b6129e2837f6bb56a1400000000000000000000000000000000000000000000000000000000612591565b15610f14576040517f6bb56a1400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841690636bb56a1490612a3b9085908590600401614284565b6000604051808303816000875af1158015612a5a573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261154c9190810190614395565b60035473ffffffffffffffffffffffffffffffffffffffff163314612b47576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f4c535031343a2063616c6c6572206973206e6f74207468652070656e64696e6760448201527f4f776e6572000000000000000000000000000000000000000000000000000000606482015260840161059f565b612b5033612449565b600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b600054610100900460ff16612c11576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161059f565b612c1a81613691565b6112d17feafec4d89fa9619884b600005ef83ad9559033e6e941db7d7c495acdce61634760001b6040518060400160405280600481526020017f5ef83ad9000000000000000000000000000000000000000000000000000000008152506123d5565b3073ffffffffffffffffffffffffffffffffffffffff821603612ccb576040517f43b248cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790556000600255565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f629aa694000000000000000000000000000000000000000000000000000000001480610671575061067182613765565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115612da45750600090506003612e53565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015612df8573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff8116612e4c57600060019250925050612e53565b9150600090505b94509492505050565b81612e6b57612e6b83826137fc565b602081511080612eaa575060006020612e8383614860565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000911b1614155b15610f145782816040517fd088ec4000000000000000000000000000000000000000000000000000000000815260040161059f9291906145de565b606082471015612f2a576040517f0df9a8f80000000000000000000000000000000000000000000000000000000081524760048201526024810184905260440161059f565b8273ffffffffffffffffffffffffffffffffffffffff851660007f4810874456b8e6487bd861375cf6abd8e1c8bb5858c8ce36a86a04dabfac199e612f6e866148e4565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390a46000808573ffffffffffffffffffffffffffffffffffffffff168585604051612fcb9190614268565b60006040518083038185875af1925050503d8060008114613008576040519150601f19603f3d011682016040523d82523d6000602084013e61300d565b606091505b509150915061305282826040518060400160405280601681526020017f455243373235583a20556e6b6e6f776e204572726f7200000000000000000000815250613678565b9695505050505050565b6060824710156130a1576040517f0df9a8f80000000000000000000000000000000000000000000000000000000081524760048201526024810184905260440161059f565b81516000036130dc576040517fb81cd8d900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082516020840185f0905073ffffffffffffffffffffffffffffffffffffffff8116613135576040517f0b07489b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b838173ffffffffffffffffffffffffffffffffffffffff1660017fa1fb700aaee2ae4a2ff6f91ce7eba292f89c2f5488b8ec4c5c5c8150692595c36000801b60405161318391815260200190565b60405180910390a46040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606083901b16602082015260340160405160208183030381529060405291505092915050565b60608151600003613212576040517fb81cd8d900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061322b83602085516132269190614930565b613842565b90506000613248846000602087516132439190614930565b6134fe565b905060006132578684846138c2565b9050858173ffffffffffffffffffffffffffffffffffffffff1660027fa1fb700aaee2ae4a2ff6f91ce7eba292f89c2f5488b8ec4c5c5c8150692595c3866040516132a491815260200190565b60405180910390a46040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606083901b166020820152603401604051602081830303815290604052935050505092915050565b6060600073ffffffffffffffffffffffffffffffffffffffff841660037f4810874456b8e6487bd861375cf6abd8e1c8bb5858c8ce36a86a04dabfac199e61333f866148e4565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390a46000808473ffffffffffffffffffffffffffffffffffffffff168460405161339b9190614268565b600060405180830381855afa9150503d80600081146133d6576040519150601f19603f3d011682016040523d82523d6000602084013e6133db565b606091505b509150915061205782826040518060400160405280601681526020017f455243373235583a20556e6b6e6f776e204572726f7200000000000000000000815250613678565b6060600073ffffffffffffffffffffffffffffffffffffffff841660047f4810874456b8e6487bd861375cf6abd8e1c8bb5858c8ce36a86a04dabfac199e613467866148e4565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390a46000808473ffffffffffffffffffffffffffffffffffffffff16846040516134c39190614268565b600060405180830381855af49150503d80600081146133d6576040519150601f19603f3d011682016040523d82523d6000602084013e6133db565b60608161350c81601f6148d1565b1015613574576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015260640161059f565b61357e82846148d1565b845110156135e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f736c6963655f6f75744f66426f756e6473000000000000000000000000000000604482015260640161059f565b606082158015613607576040519150600082526020820160405261366f565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015613640578051835260209283019201613628565b5050858452601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016604052505b50949350505050565b60608315613687575081611c71565b611c718383613a21565b600054610100900460ff16613728576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161059f565b341561375c57604051349033907f7e71433ddf847725166244795048ecf3e3f9f35628254ecbf73605666423349390600090a35b6112d181612449565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7545acac00000000000000000000000000000000000000000000000000000000148061067157507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610671565b80511561380c5780518082602001fd5b6040517f8c6a8ae3000000000000000000000000000000000000000000000000000000008152821515600482015260240161059f565b600061384f8260206148d1565b835110156138b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f746f427974657333325f6f75744f66426f756e64730000000000000000000000604482015260640161059f565b50016020015190565b60008347101561392e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e6365000000604482015260640161059f565b8151600003613999576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f604482015260640161059f565b8282516020840186f5905073ffffffffffffffffffffffffffffffffffffffff8116611c71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f7900000000000000604482015260640161059f565b815115613a315781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161059f919061401a565b7fffffffff00000000000000000000000000000000000000000000000000000000811681146112d157600080fd5b600060208284031215613aa557600080fd5b8135611c7181613a65565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613b2657613b26613ab0565b604052919050565b600067ffffffffffffffff821115613b4857613b48613ab0565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613b8557600080fd5b8135613b98613b9382613b2e565b613adf565b818152846020838601011115613bad57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215613bdd57600080fd5b82359150602083013567ffffffffffffffff811115613bfb57600080fd5b613c0785828601613b74565b9150509250929050565b803573ffffffffffffffffffffffffffffffffffffffff81168114613c3557600080fd5b919050565b60008083601f840112613c4c57600080fd5b50813567ffffffffffffffff811115613c6457600080fd5b602083019150836020828501011115611cb657600080fd5b60008060008060608587031215613c9257600080fd5b613c9b85613c11565b9350613ca960208601613c11565b9250604085013567ffffffffffffffff811115613cc557600080fd5b613cd187828801613c3a565b95989497509550505050565b600067ffffffffffffffff821115613cf757613cf7613ab0565b5060051b60200190565b600082601f830112613d1257600080fd5b81356020613d22613b9383613cdd565b82815260059290921b84018101918181019086841115613d4157600080fd5b8286015b84811015613d5c5780358352918301918301613d45565b509695505050505050565b600082601f830112613d7857600080fd5b81356020613d88613b9383613cdd565b82815260059290921b84018101918181019086841115613da757600080fd5b8286015b84811015613d5c57803567ffffffffffffffff811115613dcb5760008081fd5b613dd98986838b0101613b74565b845250918301918301613dab565b60008060008060808587031215613dfd57600080fd5b843567ffffffffffffffff80821115613e1557600080fd5b613e2188838901613d01565b9550602091508187013581811115613e3857600080fd5b8701601f81018913613e4957600080fd5b8035613e57613b9382613cdd565b81815260059190911b8201840190848101908b831115613e7657600080fd5b928501925b82841015613e9b57613e8c84613c11565b82529285019290850190613e7b565b97505050506040870135915080821115613eb457600080fd5b613ec088838901613d01565b93506060870135915080821115613ed657600080fd5b50613ee387828801613d67565b91505092959194509250565b60005b83811015613f0a578181015183820152602001613ef2565b50506000910152565b60008151808452613f2b816020860160208601613eef565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b85811015613fa5578284038952613f93848351613f13565b98850198935090840190600101613f7b565b5091979650505050505050565b602081526000611c716020830184613f5d565b60008060008060808587031215613fdb57600080fd5b84359350613feb60208601613c11565b925060408501359150606085013567ffffffffffffffff81111561400e57600080fd5b613ee387828801613b74565b602081526000611c716020830184613f13565b60008060006060848603121561404257600080fd5b833567ffffffffffffffff8082111561405a57600080fd5b61406687838801613d01565b9450602086013591508082111561407c57600080fd5b5061408986828701613d67565b92505061409860408501613c11565b90509250925092565b6000602082840312156140b357600080fd5b5035919050565b600080602083850312156140cd57600080fd5b823567ffffffffffffffff808211156140e557600080fd5b818501915085601f8301126140f957600080fd5b81358181111561410857600080fd5b8660208260051b850101111561411d57600080fd5b60209290920196919550909350505050565b60008060006040848603121561414457600080fd5b83359250602084013567ffffffffffffffff81111561416257600080fd5b61416e86828701613c3a565b9497909650939450505050565b6000806040838503121561418e57600080fd5b823567ffffffffffffffff808211156141a657600080fd5b6141b286838701613d01565b935060208501359150808211156141c857600080fd5b50613c0785828601613d67565b6000602082840312156141e757600080fd5b611c7182613c11565b60006020828403121561420257600080fd5b813567ffffffffffffffff81111561421957600080fd5b610cec84828501613d01565b8385823760609290921b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016919092019081526014810191909152603401919050565b6000825161427a818460208701613eef565b9190910192915050565b828152604060208201526000610cec6040830184613f13565b6000602082840312156142af57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b606080825284519082018190526000906020906080840190828801845b8281101561431e57815184529284019290840190600101614302565b505050838103828501526143328187613f5d565b9250505073ffffffffffffffffffffffffffffffffffffffff83166040830152949350505050565b84815273ffffffffffffffffffffffffffffffffffffffff841660208201528260408201526080606082015260006130526080830184613f13565b6000602082840312156143a757600080fd5b815167ffffffffffffffff8111156143be57600080fd5b8201601f810184136143cf57600080fd5b80516143dd613b9382613b2e565b8181528560208385010111156143f257600080fd5b612057826020830160208601613eef565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261446757600080fd5b83018035915067ffffffffffffffff82111561448257600080fd5b602001915036819003821315611cb657600080fd5b8183823760009101908152919050565b6000815160208301517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000808216935060148310156144ef5780818460140360031b1b83161693505b505050919050565b60408152600061450a6040830185613f13565b82810360208401526120578185613f13565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60408152600061457960408301858761451c565b82810360208401526130528185613f13565b73ffffffffffffffffffffffffffffffffffffffff8516815283602082015260606040820152600061305260608301848661451c565b6000602082840312156145d357600080fd5b8151611c7181613a65565b8215158152604060208201526000610cec6040830184613f13565b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008560601b16815283601482015281836034830137600091016034019081529392505050565b600181811c9082168061465357607f821691505b6020821081036118ba577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b601f821115610f1457600081815260208120601f850160051c810160208610156146b35750805b601f850160051c820191505b818110156146d2578281556001016146bf565b505050505050565b815167ffffffffffffffff8111156146f4576146f4613ab0565b61470881614702845461463f565b8461468c565b602080601f83116001811461475b57600084156147255750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556146d2565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156147a857888601518255948401946001909101908401614789565b50858210156147e457878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b83815260406020820152600061205760408301848661451c565b60008451614820818460208901613eef565b60609490941b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001691909301908152601481019190915260340192915050565b805160208083015191908110156118ba577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610671576106716148a2565b6000815160208301517fffffffff00000000000000000000000000000000000000000000000000000000808216935060048310156144ef5760049290920360031b82901b161692915050565b81810381811115610671576106716148a256fea26469706673582212204c716f85d1145bcbe75de9c2eb2914430942e4f65ea5e7afda664b1551460c7f64736f6c63430008110033 +``` + +## Universal Profile Init Post Deployment Module Source Code + +This is an exact copy of the code of the [`UniversalProfileInitPostDeploymentModule` smart contract]. + +- The source code is generated with `solc` compiler version `0.8.17` and with `9999999` optimization runs. +- The imported contracts are part of the `4.9.2` version of the `@openzeppelin/contracts` package. +- Navigate to [lsp-smart-contract](https://github.com/lukso-network/lsp-smart-contracts) repo and checkout to `b8eca3c5696acf85239130ef67edec9e8c134bfa` commit to obtain the exact copy of the code, change the compiler settings in `hardhat.config.ts` and compile to produce the same bytecode. + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +import { OPERATION_4_DELEGATECALL } from "@erc725/smart-contracts/contracts/constants.sol"; + +import { UniversalProfileInit } from "../../UniversalProfileInit.sol"; + +contract UniversalProfileInitPostDeploymentModule is UniversalProfileInit { + constructor() { + _disableInitializers(); + } + + function setDataAndTransferOwnership( + bytes32[] memory dataKeys, + bytes[] memory dataValues, + address newOwner + ) public payable { + // check that the msg.sender is the owner + require( + msg.sender == owner(), + "UniversalProfileInitPostDeploymentModule: setDataAndTransferOwnership only allowed through delegate call" + ); + + // update the dataKeys and dataValues in the UniversalProfile contract + for (uint256 i = 0; i < dataKeys.length; ) { + _setData(dataKeys[i], dataValues[i]); + + unchecked { + ++i; + } + } + + // transfer the ownership of the UniversalProfile contract to the newOwner + _setOwner(newOwner); + } + + function executePostDeployment( + address universalProfile, + address keyManager, + bytes calldata setDataBatchBytes + ) public { + // retrieve the dataKeys and dataValues to setData from the initializationCalldata bytes + (bytes32[] memory dataKeys, bytes[] memory dataValues) = abi.decode( + setDataBatchBytes, + (bytes32[], bytes[]) + ); + + // call the execute function with delegate_call on the universalProfile contract to setData and transferOwnership + UniversalProfileInit(payable(universalProfile)).execute( + OPERATION_4_DELEGATECALL, + address(this), + 0, + abi.encodeWithSignature( + "setDataAndTransferOwnership(bytes32[],bytes[],address)", + dataKeys, + dataValues, + keyManager + ) + ); + } +} +``` diff --git a/contracts/LSP23LinkedContractsFactory/modules/deployment-UP-module.md b/contracts/LSP23LinkedContractsFactory/modules/deployment-UP-module.md new file mode 100644 index 000000000..d046f4a4a --- /dev/null +++ b/contracts/LSP23LinkedContractsFactory/modules/deployment-UP-module.md @@ -0,0 +1,90 @@ +# Setup + +Before the deployment of the `UniversalProfilePostDeploymentModule` on any network, people should make sure that the [Nick's Factory contract](https://github.com/Arachnid/deterministic-deployment-proxy/tree/master) is deployed on the same network. +You also need to make sure that the LSP23 Linked Contracts Factory is deployed on the same network. Please refer to [LSP23 Linked Contracts Deployment Factory LIP](https://github.com/lukso-network/LIPs/LSPs/LSP-23-LinkedContractsFactory.md#lsp23linkedcontractsfactory-deployment) in order to deploy it. + +# Deployment of the Universal Profile Post Deployment Module + +## Standardized Address + +`0x0000005aD606bcFEF9Ea6D0BbE5b79847054BcD7` + +## Standardized Salt + +`0x42ff55d7957589c62da54a4368b10a2bc549f2038bbb6880ec6b3e0ecae2ba58 ` + +## Standardized Bytecode + +```solidity +0x60806040523480156200001157600080fd5b5060008034156200004a57604051349033907f7e71433ddf847725166244795048ecf3e3f9f35628254ecbf73605666423349390600090a35b6200006081620000b060201b620019381760201c565b506040805180820190915260048152635ef83ad960e01b6020820152620000a9907feafec4d89fa9619884b600005ef83ad9559033e6e941db7d7c495acdce6163479062000117565b50620004a4565b6000546001600160a01b038281169116146200011457600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a3505b50565b600082815260016020526040902062000131828262000360565b50817fece574603820d07bc9b91f2a932baadf4628aabcb8afba49776529c14a6104b26101008351111562000181576200017b8360006101006200019e60201b620019cf1760201c565b62000183565b825b6040516200019291906200042c565b60405180910390a25050565b606081620001ae81601f6200047c565b1015620001f35760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b60448201526064015b60405180910390fd5b620001ff82846200047c565b84511015620002455760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401620001ea565b606082158015620002665760405191506000825260208201604052620002b2565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015620002a157805183526020928301920162000287565b5050858452601f01601f1916604052505b50949350505050565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620002e657607f821691505b6020821081036200030757634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200035b57600081815260208120601f850160051c81016020861015620003365750805b601f850160051c820191505b81811015620003575782815560010162000342565b5050505b505050565b81516001600160401b038111156200037c576200037c620002bb565b62000394816200038d8454620002d1565b846200030d565b602080601f831160018114620003cc5760008415620003b35750858301515b600019600386901b1c1916600185901b17855562000357565b600085815260208120601f198616915b82811015620003fd57888601518255948401946001909101908401620003dc565b50858210156200041c5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208083528351808285015260005b818110156200045b578581018301518582016040015282016200043d565b506000604082860101526040601f19601f8301168501019250505092915050565b808201808211156200049e57634e487b7160e01b600052601160045260246000fd5b92915050565b61457880620004b46000396000f3fe6080604052600436106101485760003560e01c80636bb56a14116100c05780639790242111610074578063e30c397811610059578063e30c39781461041d578063ead3fbdf146101f2578063f2fde38b1461044857610183565b806397902421146103ea578063dedff9c6146103fd57610183565b806379ba5097116100a557806379ba5097146103765780637f23690c1461038b5780638da5cb5b1461039e57610183565b80636bb56a141461034e578063715018a61461036157610183565b806331858452116101175780634f04d60a116100fc5780634f04d60a146102fb57806354f6127f1461030e5780636963d4381461032e57610183565b806331858452146102bb57806344c028fe146102db57610183565b806301bfba61146101f257806301ffc9a71461021a5780631626ba7e1461024a57806328c4d14e1461029b57610183565b3661018357341561018157604051349033907f7e71433ddf847725166244795048ecf3e3f9f35628254ecbf73605666423349390600090a35b005b600036606034156101bc57604051349033907f7e71433ddf847725166244795048ecf3e3f9f35628254ecbf73605666423349390600090a35b60043610156101da57506040805160208101909152600081526101e7565b6101e48383610468565b90505b915050805190602001f35b3480156101fe57600080fd5b5061020760c881565b6040519081526020015b60405180910390f35b34801561022657600080fd5b5061023a610235366004613692565b610643565b6040519015158152602001610211565b34801561025657600080fd5b5061026a6102653660046137c9565b6107d8565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610211565b3480156102a757600080fd5b506101816102b636600461387b565b610aa9565b6102ce6102c93660046139e6565b610c10565b6040516102119190613bb1565b6102ee6102e9366004613bc4565b610cd4565b6040516102119190613c19565b610181610309366004613c2c565b610d6f565b34801561031a57600080fd5b506102ee610329366004613ca0565b610ec1565b34801561033a57600080fd5b506102ce610349366004613cb9565b610ecc565b6102ee61035c366004613d2e565b611042565b34801561036d57600080fd5b5061018161124a565b34801561038257600080fd5b5061018161133c565b6101816103993660046137c9565b611440565b3480156103aa57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610211565b6101816103f8366004613d7a565b6114db565b34801561040957600080fd5b506102ce610418366004613dd4565b611604565b34801561042957600080fd5b5060035473ffffffffffffffffffffffffffffffffffffffff166103c5565b34801561045457600080fd5b50610181610463366004613e09565b6116af565b606060006104996000357fffffffff0000000000000000000000000000000000000000000000000000000016611b4b565b90506000357fffffffff00000000000000000000000000000000000000000000000000000000161580156104e1575073ffffffffffffffffffffffffffffffffffffffff8116155b156104fc57505060408051602081019091526000815261063d565b73ffffffffffffffffffffffffffffffffffffffff8116610574576040517fbb370b2b0000000000000000000000000000000000000000000000000000000081527fffffffff000000000000000000000000000000000000000000000000000000006000351660048201526024015b60405180910390fd5b6000808273ffffffffffffffffffffffffffffffffffffffff16868633346040516020016105a59493929190613e24565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526105dd91613e67565b6000604051808303816000865af19150503d806000811461061a576040519150601f19603f3d011682016040523d82523d6000602084013e61061f565b606091505b5091509150811561063457925061063d915050565b80518060208301fd5b92915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f1626ba7e0000000000000000000000000000000000000000000000000000000014806106d657507fffffffff0000000000000000000000000000000000000000000000000000000082167f24871b3d00000000000000000000000000000000000000000000000000000000145b8061072257507fffffffff0000000000000000000000000000000000000000000000000000000082167f6bb56a1400000000000000000000000000000000000000000000000000000000145b8061076e57507fffffffff0000000000000000000000000000000000000000000000000000000082167f94be599900000000000000000000000000000000000000000000000000000000145b806107ba57507fffffffff0000000000000000000000000000000000000000000000000000000082167f1a0eb6a500000000000000000000000000000000000000000000000000000000145b806107c957506107c982611bbb565b8061063d575061063d82611c11565b6000806107fa60005473ffffffffffffffffffffffffffffffffffffffff1690565b905073ffffffffffffffffffffffffffffffffffffffff81163b156109c6576000808273ffffffffffffffffffffffffffffffffffffffff16631626ba7e60e01b878760405160240161084e929190613e83565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516108d79190613e67565b600060405180830381855afa9150503d8060008114610912576040519150601f19603f3d011682016040523d82523d6000602084013e610917565b606091505b5091509150600082801561092c575081516020145b801561096c575081517f1626ba7e000000000000000000000000000000000000000000000000000000009061096a9084016020908101908501613e9c565b145b905080610999577fffffffff000000000000000000000000000000000000000000000000000000006109bb565b7f1626ba7e000000000000000000000000000000000000000000000000000000005b94505050505061063d565b6000806109d38686611c6d565b909250905060008160048111156109ec576109ec613eb5565b14610a1d57507fffffffff00000000000000000000000000000000000000000000000000000000925061063d915050565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614610a76577fffffffff00000000000000000000000000000000000000000000000000000000610a98565b7f1626ba7e000000000000000000000000000000000000000000000000000000005b935050505061063d565b5092915050565b600080610ab883850185613d7a565b915091508573ffffffffffffffffffffffffffffffffffffffff166344c028fe600430600086868b604051602401610af293929190613ee4565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f4f04d60a000000000000000000000000000000000000000000000000000000001790525160e086901b7fffffffff00000000000000000000000000000000000000000000000000000000168152610ba29493929190600401613f59565b6000604051808303816000875af1158015610bc1573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610c079190810190613f94565b50505050505050565b60603415610c4657604051349033907f7e71433ddf847725166244795048ecf3e3f9f35628254ecbf73605666423349390600090a35b60005473ffffffffffffffffffffffffffffffffffffffff1633819003610c7b57610c7386868686611cb2565b915050610ccc565b6000610c8682611e42565b90506000610c9688888888611cb2565b90508115610cc757610cc78382604051602001610cb39190613bb1565b604051602081830303815290604052612055565b925050505b949350505050565b60603415610d0a57604051349033907f7e71433ddf847725166244795048ecf3e3f9f35628254ecbf73605666423349390600090a35b60005473ffffffffffffffffffffffffffffffffffffffff1633819003610d3757610c7386868686612228565b6000610d4282611e42565b90506000610d5288888888612228565b90508115610cc757610cc78382604051602001610cb39190613c19565b60005473ffffffffffffffffffffffffffffffffffffffff163314610e62576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152606860248201527f556e6976657273616c50726f66696c65496e6974506f73744465706c6f796d6560448201527f6e744d6f64756c653a2073657444617461416e645472616e736665724f776e6560648201527f7273686970206f6e6c7920616c6c6f776564207468726f7567682064656c656760848201527f6174652063616c6c00000000000000000000000000000000000000000000000060a482015260c40161056b565b60005b8351811015610eb257610eaa848281518110610e8357610e83614002565b6020026020010151848381518110610e9d57610e9d614002565b60200260200101516123ca565b600101610e65565b50610ebc81611938565b505050565b606061063d8261243e565b60608167ffffffffffffffff811115610ee757610ee76136af565b604051908082528060200260200182016040528015610f1a57816020015b6060815260200190600190039081610f055790505b50905060005b82811015610aa25760008030868685818110610f3e57610f3e614002565b9050602002810190610f509190614031565b604051610f5e929190614096565b600060405180830381855af49150503d8060008114610f99576040519150601f19603f3d011682016040523d82523d6000602084013e610f9e565b606091505b50915091508161101a57805115610fb85780518082602001fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4c5350303a20626174636843616c6c7320726576657274656400000000000000604482015260640161056b565b8084848151811061102d5761102d614002565b60209081029190910101525050600101610f20565b6060341561107857604051349033907f7e71433ddf847725166244795048ecf3e3f9f35628254ecbf73605666423349390600090a35b60006110a37f0cfc51aec37c55a4d0b1a65c6255c4bf2fbdf6277f3cc0730c45b828b6db8b4761243e565b9050606060148251106111185760006110bb836140a6565b60601c90506110ea817f6bb56a14000000000000000000000000000000000000000000000000000000006124e0565b156111165761111373ffffffffffffffffffffffffffffffffffffffff821688888833346125af565b91505b505b60006111447f0cfc51aec37c55a4d0b1000000000000000000000000000000000000000000008861274f565b905060006111518261243e565b9050606060148251106111c6576000611169836140a6565b60601c9050611198817f6bb56a14000000000000000000000000000000000000000000000000000000006124e0565b156111c4576111c173ffffffffffffffffffffffffffffffffffffffff82168b8b8b33346125af565b91505b505b83816040516020016111d99291906140f6565b604051602081830303815290604052955088343373ffffffffffffffffffffffffffffffffffffffff167f9c3ba68eb5742b8e3961aea0afc7371a71bf433c8a67a831803b64c064a178c28b8b8b60405161123693929190614164565b60405180910390a450505050509392505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633819003611276576112736127cb565b50565b600061128182611e42565b905060006112a460005473ffffffffffffffffffffffffffffffffffffffff1690565b90506112ae6127cb565b60005473ffffffffffffffffffffffffffffffffffffffff1661131d5760408051602081019091526000815261131d9073ffffffffffffffffffffffffffffffffffffffff8316907fa4e59c931d14f7c8a7a35027f92ee40b5f2886b9fdcdb78f30bc5ecce5a2f81490612907565b8115610ebc57610ebc8360405180602001604052806000815250612055565b60035474010000000000000000000000000000000000000000900460ff1615611391576040517f5758dd0700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005473ffffffffffffffffffffffffffffffffffffffff166113b26129ef565b6040805160208101909152600081526114049073ffffffffffffffffffffffffffffffffffffffff8316907fa4e59c931d14f7c8a7a35027f92ee40b5f2886b9fdcdb78f30bc5ecce5a2f81490612907565b6040805160208101909152600081526112739033907fceca317f109c43507871523e82dc2a3cc64dfa18f12da0b6db14f6e23f99553890612907565b341561147457604051349033907f7e71433ddf847725166244795048ecf3e3f9f35628254ecbf73605666423349390600090a35b60005473ffffffffffffffffffffffffffffffffffffffff163381900361149f57610ebc83836123ca565b60006114aa82611e42565b90506114b684846123ca565b80156114d5576114d58260405180602001604052806000815250612055565b50505050565b341561150f57604051349033907f7e71433ddf847725166244795048ecf3e3f9f35628254ecbf73605666423349390600090a35b805182511461154a576040517f3bcc897900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005473ffffffffffffffffffffffffffffffffffffffff16338190036115945760005b83518110156114d55761158c848281518110610e8357610e83614002565b60010161156e565b600061159f82611e42565b905060005b84518110156115e4576115dc8582815181106115c2576115c2614002565b6020026020010151858381518110610e9d57610e9d614002565b6001016115a4565b5080156114d5576114d58260405180602001604052806000815250612055565b6060815167ffffffffffffffff811115611620576116206136af565b60405190808252806020026020018201604052801561165357816020015b606081526020019060019003908161163e5790505b50905060005b82518110156116a95761168483828151811061167757611677614002565b602002602001015161243e565b82828151811061169657611696614002565b6020908102919091010152600101611659565b50919050565b60005473ffffffffffffffffffffffffffffffffffffffff16338190036117f057600380547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000017905561171882612ac9565b8173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a36040805160208101909152600081526117c49073ffffffffffffffffffffffffffffffffffffffff8416907fe17117c9d2665d1dbeb479ed8058bbebde3c50ac50e2e65619f60006caac692690612907565b600380547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690555050565b60006117fb82611e42565b600380547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055905061184583612ac9565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a36040805160208101909152600081526118f19073ffffffffffffffffffffffffffffffffffffffff8516907fe17117c9d2665d1dbeb479ed8058bbebde3c50ac50e2e65619f60006caac692690612907565b600380547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690558015610ebc57610ebc8260405180602001604052806000815250612055565b60005473ffffffffffffffffffffffffffffffffffffffff828116911614611273576000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6060816119dd81601f6141b9565b1015611a45576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015260640161056b565b611a4f82846141b9565b84511015611ab9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f736c6963655f6f75744f66426f756e6473000000000000000000000000000000604482015260640161056b565b606082158015611ad85760405191506000825260208201604052611b40565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015611b11578051835260209283019201611af9565b5050858452601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016604052505b5090505b9392505050565b600080611b9a7fcee78b4094da86011096000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000851661274f565b90506000611ba78261243e565b611bb0906140a6565b60601c949350505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167fa918fa6b00000000000000000000000000000000000000000000000000000000148061063d575061063d82612b64565b600080611c3d7f01ffc9a700000000000000000000000000000000000000000000000000000000611b4b565b905073ffffffffffffffffffffffffffffffffffffffff8116611c635750600092915050565b611b4481846124e0565b6000808251604103611ca35760208301516040840151606085015160001a611c9787828585612bba565b94509450505050611cab565b506000905060025b9250929050565b606083518551141580611cd3575082518451141580611cd357508151835114155b15611d0a576040517f3ff55f4d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8451600003611d45576040517fe9ad2b5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000855167ffffffffffffffff811115611d6157611d616136af565b604051908082528060200260200182016040528015611d9457816020015b6060815260200190600190039081611d7f5790505b50905060005b8651811015611e3857611e13878281518110611db857611db8614002565b6020026020010151878381518110611dd257611dd2614002565b6020026020010151878481518110611dec57611dec614002565b6020026020010151878581518110611e0657611e06614002565b6020026020010151612228565b828281518110611e2557611e25614002565b6020908102919091010152600101611d9a565b5095945050505050565b60008060008373ffffffffffffffffffffffffffffffffffffffff16639bf04b1160e01b3334600036604051602401611e7e94939291906141cc565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051611f079190613e67565b6000604051808303816000865af19150503d8060008114611f44576040519150601f19603f3d011682016040523d82523d6000602084013e611f49565b606091505b5091509150611f5a60008383612ca9565b600081806020019051810190611f709190614202565b90507fffffff000000000000000000000000000000000000000000000000000000000081167f9bf04b000000000000000000000000000000000000000000000000000000000014611ff2576000826040517fd088ec4000000000000000000000000000000000000000000000000000000000815260040161056b92919061421f565b7f01000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600383901a60f81b161461204957600061204c565b60015b95945050505050565b6000808373ffffffffffffffffffffffffffffffffffffffff1663d3fc45d360e01b333460003660405160200161208f949392919061423a565b60405160208183030381529060405280519060200120856040516024016120b7929190613e83565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516121409190613e67565b6000604051808303816000865af19150503d806000811461217d576040519150601f19603f3d011682016040523d82523d6000602084013e612182565b606091505b509150915061219360018383612ca9565b80517fd3fc45d300000000000000000000000000000000000000000000000000000000906121ca9083016020908101908401614202565b7fffffffff0000000000000000000000000000000000000000000000000000000016146114d5576001816040517fd088ec4000000000000000000000000000000000000000000000000000000000815260040161056b92919061421f565b6060846122415761223a848484612d32565b9050610ccc565b600185036122a15773ffffffffffffffffffffffffffffffffffffffff841615612297576040517f3041824a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61223a8383612ea9565b600285036123015773ffffffffffffffffffffffffffffffffffffffff8416156122f7576040517f3041824a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61223a8383613022565b6003850361234b578215612341576040517f72f2bc6a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61223a8483613145565b6004850361239557821561238b576040517f5ac8313500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61223a848361326d565b6040517f7583b3bc0000000000000000000000000000000000000000000000000000000081526004810186905260240161056b565b60008281526001602052604090206123e2828261431b565b50817fece574603820d07bc9b91f2a932baadf4628aabcb8afba49776529c14a6104b2610100835111156124235761241e8360006101006119cf565b612425565b825b6040516124329190613c19565b60405180910390a25050565b600081815260016020526040902080546060919061245b90614280565b80601f016020809104026020016040519081016040528092919081815260200182805461248790614280565b80156124d45780601f106124a9576101008083540402835291602001916124d4565b820191906000526020600020905b8154815290600101906020018083116124b757829003601f168201915b50505050509050919050565b604080517fffffffff000000000000000000000000000000000000000000000000000000008316602480830191909152825180830390910181526044909101909152602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825160009392849283928392918391908a617530fa92503d91506000519050828015612598575060208210155b80156125a45750600081115b979650505050505050565b60606000636bb56a1460e01b8787876040516024016125d093929190614435565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909516949094179093525161265d92879187910161444f565b60405160208183030381529060405290506000808973ffffffffffffffffffffffffffffffffffffffff16836040516126969190613e67565b6000604051808303816000865af19150503d80600081146126d3576040519150601f19603f3d011682016040523d82523d6000602084013e6126d8565b606091505b509150915061271d82826040518060400160405280602081526020017f43616c6c20746f20756e6976657273616c5265636569766572206661696c656481525061334b565b50805160000361272d5780612741565b808060200190518101906127419190613f94565b9a9950505050505050505050565b604080517fffffffffffffffffffff00000000000000000000000000000000000000000000841660208201526000602a82018190527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008416602c83015291829101604051602081830303815290604052905080610ccc906144a1565b60025443906000906127df9060c8906141b9565b905060006127ee60c8836141b9565b9050808311806127fe5750600254155b1561285e576002839055600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556040517f81b7f830f1f0084db6497c486cbe6974c86488dcc4e3738eab94ab6d6b1653e790600090a1505050565b818310156128a2576040517f8b9bf507000000000000000000000000000000000000000000000000000000008152600481018390526024810182905260440161056b565b6128ac6000611938565b60006002819055600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556040517fd1f66c3d2bc1993a86be5e3d33709d98f0442381befcedd29f578b9b2506b1ce9190a1505050565b612931837f6bb56a14000000000000000000000000000000000000000000000000000000006124e0565b15610ebc576040517f6bb56a1400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841690636bb56a149061298a9085908590600401613e83565b6000604051808303816000875af11580156129a9573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526114d59190810190613f94565b60035473ffffffffffffffffffffffffffffffffffffffff163314612a96576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f4c535031343a2063616c6c6572206973206e6f74207468652070656e64696e6760448201527f4f776e6572000000000000000000000000000000000000000000000000000000606482015260840161056b565b612a9f33611938565b600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b3073ffffffffffffffffffffffffffffffffffffffff821603612b18576040517f43b248cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790556000600255565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f629aa69400000000000000000000000000000000000000000000000000000000148061063d575061063d82613364565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115612bf15750600090506003612ca0565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015612c45573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff8116612c9957600060019250925050612ca0565b9150600090505b94509492505050565b81612cb857612cb883826133fb565b602081511080612cf7575060006020612cd0836144a1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000911b1614155b15610ebc5782816040517fd088ec4000000000000000000000000000000000000000000000000000000000815260040161056b92919061421f565b606082471015612d77576040517f0df9a8f80000000000000000000000000000000000000000000000000000000081524760048201526024810184905260440161056b565b8273ffffffffffffffffffffffffffffffffffffffff851660007f4810874456b8e6487bd861375cf6abd8e1c8bb5858c8ce36a86a04dabfac199e612dbb866144e3565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390a46000808573ffffffffffffffffffffffffffffffffffffffff168585604051612e189190613e67565b60006040518083038185875af1925050503d8060008114612e55576040519150601f19603f3d011682016040523d82523d6000602084013e612e5a565b606091505b5091509150612e9f82826040518060400160405280601681526020017f455243373235583a20556e6b6e6f776e204572726f720000000000000000000081525061334b565b9695505050505050565b606082471015612eee576040517f0df9a8f80000000000000000000000000000000000000000000000000000000081524760048201526024810184905260440161056b565b8151600003612f29576040517fb81cd8d900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082516020840185f0905073ffffffffffffffffffffffffffffffffffffffff8116612f82576040517f0b07489b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b838173ffffffffffffffffffffffffffffffffffffffff1660017fa1fb700aaee2ae4a2ff6f91ce7eba292f89c2f5488b8ec4c5c5c8150692595c36000801b604051612fd091815260200190565b60405180910390a46040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606083901b16602082015260340160405160208183030381529060405291505092915050565b6060815160000361305f576040517fb81cd8d900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006130788360208551613073919061452f565b613441565b9050600061309584600060208751613090919061452f565b6119cf565b905060006130a48684846134c1565b9050858173ffffffffffffffffffffffffffffffffffffffff1660027fa1fb700aaee2ae4a2ff6f91ce7eba292f89c2f5488b8ec4c5c5c8150692595c3866040516130f191815260200190565b60405180910390a46040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606083901b166020820152603401604051602081830303815290604052935050505092915050565b6060600073ffffffffffffffffffffffffffffffffffffffff841660037f4810874456b8e6487bd861375cf6abd8e1c8bb5858c8ce36a86a04dabfac199e61318c866144e3565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390a46000808473ffffffffffffffffffffffffffffffffffffffff16846040516131e89190613e67565b600060405180830381855afa9150503d8060008114613223576040519150601f19603f3d011682016040523d82523d6000602084013e613228565b606091505b509150915061204c82826040518060400160405280601681526020017f455243373235583a20556e6b6e6f776e204572726f720000000000000000000081525061334b565b6060600073ffffffffffffffffffffffffffffffffffffffff841660047f4810874456b8e6487bd861375cf6abd8e1c8bb5858c8ce36a86a04dabfac199e6132b4866144e3565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390a46000808473ffffffffffffffffffffffffffffffffffffffff16846040516133109190613e67565b600060405180830381855af49150503d8060008114613223576040519150601f19603f3d011682016040523d82523d6000602084013e613228565b6060831561335a575081611b44565b611b448383613620565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7545acac00000000000000000000000000000000000000000000000000000000148061063d57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161461063d565b80511561340b5780518082602001fd5b6040517f8c6a8ae3000000000000000000000000000000000000000000000000000000008152821515600482015260240161056b565b600061344e8260206141b9565b835110156134b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f746f427974657333325f6f75744f66426f756e64730000000000000000000000604482015260640161056b565b50016020015190565b60008347101561352d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e6365000000604482015260640161056b565b8151600003613598576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f604482015260640161056b565b8282516020840186f5905073ffffffffffffffffffffffffffffffffffffffff8116611b44576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f7900000000000000604482015260640161056b565b8151156136305781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161056b9190613c19565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461127357600080fd5b6000602082840312156136a457600080fd5b8135611b4481613664565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613725576137256136af565b604052919050565b600067ffffffffffffffff821115613747576137476136af565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261378457600080fd5b81356137976137928261372d565b6136de565b8181528460208386010111156137ac57600080fd5b816020850160208301376000918101602001919091529392505050565b600080604083850312156137dc57600080fd5b82359150602083013567ffffffffffffffff8111156137fa57600080fd5b61380685828601613773565b9150509250929050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461383457600080fd5b919050565b60008083601f84011261384b57600080fd5b50813567ffffffffffffffff81111561386357600080fd5b602083019150836020828501011115611cab57600080fd5b6000806000806060858703121561389157600080fd5b61389a85613810565b93506138a860208601613810565b9250604085013567ffffffffffffffff8111156138c457600080fd5b6138d087828801613839565b95989497509550505050565b600067ffffffffffffffff8211156138f6576138f66136af565b5060051b60200190565b600082601f83011261391157600080fd5b81356020613921613792836138dc565b82815260059290921b8401810191818101908684111561394057600080fd5b8286015b8481101561395b5780358352918301918301613944565b509695505050505050565b600082601f83011261397757600080fd5b81356020613987613792836138dc565b82815260059290921b840181019181810190868411156139a657600080fd5b8286015b8481101561395b57803567ffffffffffffffff8111156139ca5760008081fd5b6139d88986838b0101613773565b8452509183019183016139aa565b600080600080608085870312156139fc57600080fd5b843567ffffffffffffffff80821115613a1457600080fd5b613a2088838901613900565b9550602091508187013581811115613a3757600080fd5b8701601f81018913613a4857600080fd5b8035613a56613792826138dc565b81815260059190911b8201840190848101908b831115613a7557600080fd5b928501925b82841015613a9a57613a8b84613810565b82529285019290850190613a7a565b97505050506040870135915080821115613ab357600080fd5b613abf88838901613900565b93506060870135915080821115613ad557600080fd5b50613ae287828801613966565b91505092959194509250565b60005b83811015613b09578181015183820152602001613af1565b50506000910152565b60008151808452613b2a816020860160208601613aee565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b85811015613ba4578284038952613b92848351613b12565b98850198935090840190600101613b7a565b5091979650505050505050565b602081526000611b446020830184613b5c565b60008060008060808587031215613bda57600080fd5b84359350613bea60208601613810565b925060408501359150606085013567ffffffffffffffff811115613c0d57600080fd5b613ae287828801613773565b602081526000611b446020830184613b12565b600080600060608486031215613c4157600080fd5b833567ffffffffffffffff80821115613c5957600080fd5b613c6587838801613900565b94506020860135915080821115613c7b57600080fd5b50613c8886828701613966565b925050613c9760408501613810565b90509250925092565b600060208284031215613cb257600080fd5b5035919050565b60008060208385031215613ccc57600080fd5b823567ffffffffffffffff80821115613ce457600080fd5b818501915085601f830112613cf857600080fd5b813581811115613d0757600080fd5b8660208260051b8501011115613d1c57600080fd5b60209290920196919550909350505050565b600080600060408486031215613d4357600080fd5b83359250602084013567ffffffffffffffff811115613d6157600080fd5b613d6d86828701613839565b9497909650939450505050565b60008060408385031215613d8d57600080fd5b823567ffffffffffffffff80821115613da557600080fd5b613db186838701613900565b93506020850135915080821115613dc757600080fd5b5061380685828601613966565b600060208284031215613de657600080fd5b813567ffffffffffffffff811115613dfd57600080fd5b610ccc84828501613900565b600060208284031215613e1b57600080fd5b611b4482613810565b8385823760609290921b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016919092019081526014810191909152603401919050565b60008251613e79818460208701613aee565b9190910192915050565b828152604060208201526000610ccc6040830184613b12565b600060208284031215613eae57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b606080825284519082018190526000906020906080840190828801845b82811015613f1d57815184529284019290840190600101613f01565b50505083810382850152613f318187613b5c565b9250505073ffffffffffffffffffffffffffffffffffffffff83166040830152949350505050565b84815273ffffffffffffffffffffffffffffffffffffffff84166020820152826040820152608060608201526000612e9f6080830184613b12565b600060208284031215613fa657600080fd5b815167ffffffffffffffff811115613fbd57600080fd5b8201601f81018413613fce57600080fd5b8051613fdc6137928261372d565b818152856020838501011115613ff157600080fd5b61204c826020830160208601613aee565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261406657600080fd5b83018035915067ffffffffffffffff82111561408157600080fd5b602001915036819003821315611cab57600080fd5b8183823760009101908152919050565b6000815160208301517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000808216935060148310156140ee5780818460140360031b1b83161693505b505050919050565b6040815260006141096040830185613b12565b828103602084015261204c8185613b12565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60408152600061417860408301858761411b565b8281036020840152612e9f8185613b12565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561063d5761063d61418a565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201526000612e9f60608301848661411b565b60006020828403121561421457600080fd5b8151611b4481613664565b8215158152604060208201526000610ccc6040830184613b12565b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008560601b16815283601482015281836034830137600091016034019081529392505050565b600181811c9082168061429457607f821691505b6020821081036116a9577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b601f821115610ebc57600081815260208120601f850160051c810160208610156142f45750805b601f850160051c820191505b8181101561431357828155600101614300565b505050505050565b815167ffffffffffffffff811115614335576143356136af565b614349816143438454614280565b846142cd565b602080601f83116001811461439c57600084156143665750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555614313565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156143e9578886015182559484019460019091019084016143ca565b508582101561442557878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b83815260406020820152600061204c60408301848661411b565b60008451614461818460208901613aee565b60609490941b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001691909301908152601481019190915260340192915050565b805160208083015191908110156116a9577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b6000815160208301517fffffffff00000000000000000000000000000000000000000000000000000000808216935060048310156140ee5760049290920360031b82901b161692915050565b8181038181111561063d5761063d61418a56fea2646970667358221220709024acd2bc0a3533c747974ab8f11d519f7708b55eb0107adc4574f225e7d964736f6c63430008110033 +``` + +## Universal Profile Post Deployment Module Source Code + +This is an exact copy of the code of the [`UniversalProfilePostDeploymentModule` smart contract]. + +- The source code is generated with `solc` compiler version `0.8.17` and with `9999999` optimization runs. +- The imported contracts are part of the `4.9.2` version of the `@openzeppelin/contracts` package. +- Navigate to [lsp-smart-contract](https://github.com/lukso-network/lsp-smart-contracts) repo and checkout to `b8eca3c5696acf85239130ef67edec9e8c134bfa` commit to obtain the exact copy of the code, change the compiler settings in `hardhat.config.ts` and compile to produce the same bytecode. + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +import { OPERATION_4_DELEGATECALL } from "@erc725/smart-contracts/contracts/constants.sol"; + +import { UniversalProfile } from "../../UniversalProfile.sol"; + +contract UniversalProfilePostDeploymentModule is UniversalProfile { + constructor() UniversalProfile(address(0)) {} + + function setDataAndTransferOwnership( + bytes32[] memory dataKeys, + bytes[] memory dataValues, + address newOwner + ) public payable { + // check that the msg.sender is the owner + require( + msg.sender == owner(), + "UniversalProfilePostDeploymentModule: setDataAndTransferOwnership only allowed through delegate call" + ); + + // update the dataKeys and dataValues in the UniversalProfile contract + for (uint256 i = 0; i < dataKeys.length; ) { + _setData(dataKeys[i], dataValues[i]); + + unchecked { + ++i; + } + } + + // transfer the ownership of the UniversalProfile contract to the newOwner + _setOwner(newOwner); + } + + function executePostDeployment( + address universalProfile, + address keyManager, + bytes calldata setDataBatchBytes + ) public { + // retrieve the dataKeys and dataValues to setData from the initializationCalldata bytes + (bytes32[] memory dataKeys, bytes[] memory dataValues) = abi.decode( + setDataBatchBytes, + (bytes32[], bytes[]) + ); + + // call the execute function with delegate_call on the universalProfile contract to setData and transferOwnership + UniversalProfile(payable(universalProfile)).execute( + OPERATION_4_DELEGATECALL, + address(this), + 0, + abi.encodeWithSignature( + "setDataAndTransferOwnership(bytes32[],bytes[],address)", + dataKeys, + dataValues, + keyManager + ) + ); + } +} +``` From c2f1f4f9278e0a0a5db99abab155597926784522 Mon Sep 17 00:00:00 2001 From: "b00ste.lyx" <62855857+b00ste@users.noreply.github.com> Date: Wed, 13 Sep 2023 17:28:18 +0300 Subject: [PATCH 04/55] chore: update CI to check for difs when generating docs (#694) * chore: update CI * chore: update package scripts * chore: bump `@b00ste/hardhat-dodoc` version * chore: update dodoc template * docs: update ABI docs --- .github/workflows/build-lint-test.yml | 11 ++ docs/contracts/ERC725/ERC725.md | 2 +- .../LSP16UniversalFactory.md | 2 +- .../IPostDeploymentModule.md | 8 +- .../LSP23LinkedContractsFactory.md | 132 ++++++++++-------- .../LSP6KeyManager/LSP6KeyManager.md | 2 +- .../LSP7DigitalAsset/LSP7DigitalAsset.md | 36 ++--- .../extensions/LSP7Burnable.md | 36 ++--- .../extensions/LSP7CappedSupply.md | 36 ++--- .../extensions/LSP7CompatibleERC20.md | 75 ++++++---- .../presets/LSP7CompatibleERC20Mintable.md | 77 ++++++---- .../LSP7DigitalAsset/presets/LSP7Mintable.md | 38 ++--- .../extensions/LSP8CompatibleERC721.md | 45 ++++-- .../presets/LSP8CompatibleERC721Mintable.md | 47 +++++-- .../presets/LSP8Mintable.md | 2 +- dodoc/config.ts | 4 +- dodoc/template.sqrl | 4 +- package-lock.json | 18 +-- package.json | 5 +- 19 files changed, 356 insertions(+), 224 deletions(-) rename docs/contracts/{LSP23LinkedContractsDeployment => LSP23LinkedContractsFactory}/IPostDeploymentModule.md (80%) rename docs/contracts/{LSP23LinkedContractsDeployment => LSP23LinkedContractsFactory}/LSP23LinkedContractsFactory.md (61%) diff --git a/.github/workflows/build-lint-test.yml b/.github/workflows/build-lint-test.yml index 223d60b02..887607dfc 100644 --- a/.github/workflows/build-lint-test.yml +++ b/.github/workflows/build-lint-test.yml @@ -44,6 +44,17 @@ jobs: - name: 🧪 run import/requires tests run: npm run test:importRequire + - name: 📚 generate ABI docs + run: npm run build:docs + + - name: 🔍 check if ABI auto-generated docs need to be updated + run: |- + if [[ $(git diff --name-only) != "" ]]; + then + echo "Error: Please generate ABI docs after making changes to Solidity code and Natspec comments!" + exit 1 + fi + test-suites: strategy: matrix: diff --git a/docs/contracts/ERC725/ERC725.md b/docs/contracts/ERC725/ERC725.md index 3b4365ec0..ebd40e6f9 100644 --- a/docs/contracts/ERC725/ERC725.md +++ b/docs/contracts/ERC725/ERC725.md @@ -716,7 +716,7 @@ event ContractCreated(uint256 indexed operationType, address indexed contractAdd _Deployed new contract at address `contractAddress` and funded with `value` wei (deployed using opcode: `operationType`)._ -Emitted whenever a contract is created +Emitted when a new contract was created and deployed. #### Parameters diff --git a/docs/contracts/LSP16UniversalFactory/LSP16UniversalFactory.md b/docs/contracts/LSP16UniversalFactory/LSP16UniversalFactory.md index 48044bfd4..5b8d86c50 100644 --- a/docs/contracts/LSP16UniversalFactory/LSP16UniversalFactory.md +++ b/docs/contracts/LSP16UniversalFactory/LSP16UniversalFactory.md @@ -342,7 +342,7 @@ Bubble the revert reason if present, revert with `ContractInitializationFailed` event ContractCreated(address indexed contractCreated, bytes32 indexed providedSalt, bytes32 generatedSalt, bool indexed initialized, bytes initializeCalldata); ``` -Emitted when a new contract was created and deployed. +Emitted whenever a contract is created #### Parameters diff --git a/docs/contracts/LSP23LinkedContractsDeployment/IPostDeploymentModule.md b/docs/contracts/LSP23LinkedContractsFactory/IPostDeploymentModule.md similarity index 80% rename from docs/contracts/LSP23LinkedContractsDeployment/IPostDeploymentModule.md rename to docs/contracts/LSP23LinkedContractsFactory/IPostDeploymentModule.md index dbb425ddc..c9efd3a70 100644 --- a/docs/contracts/LSP23LinkedContractsDeployment/IPostDeploymentModule.md +++ b/docs/contracts/LSP23LinkedContractsFactory/IPostDeploymentModule.md @@ -5,12 +5,12 @@ :::info Standard Specifications -[`LSP-23-LinkedContractsDeployment`](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsDeployment.md) +[`LSP-23-LinkedContractsFactory`](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsFactory.md) ::: :::info Solidity implementation -[`IPostDeploymentModule.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsDeployment/IPostDeploymentModule.sol) +[`IPostDeploymentModule.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsFactory/IPostDeploymentModule.sol) ::: @@ -23,8 +23,8 @@ When marked as 'public', a method can be called both externally and internally, :::note References -- Specification details: [**LSP-23-LinkedContractsDeployment**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsDeployment.md#executepostdeployment) -- Solidity implementation: [`IPostDeploymentModule.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsDeployment/IPostDeploymentModule.sol) +- Specification details: [**LSP-23-LinkedContractsFactory**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsFactory.md#executepostdeployment) +- Solidity implementation: [`IPostDeploymentModule.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsFactory/IPostDeploymentModule.sol) - Function signature: `executePostDeployment(address,address,bytes)` - Function selector: `0x28c4d14e` diff --git a/docs/contracts/LSP23LinkedContractsDeployment/LSP23LinkedContractsFactory.md b/docs/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.md similarity index 61% rename from docs/contracts/LSP23LinkedContractsDeployment/LSP23LinkedContractsFactory.md rename to docs/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.md index f95f1949f..1eab86124 100644 --- a/docs/contracts/LSP23LinkedContractsDeployment/LSP23LinkedContractsFactory.md +++ b/docs/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.md @@ -5,12 +5,12 @@ :::info Standard Specifications -[`LSP-23-LinkedContractsDeployment`](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsDeployment.md) +[`LSP-23-LinkedContractsFactory`](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsFactory.md) ::: :::info Solidity implementation -[`LSP23LinkedContractsFactory.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsDeployment/LSP23LinkedContractsFactory.sol) +[`LSP23LinkedContractsFactory.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol) ::: @@ -23,8 +23,8 @@ When marked as 'public', a method can be called both externally and internally, :::note References -- Specification details: [**LSP-23-LinkedContractsDeployment**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsDeployment.md#computeaddresses) -- Solidity implementation: [`LSP23LinkedContractsFactory.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsDeployment/LSP23LinkedContractsFactory.sol) +- Specification details: [**LSP-23-LinkedContractsFactory**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsFactory.md#computeaddresses) +- Solidity implementation: [`LSP23LinkedContractsFactory.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol) - Function signature: `computeAddresses(ILSP23LinkedContractsFactory.PrimaryContractDeployment,ILSP23LinkedContractsFactory.SecondaryContractDeployment,address,bytes)` - Function selector: `0xdecfb0b9` @@ -42,21 +42,23 @@ function computeAddresses( returns (address primaryContractAddress, address secondaryContractAddress); ``` +Computes the addresses of a primary contract and a secondary linked contract + #### Parameters -| Name | Type | Description | -| ------------------------------ | :--------------------------------------------------------: | ----------- | -| `primaryContractDeployment` | `ILSP23LinkedContractsFactory.PrimaryContractDeployment` | - | -| `secondaryContractDeployment` | `ILSP23LinkedContractsFactory.SecondaryContractDeployment` | - | -| `postDeploymentModule` | `address` | - | -| `postDeploymentModuleCalldata` | `bytes` | - | +| Name | Type | Description | +| ------------------------------ | :--------------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `primaryContractDeployment` | `ILSP23LinkedContractsFactory.PrimaryContractDeployment` | Contains the needed parameter to deploy the primary contract. (`salt`, `fundingAmount`, `creationBytecode`) | +| `secondaryContractDeployment` | `ILSP23LinkedContractsFactory.SecondaryContractDeployment` | Contains the needed parameter to deploy the secondary contract. (`fundingAmount`, `creationBytecode`, `addPrimaryContractAddress`, `extraConstructorParams`) | +| `postDeploymentModule` | `address` | The optional module to be executed after deployment | +| `postDeploymentModuleCalldata` | `bytes` | The data to be passed to the post deployment module | #### Returns -| Name | Type | Description | -| -------------------------- | :-------: | ----------- | -| `primaryContractAddress` | `address` | - | -| `secondaryContractAddress` | `address` | - | +| Name | Type | Description | +| -------------------------- | :-------: | ----------------------------------------------- | +| `primaryContractAddress` | `address` | The address of the deployed primary contract. | +| `secondaryContractAddress` | `address` | The address of the deployed secondary contract. |
@@ -64,8 +66,8 @@ function computeAddresses( :::note References -- Specification details: [**LSP-23-LinkedContractsDeployment**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsDeployment.md#computeerc1167addresses) -- Solidity implementation: [`LSP23LinkedContractsFactory.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsDeployment/LSP23LinkedContractsFactory.sol) +- Specification details: [**LSP-23-LinkedContractsFactory**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsFactory.md#computeerc1167addresses) +- Solidity implementation: [`LSP23LinkedContractsFactory.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol) - Function signature: `computeERC1167Addresses(ILSP23LinkedContractsFactory.PrimaryContractDeploymentInit,ILSP23LinkedContractsFactory.SecondaryContractDeploymentInit,address,bytes)` - Function selector: `0x8da85898` @@ -83,21 +85,23 @@ function computeERC1167Addresses( returns (address primaryContractAddress, address secondaryContractAddress); ``` +Computes the addresses of a primary and a secondary linked contracts ERC1167 proxies to be created + #### Parameters -| Name | Type | Description | -| --------------------------------- | :------------------------------------------------------------: | ----------- | -| `primaryContractDeploymentInit` | `ILSP23LinkedContractsFactory.PrimaryContractDeploymentInit` | - | -| `secondaryContractDeploymentInit` | `ILSP23LinkedContractsFactory.SecondaryContractDeploymentInit` | - | -| `postDeploymentModule` | `address` | - | -| `postDeploymentModuleCalldata` | `bytes` | - | +| Name | Type | Description | +| --------------------------------- | :------------------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `primaryContractDeploymentInit` | `ILSP23LinkedContractsFactory.PrimaryContractDeploymentInit` | Contains the needed parameters to deploy a primary proxy contract. (`salt`, `fundingAmount`, `implementationContract`, `initializationCalldata`) | +| `secondaryContractDeploymentInit` | `ILSP23LinkedContractsFactory.SecondaryContractDeploymentInit` | Contains the needed parameters to deploy the secondary proxy contract. (`fundingAmount`, `implementationContract`, `initializationCalldata`, `addPrimaryContractAddress`, `extraInitializationParams`) | +| `postDeploymentModule` | `address` | The optional module to be executed after deployment. | +| `postDeploymentModuleCalldata` | `bytes` | The data to be passed to the post deployment module. | #### Returns -| Name | Type | Description | -| -------------------------- | :-------: | ----------- | -| `primaryContractAddress` | `address` | - | -| `secondaryContractAddress` | `address` | - | +| Name | Type | Description | +| -------------------------- | :-------: | ---------------------------------------------------- | +| `primaryContractAddress` | `address` | The address of the deployed primary contract proxy | +| `secondaryContractAddress` | `address` | The address of the deployed secondary contract proxy |
@@ -105,8 +109,8 @@ function computeERC1167Addresses( :::note References -- Specification details: [**LSP-23-LinkedContractsDeployment**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsDeployment.md#deploycontracts) -- Solidity implementation: [`LSP23LinkedContractsFactory.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsDeployment/LSP23LinkedContractsFactory.sol) +- Specification details: [**LSP-23-LinkedContractsFactory**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsFactory.md#deploycontracts) +- Solidity implementation: [`LSP23LinkedContractsFactory.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol) - Function signature: `deployContracts(ILSP23LinkedContractsFactory.PrimaryContractDeployment,ILSP23LinkedContractsFactory.SecondaryContractDeployment,address,bytes)` - Function selector: `0xf830c0ab` @@ -124,21 +128,25 @@ function deployContracts( returns (address primaryContractAddress, address secondaryContractAddress); ``` +_Contracts deployed. Contract Address: `primaryContractAddress`. Primary Contract Address: `primaryContractAddress`_ + +Deploys a primary and a secondary linked contract. + #### Parameters -| Name | Type | Description | -| ------------------------------ | :--------------------------------------------------------: | ----------- | -| `primaryContractDeployment` | `ILSP23LinkedContractsFactory.PrimaryContractDeployment` | - | -| `secondaryContractDeployment` | `ILSP23LinkedContractsFactory.SecondaryContractDeployment` | - | -| `postDeploymentModule` | `address` | - | -| `postDeploymentModuleCalldata` | `bytes` | - | +| Name | Type | Description | +| ------------------------------ | :--------------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `primaryContractDeployment` | `ILSP23LinkedContractsFactory.PrimaryContractDeployment` | Contains the needed parameter to deploy a contract. (`salt`, `fundingAmount`, `creationBytecode`) | +| `secondaryContractDeployment` | `ILSP23LinkedContractsFactory.SecondaryContractDeployment` | Contains the needed parameter to deploy the secondary contract. (`fundingAmount`, `creationBytecode`, `addPrimaryContractAddress`, `extraConstructorParams`) | +| `postDeploymentModule` | `address` | The optional module to be executed after deployment | +| `postDeploymentModuleCalldata` | `bytes` | The data to be passed to the post deployment module | #### Returns -| Name | Type | Description | -| -------------------------- | :-------: | ----------- | -| `primaryContractAddress` | `address` | - | -| `secondaryContractAddress` | `address` | - | +| Name | Type | Description | +| -------------------------- | :-------: | -------------------------------------- | +| `primaryContractAddress` | `address` | The address of the primary contract. | +| `secondaryContractAddress` | `address` | The address of the secondary contract. |
@@ -146,8 +154,8 @@ function deployContracts( :::note References -- Specification details: [**LSP-23-LinkedContractsDeployment**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsDeployment.md#deployerc1167proxies) -- Solidity implementation: [`LSP23LinkedContractsFactory.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsDeployment/LSP23LinkedContractsFactory.sol) +- Specification details: [**LSP-23-LinkedContractsFactory**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsFactory.md#deployerc1167proxies) +- Solidity implementation: [`LSP23LinkedContractsFactory.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol) - Function signature: `deployERC1167Proxies(ILSP23LinkedContractsFactory.PrimaryContractDeploymentInit,ILSP23LinkedContractsFactory.SecondaryContractDeploymentInit,address,bytes)` - Function selector: `0x17c042c4` @@ -165,21 +173,25 @@ function deployERC1167Proxies( returns (address primaryContractAddress, address secondaryContractAddress); ``` +_Contract proxies deployed. Primary Proxy Address: `primaryContractAddress`. Secondary Contract Proxy Address: `secondaryContractAddress`_ + +Deploys ERC1167 proxies of a primary contract and a secondary linked contract + #### Parameters -| Name | Type | Description | -| --------------------------------- | :------------------------------------------------------------: | ----------- | -| `primaryContractDeploymentInit` | `ILSP23LinkedContractsFactory.PrimaryContractDeploymentInit` | - | -| `secondaryContractDeploymentInit` | `ILSP23LinkedContractsFactory.SecondaryContractDeploymentInit` | - | -| `postDeploymentModule` | `address` | - | -| `postDeploymentModuleCalldata` | `bytes` | - | +| Name | Type | Description | +| --------------------------------- | :------------------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `primaryContractDeploymentInit` | `ILSP23LinkedContractsFactory.PrimaryContractDeploymentInit` | Contains the needed parameters to deploy a proxy contract. (`salt`, `fundingAmount`, `implementationContract`, `initializationCalldata`) | +| `secondaryContractDeploymentInit` | `ILSP23LinkedContractsFactory.SecondaryContractDeploymentInit` | Contains the needed parameters to deploy the secondary proxy contract. (`fundingAmount`, `implementationContract`, `initializationCalldata`, `addPrimaryContractAddress`, `extraInitializationParams`) | +| `postDeploymentModule` | `address` | The optional module to be executed after deployment. | +| `postDeploymentModuleCalldata` | `bytes` | The data to be passed to the post deployment module. | #### Returns -| Name | Type | Description | -| -------------------------- | :-------: | ----------- | -| `primaryContractAddress` | `address` | - | -| `secondaryContractAddress` | `address` | - | +| Name | Type | Description | +| -------------------------- | :-------: | ---------------------------------------------------- | +| `primaryContractAddress` | `address` | The address of the deployed primary contract proxy | +| `secondaryContractAddress` | `address` | The address of the deployed secondary contract proxy |
@@ -243,8 +255,8 @@ function _generatePrimaryContractProxySalt(struct ILSP23LinkedContractsFactory.P :::note References -- Specification details: [**LSP-23-LinkedContractsDeployment**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsDeployment.md#deployedcontracts) -- Solidity implementation: [`LSP23LinkedContractsFactory.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsDeployment/LSP23LinkedContractsFactory.sol) +- Specification details: [**LSP-23-LinkedContractsFactory**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsFactory.md#deployedcontracts) +- Solidity implementation: [`LSP23LinkedContractsFactory.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol) - Event signature: `DeployedContracts(address,address,ILSP23LinkedContractsFactory.PrimaryContractDeployment,ILSP23LinkedContractsFactory.SecondaryContractDeployment,address,bytes)` - Event topic hash: `0x1ea27dabd8fd1508e844ab51c2fd3d9081f2684346857f9187da6d4a1aa7d3e6` @@ -273,8 +285,8 @@ Emitted when a primary and secondary contract are deployed. :::note References -- Specification details: [**LSP-23-LinkedContractsDeployment**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsDeployment.md#deployederc1167proxies) -- Solidity implementation: [`LSP23LinkedContractsFactory.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsDeployment/LSP23LinkedContractsFactory.sol) +- Specification details: [**LSP-23-LinkedContractsFactory**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsFactory.md#deployederc1167proxies) +- Solidity implementation: [`LSP23LinkedContractsFactory.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol) - Event signature: `DeployedERC1167Proxies(address,address,ILSP23LinkedContractsFactory.PrimaryContractDeploymentInit,ILSP23LinkedContractsFactory.SecondaryContractDeploymentInit,address,bytes)` - Event topic hash: `0xb03dbe7a02c063899f863d542410b5b038c8f537045be3a26e7144e0074e1c7b` @@ -305,8 +317,8 @@ Emitted when proxies of a primary and secondary contract are deployed. :::note References -- Specification details: [**LSP-23-LinkedContractsDeployment**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsDeployment.md#invalidvaluesum) -- Solidity implementation: [`LSP23LinkedContractsFactory.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsDeployment/LSP23LinkedContractsFactory.sol) +- Specification details: [**LSP-23-LinkedContractsFactory**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsFactory.md#invalidvaluesum) +- Solidity implementation: [`LSP23LinkedContractsFactory.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol) - Error signature: `InvalidValueSum()` - Error hash: `0x2fd9ca91` @@ -326,8 +338,8 @@ Reverts when the `msg.value` sent is not equal to the sum of value used for the :::note References -- Specification details: [**LSP-23-LinkedContractsDeployment**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsDeployment.md#primarycontractproxyinitfailureerror) -- Solidity implementation: [`LSP23LinkedContractsFactory.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsDeployment/LSP23LinkedContractsFactory.sol) +- Specification details: [**LSP-23-LinkedContractsFactory**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsFactory.md#primarycontractproxyinitfailureerror) +- Solidity implementation: [`LSP23LinkedContractsFactory.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol) - Error signature: `PrimaryContractProxyInitFailureError(bytes)` - Error hash: `0x4364b6ee` @@ -353,8 +365,8 @@ Reverts when the deployment & intialization of the contract has failed. :::note References -- Specification details: [**LSP-23-LinkedContractsDeployment**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsDeployment.md#secondarycontractproxyinitfailureerror) -- Solidity implementation: [`LSP23LinkedContractsFactory.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsDeployment/LSP23LinkedContractsFactory.sol) +- Specification details: [**LSP-23-LinkedContractsFactory**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-23-LinkedContractsFactory.md#secondarycontractproxyinitfailureerror) +- Solidity implementation: [`LSP23LinkedContractsFactory.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol) - Error signature: `SecondaryContractProxyInitFailureError(bytes)` - Error hash: `0x9654a854` diff --git a/docs/contracts/LSP6KeyManager/LSP6KeyManager.md b/docs/contracts/LSP6KeyManager/LSP6KeyManager.md index f48c54779..621dc560d 100644 --- a/docs/contracts/LSP6KeyManager/LSP6KeyManager.md +++ b/docs/contracts/LSP6KeyManager/LSP6KeyManager.md @@ -36,7 +36,7 @@ When marked as 'public', a method can be called both externally and internally, constructor(address target_); ``` -_Deploying a LSP6KeyManager linked to the contract at address `target_`.\_ +_Deploying a LSP6KeyManager linked to the contract at address `target_`._ Deploy a Key Manager and set the `target_` address in the contract storage, making this Key Manager linked to this `target_` contract. diff --git a/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md b/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md index 6c62e8c45..6f2fc0e21 100644 --- a/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md +++ b/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md @@ -1070,14 +1070,14 @@ Otherwise, the codes after \_fallbackLSP17Extendable() may never be reached. event AuthorizedOperator(address indexed operator, address indexed tokenOwner, uint256 indexed amount, bytes operatorNotificationData); ``` -Emitted when `tokenOwner` enables `operator` to transfer or burn the `tokenId`. +Emitted when `tokenOwner` enables `operator` for `amount` tokens. #### Parameters | Name | Type | Description | | -------------------------- | :-------: | ----------------------------------------------------------------------- | -| `operator` **`indexed`** | `address` | The address authorized as an operator. | -| `tokenOwner` **`indexed`** | `address` | The owner of the `tokenId`. | +| `operator` **`indexed`** | `address` | The address authorized as an operator | +| `tokenOwner` **`indexed`** | `address` | The token owner | | `amount` **`indexed`** | `uint256` | The amount of tokens `operator` address has access to from `tokenOwner` | | `operatorNotificationData` | `bytes` | The data to notify the operator about via LSP1. | @@ -1150,15 +1150,15 @@ event OwnershipTransferred(address indexed previousOwner, address indexed newOwn event RevokedOperator(address indexed operator, address indexed tokenOwner, bytes operatorNotificationData); ``` -Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on its behalf. +Emitted when `tokenOwner` disables `operator` for `amount` tokens and set its [`authorizedAmountFor(...)`](#`authorizedamountfor) to `0`. #### Parameters -| Name | Type | Description | -| -------------------------- | :-------: | --------------------------------------------------------------- | -| `operator` **`indexed`** | `address` | The address revoked from the operator array ({getOperatorsOf}). | -| `tokenOwner` **`indexed`** | `address` | The owner of the `tokenId`. | -| `operatorNotificationData` | `bytes` | The data to notify the operator about via LSP1. | +| Name | Type | Description | +| -------------------------- | :-------: | ----------------------------------------------- | +| `operator` **`indexed`** | `address` | The address revoked from operating | +| `tokenOwner` **`indexed`** | `address` | The token owner | +| `operatorNotificationData` | `bytes` | The data to notify the operator about via LSP1. |
@@ -1177,18 +1177,18 @@ Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on i event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool allowNonLSP1Recipient, bytes data); ``` -Emitted when `tokenId` token is transferred from the `from` to the `to` address. +Emitted when the `from` transferred successfully `amount` of tokens to `to`. #### Parameters -| Name | Type | Description | -| ------------------------ | :-------: | ---------------------------------------------------------------------------------------------------------------------------------- | -| `operator` **`indexed`** | `address` | The address of operator that sent the `tokenId` | -| `from` **`indexed`** | `address` | The previous owner of the `tokenId` | -| `to` **`indexed`** | `address` | The new owner of `tokenId` | -| `amount` | `uint256` | The amount of tokens transferred. | -| `allowNonLSP1Recipient` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | -| `data` | `bytes` | Any additional data the caller included by the caller during the transfer, and sent in the hooks to the `from` and `to` addresses. | +| Name | Type | Description | +| ------------------------ | :-------: | ---------------------------------------------------------------------------------------------------------------------------- | +| `operator` **`indexed`** | `address` | The address of the operator that executed the transfer. | +| `from` **`indexed`** | `address` | The address which tokens were sent from (balance decreased by `-amount`). | +| `to` **`indexed`** | `address` | The address that received the tokens (balance increased by `+amount`). | +| `amount` | `uint256` | The amount of tokens transferred. | +| `allowNonLSP1Recipient` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `data` | `bytes` | Any additional data included by the caller during the transfer, and sent in the LSP1 hooks to the `from` and `to` addresses. |
diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md index 7322b5e9e..cbd5d9599 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md @@ -1095,14 +1095,14 @@ Otherwise, the codes after \_fallbackLSP17Extendable() may never be reached. event AuthorizedOperator(address indexed operator, address indexed tokenOwner, uint256 indexed amount, bytes operatorNotificationData); ``` -Emitted when `tokenOwner` enables `operator` to transfer or burn the `tokenId`. +Emitted when `tokenOwner` enables `operator` for `amount` tokens. #### Parameters | Name | Type | Description | | -------------------------- | :-------: | ----------------------------------------------------------------------- | -| `operator` **`indexed`** | `address` | The address authorized as an operator. | -| `tokenOwner` **`indexed`** | `address` | The owner of the `tokenId`. | +| `operator` **`indexed`** | `address` | The address authorized as an operator | +| `tokenOwner` **`indexed`** | `address` | The token owner | | `amount` **`indexed`** | `uint256` | The amount of tokens `operator` address has access to from `tokenOwner` | | `operatorNotificationData` | `bytes` | The data to notify the operator about via LSP1. | @@ -1175,15 +1175,15 @@ event OwnershipTransferred(address indexed previousOwner, address indexed newOwn event RevokedOperator(address indexed operator, address indexed tokenOwner, bytes operatorNotificationData); ``` -Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on its behalf. +Emitted when `tokenOwner` disables `operator` for `amount` tokens and set its [`authorizedAmountFor(...)`](#`authorizedamountfor) to `0`. #### Parameters -| Name | Type | Description | -| -------------------------- | :-------: | --------------------------------------------------------------- | -| `operator` **`indexed`** | `address` | The address revoked from the operator array ({getOperatorsOf}). | -| `tokenOwner` **`indexed`** | `address` | The owner of the `tokenId`. | -| `operatorNotificationData` | `bytes` | The data to notify the operator about via LSP1. | +| Name | Type | Description | +| -------------------------- | :-------: | ----------------------------------------------- | +| `operator` **`indexed`** | `address` | The address revoked from operating | +| `tokenOwner` **`indexed`** | `address` | The token owner | +| `operatorNotificationData` | `bytes` | The data to notify the operator about via LSP1. |
@@ -1202,18 +1202,18 @@ Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on i event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool allowNonLSP1Recipient, bytes data); ``` -Emitted when `tokenId` token is transferred from the `from` to the `to` address. +Emitted when the `from` transferred successfully `amount` of tokens to `to`. #### Parameters -| Name | Type | Description | -| ------------------------ | :-------: | ---------------------------------------------------------------------------------------------------------------------------------- | -| `operator` **`indexed`** | `address` | The address of operator that sent the `tokenId` | -| `from` **`indexed`** | `address` | The previous owner of the `tokenId` | -| `to` **`indexed`** | `address` | The new owner of `tokenId` | -| `amount` | `uint256` | The amount of tokens transferred. | -| `allowNonLSP1Recipient` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | -| `data` | `bytes` | Any additional data the caller included by the caller during the transfer, and sent in the hooks to the `from` and `to` addresses. | +| Name | Type | Description | +| ------------------------ | :-------: | ---------------------------------------------------------------------------------------------------------------------------- | +| `operator` **`indexed`** | `address` | The address of the operator that executed the transfer. | +| `from` **`indexed`** | `address` | The address which tokens were sent from (balance decreased by `-amount`). | +| `to` **`indexed`** | `address` | The address that received the tokens (balance increased by `+amount`). | +| `amount` | `uint256` | The amount of tokens transferred. | +| `allowNonLSP1Recipient` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `data` | `bytes` | Any additional data included by the caller during the transfer, and sent in the LSP1 hooks to the `from` and `to` addresses. |
diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md index 6d94cff7f..503d783e2 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md @@ -1079,14 +1079,14 @@ Otherwise, the codes after \_fallbackLSP17Extendable() may never be reached. event AuthorizedOperator(address indexed operator, address indexed tokenOwner, uint256 indexed amount, bytes operatorNotificationData); ``` -Emitted when `tokenOwner` enables `operator` to transfer or burn the `tokenId`. +Emitted when `tokenOwner` enables `operator` for `amount` tokens. #### Parameters | Name | Type | Description | | -------------------------- | :-------: | ----------------------------------------------------------------------- | -| `operator` **`indexed`** | `address` | The address authorized as an operator. | -| `tokenOwner` **`indexed`** | `address` | The owner of the `tokenId`. | +| `operator` **`indexed`** | `address` | The address authorized as an operator | +| `tokenOwner` **`indexed`** | `address` | The token owner | | `amount` **`indexed`** | `uint256` | The amount of tokens `operator` address has access to from `tokenOwner` | | `operatorNotificationData` | `bytes` | The data to notify the operator about via LSP1. | @@ -1159,15 +1159,15 @@ event OwnershipTransferred(address indexed previousOwner, address indexed newOwn event RevokedOperator(address indexed operator, address indexed tokenOwner, bytes operatorNotificationData); ``` -Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on its behalf. +Emitted when `tokenOwner` disables `operator` for `amount` tokens and set its [`authorizedAmountFor(...)`](#`authorizedamountfor) to `0`. #### Parameters -| Name | Type | Description | -| -------------------------- | :-------: | --------------------------------------------------------------- | -| `operator` **`indexed`** | `address` | The address revoked from the operator array ({getOperatorsOf}). | -| `tokenOwner` **`indexed`** | `address` | The owner of the `tokenId`. | -| `operatorNotificationData` | `bytes` | The data to notify the operator about via LSP1. | +| Name | Type | Description | +| -------------------------- | :-------: | ----------------------------------------------- | +| `operator` **`indexed`** | `address` | The address revoked from operating | +| `tokenOwner` **`indexed`** | `address` | The token owner | +| `operatorNotificationData` | `bytes` | The data to notify the operator about via LSP1. |
@@ -1186,18 +1186,18 @@ Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on i event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool allowNonLSP1Recipient, bytes data); ``` -Emitted when `tokenId` token is transferred from the `from` to the `to` address. +Emitted when the `from` transferred successfully `amount` of tokens to `to`. #### Parameters -| Name | Type | Description | -| ------------------------ | :-------: | ---------------------------------------------------------------------------------------------------------------------------------- | -| `operator` **`indexed`** | `address` | The address of operator that sent the `tokenId` | -| `from` **`indexed`** | `address` | The previous owner of the `tokenId` | -| `to` **`indexed`** | `address` | The new owner of `tokenId` | -| `amount` | `uint256` | The amount of tokens transferred. | -| `allowNonLSP1Recipient` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | -| `data` | `bytes` | Any additional data the caller included by the caller during the transfer, and sent in the hooks to the `from` and `to` addresses. | +| Name | Type | Description | +| ------------------------ | :-------: | ---------------------------------------------------------------------------------------------------------------------------- | +| `operator` **`indexed`** | `address` | The address of the operator that executed the transfer. | +| `from` **`indexed`** | `address` | The address which tokens were sent from (balance decreased by `-amount`). | +| `to` **`indexed`** | `address` | The address that received the tokens (balance increased by `+amount`). | +| `amount` | `uint256` | The amount of tokens transferred. | +| `allowNonLSP1Recipient` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `data` | `bytes` | Any additional data included by the caller during the transfer, and sent in the LSP1 hooks to the `from` and `to` addresses. |
diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md index 1a9e37e4f..bff5340d0 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md @@ -1186,15 +1186,15 @@ Otherwise, the codes after \_fallbackLSP17Extendable() may never be reached. event Approval(address indexed owner, address indexed spender, uint256 value); ``` -ERC721 `Approval` event emitted when `owner` enables `operator` for `tokenId`. To provide compatibility with indexing ERC721 events. +Emitted when the allowance of a `spender` for an `owner` is set by a call to [`approve`](#approve). `value` is the new allowance. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ------------------------------------------ | -| `owner` **`indexed`** | `address` | The address of the owner of the `tokenId`. | -| `spender` **`indexed`** | `address` | - | -| `value` | `uint256` | - | +| Name | Type | Description | +| ----------------------- | :-------: | --------------------------------------------------------- | +| `owner` **`indexed`** | `address` | The account giving approval | +| `spender` **`indexed`** | `address` | The account receiving approval | +| `value` | `uint256` | The amount of tokens `spender` has access to from `owner` |
@@ -1213,14 +1213,14 @@ ERC721 `Approval` event emitted when `owner` enables `operator` for `tokenId`. T event AuthorizedOperator(address indexed operator, address indexed tokenOwner, uint256 indexed amount, bytes operatorNotificationData); ``` -Emitted when `tokenOwner` enables `operator` to transfer or burn the `tokenId`. +Emitted when `tokenOwner` enables `operator` for `amount` tokens. #### Parameters | Name | Type | Description | | -------------------------- | :-------: | ----------------------------------------------------------------------- | -| `operator` **`indexed`** | `address` | The address authorized as an operator. | -| `tokenOwner` **`indexed`** | `address` | The owner of the `tokenId`. | +| `operator` **`indexed`** | `address` | The address authorized as an operator | +| `tokenOwner` **`indexed`** | `address` | The token owner | | `amount` **`indexed`** | `uint256` | The amount of tokens `operator` address has access to from `tokenOwner` | | `operatorNotificationData` | `bytes` | The data to notify the operator about via LSP1. | @@ -1293,15 +1293,42 @@ event OwnershipTransferred(address indexed previousOwner, address indexed newOwn event RevokedOperator(address indexed operator, address indexed tokenOwner, bytes operatorNotificationData); ``` -Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on its behalf. +Emitted when `tokenOwner` disables `operator` for `amount` tokens and set its [`authorizedAmountFor(...)`](#`authorizedamountfor) to `0`. #### Parameters -| Name | Type | Description | -| -------------------------- | :-------: | --------------------------------------------------------------- | -| `operator` **`indexed`** | `address` | The address revoked from the operator array ({getOperatorsOf}). | -| `tokenOwner` **`indexed`** | `address` | The owner of the `tokenId`. | -| `operatorNotificationData` | `bytes` | The data to notify the operator about via LSP1. | +| Name | Type | Description | +| -------------------------- | :-------: | ----------------------------------------------- | +| `operator` **`indexed`** | `address` | The address revoked from operating | +| `tokenOwner` **`indexed`** | `address` | The token owner | +| `operatorNotificationData` | `bytes` | The data to notify the operator about via LSP1. | + +
+ +### Transfer + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#transfer) +- Solidity implementation: [`LSP7CompatibleERC20.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol) +- Event signature: `Transfer(address,address,uint256)` +- Event topic hash: `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` + +::: + +```solidity +event Transfer(address indexed from, address indexed to, uint256 value); +``` + +Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero. + +#### Parameters + +| Name | Type | Description | +| -------------------- | :-------: | -------------------------------- | +| `from` **`indexed`** | `address` | The sending address | +| `to` **`indexed`** | `address` | The receiving address | +| `value` | `uint256` | The amount of tokens transfered. |
@@ -1320,18 +1347,18 @@ Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on i event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool allowNonLSP1Recipient, bytes data); ``` -Emitted when `tokenId` token is transferred from the `from` to the `to` address. +Emitted when the `from` transferred successfully `amount` of tokens to `to`. #### Parameters -| Name | Type | Description | -| ------------------------ | :-------: | ---------------------------------------------------------------------------------------------------------------------------------- | -| `operator` **`indexed`** | `address` | The address of operator that sent the `tokenId` | -| `from` **`indexed`** | `address` | The previous owner of the `tokenId` | -| `to` **`indexed`** | `address` | The new owner of `tokenId` | -| `amount` | `uint256` | The amount of tokens transferred. | -| `allowNonLSP1Recipient` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | -| `data` | `bytes` | Any additional data the caller included by the caller during the transfer, and sent in the hooks to the `from` and `to` addresses. | +| Name | Type | Description | +| ------------------------ | :-------: | ---------------------------------------------------------------------------------------------------------------------------- | +| `operator` **`indexed`** | `address` | The address of the operator that executed the transfer. | +| `from` **`indexed`** | `address` | The address which tokens were sent from (balance decreased by `-amount`). | +| `to` **`indexed`** | `address` | The address that received the tokens (balance increased by `+amount`). | +| `amount` | `uint256` | The amount of tokens transferred. | +| `allowNonLSP1Recipient` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `data` | `bytes` | Any additional data included by the caller during the transfer, and sent in the LSP1 hooks to the `from` and `to` addresses. |
diff --git a/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md b/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md index 7562efafa..b854b5904 100644 --- a/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md +++ b/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md @@ -34,7 +34,7 @@ When marked as 'public', a method can be called both externally and internally, constructor(string name_, string symbol_, address newOwner_); ``` -_Deploying a `LSP7CompatibleERC20Mintable` token contract with: token name = `name_`, token symbol = `symbol*`, and address `newOwner*` as the token contract owner.\_ +_Deploying a `LSP7CompatibleERC20Mintable` token contract with: token name = `name_`, token symbol = `symbol_`, and address `newOwner_` as the token contract owner._ #### Parameters @@ -1224,15 +1224,15 @@ Otherwise, the codes after \_fallbackLSP17Extendable() may never be reached. event Approval(address indexed owner, address indexed spender, uint256 value); ``` -ERC721 `Approval` event emitted when `owner` enables `operator` for `tokenId`. To provide compatibility with indexing ERC721 events. +Emitted when the allowance of a `spender` for an `owner` is set by a call to [`approve`](#approve). `value` is the new allowance. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ------------------------------------------ | -| `owner` **`indexed`** | `address` | The address of the owner of the `tokenId`. | -| `spender` **`indexed`** | `address` | - | -| `value` | `uint256` | - | +| Name | Type | Description | +| ----------------------- | :-------: | --------------------------------------------------------- | +| `owner` **`indexed`** | `address` | The account giving approval | +| `spender` **`indexed`** | `address` | The account receiving approval | +| `value` | `uint256` | The amount of tokens `spender` has access to from `owner` |
@@ -1251,14 +1251,14 @@ ERC721 `Approval` event emitted when `owner` enables `operator` for `tokenId`. T event AuthorizedOperator(address indexed operator, address indexed tokenOwner, uint256 indexed amount, bytes operatorNotificationData); ``` -Emitted when `tokenOwner` enables `operator` to transfer or burn the `tokenId`. +Emitted when `tokenOwner` enables `operator` for `amount` tokens. #### Parameters | Name | Type | Description | | -------------------------- | :-------: | ----------------------------------------------------------------------- | -| `operator` **`indexed`** | `address` | The address authorized as an operator. | -| `tokenOwner` **`indexed`** | `address` | The owner of the `tokenId`. | +| `operator` **`indexed`** | `address` | The address authorized as an operator | +| `tokenOwner` **`indexed`** | `address` | The token owner | | `amount` **`indexed`** | `uint256` | The amount of tokens `operator` address has access to from `tokenOwner` | | `operatorNotificationData` | `bytes` | The data to notify the operator about via LSP1. | @@ -1331,15 +1331,42 @@ event OwnershipTransferred(address indexed previousOwner, address indexed newOwn event RevokedOperator(address indexed operator, address indexed tokenOwner, bytes operatorNotificationData); ``` -Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on its behalf. +Emitted when `tokenOwner` disables `operator` for `amount` tokens and set its [`authorizedAmountFor(...)`](#`authorizedamountfor) to `0`. #### Parameters -| Name | Type | Description | -| -------------------------- | :-------: | --------------------------------------------------------------- | -| `operator` **`indexed`** | `address` | The address revoked from the operator array ({getOperatorsOf}). | -| `tokenOwner` **`indexed`** | `address` | The owner of the `tokenId`. | -| `operatorNotificationData` | `bytes` | The data to notify the operator about via LSP1. | +| Name | Type | Description | +| -------------------------- | :-------: | ----------------------------------------------- | +| `operator` **`indexed`** | `address` | The address revoked from operating | +| `tokenOwner` **`indexed`** | `address` | The token owner | +| `operatorNotificationData` | `bytes` | The data to notify the operator about via LSP1. | + +
+ +### Transfer + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#transfer) +- Solidity implementation: [`LSP7CompatibleERC20Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol) +- Event signature: `Transfer(address,address,uint256)` +- Event topic hash: `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` + +::: + +```solidity +event Transfer(address indexed from, address indexed to, uint256 value); +``` + +Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero. + +#### Parameters + +| Name | Type | Description | +| -------------------- | :-------: | -------------------------------- | +| `from` **`indexed`** | `address` | The sending address | +| `to` **`indexed`** | `address` | The receiving address | +| `value` | `uint256` | The amount of tokens transfered. |
@@ -1358,18 +1385,18 @@ Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on i event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool allowNonLSP1Recipient, bytes data); ``` -Emitted when `tokenId` token is transferred from the `from` to the `to` address. +Emitted when the `from` transferred successfully `amount` of tokens to `to`. #### Parameters -| Name | Type | Description | -| ------------------------ | :-------: | ---------------------------------------------------------------------------------------------------------------------------------- | -| `operator` **`indexed`** | `address` | The address of operator that sent the `tokenId` | -| `from` **`indexed`** | `address` | The previous owner of the `tokenId` | -| `to` **`indexed`** | `address` | The new owner of `tokenId` | -| `amount` | `uint256` | The amount of tokens transferred. | -| `allowNonLSP1Recipient` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | -| `data` | `bytes` | Any additional data the caller included by the caller during the transfer, and sent in the hooks to the `from` and `to` addresses. | +| Name | Type | Description | +| ------------------------ | :-------: | ---------------------------------------------------------------------------------------------------------------------------- | +| `operator` **`indexed`** | `address` | The address of the operator that executed the transfer. | +| `from` **`indexed`** | `address` | The address which tokens were sent from (balance decreased by `-amount`). | +| `to` **`indexed`** | `address` | The address that received the tokens (balance increased by `+amount`). | +| `amount` | `uint256` | The amount of tokens transferred. | +| `allowNonLSP1Recipient` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `data` | `bytes` | Any additional data included by the caller during the transfer, and sent in the LSP1 hooks to the `from` and `to` addresses. |
diff --git a/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md b/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md index 8deb38829..e3ee21c6a 100644 --- a/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md +++ b/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md @@ -39,7 +39,7 @@ constructor( ); ``` -_Deploying a `LSP7Mintable` token contract with: token name = `name_`, token symbol = `symbol*`, and address `newOwner*` as the token contract owner.\_ +_Deploying a `LSP7Mintable` token contract with: token name = `name_`, token symbol = `symbol_`, and address `newOwner_` as the token contract owner._ #### Parameters @@ -1132,14 +1132,14 @@ Otherwise, the codes after \_fallbackLSP17Extendable() may never be reached. event AuthorizedOperator(address indexed operator, address indexed tokenOwner, uint256 indexed amount, bytes operatorNotificationData); ``` -Emitted when `tokenOwner` enables `operator` to transfer or burn the `tokenId`. +Emitted when `tokenOwner` enables `operator` for `amount` tokens. #### Parameters | Name | Type | Description | | -------------------------- | :-------: | ----------------------------------------------------------------------- | -| `operator` **`indexed`** | `address` | The address authorized as an operator. | -| `tokenOwner` **`indexed`** | `address` | The owner of the `tokenId`. | +| `operator` **`indexed`** | `address` | The address authorized as an operator | +| `tokenOwner` **`indexed`** | `address` | The token owner | | `amount` **`indexed`** | `uint256` | The amount of tokens `operator` address has access to from `tokenOwner` | | `operatorNotificationData` | `bytes` | The data to notify the operator about via LSP1. | @@ -1212,15 +1212,15 @@ event OwnershipTransferred(address indexed previousOwner, address indexed newOwn event RevokedOperator(address indexed operator, address indexed tokenOwner, bytes operatorNotificationData); ``` -Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on its behalf. +Emitted when `tokenOwner` disables `operator` for `amount` tokens and set its [`authorizedAmountFor(...)`](#`authorizedamountfor) to `0`. #### Parameters -| Name | Type | Description | -| -------------------------- | :-------: | --------------------------------------------------------------- | -| `operator` **`indexed`** | `address` | The address revoked from the operator array ({getOperatorsOf}). | -| `tokenOwner` **`indexed`** | `address` | The owner of the `tokenId`. | -| `operatorNotificationData` | `bytes` | The data to notify the operator about via LSP1. | +| Name | Type | Description | +| -------------------------- | :-------: | ----------------------------------------------- | +| `operator` **`indexed`** | `address` | The address revoked from operating | +| `tokenOwner` **`indexed`** | `address` | The token owner | +| `operatorNotificationData` | `bytes` | The data to notify the operator about via LSP1. |
@@ -1239,18 +1239,18 @@ Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on i event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool allowNonLSP1Recipient, bytes data); ``` -Emitted when `tokenId` token is transferred from the `from` to the `to` address. +Emitted when the `from` transferred successfully `amount` of tokens to `to`. #### Parameters -| Name | Type | Description | -| ------------------------ | :-------: | ---------------------------------------------------------------------------------------------------------------------------------- | -| `operator` **`indexed`** | `address` | The address of operator that sent the `tokenId` | -| `from` **`indexed`** | `address` | The previous owner of the `tokenId` | -| `to` **`indexed`** | `address` | The new owner of `tokenId` | -| `amount` | `uint256` | The amount of tokens transferred. | -| `allowNonLSP1Recipient` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | -| `data` | `bytes` | Any additional data the caller included by the caller during the transfer, and sent in the hooks to the `from` and `to` addresses. | +| Name | Type | Description | +| ------------------------ | :-------: | ---------------------------------------------------------------------------------------------------------------------------- | +| `operator` **`indexed`** | `address` | The address of the operator that executed the transfer. | +| `from` **`indexed`** | `address` | The address which tokens were sent from (balance decreased by `-amount`). | +| `to` **`indexed`** | `address` | The address that received the tokens (balance increased by `+amount`). | +| `amount` | `uint256` | The amount of tokens transferred. | +| `allowNonLSP1Recipient` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `data` | `bytes` | Any additional data included by the caller during the transfer, and sent in the LSP1 hooks to the `from` and `to` addresses. |
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md index 119d2a718..85efdae38 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md @@ -1354,15 +1354,15 @@ event Approval(address indexed owner, address indexed operator, uint256 indexed _ERC721 `Approval` compatible event emitted. Successfully approved operator `operator` to operate on tokenId `tokenId` on behalf of token owner `owner`._ -ERC721 `Approval` event emitted when `owner` enables `operator` for `tokenId`. To provide compatibility with indexing ERC721 events. +Emitted when the allowance of a `spender` for an `owner` is set by a call to [`approve`](#approve). `value` is the new allowance. #### Parameters -| Name | Type | Description | -| ------------------------ | :-------: | ------------------------------------------ | -| `owner` **`indexed`** | `address` | The address of the owner of the `tokenId`. | -| `operator` **`indexed`** | `address` | The address set as operator. | -| `tokenId` **`indexed`** | `uint256` | The approved tokenId. | +| Name | Type | Description | +| ------------------------ | :-------: | ---------------------------- | +| `owner` **`indexed`** | `address` | The account giving approval | +| `operator` **`indexed`** | `address` | The address set as operator. | +| `tokenId` **`indexed`** | `uint256` | The approved tokenId. |
@@ -1383,7 +1383,7 @@ event ApprovalForAll(address indexed owner, address indexed operator, bool appro _ERC721 `ApprovalForAll` compatible event emitted. Successfully set "approved for all" status to `approved` for operator `operator` for token owner `owner`._ -ERC721 `ApprovalForAll` event emitted when an `operator` is enabled or disabled for an owner to transfer any of its tokenIds. The operator can manage all NFTs of the owner. +Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to `approved`. #### Parameters @@ -1507,6 +1507,35 @@ Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on i :::note References +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#transfer) +- Solidity implementation: [`LSP8CompatibleERC721.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol) +- Event signature: `Transfer(address,address,uint256)` +- Event topic hash: `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` + +::: + +```solidity +event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); +``` + +_ERC721 `Transfer` compatible event emitted. Successfully transferred tokenId `tokenId` from `from` to `to`._ + +Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero. + +#### Parameters + +| Name | Type | Description | +| ----------------------- | :-------: | ------------------------ | +| `from` **`indexed`** | `address` | The sending address | +| `to` **`indexed`** | `address` | The receiving address | +| `tokenId` **`indexed`** | `uint256` | The tokenId to transfer. | + +
+ +### Transfer + +:::note References + - Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#transfer) - Solidity implementation: [`LSP8CompatibleERC721.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol) - Event signature: `Transfer(address,address,address,bytes32,bool,bytes)` @@ -1518,8 +1547,6 @@ Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on i event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool allowNonLSP1Recipient, bytes data); ``` -_ERC721 `Transfer` compatible event emitted. Successfully transferred tokenId `tokenId` from `from` to `to`._ - Emitted when `tokenId` token is transferred from the `from` to the `to` address. #### Parameters diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md index a9c5b10aa..b495bd998 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md @@ -34,7 +34,7 @@ When marked as 'public', a method can be called both externally and internally, constructor(string name_, string symbol_, address newOwner_); ``` -_Deploying a `LSP8CompatibleERC721Mintable` token contract with: token name = `name_`, token symbol = `symbol*`, and address `newOwner*` as the token contract owner.\_ +_Deploying a `LSP8CompatibleERC721Mintable` token contract with: token name = `name_`, token symbol = `symbol_`, and address `newOwner_` as the token contract owner._ #### Parameters @@ -1394,15 +1394,15 @@ event Approval(address indexed owner, address indexed operator, uint256 indexed _ERC721 `Approval` compatible event emitted. Successfully approved operator `operator` to operate on tokenId `tokenId` on behalf of token owner `owner`._ -ERC721 `Approval` event emitted when `owner` enables `operator` for `tokenId`. To provide compatibility with indexing ERC721 events. +Emitted when the allowance of a `spender` for an `owner` is set by a call to [`approve`](#approve). `value` is the new allowance. #### Parameters -| Name | Type | Description | -| ------------------------ | :-------: | ------------------------------------------ | -| `owner` **`indexed`** | `address` | The address of the owner of the `tokenId`. | -| `operator` **`indexed`** | `address` | The address set as operator. | -| `tokenId` **`indexed`** | `uint256` | The approved tokenId. | +| Name | Type | Description | +| ------------------------ | :-------: | ---------------------------- | +| `owner` **`indexed`** | `address` | The account giving approval | +| `operator` **`indexed`** | `address` | The address set as operator. | +| `tokenId` **`indexed`** | `uint256` | The approved tokenId. |
@@ -1423,7 +1423,7 @@ event ApprovalForAll(address indexed owner, address indexed operator, bool appro _ERC721 `ApprovalForAll` compatible event emitted. Successfully set "approved for all" status to `approved` for operator `operator` for token owner `owner`._ -ERC721 `ApprovalForAll` event emitted when an `operator` is enabled or disabled for an owner to transfer any of its tokenIds. The operator can manage all NFTs of the owner. +Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to `approved`. #### Parameters @@ -1547,6 +1547,35 @@ Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on i :::note References +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#transfer) +- Solidity implementation: [`LSP8CompatibleERC721Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol) +- Event signature: `Transfer(address,address,uint256)` +- Event topic hash: `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` + +::: + +```solidity +event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); +``` + +_ERC721 `Transfer` compatible event emitted. Successfully transferred tokenId `tokenId` from `from` to `to`._ + +Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero. + +#### Parameters + +| Name | Type | Description | +| ----------------------- | :-------: | ------------------------ | +| `from` **`indexed`** | `address` | The sending address | +| `to` **`indexed`** | `address` | The receiving address | +| `tokenId` **`indexed`** | `uint256` | The tokenId to transfer. | + +
+ +### Transfer + +:::note References + - Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#transfer) - Solidity implementation: [`LSP8CompatibleERC721Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol) - Event signature: `Transfer(address,address,address,bytes32,bool,bytes)` @@ -1558,8 +1587,6 @@ Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on i event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool allowNonLSP1Recipient, bytes data); ``` -_ERC721 `Transfer` compatible event emitted. Successfully transferred tokenId `tokenId` from `from` to `to`._ - Emitted when `tokenId` token is transferred from the `from` to the `to` address. #### Parameters diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md index 3c58a84fa..1e54c36b0 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md @@ -34,7 +34,7 @@ When marked as 'public', a method can be called both externally and internally, constructor(string name_, string symbol_, address newOwner_); ``` -_Deploying a `LSP8Mintable` token contract with: token name = `name_`, token symbol = `symbol*`, and address `newOwner*` as the token contract owner.\_ +_Deploying a `LSP8Mintable` token contract with: token name = `name_`, token symbol = `symbol_`, and address `newOwner_` as the token contract owner._ #### Parameters diff --git a/dodoc/config.ts b/dodoc/config.ts index 942b40a47..d81ec045b 100644 --- a/dodoc/config.ts +++ b/dodoc/config.ts @@ -16,8 +16,8 @@ export const dodocConfig = { 'contracts/LSP17ContractExtension/LSP17Extendable.sol', 'contracts/LSP17ContractExtension/LSP17Extension.sol', 'contracts/LSP20CallVerification/LSP20CallVerification.sol', - 'contracts/LSP23LinkedContractsDeployment/LSP23LinkedContractsFactory.sol', - 'contracts/LSP23LinkedContractsDeployment/IPostDeploymentModule.sol', + 'contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol', + 'contracts/LSP23LinkedContractsFactory/IPostDeploymentModule.sol', 'contracts/LSP25ExecuteRelayCall/LSP25MultiChannelNonce.sol', // tokens diff --git a/dodoc/template.sqrl b/dodoc/template.sqrl index ae9ec093a..b71d43195 100644 --- a/dodoc/template.sqrl +++ b/dodoc/template.sqrl @@ -233,7 +233,7 @@ Internal functions cannot be called externally, whether from other smart contrac {{@foreach(it.events) => key, val}} -### {{key}} +### {{key.split('(')[0]}} :::note References{{'\n\n'}}{{@generateAdditionalEventInfo(it.name, val.code) /}}{{'\n\n'}}::: @@ -275,7 +275,7 @@ Internal functions cannot be called externally, whether from other smart contrac {{@foreach(it.errors) => key, val}} -### {{key}} +### {{key.split('(')[0]}} :::note References{{'\n\n'}}{{@generateAdditionalErrorInfo(it.name, val.code) /}}{{'\n\n'}}::: diff --git a/package-lock.json b/package-lock.json index 0587a8d80..6ce1eb923 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@lukso/lsp-smart-contracts", - "version": "0.11.0-rc.1", + "version": "0.11.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@lukso/lsp-smart-contracts", - "version": "0.11.0-rc.1", + "version": "0.11.1", "license": "Apache-2.0", "dependencies": { "@erc725/smart-contracts": "^5.2.0", @@ -15,7 +15,7 @@ "solidity-bytes-utils": "0.8.0" }, "devDependencies": { - "@b00ste/hardhat-dodoc": "^0.3.11", + "@b00ste/hardhat-dodoc": "^0.3.15", "@defi-wonderland/smock": "^2.3.4", "@erc725/erc725.js": "0.17.2", "@lukso/eip191-signer.js": "^0.2.2", @@ -71,9 +71,9 @@ } }, "node_modules/@b00ste/hardhat-dodoc": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/@b00ste/hardhat-dodoc/-/hardhat-dodoc-0.3.11.tgz", - "integrity": "sha512-GzH7yOJyux47ShCGxsGDeu3phm5iDOAAM+Vj/c8hm8oH5LT5uJ+RpvMVN+U7nNvRebJPnM2J6yc5hkRarHgRDQ==", + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/@b00ste/hardhat-dodoc/-/hardhat-dodoc-0.3.15.tgz", + "integrity": "sha512-3aGhCRr09oe0meHxoE1xxk0aXbTe0XHcTbyeNEuaNBgCvN+ESAtsi/VUCL3IG9kWEgOgeXeEfHlPTGRjNx2dmg==", "dev": true, "dependencies": { "squirrelly": "^8.0.8" @@ -22937,9 +22937,9 @@ } }, "@b00ste/hardhat-dodoc": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/@b00ste/hardhat-dodoc/-/hardhat-dodoc-0.3.11.tgz", - "integrity": "sha512-GzH7yOJyux47ShCGxsGDeu3phm5iDOAAM+Vj/c8hm8oH5LT5uJ+RpvMVN+U7nNvRebJPnM2J6yc5hkRarHgRDQ==", + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/@b00ste/hardhat-dodoc/-/hardhat-dodoc-0.3.15.tgz", + "integrity": "sha512-3aGhCRr09oe0meHxoE1xxk0aXbTe0XHcTbyeNEuaNBgCvN+ESAtsi/VUCL3IG9kWEgOgeXeEfHlPTGRjNx2dmg==", "dev": true, "requires": { "squirrelly": "^8.0.8" diff --git a/package.json b/package.json index c8700f37c..274c04d3d 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,8 @@ "test:foundry": "forge test --no-match-test Skip -vvv --gas-report > gasreport.ansi", "test:importRequire": "npm run build:js && ./tests/importRequire.sh", "clean": "hardhat clean && rm -rf module common", - "build": "hardhat dodoc && ts-node scripts/interfaceIds.ts && prettier -w ./docs ", + "build": "hardhat compile", + "build:docs": "hardhat dodoc && ts-node scripts/interfaceIds.ts && prettier -w ./docs", "build:js": "vite build && dts-bundle-generator --config dtsconfig.json", "package": "hardhat prepare-package", "release": "run-s clean build package && standard-version", @@ -107,7 +108,7 @@ "solidity-bytes-utils": "0.8.0" }, "devDependencies": { - "@b00ste/hardhat-dodoc": "^0.3.11", + "@b00ste/hardhat-dodoc": "^0.3.15", "@defi-wonderland/smock": "^2.3.4", "@erc725/erc725.js": "0.17.2", "@lukso/eip191-signer.js": "^0.2.2", From 257a59cdec6da4d0187c16c5c42ddd0489af248a Mon Sep 17 00:00:00 2001 From: Johann BICH <2253470+kalote@users.noreply.github.com> Date: Wed, 13 Sep 2023 16:56:02 +0200 Subject: [PATCH 05/55] fix comment typo in LSP0 --- contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol b/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol index 133318d74..7ed6b5cb8 100644 --- a/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol +++ b/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol @@ -449,13 +449,13 @@ abstract contract LSP0ERC725AccountCore is } } - // Generate the data key {_LSP1_UNIVERSAL_RECEIVER_DELEGATE_KEY + } + // Generate the data key {_LSP1_UNIVERSAL_RECEIVER_DELEGATE_PREFIX + } bytes32 lsp1typeIdDelegateKey = LSP2Utils.generateMappingKey( _LSP1_UNIVERSAL_RECEIVER_DELEGATE_PREFIX, bytes20(typeId) ); - // Query the ERC725Y storage with the data key {_LSP1_UNIVERSAL_RECEIVER_DELEGATE_KEY + } + // Query the ERC725Y storage with the data key {_LSP1_UNIVERSAL_RECEIVER_DELEGATE_PREFIX + } bytes memory lsp1TypeIdDelegateValue = _getData(lsp1typeIdDelegateKey); bytes memory resultTypeIdDelegate; From 6dc1b0c9638ca86f7bb64f3a3e06d61a9f153f0c Mon Sep 17 00:00:00 2001 From: CJ42 Date: Thu, 14 Sep 2023 16:51:10 +0100 Subject: [PATCH 06/55] docs: add intro to comments in `CONTRIBUTING.md` --- CONTRIBUTING.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 92db00f36..9490584a7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -54,6 +54,10 @@ When merging a branch to `develop` PRs should be squashed into one conventional ## Solidity Code Comments +A good level of documentation is crucial for understanding the intended behaviour of the smart contracts and for identifying any potential discrepancies between the implementation and the intended behaviour. + +When making contributions, each smart contracts and functions should be well-documented, with clear comments explaining the purpose and functionality of each function and module. + When changing or adding NatSpec comments to any `function`, `error` or `event` in any contract make sure to adhere to the following guidelines: 1. `@dev` and `@notice` tags can both contain text descriptions and two types of lists: bullet points or numbered lists. Make sure that those tags always start with text descriptions first, not with lists. From 8e13ff231cc40c53e5a539be46494d8be96f57d4 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Fri, 15 Sep 2023 08:48:20 +0100 Subject: [PATCH 07/55] chore: fix ESLint warnings in LSP17 and LSP23 tests --- .../LSP17ExtendableTokens.behaviour.ts | 19 ------------------- .../LSP23LinkedContractsDeployment.test.ts | 8 ++------ 2 files changed, 2 insertions(+), 25 deletions(-) diff --git a/tests/LSP17ContractExtension/LSP17ExtendableTokens.behaviour.ts b/tests/LSP17ContractExtension/LSP17ExtendableTokens.behaviour.ts index 9838fb6d3..095008e08 100644 --- a/tests/LSP17ContractExtension/LSP17ExtendableTokens.behaviour.ts +++ b/tests/LSP17ContractExtension/LSP17ExtendableTokens.behaviour.ts @@ -1,5 +1,4 @@ import { expect } from 'chai'; -import { ethers } from 'hardhat'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; import { FakeContract, smock } from '@defi-wonderland/smock'; @@ -18,12 +17,6 @@ import { TransferExtension, ReenterAccountExtension__factory, ReenterAccountExtension, - OnERC721ReceivedExtension, - OnERC721ReceivedExtension__factory, - RequireCallbackToken, - RequireCallbackToken__factory, - RevertFallbackExtension, - RevertFallbackExtension__factory, BuyExtension, BuyExtension__factory, } from '../../types'; @@ -43,7 +36,6 @@ export type LSP17TestContext = { export const shouldBehaveLikeLSP17 = (buildContext: () => Promise) => { let context: LSP17TestContext; let notExistingFunctionSignature, - onERC721ReceivedFunctionSelector, checkMsgVariableFunctionSelector, nameFunctionSelector, ageFunctionSelector, @@ -63,7 +55,6 @@ export const shouldBehaveLikeLSP17 = (buildContext: () => Promise Promise Promise Promise { describe('when calling with a payload of length less than 4bytes', () => { - let revertFallbackExtension: RevertFallbackExtension; - it('should revert', async () => { await expect( context.accounts[0].sendTransaction({ diff --git a/tests/LSP23LinkedContractsDeployment/LSP23LinkedContractsDeployment.test.ts b/tests/LSP23LinkedContractsDeployment/LSP23LinkedContractsDeployment.test.ts index 4dfa7a6ff..a49ef6752 100644 --- a/tests/LSP23LinkedContractsDeployment/LSP23LinkedContractsDeployment.test.ts +++ b/tests/LSP23LinkedContractsDeployment/LSP23LinkedContractsDeployment.test.ts @@ -779,12 +779,8 @@ describe('UniversalProfileDeployer', function () { expect(secondaryAddress).to.not.equal(ethers.constants.AddressZero); }); it('should deploy proxies with correct initialization calldata (with secondary contract contains extraParams)', async function () { - const { - LSP23LinkedContractsFactory, - upInitPostDeploymentModule, - universalProfileInit, - keyManagerInit, - } = await deployImplementationContracts(); + const { LSP23LinkedContractsFactory, upInitPostDeploymentModule, universalProfileInit } = + await deployImplementationContracts(); const KeyManagerWithExtraParamsFactory = await ethers.getContractFactory( 'KeyManagerInitWithExtraParams', From 39704a118580a02280ddb0fdda04fe76e3c0a8b0 Mon Sep 17 00:00:00 2001 From: b00ste Date: Fri, 15 Sep 2023 13:26:40 +0300 Subject: [PATCH 08/55] docs: update LSP16 natspec --- .../LSP16UniversalFactory.sol | 159 +++++++----------- .../LSP16UniversalFactory.md | 66 ++++++-- 2 files changed, 113 insertions(+), 112 deletions(-) diff --git a/contracts/LSP16UniversalFactory/LSP16UniversalFactory.sol b/contracts/LSP16UniversalFactory/LSP16UniversalFactory.sol index d0606af24..a2cf5e67d 100644 --- a/contracts/LSP16UniversalFactory/LSP16UniversalFactory.sol +++ b/contracts/LSP16UniversalFactory/LSP16UniversalFactory.sol @@ -8,13 +8,13 @@ import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; // errors /** - * @dev Reverts when there is no revert reason bubbled up by the contract created when initializing + * @notice Couldn't initialize the contract. + * @dev Reverts when there is no revert reason bubbled up by the created contract when initializing */ error ContractInitializationFailed(); /** - * @dev Reverts when msg.value sent to {deployCreate2AndInitialize} function is not equal to the sum of the - * `initializeCalldataMsgValue` and `constructorMsgValue` + * @dev Reverts when `msg.value` sent to {deployCreate2AndInitialize(..)} function is not equal to the sum of the `initializeCalldataMsgValue` and `constructorMsgValue` */ error InvalidValueSum(); @@ -61,16 +61,17 @@ contract LSP16UniversalFactory { bytes private constant _EMPTY_BYTE = ""; /** - * @dev Emitted whenever a contract is created - * @param contractCreated The address of the contract created - * @param providedSalt The salt provided by the deployer, which will be used to generate the final salt - * that will be used by the `CREATE2` opcode for contract deployment - * @param generatedSalt The salt used by the `CREATE2` opcode for contract deployment - * @param initialized The Boolean that specifies if the contract must be initialized or not - * @param initializeCalldata The bytes provided as initializeCalldata (Empty string when `initialized` is set to false) + * @notice Contract created. Contract address: `createdContract`. + * @dev Emitted whenever a contract is created. + * + * @param createdContract The address of the contract created. + * @param providedSalt The salt provided by the deployer, which will be used to generate the final salt that will be used by the `CREATE2` opcode for contract deployment. + * @param generatedSalt The salt used by the `CREATE2` opcode for contract deployment. + * @param initialized The Boolean that specifies if the contract must be initialized or not. + * @param initializeCalldata The bytes provided as initializeCalldata (Empty string when `initialized` is set to false). */ event ContractCreated( - address indexed contractCreated, + address indexed createdContract, bytes32 indexed providedSalt, bytes32 generatedSalt, bool indexed initialized, @@ -78,24 +79,20 @@ contract LSP16UniversalFactory { ); /** - * @dev Deploys a contract using the CREATE2 opcode. The address where the contract will be deployed - * can be known in advance via the {computeAddress} function. + * @notice Contract deployed. Salt, `providedSalt`, used. + * + * @dev Deploys a contract using the CREATE2 opcode. The address where the contract will be deployed can be known in advance via the {computeAddress} function. * * This function deploys contracts without initialization (external call after deployment). * - * The `providedSalt` parameter is not used directly as the salt by the CREATE2 opcode. Instead, it is hashed with - * keccak256: `keccak256(abi.encodePacked(false, providedSalt))`. See {generateSalt} function for more details. + * The `providedSalt` parameter is not used directly as the salt by the CREATE2 opcode. Instead, it is hashed with keccak256: `keccak256(abi.encodePacked(false, providedSalt))`. See {generateSalt} function for more details. * - * Using the same `byteCode` and `providedSalt` multiple times will revert, as the contract cannot be deployed - * twice at the same address. + * Using the same `byteCode` and `providedSalt` multiple times will revert, as the contract cannot be deployed twice at the same address. * - * If the constructor of the contract to deploy is payable, value can be sent to this function to fund - * the created contract. However, sending value to this function while the constructor is not payable will - * result in a revert. + * If the constructor of the contract to deploy is payable, value can be sent to this function to fund the created contract. However, sending value to this function while the constructor is not payable will result in a revert. * * @param byteCode The bytecode of the contract to be deployed - * @param providedSalt The salt provided by the deployer, which will be used to generate the final salt - * that will be used by the `CREATE2` opcode for contract deployment + * @param providedSalt The salt provided by the deployer, which will be used to generate the final salt that will be used by the `CREATE2` opcode for contract deployment * * @return The address of the deployed contract */ @@ -121,28 +118,22 @@ contract LSP16UniversalFactory { } /** - * @dev Deploys a contract using the CREATE2 opcode. The address where the contract will be deployed - * can be known in advance via the {computeAddress} function. + * @notice Contract deployed. Salt, `providedSalt`, used. + * + * @dev Deploys a contract using the CREATE2 opcode. The address where the contract will be deployed can be known in advance via the {computeAddress} function. * * This function deploys contracts with initialization (external call after deployment). * - * The `providedSalt` parameter is not used directly as the salt by the CREATE2 opcode. Instead, it is hashed with - * keccak256: `keccak256(abi.encodePacked(true, initializeCalldata, providedSalt))`. - * See {generateSalt} function for more details. + * The `providedSalt` parameter is not used directly as the salt by the CREATE2 opcode. Instead, it is hashed with keccak256: `keccak256(abi.encodePacked(true, initializeCalldata, providedSalt))`. See {generateSalt} function for more details. * - * Using the same `byteCode`, `providedSalt` and `initializeCalldata` multiple times will revert, as the - * contract cannot be deployed twice at the same address. + * Using the same `byteCode`, `providedSalt` and `initializeCalldata` multiple times will revert, as the contract cannot be deployed twice at the same address. * - * If the constructor or the initialize function of the contract to deploy is payable, value can be sent along - * with the deployment/initialization to fund the created contract. However, sending value to this function while - * the constructor/initialize function is not payable will result in a revert. + * If the constructor or the initialize function of the contract to deploy is payable, value can be sent along with the deployment/initialization to fund the created contract. However, sending value to this function while the constructor/initialize function is not payable will result in a revert. * - * Will revert if the `msg.value` sent to the function is not equal to the sum of `constructorMsgValue` and - * `initializeCalldataMsgValue`. + * Will revert if the `msg.value` sent to the function is not equal to the sum of `constructorMsgValue` and `initializeCalldataMsgValue`. * * @param byteCode The bytecode of the contract to be deployed - * @param providedSalt The salt provided by the deployer, which will be used to generate the final salt - * that will be used by the `CREATE2` opcode for contract deployment + * @param providedSalt The salt provided by the deployer, which will be used to generate the final salt that will be used by the `CREATE2` opcode for contract deployment * @param initializeCalldata The calldata to be executed on the created contract * @param constructorMsgValue The value sent to the contract during deployment * @param initializeCalldataMsgValue The value sent to the contract during initialization @@ -186,24 +177,22 @@ contract LSP16UniversalFactory { } /** - * @dev Deploys an ERC1167 minimal proxy contract using the CREATE2 opcode. The address where the contract will be deployed - * can be known in advance via the {computeERC1167Address} function. + * @notice Proxy deployed. Salt, `providedSalt`, used. + * + * @dev Deploys an ERC1167 minimal proxy contract using the CREATE2 opcode. The address where the contract will be deployed can be known in advance via the {computeERC1167Address} function. * * This function deploys contracts without initialization (external call after deployment). * - * The `providedSalt` parameter is not used directly as the salt by the CREATE2 opcode. Instead, it is hashed with - * keccak256: `keccak256(abi.encodePacked(false, providedSalt))`. See {generateSalt} function for more details. + * The `providedSalt` parameter is not used directly as the salt by the CREATE2 opcode. Instead, it is hashed with keccak256: `keccak256(abi.encodePacked(false, providedSalt))`. See {generateSalt} function for more details. * * See {generateSalt} function for more details. * - * Using the same `implementationContract` and `providedSalt` multiple times will revert, as the contract cannot be deployed - * twice at the same address. + * Using the same `implementationContract` and `providedSalt` multiple times will revert, as the contract cannot be deployed twice at the same address. * * Sending value to the contract created is not possible since the constructor of the ERC1167 minimal proxy is not payable. * * @param implementationContract The contract address to use as the base implementation behind the proxy that will be deployed - * @param providedSalt The salt provided by the deployer, which will be used to generate the final salt - * that will be used by the `CREATE2` opcode for contract deployment + * @param providedSalt The salt provided by the deployer, which will be used to generate the final salt that will be used by the `CREATE2` opcode for contract deployment * * @return The address of the minimal proxy deployed */ @@ -229,25 +218,22 @@ contract LSP16UniversalFactory { } /** + * @notice Proxy deployed & initialized. Salt, `providedSalt`, used. + * * @dev Deploys an ERC1167 minimal proxy contract using the CREATE2 opcode. The address where the contract will be deployed * can be known in advance via the {computeERC1167Address} function. * * This function deploys contracts with initialization (external call after deployment). * - * The `providedSalt` parameter is not used directly as the salt by the CREATE2 opcode. Instead, it is hashed with - * keccak256: `keccak256(abi.encodePacked(true, initializeCalldata, providedSalt))`. + * The `providedSalt` parameter is not used directly as the salt by the CREATE2 opcode. Instead, it is hashed with keccak256: `keccak256(abi.encodePacked(true, initializeCalldata, providedSalt))`. * See {generateSalt} function for more details. * - * Using the same `implementationContract`, `providedSalt` and `initializeCalldata` multiple times will revert, as the - * contract cannot be deployed twice at the same address. + * Using the same `implementationContract`, `providedSalt` and `initializeCalldata` multiple times will revert, as the contract cannot be deployed twice at the same address. * - * If the initialize function of the contract to deploy is payable, value can be sent along to fund the created - * contract while initializing. However, sending value to this function while the initialize function is not - * payable will result in a revert. + * If the initialize function of the contract to deploy is payable, value can be sent along to fund the created contract while initializing. However, sending value to this function while the initialize function is not payable will result in a revert. * * @param implementationContract The contract address to use as the base implementation behind the proxy that will be deployed - * @param providedSalt The salt provided by the deployer, which will be used to generate the final salt - * that will be used by the `CREATE2` opcode for contract deployment + * @param providedSalt The salt provided by the deployer, which will be used to generate the final salt that will be used by the `CREATE2` opcode for contract deployment * @param initializeCalldata The calldata to be executed on the created contract * * @return The address of the minimal proxy deployed @@ -285,14 +271,12 @@ contract LSP16UniversalFactory { /** * @dev Computes the address of a contract to be deployed using CREATE2, based on the input parameters. - * Any change in one of these parameters will result in a different address. When the `initializable` - * boolean is set to `false`, `initializeCalldata` will not affect the function output. + * + * Any change in one of these parameters will result in a different address. When the `initializable` boolean is set to `false`, `initializeCalldata` will not affect the function output. * * @param byteCodeHash The keccak256 hash of the bytecode to be deployed - * @param providedSalt The salt provided by the deployer, which will be used to generate the final salt - * that will be used by the `CREATE2` opcode for contract deployment - * @param initializable A boolean that indicates whether an external call should be made to initialize the - * contract after deployment + * @param providedSalt The salt provided by the deployer, which will be used to generate the final salt that will be used by the `CREATE2` opcode for contract deployment + * @param initializable A boolean that indicates whether an external call should be made to initialize the contract after deployment * @param initializeCalldata The calldata to be executed on the created contract if `initializable` is set to `true` * * @return The address where the contract will be deployed @@ -313,14 +297,12 @@ contract LSP16UniversalFactory { /** * @dev Computes the address of an ERC1167 proxy contract based on the input parameters. - * Any change in one of these parameters will result in a different address. When the `initializable` - * boolean is set to `false`, `initializeCalldata` will not affect the function output. + * + * Any change in one of these parameters will result in a different address. When the `initializable` boolean is set to `false`, `initializeCalldata` will not affect the function output. * * @param implementationContract The contract to create a clone of according to ERC1167 - * @param providedSalt The salt provided by the deployer, which will be used to generate the final salt - * that will be used by the `CREATE2` opcode for contract deployment - * @param initializable A boolean that indicates whether an external call should be made to initialize the - * proxy contract after deployment + * @param providedSalt The salt provided by the deployer, which will be used to generate the final salt that will be used by the `CREATE2` opcode for contract deployment + * @param initializable A boolean that indicates whether an external call should be made to initialize the proxy contract after deployment * @param initializeCalldata The calldata to be executed on the created contract if `initializable` is set to `true` * * @return The address where the ERC1167 proxy contract will be deployed @@ -344,61 +326,48 @@ contract LSP16UniversalFactory { } /** - * @dev Generates the salt used to deploy the contract by hashing the following parameters (concatenated - * together) with keccak256: - * - * - the `providedSalt` - * - the `initializable` boolean - * - the `initializeCalldata`, only if the contract is initializable (the `initializable` boolean is set to `true`) - * - * The `providedSalt` parameter is not used directly as the salt by the CREATE2 opcode. Instead, it is - * used along with these parameters: - * - `initializable` boolean - * - `initializeCalldata` (when the contract is initializable and `initializable` is set to `true`). - * These three parameters are concatenated together and hashed to generate the final salt for CREATE2. + * @dev Generates the salt used to deploy the contract by hashing the following parameters (concatenated together) with keccak256: + * 1. the `providedSalt` + * 2. the `initializable` boolean + * 3. the `initializeCalldata`, only if the contract is initializable (the `initializable` boolean is set to `true`) * - * This approach ensures that in order to reproduce an initializable contract at the same address on another chain, - * not only the `providedSalt` is required to be the same, but also the initialize parameters within the `initializeCalldata` - * must also be the same. + * - The `providedSalt` parameter is not used directly as the salt by the CREATE2 opcode. Instead, it is used along with these parameters: + * 1. `initializable` boolean + * 2. `initializeCalldata` (when the contract is initializable and `initializable` is set to `true`). * - * This maintains consistent deployment behaviour. Users are required to initialize contracts with the same parameters across - * different chains to ensure contracts are deployed at the same address across different chains. + * - This approach ensures that in order to reproduce an initializable contract at the same address on another chain, not only the `providedSalt` is required to be the same, but also the initialize parameters within the `initializeCalldata` must also be the same. This maintains consistent deployment behaviour. Users are required to initialize contracts with the same parameters across different chains to ensure contracts are deployed at the same address across different chains. * - * ----------- - * Example (for initializable contracts) + * 1. Example (for initializable contracts) * - * For an existing contract A on chain 1 owned by X, to replicate the same contract at the same address with + * - For an existing contract A on chain 1 owned by X, to replicate the same contract at the same address with * the same owner X on chain 2, the salt used to generate the address should include the initializeCalldata * that assigns X as the owner of contract A. * - * For instance, if another user, Y, tries to deploy the contract at the same address + * - For instance, if another user, Y, tries to deploy the contract at the same address * on chain 2 using the same providedSalt, but with a different initializeCalldata to make Y the owner instead of X, * the generated address would be different, preventing Y from deploying the contract with different ownership * at the same address. - * ----------- * - * However, for non-initializable contracts, if the constructor has arguments that specify the deployment behavior, they + * - However, for non-initializable contracts, if the constructor has arguments that specify the deployment behavior, they * will be included in the bytecode. Any change in the constructor arguments will lead to a different contract's bytecode * which will result in a different address on other chains. * - * ----------- - * Example (for non-initializable contracts) + * 2. Example (for non-initializable contracts) * - * If a contract is deployed with specific constructor arguments on chain 1, these arguments are embedded within the bytecode. + * - If a contract is deployed with specific constructor arguments on chain 1, these arguments are embedded within the bytecode. * For instance, if contract B is deployed with a specific `tokenName` and `tokenSymbol` on chain 1, and a user wants to deploy * the same contract with the same `tokenName` and `tokenSymbol` on chain 2, they must use the same constructor arguments to * produce the same bytecode. This ensures that the same deployment behaviour is maintained across different chains, * as long as the same bytecode is used. * - * If another user Z, tries to deploy the same contract B at the same address on chain 2 using the same `providedSalt` + * - If another user Z, tries to deploy the same contract B at the same address on chain 2 using the same `providedSalt` * but different constructor arguments (a different `tokenName` and/or `tokenSymbol`), the generated address will be different. * This prevents user Z from deploying the contract with different constructor arguments at the same address on chain 2. - * ----------- * - * The providedSalt was hashed to produce the salt used by CREATE2 opcode to prevent users from deploying initializable contracts + * - The providedSalt was hashed to produce the salt used by CREATE2 opcode to prevent users from deploying initializable contracts * using non-initializable functions such as {deployCreate2} without having the initialization call. * - * In other words, if the providedSalt was not hashed and was used as it is as the salt by the CREATE2 opcode, malicious users + * - In other words, if the providedSalt was not hashed and was used as it is as the salt by the CREATE2 opcode, malicious users * can check the generated salt used for the already deployed initializable contract on chain 1, and deploy the contract * from {deployCreate2} function on chain 2, with passing the generated salt of the deployed contract as providedSalt * that will produce the same address but without the initialization, where the malicious user can initialize after. diff --git a/docs/contracts/LSP16UniversalFactory/LSP16UniversalFactory.md b/docs/contracts/LSP16UniversalFactory/LSP16UniversalFactory.md index 5b8d86c50..2478c481f 100644 --- a/docs/contracts/LSP16UniversalFactory/LSP16UniversalFactory.md +++ b/docs/contracts/LSP16UniversalFactory/LSP16UniversalFactory.md @@ -129,6 +129,8 @@ function deployCreate2( ) external payable returns (address); ``` +_Contract deployed. Salt, `providedSalt`, used._ + Deploys a contract using the CREATE2 opcode. The address where the contract will be deployed can be known in advance via the [`computeAddress`](#computeaddress) function. This function deploys contracts without initialization (external call after deployment). The `providedSalt` parameter is not used directly as the salt by the CREATE2 opcode. Instead, it is hashed with keccak256: `keccak256(abi.encodePacked(false, providedSalt))`. See [`generateSalt`](#generatesalt) function for more details. Using the same `byteCode` and `providedSalt` multiple times will revert, as the contract cannot be deployed twice at the same address. If the constructor of the contract to deploy is payable, value can be sent to this function to fund the created contract. However, sending value to this function while the constructor is not payable will result in a revert. #### Parameters @@ -167,6 +169,8 @@ function deployCreate2AndInitialize( ) external payable returns (address); ``` +_Contract deployed. Salt, `providedSalt`, used._ + Deploys a contract using the CREATE2 opcode. The address where the contract will be deployed can be known in advance via the [`computeAddress`](#computeaddress) function. This function deploys contracts with initialization (external call after deployment). The `providedSalt` parameter is not used directly as the salt by the CREATE2 opcode. Instead, it is hashed with keccak256: `keccak256(abi.encodePacked(true, initializeCalldata, providedSalt))`. See [`generateSalt`](#generatesalt) function for more details. Using the same `byteCode`, `providedSalt` and `initializeCalldata` multiple times will revert, as the contract cannot be deployed twice at the same address. If the constructor or the initialize function of the contract to deploy is payable, value can be sent along with the deployment/initialization to fund the created contract. However, sending value to this function while the constructor/initialize function is not payable will result in a revert. Will revert if the `msg.value` sent to the function is not equal to the sum of `constructorMsgValue` and `initializeCalldataMsgValue`. #### Parameters @@ -205,6 +209,8 @@ function deployERC1167Proxy( ) external nonpayable returns (address); ``` +_Proxy deployed. Salt, `providedSalt`, used._ + Deploys an ERC1167 minimal proxy contract using the CREATE2 opcode. The address where the contract will be deployed can be known in advance via the [`computeERC1167Address`](#computeerc1167address) function. This function deploys contracts without initialization (external call after deployment). The `providedSalt` parameter is not used directly as the salt by the CREATE2 opcode. Instead, it is hashed with keccak256: `keccak256(abi.encodePacked(false, providedSalt))`. See [`generateSalt`](#generatesalt) function for more details. See [`generateSalt`](#generatesalt) function for more details. Using the same `implementationContract` and `providedSalt` multiple times will revert, as the contract cannot be deployed twice at the same address. Sending value to the contract created is not possible since the constructor of the ERC1167 minimal proxy is not payable. #### Parameters @@ -241,6 +247,8 @@ function deployERC1167ProxyAndInitialize( ) external payable returns (address); ``` +_Proxy deployed & initialized. Salt, `providedSalt`, used._ + Deploys an ERC1167 minimal proxy contract using the CREATE2 opcode. The address where the contract will be deployed can be known in advance via the [`computeERC1167Address`](#computeerc1167address) function. This function deploys contracts with initialization (external call after deployment). The `providedSalt` parameter is not used directly as the salt by the CREATE2 opcode. Instead, it is hashed with keccak256: `keccak256(abi.encodePacked(true, initializeCalldata, providedSalt))`. See [`generateSalt`](#generatesalt) function for more details. Using the same `implementationContract`, `providedSalt` and `initializeCalldata` multiple times will revert, as the contract cannot be deployed twice at the same address. If the initialize function of the contract to deploy is payable, value can be sent along to fund the created contract while initializing. However, sending value to this function while the initialize function is not payable will result in a revert. #### Parameters @@ -280,17 +288,37 @@ function generateSalt( Generates the salt used to deploy the contract by hashing the following parameters (concatenated together) with keccak256: -- the `providedSalt` +1. the `providedSalt` -- the `initializable` boolean +2. the `initializable` boolean -- the `initializeCalldata`, only if the contract is initializable (the `initializable` boolean is set to `true`) The `providedSalt` parameter is not used directly as the salt by the CREATE2 opcode. Instead, it is used along with these parameters: +3. the `initializeCalldata`, only if the contract is initializable (the `initializable` boolean is set to `true`) -- `initializable` boolean +- The `providedSalt` parameter is not used directly as the salt by the CREATE2 opcode. Instead, it is used along with these parameters: + +1. `initializable` boolean + +2. `initializeCalldata` (when the contract is initializable and `initializable` is set to `true`). + +- This approach ensures that in order to reproduce an initializable contract at the same address on another chain, not only the `providedSalt` is required to be the same, but also the initialize parameters within the `initializeCalldata` must also be the same. This maintains consistent deployment behaviour. Users are required to initialize contracts with the same parameters across different chains to ensure contracts are deployed at the same address across different chains. + +1. Example (for initializable contracts) -- `initializeCalldata` (when the contract is initializable and `initializable` is set to `true`). These three parameters are concatenated together and hashed to generate the final salt for CREATE2. This approach ensures that in order to reproduce an initializable contract at the same address on another chain, not only the `providedSalt` is required to be the same, but also the initialize parameters within the `initializeCalldata` must also be the same. This maintains consistent deployment behaviour. Users are required to initialize contracts with the same parameters across different chains to ensure contracts are deployed at the same address across different chains. ----------- Example (for initializable contracts) For an existing contract A on chain 1 owned by X, to replicate the same contract at the same address with the same owner X on chain 2, the salt used to generate the address should include the initializeCalldata that assigns X as the owner of contract A. For instance, if another user, Y, tries to deploy the contract at the same address on chain 2 using the same providedSalt, but with a different initializeCalldata to make Y the owner instead of X, the generated address would be different, preventing Y from deploying the contract with different ownership at the same address. ----------- However, for non-initializable contracts, if the constructor has arguments that specify the deployment behavior, they will be included in the bytecode. Any change in the constructor arguments will lead to a different contract's bytecode which will result in a different address on other chains. ----------- Example (for non-initializable contracts) If a contract is deployed with specific constructor arguments on chain 1, these arguments are embedded within the bytecode. For instance, if contract B is deployed with a specific `tokenName` and `tokenSymbol` on chain 1, and a user wants to deploy the same contract with the same `tokenName` and `tokenSymbol` on chain 2, they must use the same constructor arguments to produce the same bytecode. This ensures that the same deployment behaviour is maintained across different chains, as long as the same bytecode is used. If another user Z, tries to deploy the same contract B at the same address on chain 2 using the same `providedSalt` but different constructor arguments (a different `tokenName` and/or `tokenSymbol`), the generated address will be different. This prevents user Z from deploying the contract with different constructor arguments at the same address on chain +- For an existing contract A on chain 1 owned by X, to replicate the same contract at the same address with the same owner X on chain 2, the salt used to generate the address should include the initializeCalldata that assigns X as the owner of contract A. -2. ----------- The providedSalt was hashed to produce the salt used by CREATE2 opcode to prevent users from deploying initializable contracts using non-initializable functions such as [`deployCreate2`](#deploycreate2) without having the initialization call. In other words, if the providedSalt was not hashed and was used as it is as the salt by the CREATE2 opcode, malicious users can check the generated salt used for the already deployed initializable contract on chain 1, and deploy the contract from [`deployCreate2`](#deploycreate2) function on chain 2, with passing the generated salt of the deployed contract as providedSalt that will produce the same address but without the initialization, where the malicious user can initialize after. +- For instance, if another user, Y, tries to deploy the contract at the same address on chain 2 using the same providedSalt, but with a different initializeCalldata to make Y the owner instead of X, the generated address would be different, preventing Y from deploying the contract with different ownership at the same address. + +- However, for non-initializable contracts, if the constructor has arguments that specify the deployment behavior, they will be included in the bytecode. Any change in the constructor arguments will lead to a different contract's bytecode which will result in a different address on other chains. + +2. Example (for non-initializable contracts) + +- If a contract is deployed with specific constructor arguments on chain 1, these arguments are embedded within the bytecode. For instance, if contract B is deployed with a specific `tokenName` and `tokenSymbol` on chain 1, and a user wants to deploy the same contract with the same `tokenName` and `tokenSymbol` on chain 2, they must use the same constructor arguments to produce the same bytecode. This ensures that the same deployment behaviour is maintained across different chains, as long as the same bytecode is used. + +- If another user Z, tries to deploy the same contract B at the same address on chain 2 using the same `providedSalt` but different constructor arguments (a different `tokenName` and/or `tokenSymbol`), the generated address will be different. This prevents user Z from deploying the contract with different constructor arguments at the same address on chain 2. + +- The providedSalt was hashed to produce the salt used by CREATE2 opcode to prevent users from deploying initializable contracts using non-initializable functions such as [`deployCreate2`](#deploycreate2) without having the initialization call. + +- In other words, if the providedSalt was not hashed and was used as it is as the salt by the CREATE2 opcode, malicious users can check the generated salt used for the already deployed initializable contract on chain 1, and deploy the contract from [`deployCreate2`](#deploycreate2) function on chain 2, with passing the generated salt of the deployed contract as providedSalt that will produce the same address but without the initialization, where the malicious user can initialize after. #### Parameters @@ -339,20 +367,22 @@ Bubble the revert reason if present, revert with `ContractInitializationFailed` ::: ```solidity -event ContractCreated(address indexed contractCreated, bytes32 indexed providedSalt, bytes32 generatedSalt, bool indexed initialized, bytes initializeCalldata); +event ContractCreated(address indexed createdContract, bytes32 indexed providedSalt, bytes32 generatedSalt, bool indexed initialized, bytes initializeCalldata); ``` -Emitted whenever a contract is created +_Contract created. Contract address: `createdContract`._ + +Emitted whenever a contract is created. #### Parameters -| Name | Type | Description | -| ------------------------------- | :-------: | -------------------------------------------------------------------------------------------------------------------------------------------------- | -| `contractCreated` **`indexed`** | `address` | The address of the contract created | -| `providedSalt` **`indexed`** | `bytes32` | The salt provided by the deployer, which will be used to generate the final salt that will be used by the `CREATE2` opcode for contract deployment | -| `generatedSalt` | `bytes32` | The salt used by the `CREATE2` opcode for contract deployment | -| `initialized` **`indexed`** | `bool` | The Boolean that specifies if the contract must be initialized or not | -| `initializeCalldata` | `bytes` | The bytes provided as initializeCalldata (Empty string when `initialized` is set to false) | +| Name | Type | Description | +| ------------------------------- | :-------: | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| `createdContract` **`indexed`** | `address` | The address of the contract created. | +| `providedSalt` **`indexed`** | `bytes32` | The salt provided by the deployer, which will be used to generate the final salt that will be used by the `CREATE2` opcode for contract deployment. | +| `generatedSalt` | `bytes32` | The salt used by the `CREATE2` opcode for contract deployment. | +| `initialized` **`indexed`** | `bool` | The Boolean that specifies if the contract must be initialized or not. | +| `initializeCalldata` | `bytes` | The bytes provided as initializeCalldata (Empty string when `initialized` is set to false). |
@@ -373,7 +403,9 @@ Emitted whenever a contract is created error ContractInitializationFailed(); ``` -Reverts when there is no revert reason bubbled up by the contract created when initializing +_Couldn't initialize the contract._ + +Reverts when there is no revert reason bubbled up by the created contract when initializing
@@ -392,6 +424,6 @@ Reverts when there is no revert reason bubbled up by the contract created when i error InvalidValueSum(); ``` -Reverts when msg.value sent to [`deployCreate2AndInitialize`](#deploycreate2andinitialize) function is not equal to the sum of the `initializeCalldataMsgValue` and `constructorMsgValue` +Reverts when `msg.value` sent to [`deployCreate2AndInitialize(..)`](#deploycreate2andinitialize) function is not equal to the sum of the `initializeCalldataMsgValue` and `constructorMsgValue`
From 19b467409dad621f4eeda48d9a1aa23e5885eecb Mon Sep 17 00:00:00 2001 From: Jean Cvllr <31145285+CJ42@users.noreply.github.com> Date: Tue, 19 Sep 2023 09:59:56 +0100 Subject: [PATCH 09/55] chore: clean unused imports, upgrade solhint and adjust Solidity linter rules (#713) * build: upgrade solhint version * chore: remove unused imports * chore: remove unused imports for LSP1 * chore: remove unused imports for LSP4 * chore: remove unused imports for LSP5 and LSP10 * chore: LSP6 - remove unusued + fix global imports * chore: fix imports + remove unused ones in LSP7 / LSP8 * chore: fix + remove unused imports for LSP9 * chore: fix global import for LSP11 * chore: fix global imports for LSP14, LSP17 and LSP20 * chore: fix imports for Mock contracts * chore: update solhint rules for `no-empty-blocks`, import rules + turn off `custom-errors` * chore: use capitalized `SNAKE_CASE` for total supply immutable * docs: update auto-generated docs for LSP7/8 Capped Supply * chore: adjust solhint-disable comments for next line + fix failing tests * docs: update auto-generated docs for LSP7/8 Compatible --- .solhint.json | 5 +- .../LSP0ERC725Account/ILSP0ERC725Account.sol | 14 - .../LSP0ERC725AccountCore.sol | 26 +- contracts/LSP10ReceivedVaults/LSP10Utils.sol | 8 +- .../LSP11BasicSocialRecoveryCore.sol | 12 +- .../LSP14Ownable2Step/LSP14Ownable2Step.sol | 6 +- .../LSP17Extendable.sol | 2 +- .../LSP1UniversalReceiverDelegateUP.sol | 22 +- .../LSP1UniversalReceiverDelegateVault.sol | 12 +- contracts/LSP1UniversalReceiver/LSP1Utils.sol | 9 +- .../LSP20CallVerification.sol | 5 +- .../LSP25MultiChannelNonce.sol | 4 +- .../LSP4Compatibility.sol | 5 +- .../LSP4DigitalAssetMetadata.sol | 7 +- .../LSP4DigitalAssetMetadataInitAbstract.sol | 7 +- contracts/LSP5ReceivedAssets/LSP5Utils.sol | 7 +- .../LSP6KeyManager/LSP6KeyManagerCore.sol | 8 +- .../LSP6Modules/LSP6ExecuteModule.sol | 1 - contracts/LSP6KeyManager/LSP6Utils.sol | 22 +- .../LSP7DigitalAsset/LSP7DigitalAsset.sol | 8 +- .../LSP7DigitalAsset/LSP7DigitalAssetCore.sol | 15 +- .../LSP7DigitalAssetInitAbstract.sol | 6 +- .../extensions/LSP7CappedSupply.sol | 8 +- .../extensions/LSP7CompatibleERC20.sol | 10 - .../LSP7CompatibleERC20InitAbstract.sol | 10 - .../LSP8IdentifiableDigitalAsset.sol | 6 +- .../LSP8IdentifiableDigitalAssetCore.sol | 18 +- ...P8IdentifiableDigitalAssetInitAbstract.sol | 6 +- .../extensions/LSP8CappedSupply.sol | 8 +- .../extensions/LSP8CompatibleERC721.sol | 8 +- .../LSP8CompatibleERC721InitAbstract.sol | 8 +- contracts/LSP9Vault/ILSP9Vault.sol | 13 - contracts/LSP9Vault/LSP9VaultCore.sol | 43 +- contracts/Mocks/ERC165Interfaces.sol | 1 + contracts/Mocks/ExecutorLSP20.sol | 2 - contracts/Mocks/KeyManagerWithExtraParams.sol | 8 +- .../FirstCallReturnExpandedInvalidValue.sol | 3 - .../FirstCallReturnInvalidMagicValue.sol | 4 - contracts/Mocks/PayableContract.sol | 3 + .../Reentrancy/LSP20ReentrantContract.sol | 10 +- .../Mocks/Reentrancy/ReentrantContract.sol | 9 +- .../Mocks/Reentrancy/ThreeReentrancy.sol | 4 +- .../Tokens/LSP7CompatibleERC20InitTester.sol | 1 - .../Tokens/LSP7CompatibleERC20Tester.sol | 1 - .../Tokens/LSP8CompatibleERC721Tester.sol | 3 - .../Tokens/LSP8CompatibleERC721TesterInit.sol | 3 - .../Mocks/Tokens/RequireCallbackToken.sol | 4 +- ...nReceiverWithoutLSP1WithERC721Received.sol | 3 - ...erWithoutLSP1WithERC721ReceivedInvalid.sol | 3 - ...verWithoutLSP1WithERC721ReceivedRevert.sol | 3 - .../Mocks/UPWithInstantAcceptOwnership.sol | 12 +- .../UniversalReceiverDelegateDataUpdater.sol | 8 - .../UniversalReceiverDelegateGasConsumer.sol | 1 + ...niversalReceiverDelegateTokenReentrant.sol | 3 - ...niversalReceiverDelegateVaultMalicious.sol | 22 +- ...iversalReceiverDelegateVaultReentrantA.sol | 14 +- ...iversalReceiverDelegateVaultReentrantB.sol | 16 +- .../UniversalReceiverDelegateVaultSetter.sol | 3 - .../extensions/LSP7CappedSupply.md | 2 +- .../extensions/LSP8CappedSupply.md | 2 +- package-lock.json | 1763 +++-------------- package.json | 2 +- .../LSP23LinkedContractsDeployment.test.ts | 4 +- 63 files changed, 595 insertions(+), 1671 deletions(-) diff --git a/.solhint.json b/.solhint.json index 098ebd76c..26e01c48a 100644 --- a/.solhint.json +++ b/.solhint.json @@ -15,8 +15,11 @@ "private-vars-leading-underscore": ["error", { "strict": false }], "imports-on-top": "error", "visibility-modifier-order": "error", + "no-unused-import": "error", + "no-global-import": "error", "reason-string": ["warn", { "maxLength": 120 }], "avoid-low-level-calls": "off", - "no-empty-blocks": "off" + "no-empty-blocks": ["error", { "ignoreConstructors": true }], + "custom-errors": "off" } } diff --git a/contracts/LSP0ERC725Account/ILSP0ERC725Account.sol b/contracts/LSP0ERC725Account/ILSP0ERC725Account.sol index f930c39da..f2704401a 100644 --- a/contracts/LSP0ERC725Account/ILSP0ERC725Account.sol +++ b/contracts/LSP0ERC725Account/ILSP0ERC725Account.sol @@ -1,20 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; -// interfaces -import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; -import { - IERC725X -} from "@erc725/smart-contracts/contracts/interfaces/IERC725X.sol"; -import { - IERC725Y -} from "@erc725/smart-contracts/contracts/interfaces/IERC725Y.sol"; -import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol"; -import { - ILSP1UniversalReceiver -} from "../LSP1UniversalReceiver/ILSP1UniversalReceiver.sol"; -import {ILSP14Ownable2Step} from "../LSP14Ownable2Step/ILSP14Ownable2Step.sol"; - /** * @title Interface of the [LSP-0-ERC725Account] standard, an account based smart contract that represents an identity on-chain. * diff --git a/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol b/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol index 7ed6b5cb8..0585fee4e 100644 --- a/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol +++ b/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol @@ -19,14 +19,8 @@ import {LSP1Utils} from "../LSP1UniversalReceiver/LSP1Utils.sol"; import {LSP2Utils} from "../LSP2ERC725YJSONSchema/LSP2Utils.sol"; // modules -import { - ERC725YCore, - IERC725Y -} from "@erc725/smart-contracts/contracts/ERC725YCore.sol"; -import { - ERC725XCore, - IERC725X -} from "@erc725/smart-contracts/contracts/ERC725XCore.sol"; +import {ERC725YCore} from "@erc725/smart-contracts/contracts/ERC725YCore.sol"; +import {ERC725XCore} from "@erc725/smart-contracts/contracts/ERC725XCore.sol"; import { OwnableUnset } from "@erc725/smart-contracts/contracts/custom/OwnableUnset.sol"; @@ -37,7 +31,6 @@ import { } from "../LSP20CallVerification/LSP20CallVerification.sol"; // constants -import "@erc725/smart-contracts/contracts/constants.sol"; import { _INTERFACEID_LSP0, _INTERFACEID_ERC1271, @@ -69,10 +62,6 @@ import { NoExtensionFoundForFunctionSelector } from "../LSP17ContractExtension/LSP17Errors.sol"; -import { - LSP14MustAcceptOwnershipInSeparateTransaction -} from "../LSP14Ownable2Step/LSP14Errors.sol"; - /** * @title The Core Implementation of [LSP-0-ERC725Account] Standard. * @@ -105,8 +94,6 @@ abstract contract LSP0ERC725AccountCore is } } - // solhint-disable no-complex-fallback - /** * @notice The `fallback` function was called with the following amount of native tokens: `msg.value`; and the following calldata: `callData`. * @@ -128,6 +115,7 @@ abstract contract LSP0ERC725AccountCore is * * @custom:events {ValueReceived} event when receiving native tokens. */ + // solhint-disable-next-line no-complex-fallback fallback( bytes calldata callData ) external payable virtual returns (bytes memory) { @@ -180,7 +168,7 @@ abstract contract LSP0ERC725AccountCore is } /** - * @inheritdoc IERC725X + * @inheritdoc ERC725XCore * * @custom:requirements * - Can be only called by the {owner} or by an authorised address that pass the verification check performed on the owner. @@ -231,7 +219,7 @@ abstract contract LSP0ERC725AccountCore is } /** - * @inheritdoc IERC725X + * @inheritdoc ERC725XCore * * @custom:requirements * - The length of the parameters provided must be equal. @@ -292,7 +280,7 @@ abstract contract LSP0ERC725AccountCore is } /** - * @inheritdoc IERC725Y + * @inheritdoc ERC725YCore * * @custom:requirements Can be only called by the {owner} or by an authorised address that pass the verification check performed on the owner. * @@ -329,7 +317,7 @@ abstract contract LSP0ERC725AccountCore is } /** - * @inheritdoc IERC725Y + * @inheritdoc ERC725YCore * * @custom:requirements Can be only called by the {owner} or by an authorised address that pass the verification check performed on the owner. * diff --git a/contracts/LSP10ReceivedVaults/LSP10Utils.sol b/contracts/LSP10ReceivedVaults/LSP10Utils.sol index 869358bc7..0321eec00 100644 --- a/contracts/LSP10ReceivedVaults/LSP10Utils.sol +++ b/contracts/LSP10ReceivedVaults/LSP10Utils.sol @@ -7,12 +7,14 @@ import { } from "@erc725/smart-contracts/contracts/interfaces/IERC725Y.sol"; // libraries -import {BytesLib} from "solidity-bytes-utils/contracts/BytesLib.sol"; import {LSP2Utils} from "../LSP2ERC725YJSONSchema/LSP2Utils.sol"; // constants -import "../LSP10ReceivedVaults/LSP10Constants.sol"; -import "../LSP9Vault/LSP9Constants.sol"; +import {_INTERFACEID_LSP9} from "../LSP9Vault/LSP9Constants.sol"; +import { + _LSP10_VAULTS_MAP_KEY_PREFIX, + _LSP10_VAULTS_ARRAY_KEY +} from "../LSP10ReceivedVaults/LSP10Constants.sol"; /** * @title LSP10 Utility library. diff --git a/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryCore.sol b/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryCore.sol index 96c47b785..5becb85f2 100644 --- a/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryCore.sol +++ b/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryCore.sol @@ -20,7 +20,17 @@ import { // constants import {ALL_REGULAR_PERMISSIONS} from "../LSP6KeyManager/LSP6Constants.sol"; import {_INTERFACEID_LSP11} from "./LSP11Constants.sol"; -import "./LSP11Errors.sol"; +import { + CallerIsNotGuardian, + GuardianAlreadyExist, + GuardianDoNotExist, + GuardiansNumberCannotGoBelowThreshold, + ThresholdCannotBeHigherThanGuardiansNumber, + SecretHashCannotBeZero, + AddressZeroNotAllowed, + ThresholdNotReachedForRecoverer, + WrongPlainSecret +} from "./LSP11Errors.sol"; /** * @title Core Implementation of LSP11-BasicSocialRecovery standard diff --git a/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol b/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol index e66a30632..6bd2f3716 100644 --- a/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol +++ b/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol @@ -13,7 +13,11 @@ import { import {LSP1Utils} from "../LSP1UniversalReceiver/LSP1Utils.sol"; // errors -import "./LSP14Errors.sol"; +import { + LSP14MustAcceptOwnershipInSeparateTransaction, + CannotTransferOwnershipToSelf, + NotInRenounceOwnershipInterval +} from "./LSP14Errors.sol"; // constants import { diff --git a/contracts/LSP17ContractExtension/LSP17Extendable.sol b/contracts/LSP17ContractExtension/LSP17Extendable.sol index 075f53711..7311879d4 100644 --- a/contracts/LSP17ContractExtension/LSP17Extendable.sol +++ b/contracts/LSP17ContractExtension/LSP17Extendable.sol @@ -11,7 +11,7 @@ import { import {_INTERFACEID_LSP17_EXTENDABLE} from "./LSP17Constants.sol"; // errors -import "./LSP17Errors.sol"; +import {NoExtensionFoundForFunctionSelector} from "./LSP17Errors.sol"; /** * @title Module to add more functionalities to a contract using extensions. diff --git a/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol b/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol index eef3894e2..e272690ab 100644 --- a/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol +++ b/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol @@ -15,9 +15,11 @@ import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; -import {LSP1Utils} from "../LSP1Utils.sol"; -import {LSP2Utils} from "../../LSP2ERC725YJSONSchema/LSP2Utils.sol"; import {LSP5Utils} from "../../LSP5ReceivedAssets/LSP5Utils.sol"; +import {LSP10Utils} from "../../LSP10ReceivedVaults/LSP10Utils.sol"; + +// constants +import {_INTERFACEID_LSP1} from "../LSP1Constants.sol"; import { _TYPEID_LSP7_TOKENSSENDER, _TYPEID_LSP7_TOKENSRECIPIENT, @@ -32,18 +34,12 @@ import { _TYPEID_LSP9_OwnershipTransferred_SenderNotification, _TYPEID_LSP9_OwnershipTransferred_RecipientNotification } from "../../LSP9Vault/LSP9Constants.sol"; -import {LSP10Utils} from "../../LSP10ReceivedVaults/LSP10Utils.sol"; - -// constants -import "../LSP1Constants.sol"; -import "../../LSP0ERC725Account/LSP0Constants.sol"; -import "../../LSP6KeyManager/LSP6Constants.sol"; -import "../../LSP9Vault/LSP9Constants.sol"; -import "../../LSP10ReceivedVaults/LSP10Constants.sol"; -import "../../LSP14Ownable2Step/LSP14Constants.sol"; // errors -import "../LSP1Errors.sol"; +import { + NativeTokensNotAccepted, + CannotRegisterEOAsAsAssets +} from "../LSP1Errors.sol"; /** * @title Implementation of a UniversalReceiverDelegate for the [LSP-0-ERC725Account] @@ -93,7 +89,7 @@ contract LSP1UniversalReceiverDelegateUP is ERC165, ILSP1UniversalReceiver { // The notifier is supposed to be either the LSP7 or LSP8 or LSP9 contract // If it's EOA we revert to avoid registering the EOA as asset or vault (spam protection) - // solhint-disable avoid-tx-origin + // solhint-disable-next-line avoid-tx-origin if (notifier == tx.origin) { revert CannotRegisterEOAsAsAssets(notifier); } diff --git a/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol b/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol index 669049f06..e88ed8d45 100644 --- a/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol +++ b/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol @@ -12,12 +12,10 @@ import {ILSP7DigitalAsset} from "../../LSP7DigitalAsset/ILSP7DigitalAsset.sol"; import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; // libraries -import {LSP1Utils} from "../LSP1Utils.sol"; -import {LSP2Utils} from "../../LSP2ERC725YJSONSchema/LSP2Utils.sol"; import {LSP5Utils} from "../../LSP5ReceivedAssets/LSP5Utils.sol"; // constants -import "../LSP1Constants.sol"; +import {_INTERFACEID_LSP1} from "../LSP1Constants.sol"; import { _TYPEID_LSP7_TOKENSSENDER, _TYPEID_LSP7_TOKENSRECIPIENT, @@ -28,10 +26,12 @@ import { _TYPEID_LSP8_TOKENSRECIPIENT, _INTERFACEID_LSP8 } from "../../LSP8IdentifiableDigitalAsset/LSP8Constants.sol"; -import "../../LSP9Vault/LSP9Constants.sol"; // errors -import "../LSP1Errors.sol"; +import { + CannotRegisterEOAsAsAssets, + NativeTokensNotAccepted +} from "../LSP1Errors.sol"; /** * @title Implementation of a UniversalReceiverDelegate for the [LSP9Vault] @@ -73,7 +73,7 @@ contract LSP1UniversalReceiverDelegateVault is ERC165, ILSP1UniversalReceiver { // The notifier is supposed to be either the LSP7 or LSP8 contract // If it's EOA we revert to avoid registering the EOA as asset (spam protection) - // solhint-disable avoid-tx-origin + // solhint-disable-next-line avoid-tx-origin if (notifier == tx.origin) { revert CannotRegisterEOAsAsAssets(notifier); } diff --git a/contracts/LSP1UniversalReceiver/LSP1Utils.sol b/contracts/LSP1UniversalReceiver/LSP1Utils.sol index f954020c9..0d3c2cd0a 100644 --- a/contracts/LSP1UniversalReceiver/LSP1Utils.sol +++ b/contracts/LSP1UniversalReceiver/LSP1Utils.sol @@ -9,7 +9,7 @@ import { import {LSP2Utils} from "../LSP2ERC725YJSONSchema/LSP2Utils.sol"; // constants -import "./ILSP1UniversalReceiver.sol"; +import {ILSP1UniversalReceiver as ILSP1} from "./ILSP1UniversalReceiver.sol"; // constants import { @@ -45,10 +45,7 @@ library LSP1Utils { _INTERFACEID_LSP1 ) ) { - ILSP1UniversalReceiver(lsp1Implementation).universalReceiver( - typeId, - data - ); + ILSP1(lsp1Implementation).universalReceiver(typeId, data); } } @@ -73,7 +70,7 @@ library LSP1Utils { ) internal returns (bytes memory) { bytes memory callData = abi.encodePacked( abi.encodeWithSelector( - ILSP1UniversalReceiver.universalReceiver.selector, + ILSP1.universalReceiver.selector, typeId, receivedData ), diff --git a/contracts/LSP20CallVerification/LSP20CallVerification.sol b/contracts/LSP20CallVerification/LSP20CallVerification.sol index 81f2c5cd2..5c1477d24 100644 --- a/contracts/LSP20CallVerification/LSP20CallVerification.sol +++ b/contracts/LSP20CallVerification/LSP20CallVerification.sol @@ -6,7 +6,10 @@ pragma solidity ^0.8.4; import {ILSP20CallVerifier as ILSP20} from "./ILSP20CallVerifier.sol"; // errors -import "./LSP20Errors.sol"; +import { + LSP20InvalidMagicValue, + LSP20CallingVerifierFailed +} from "./LSP20Errors.sol"; /** * @title Implementation of a contract calling the verification functions according to LSP20 - Call Verification standard. diff --git a/contracts/LSP25ExecuteRelayCall/LSP25MultiChannelNonce.sol b/contracts/LSP25ExecuteRelayCall/LSP25MultiChannelNonce.sol index ff90206f1..15dbc1cb7 100644 --- a/contracts/LSP25ExecuteRelayCall/LSP25MultiChannelNonce.sol +++ b/contracts/LSP25ExecuteRelayCall/LSP25MultiChannelNonce.sol @@ -109,10 +109,12 @@ abstract contract LSP25MultiChannelNonce { uint128 startingTimestamp = uint128(validityTimestamps >> 128); uint128 endingTimestamp = uint128(validityTimestamps); - // solhint-disable not-rely-on-time + // solhint-disable-next-line not-rely-on-time if (block.timestamp < startingTimestamp) { revert RelayCallBeforeStartTime(); } + + // solhint-disable-next-line not-rely-on-time if (block.timestamp > endingTimestamp) { revert RelayCallExpired(); } diff --git a/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol b/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol index 7442f739e..e2c394a18 100644 --- a/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol +++ b/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol @@ -8,7 +8,10 @@ import {ILSP4Compatibility} from "./ILSP4Compatibility.sol"; import {ERC725YCore} from "@erc725/smart-contracts/contracts/ERC725YCore.sol"; // constants -import "./LSP4Constants.sol"; +import { + _LSP4_TOKEN_NAME_KEY, + _LSP4_TOKEN_SYMBOL_KEY +} from "./LSP4Constants.sol"; /** * @title LSP4Compatibility diff --git a/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.sol b/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.sol index 9aedc4f0b..7fff22763 100644 --- a/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.sol +++ b/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.sol @@ -8,7 +8,12 @@ import {ERC725Y} from "@erc725/smart-contracts/contracts/ERC725Y.sol"; import {BytesLib} from "solidity-bytes-utils/contracts/BytesLib.sol"; // constants -import "./LSP4Constants.sol"; +import { + _LSP4_SUPPORTED_STANDARDS_KEY, + _LSP4_SUPPORTED_STANDARDS_VALUE, + _LSP4_TOKEN_NAME_KEY, + _LSP4_TOKEN_SYMBOL_KEY +} from "./LSP4Constants.sol"; // errors import { diff --git a/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadataInitAbstract.sol b/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadataInitAbstract.sol index a77c55c9f..59ba3a837 100644 --- a/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadataInitAbstract.sol +++ b/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadataInitAbstract.sol @@ -10,7 +10,12 @@ import { import {BytesLib} from "solidity-bytes-utils/contracts/BytesLib.sol"; // constants -import "./LSP4Constants.sol"; +import { + _LSP4_SUPPORTED_STANDARDS_KEY, + _LSP4_SUPPORTED_STANDARDS_VALUE, + _LSP4_TOKEN_NAME_KEY, + _LSP4_TOKEN_SYMBOL_KEY +} from "./LSP4Constants.sol"; // errors import { diff --git a/contracts/LSP5ReceivedAssets/LSP5Utils.sol b/contracts/LSP5ReceivedAssets/LSP5Utils.sol index cea4fdf93..83ea23d46 100644 --- a/contracts/LSP5ReceivedAssets/LSP5Utils.sol +++ b/contracts/LSP5ReceivedAssets/LSP5Utils.sol @@ -7,12 +7,13 @@ import { } from "@erc725/smart-contracts/contracts/interfaces/IERC725Y.sol"; // libraries -import {BytesLib} from "solidity-bytes-utils/contracts/BytesLib.sol"; import {LSP2Utils} from "../LSP2ERC725YJSONSchema/LSP2Utils.sol"; // constants -import "../LSP5ReceivedAssets/LSP5Constants.sol"; -import "../LSP7DigitalAsset/LSP7Constants.sol"; +import { + _LSP5_RECEIVED_ASSETS_MAP_KEY_PREFIX, + _LSP5_RECEIVED_ASSETS_ARRAY_KEY +} from "../LSP5ReceivedAssets/LSP5Constants.sol"; /** * @title LSP5 Utility library. diff --git a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol index a20d146fd..3270053fa 100644 --- a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol +++ b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol @@ -57,7 +57,12 @@ import { _PERMISSION_SIGN, _PERMISSION_REENTRANCY } from "./LSP6Constants.sol"; -import "../LSP20CallVerification/LSP20Constants.sol"; +import { + _INTERFACEID_LSP20_CALL_VERIFIER, + _LSP20_VERIFY_CALL_MAGIC_VALUE_WITHOUT_POST_VERIFICATION, + _LSP20_VERIFY_CALL_MAGIC_VALUE_WITH_POST_VERIFICATION, + _LSP20_VERIFY_CALL_RESULT_MAGIC_VALUE +} from "../LSP20CallVerification/LSP20Constants.sol"; import {_INTERFACEID_LSP25} from "../LSP25ExecuteRelayCall/LSP25Constants.sol"; /** @@ -72,6 +77,7 @@ import {_INTERFACEID_LSP25} from "../LSP25ExecuteRelayCall/LSP25Constants.sol"; */ abstract contract LSP6KeyManagerCore is ERC165, + IERC1271, ILSP6, ILSP20, ILSP25, diff --git a/contracts/LSP6KeyManager/LSP6Modules/LSP6ExecuteModule.sol b/contracts/LSP6KeyManager/LSP6Modules/LSP6ExecuteModule.sol index 84c85939a..1747ca931 100644 --- a/contracts/LSP6KeyManager/LSP6Modules/LSP6ExecuteModule.sol +++ b/contracts/LSP6KeyManager/LSP6Modules/LSP6ExecuteModule.sol @@ -41,7 +41,6 @@ import { InvalidEncodedAllowedCalls, InvalidWhitelistedCall, NotAuthorised, - InvalidPayload, CallingKeyManagerNotAllowed } from "../LSP6Errors.sol"; diff --git a/contracts/LSP6KeyManager/LSP6Utils.sol b/contracts/LSP6KeyManager/LSP6Utils.sol index da04f1612..03f4516ac 100644 --- a/contracts/LSP6KeyManager/LSP6Utils.sol +++ b/contracts/LSP6KeyManager/LSP6Utils.sol @@ -11,7 +11,27 @@ import {ILSP6KeyManager} from "./ILSP6KeyManager.sol"; import {LSP2Utils} from "../LSP2ERC725YJSONSchema/LSP2Utils.sol"; // constants -import "./LSP6Constants.sol"; +import { + _LSP6KEY_ADDRESSPERMISSIONS_PERMISSIONS_PREFIX, + _LSP6KEY_ADDRESSPERMISSIONS_ALLOWEDCALLS_PREFIX, + _LSP6KEY_ADDRESSPERMISSIONS_AllowedERC725YDataKeys_PREFIX, + _LSP6KEY_ADDRESSPERMISSIONS_ARRAY, + _PERMISSION_CHANGEOWNER, + _PERMISSION_EDITPERMISSIONS, + _PERMISSION_ADDCONTROLLER, + _PERMISSION_ADDEXTENSIONS, + _PERMISSION_CHANGEEXTENSIONS, + _PERMISSION_ADDUNIVERSALRECEIVERDELEGATE, + _PERMISSION_CHANGEUNIVERSALRECEIVERDELEGATE, + _PERMISSION_REENTRANCY, + _PERMISSION_SETDATA, + _PERMISSION_CALL, + _PERMISSION_STATICCALL, + _PERMISSION_DELEGATECALL, + _PERMISSION_DEPLOY, + _PERMISSION_TRANSFERVALUE, + _PERMISSION_SIGN +} from "./LSP6Constants.sol"; /** * @title LSP6 Utility library. diff --git a/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol b/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol index 533e408c5..85e877afd 100644 --- a/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol +++ b/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol @@ -18,7 +18,9 @@ import {LSP2Utils} from "../LSP2ERC725YJSONSchema/LSP2Utils.sol"; // constants import {_INTERFACEID_LSP7} from "./LSP7Constants.sol"; -import "../LSP17ContractExtension/LSP17Constants.sol"; +import { + _LSP17_EXTENSION_PREFIX +} from "../LSP17ContractExtension/LSP17Constants.sol"; // errors @@ -60,7 +62,6 @@ abstract contract LSP7DigitalAsset is // fallback function - // solhint-disable no-complex-fallback /** * @notice The `fallback` function was called with the following amount of native tokens: `msg.value`; and the following calldata: `callData`. * @@ -80,6 +81,7 @@ abstract contract LSP7DigitalAsset is * * 2. If the data sent to this function is of length less than 4 bytes (not a function selector), revert. */ + // solhint-disable-next-line no-complex-fallback fallback( bytes calldata callData ) external payable virtual returns (bytes memory) { @@ -125,8 +127,8 @@ abstract contract LSP7DigitalAsset is } else { // `mload(result)` -> offset in memory where `result.length` is located // `add(result, 32)` -> offset in memory where `result` data starts - // solhint-disable no-inline-assembly /// @solidity memory-safe-assembly + // solhint-disable-next-line no-inline-assembly assembly { let resultdata_size := mload(result) revert(add(result, 32), resultdata_size) diff --git a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol index d542a8581..c878ef51c 100644 --- a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol +++ b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol @@ -17,7 +17,18 @@ import { } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; // errors -import "./LSP7Errors.sol"; +import { + LSP7CannotSendToSelf, + LSP7AmountExceedsAuthorizedAmount, + LSP7InvalidTransferBatch, + LSP7AmountExceedsBalance, + LSP7DecreasedAllowanceBelowZero, + LSP7CannotUseAddressZeroAsOperator, + LSP7TokenOwnerCannotBeOperator, + LSP7CannotSendWithAddressZero, + LSP7NotifyTokenReceiverContractMissingLSP1Interface, + LSP7NotifyTokenReceiverIsEOA +} from "./LSP7Errors.sol"; // constants import {_INTERFACEID_LSP1} from "../LSP1UniversalReceiver/LSP1Constants.sol"; @@ -536,7 +547,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { function _beforeTokenTransfer( address from, address to, - uint256 amount + uint256 amount // solhint-disable-next-line no-empty-blocks ) internal virtual {} /** diff --git a/contracts/LSP7DigitalAsset/LSP7DigitalAssetInitAbstract.sol b/contracts/LSP7DigitalAsset/LSP7DigitalAssetInitAbstract.sol index 30e4dfcde..33295a77b 100644 --- a/contracts/LSP7DigitalAsset/LSP7DigitalAssetInitAbstract.sol +++ b/contracts/LSP7DigitalAsset/LSP7DigitalAssetInitAbstract.sol @@ -19,7 +19,9 @@ import {LSP2Utils} from "../LSP2ERC725YJSONSchema/LSP2Utils.sol"; // constants import {_INTERFACEID_LSP7} from "./LSP7Constants.sol"; -import "../LSP17ContractExtension/LSP17Constants.sol"; +import { + _LSP17_EXTENSION_PREFIX +} from "../LSP17ContractExtension/LSP17Constants.sol"; // errors @@ -55,7 +57,6 @@ abstract contract LSP7DigitalAssetInitAbstract is // fallback function - // solhint-disable no-complex-fallback /** * @notice The `fallback` function was called with the following amount of native tokens: `msg.value`; and the following calldata: `callData`. * @@ -75,6 +76,7 @@ abstract contract LSP7DigitalAssetInitAbstract is * * 2. If the data sent to this function is of length less than 4 bytes (not a function selector), revert. */ + // solhint-disable-next-line no-complex-fallback fallback( bytes calldata callData ) external payable virtual returns (bytes memory) { diff --git a/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.sol b/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.sol index 0356132bb..1d4b06082 100644 --- a/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.sol +++ b/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.sol @@ -24,7 +24,7 @@ abstract contract LSP7CappedSupply is LSP7DigitalAsset { error LSP7CappedSupplyCannotMintOverCap(); // --- Storage - uint256 private immutable _tokenSupplyCap; + uint256 private immutable _TOKEN_SUPPLY_CAP; /** * @notice Deploying a `LSP7CappedSupply` token contract with max token supply cap set to `tokenSupplyCap_`. @@ -41,13 +41,13 @@ abstract contract LSP7CappedSupply is LSP7DigitalAsset { revert LSP7CappedSupplyRequired(); } - _tokenSupplyCap = tokenSupplyCap_; + _TOKEN_SUPPLY_CAP = tokenSupplyCap_; } // --- Token queries /** - * @notice The maximum supply amount of tokens allowed to exist is `_tokenSupplyCap`. + * @notice The maximum supply amount of tokens allowed to exist is `_TOKEN_SUPPLY_CAP`. * * @dev Get the maximum number of tokens that can exist to circulate. Once {totalSupply} reaches * reaches {totalSuuplyCap}, it is not possible to mint more tokens. @@ -55,7 +55,7 @@ abstract contract LSP7CappedSupply is LSP7DigitalAsset { * @return The maximum number of tokens that can exist in the contract. */ function tokenSupplyCap() public view virtual returns (uint256) { - return _tokenSupplyCap; + return _TOKEN_SUPPLY_CAP; } // --- Transfer functionality diff --git a/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol b/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol index 207bded2b..d63562b0e 100644 --- a/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol +++ b/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol @@ -11,7 +11,6 @@ import { } from "../../LSP4DigitalAssetMetadata/LSP4Compatibility.sol"; import { LSP7DigitalAsset, - LSP7DigitalAssetCore, LSP4DigitalAssetMetadata, ERC725YCore } from "../LSP7DigitalAsset.sol"; @@ -103,9 +102,6 @@ abstract contract LSP7CompatibleERC20 is return true; } - /** - * @inheritdoc LSP7DigitalAssetCore - */ function _updateOperator( address tokenOwner, address operator, @@ -122,8 +118,6 @@ abstract contract LSP7CompatibleERC20 is } /** - * @inheritdoc LSP7DigitalAssetCore - * * @custom:events * - LSP7 {Transfer} event. * - ERC20 {Transfer} event. @@ -140,8 +134,6 @@ abstract contract LSP7CompatibleERC20 is } /** - * @inheritdoc LSP7DigitalAssetCore - * * @custom:events * - LSP7 {Transfer} event with `address(0)` as `from`. * - ERC20 {Transfer} event with `address(0)` as `from`. @@ -157,8 +149,6 @@ abstract contract LSP7CompatibleERC20 is } /** - * @inheritdoc LSP7DigitalAssetCore - * * @custom:events * - LSP7 {Transfer} event with `address(0)` as the `to` address. * - ERC20 {Transfer} event with `address(0)` as the `to` address. diff --git a/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20InitAbstract.sol b/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20InitAbstract.sol index c79f81e7c..2ab5adbe5 100644 --- a/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20InitAbstract.sol +++ b/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20InitAbstract.sol @@ -10,7 +10,6 @@ import { LSP4Compatibility } from "../../LSP4DigitalAssetMetadata/LSP4Compatibility.sol"; import { - LSP7DigitalAssetCore, LSP7DigitalAssetInitAbstract, LSP4DigitalAssetMetadataInitAbstract, ERC725YCore @@ -110,9 +109,6 @@ abstract contract LSP7CompatibleERC20InitAbstract is return true; } - /** - * @inheritdoc LSP7DigitalAssetCore - */ function _updateOperator( address tokenOwner, address operator, @@ -129,8 +125,6 @@ abstract contract LSP7CompatibleERC20InitAbstract is } /** - * @inheritdoc LSP7DigitalAssetCore - * * @custom:events * - LSP7 {Transfer} event. * - ERC20 {Transfer} event. @@ -147,8 +141,6 @@ abstract contract LSP7CompatibleERC20InitAbstract is } /** - * @inheritdoc LSP7DigitalAssetCore - * * @custom:events * - LSP7 {Transfer} event with `address(0)` as `from`. * - ERC20 {Transfer} event with `address(0)` as `from`. @@ -164,8 +156,6 @@ abstract contract LSP7CompatibleERC20InitAbstract is } /** - * @inheritdoc LSP7DigitalAssetCore - * * @custom:events * - LSP7 {Transfer} event with `address(0)` as the `to` address. * - ERC20 {Transfer} event with `address(0)` as the `to` address. diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol index 44065d764..42d996a48 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol @@ -21,7 +21,9 @@ import {LSP2Utils} from "../LSP2ERC725YJSONSchema/LSP2Utils.sol"; // constants import {_INTERFACEID_LSP8} from "./LSP8Constants.sol"; -import "../LSP17ContractExtension/LSP17Constants.sol"; +import { + _LSP17_EXTENSION_PREFIX +} from "../LSP17ContractExtension/LSP17Constants.sol"; // errors @@ -61,7 +63,6 @@ abstract contract LSP8IdentifiableDigitalAsset is // fallback function - // solhint-disable no-complex-fallback /** * @notice The `fallback` function was called with the following amount of native tokens: `msg.value`; and the following calldata: `callData`. * @@ -81,6 +82,7 @@ abstract contract LSP8IdentifiableDigitalAsset is * * 2. If the data sent to this function is of length less than 4 bytes (not a function selector), revert. */ + // solhint-disable-next-line no-complex-fallback fallback( bytes calldata callData ) external payable virtual returns (bytes memory) { diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol index 2a8c93257..09b940984 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol @@ -18,7 +18,21 @@ import { } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; // errors -import "./LSP8Errors.sol"; +import { + LSP8NonExistentTokenId, + LSP8NotTokenOwner, + LSP8CannotUseAddressZeroAsOperator, + LSP8TokenOwnerCannotBeOperator, + LSP8OperatorAlreadyAuthorized, + LSP8NotTokenOperator, + LSP8InvalidTransferBatch, + LSP8NonExistingOperator, + LSP8CannotSendToAddressZero, + LSP8TokenIdAlreadyMinted, + LSP8CannotSendToSelf, + LSP8NotifyTokenReceiverContractMissingLSP1Interface, + LSP8NotifyTokenReceiverIsEOA +} from "./LSP8Errors.sol"; // constants import {_INTERFACEID_LSP1} from "../LSP1UniversalReceiver/LSP1Constants.sol"; @@ -506,7 +520,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is function _beforeTokenTransfer( address from, address to, - bytes32 tokenId + bytes32 tokenId // solhint-disable-next-line no-empty-blocks ) internal virtual {} /** diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetInitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetInitAbstract.sol index 0187cc919..8cb9de384 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetInitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetInitAbstract.sol @@ -21,7 +21,9 @@ import {LSP2Utils} from "../LSP2ERC725YJSONSchema/LSP2Utils.sol"; // constants import {_INTERFACEID_LSP8} from "./LSP8Constants.sol"; -import "../LSP17ContractExtension/LSP17Constants.sol"; +import { + _LSP17_EXTENSION_PREFIX +} from "../LSP17ContractExtension/LSP17Constants.sol"; // errors @@ -61,7 +63,6 @@ abstract contract LSP8IdentifiableDigitalAssetInitAbstract is // fallback function - // solhint-disable no-complex-fallback /** * @notice The `fallback` function was called with the following amount of native tokens: `msg.value`; and the following calldata: `callData`. * @@ -81,6 +82,7 @@ abstract contract LSP8IdentifiableDigitalAssetInitAbstract is * * 2. If the data sent to this function is of length less than 4 bytes (not a function selector), revert. */ + // solhint-disable-next-line no-complex-fallback fallback( bytes calldata callData ) external payable virtual returns (bytes memory) { diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.sol index 8cf3336ed..e0e4226f1 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.sol @@ -26,7 +26,7 @@ abstract contract LSP8CappedSupply is LSP8IdentifiableDigitalAsset { error LSP8CappedSupplyCannotMintOverCap(); // --- Storage - uint256 private immutable _tokenSupplyCap; + uint256 private immutable _TOKEN_SUPPLY_CAP; /** * @notice Deploying a `LSP8CappedSupply` token contract with max token supply cap set to `tokenSupplyCap_`. @@ -43,13 +43,13 @@ abstract contract LSP8CappedSupply is LSP8IdentifiableDigitalAsset { revert LSP8CappedSupplyRequired(); } - _tokenSupplyCap = tokenSupplyCap_; + _TOKEN_SUPPLY_CAP = tokenSupplyCap_; } // --- Token queries /** - * @notice The maximum supply amount of tokens allowed to exist is `_tokenSupplyCap`. + * @notice The maximum supply amount of tokens allowed to exist is `_TOKEN_SUPPLY_CAP`. * * @dev Get the maximum number of tokens that can exist to circulate. Once {totalSupply} reaches * reaches {totalSuuplyCap}, it is not possible to mint more tokens. @@ -57,7 +57,7 @@ abstract contract LSP8CappedSupply is LSP8IdentifiableDigitalAsset { * @return The maximum number of tokens that can exist in the contract. */ function tokenSupplyCap() public view virtual returns (uint256) { - return _tokenSupplyCap; + return _TOKEN_SUPPLY_CAP; } // --- Transfer functionality diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol index 9e21d8487..7f453b5e5 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol @@ -31,7 +31,13 @@ import { } from "../LSP8IdentifiableDigitalAssetCore.sol"; // errors -import "../LSP8Errors.sol"; +import { + LSP8NotTokenOwner, + LSP8CannotUseAddressZeroAsOperator, + LSP8TokenOwnerCannotBeOperator, + LSP8OperatorAlreadyAuthorized, + LSP8NotTokenOperator +} from "../LSP8Errors.sol"; // constants import { diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol index 31550e9e4..294e74091 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol @@ -31,7 +31,13 @@ import { } from "../LSP8IdentifiableDigitalAssetCore.sol"; // errors -import "../LSP8Errors.sol"; +import { + LSP8NotTokenOwner, + LSP8CannotUseAddressZeroAsOperator, + LSP8TokenOwnerCannotBeOperator, + LSP8OperatorAlreadyAuthorized, + LSP8NotTokenOperator +} from "../LSP8Errors.sol"; // constants import { diff --git a/contracts/LSP9Vault/ILSP9Vault.sol b/contracts/LSP9Vault/ILSP9Vault.sol index d8649f4d7..33bc9d443 100644 --- a/contracts/LSP9Vault/ILSP9Vault.sol +++ b/contracts/LSP9Vault/ILSP9Vault.sol @@ -1,19 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; -// interfaces -import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; -import { - IERC725X -} from "@erc725/smart-contracts/contracts/interfaces/IERC725X.sol"; -import { - IERC725Y -} from "@erc725/smart-contracts/contracts/interfaces/IERC725Y.sol"; -import { - ILSP1UniversalReceiver -} from "../LSP1UniversalReceiver/ILSP1UniversalReceiver.sol"; -import {ILSP14Ownable2Step} from "../LSP14Ownable2Step/ILSP14Ownable2Step.sol"; - /** * @title Interface of LSP9 - Vault standard, a blockchain vault that can hold assets and interact with other smart contracts. * @dev Could be owned by an EOA or by a contract and is able to receive and send assets. Also allows for registering received assets by leveraging the key-value storage. diff --git a/contracts/LSP9Vault/LSP9VaultCore.sol b/contracts/LSP9Vault/LSP9VaultCore.sol index 64e73f34a..d6158c740 100644 --- a/contracts/LSP9Vault/LSP9VaultCore.sol +++ b/contracts/LSP9Vault/LSP9VaultCore.sol @@ -9,8 +9,6 @@ import {ILSP9Vault} from "./ILSP9Vault.sol"; // libraries import {BytesLib} from "solidity-bytes-utils/contracts/BytesLib.sol"; - -import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; @@ -18,14 +16,8 @@ import {LSP1Utils} from "../LSP1UniversalReceiver/LSP1Utils.sol"; import {LSP2Utils} from "../LSP2ERC725YJSONSchema/LSP2Utils.sol"; // modules -import { - ERC725XCore, - IERC725X -} from "@erc725/smart-contracts/contracts/ERC725XCore.sol"; -import { - ERC725YCore, - IERC725Y -} from "@erc725/smart-contracts/contracts/ERC725YCore.sol"; +import {ERC725XCore} from "@erc725/smart-contracts/contracts/ERC725XCore.sol"; +import {ERC725YCore} from "@erc725/smart-contracts/contracts/ERC725YCore.sol"; import { OwnableUnset } from "@erc725/smart-contracts/contracts/custom/OwnableUnset.sol"; @@ -33,7 +25,14 @@ import {LSP14Ownable2Step} from "../LSP14Ownable2Step/LSP14Ownable2Step.sol"; import {LSP17Extendable} from "../LSP17ContractExtension/LSP17Extendable.sol"; // constants -import "@erc725/smart-contracts/contracts/errors.sol"; +import { + ERC725Y_MsgValueDisallowed, + ERC725Y_DataKeysValuesLengthMismatch, + ERC725X_CreateOperationsRequireEmptyRecipientAddress, + ERC725X_CreateOperationsRequireEmptyRecipientAddress, + ERC725X_MsgValueDisallowedInStaticCall, + ERC725X_UnknownOperationType +} from "@erc725/smart-contracts/contracts/errors.sol"; import { OPERATION_0_CALL, OPERATION_1_CREATE, @@ -61,12 +60,11 @@ import { } from "../LSP17ContractExtension/LSP17Constants.sol"; // errors -import "./LSP9Errors.sol"; -import "../LSP17ContractExtension/LSP17Errors.sol"; +import {LSP1DelegateNotAllowedToSetDataKey} from "./LSP9Errors.sol"; import { - LSP14MustAcceptOwnershipInSeparateTransaction -} from "../LSP14Ownable2Step/LSP14Errors.sol"; + NoExtensionFoundForFunctionSelector +} from "../LSP17ContractExtension/LSP17Errors.sol"; /** * @title Core Implementation of LSP9Vault built on top of [ERC725], [LSP1UniversalReceiver] @@ -97,8 +95,6 @@ contract LSP9VaultCore is if (msg.value > 0) emit ValueReceived(msg.sender, msg.value); } - // solhint-disable no-complex-fallback - /** * @notice The `fallback` function was called with the following amount of native tokens: `msg.value`; and the following calldata: `callData`. * @@ -120,6 +116,7 @@ contract LSP9VaultCore is * * @custom:events {ValueReceived} event when receiving native tokens. */ + // solhint-disable-next-line no-complex-fallback fallback( bytes calldata callData ) external payable virtual returns (bytes memory) { @@ -172,7 +169,7 @@ contract LSP9VaultCore is } /** - * @inheritdoc IERC725X + * @inheritdoc ERC725XCore * * @custom:requirements * - Can be only called by the {owner} or by an authorised address that pass the verification check performed on the owner. @@ -225,7 +222,7 @@ contract LSP9VaultCore is } /** - * @inheritdoc IERC725Y + * @inheritdoc ERC725YCore * * @custom:requirements Can be only called by the {owner} or by an authorised address that pass the verification check performed on the owner. * @@ -253,7 +250,7 @@ contract LSP9VaultCore is } /** - * @inheritdoc IERC725Y + * @inheritdoc ERC725YCore * * @custom:requirements Can be only called by the {owner} or by an authorised address that pass the verification check performed on the owner. * @@ -626,15 +623,17 @@ contract LSP9VaultCore is // Deploy with CREATE if (operationType == uint256(OPERATION_1_CREATE)) { - if (target != address(0)) + if (target != address(0)) { revert ERC725X_CreateOperationsRequireEmptyRecipientAddress(); + } return _deployCreate(value, data); } // Deploy with CREATE2 if (operationType == uint256(OPERATION_2_CREATE2)) { - if (target != address(0)) + if (target != address(0)) { revert ERC725X_CreateOperationsRequireEmptyRecipientAddress(); + } return _deployCreate2(value, data); } diff --git a/contracts/Mocks/ERC165Interfaces.sol b/contracts/Mocks/ERC165Interfaces.sol index 770ee562b..ca4480dba 100644 --- a/contracts/Mocks/ERC165Interfaces.sol +++ b/contracts/Mocks/ERC165Interfaces.sol @@ -1,3 +1,4 @@ +// solhint-disable one-contract-per-file // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/Mocks/ExecutorLSP20.sol b/contracts/Mocks/ExecutorLSP20.sol index 4d6c6aeb9..0d26cbb6d 100644 --- a/contracts/Mocks/ExecutorLSP20.sol +++ b/contracts/Mocks/ExecutorLSP20.sol @@ -8,11 +8,9 @@ import { import { IERC725Y } from "@erc725/smart-contracts/contracts/interfaces/IERC725Y.sol"; -import {ILSP6KeyManager} from "../LSP6KeyManager/ILSP6KeyManager.sol"; // modules import {UniversalProfile} from "../UniversalProfile.sol"; -import {LSP6KeyManager} from "../LSP6KeyManager/LSP6KeyManager.sol"; // constants import { diff --git a/contracts/Mocks/KeyManagerWithExtraParams.sol b/contracts/Mocks/KeyManagerWithExtraParams.sol index c901ef74d..c65588687 100644 --- a/contracts/Mocks/KeyManagerWithExtraParams.sol +++ b/contracts/Mocks/KeyManagerWithExtraParams.sol @@ -4,15 +4,15 @@ pragma solidity ^0.8.4; import {LSP6KeyManager} from "../LSP6KeyManager/LSP6KeyManager.sol"; contract KeyManagerWithExtraParams is LSP6KeyManager { - address public immutable firstParam; - address public immutable lastParam; + address public immutable FIRST_PARAM; + address public immutable LAST_PARAM; constructor( address firstParam_, address target_, address lastParam_ ) LSP6KeyManager(target_) { - firstParam = firstParam_; - lastParam = lastParam_; + FIRST_PARAM = firstParam_; + LAST_PARAM = lastParam_; } } diff --git a/contracts/Mocks/LSP20Owners/FirstCallReturnExpandedInvalidValue.sol b/contracts/Mocks/LSP20Owners/FirstCallReturnExpandedInvalidValue.sol index 326fb0c88..cc5f69c7e 100644 --- a/contracts/Mocks/LSP20Owners/FirstCallReturnExpandedInvalidValue.sol +++ b/contracts/Mocks/LSP20Owners/FirstCallReturnExpandedInvalidValue.sol @@ -1,9 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; -import { - ILSP20CallVerifier -} from "../../LSP20CallVerification/ILSP20CallVerifier.sol"; import { ILSP14Ownable2Step } from "../../LSP14Ownable2Step/ILSP14Ownable2Step.sol"; diff --git a/contracts/Mocks/LSP20Owners/FirstCallReturnInvalidMagicValue.sol b/contracts/Mocks/LSP20Owners/FirstCallReturnInvalidMagicValue.sol index aaf31bf9d..1a7d361c7 100644 --- a/contracts/Mocks/LSP20Owners/FirstCallReturnInvalidMagicValue.sol +++ b/contracts/Mocks/LSP20Owners/FirstCallReturnInvalidMagicValue.sol @@ -1,9 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; - -import { - ILSP20CallVerifier -} from "../../LSP20CallVerification/ILSP20CallVerifier.sol"; import { ILSP14Ownable2Step } from "../../LSP14Ownable2Step/ILSP14Ownable2Step.sol"; diff --git a/contracts/Mocks/PayableContract.sol b/contracts/Mocks/PayableContract.sol index 04493edc6..c638d0c7b 100644 --- a/contracts/Mocks/PayableContract.sol +++ b/contracts/Mocks/PayableContract.sol @@ -5,9 +5,12 @@ pragma solidity ^0.8.4; * @dev sample contract used for testing */ contract PayableContract { + // solhint-disable no-empty-blocks constructor() payable {} + // solhint-disable no-empty-blocks function payableTrue() public payable {} + // solhint-disable no-empty-blocks function payableFalse() public {} } diff --git a/contracts/Mocks/Reentrancy/LSP20ReentrantContract.sol b/contracts/Mocks/Reentrancy/LSP20ReentrantContract.sol index 3286842d2..4f779d7a8 100644 --- a/contracts/Mocks/Reentrancy/LSP20ReentrantContract.sol +++ b/contracts/Mocks/Reentrancy/LSP20ReentrantContract.sol @@ -10,8 +10,14 @@ import { } from "@erc725/smart-contracts/contracts/interfaces/IERC725X.sol"; // constants -import "../../LSP1UniversalReceiver/LSP1Constants.sol"; -import "../../LSP6KeyManager/LSP6Constants.sol"; +import { + _LSP1_UNIVERSAL_RECEIVER_DELEGATE_PREFIX +} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; + +import { + _LSP6KEY_ADDRESSPERMISSIONS_PERMISSIONS_PREFIX, + ALL_REGULAR_PERMISSIONS +} from "../../LSP6KeyManager/LSP6Constants.sol"; contract LSP20ReentrantContract { event ValueReceived(uint256); diff --git a/contracts/Mocks/Reentrancy/ReentrantContract.sol b/contracts/Mocks/Reentrancy/ReentrantContract.sol index a1c59ffd5..70732bedf 100644 --- a/contracts/Mocks/Reentrancy/ReentrantContract.sol +++ b/contracts/Mocks/Reentrancy/ReentrantContract.sol @@ -5,8 +5,13 @@ pragma solidity ^0.8.4; import {ILSP6KeyManager} from "../../LSP6KeyManager/ILSP6KeyManager.sol"; // constants -import "../../LSP1UniversalReceiver/LSP1Constants.sol"; -import "../../LSP6KeyManager/LSP6Constants.sol"; +import { + _LSP1_UNIVERSAL_RECEIVER_DELEGATE_PREFIX +} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; + +import { + _LSP6KEY_ADDRESSPERMISSIONS_PERMISSIONS_PREFIX +} from "../../LSP6KeyManager/LSP6Constants.sol"; contract ReentrantContract { event ValueReceived(uint256); diff --git a/contracts/Mocks/Reentrancy/ThreeReentrancy.sol b/contracts/Mocks/Reentrancy/ThreeReentrancy.sol index 0caea494e..2715082e4 100644 --- a/contracts/Mocks/Reentrancy/ThreeReentrancy.sol +++ b/contracts/Mocks/Reentrancy/ThreeReentrancy.sol @@ -1,3 +1,4 @@ +// solhint-disable one-contract-per-file // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; @@ -7,8 +8,7 @@ import { import { IERC725X } from "@erc725/smart-contracts/contracts/interfaces/IERC725X.sol"; -import {Address} from "@openzeppelin/contracts/utils/Address.sol"; -import "../../LSP6KeyManager/ILSP6KeyManager.sol"; +import {ILSP6KeyManager} from "../../LSP6KeyManager/ILSP6KeyManager.sol"; /** * The purpose of these contracts is to perform tests on chained reentrancy scenarios diff --git a/contracts/Mocks/Tokens/LSP7CompatibleERC20InitTester.sol b/contracts/Mocks/Tokens/LSP7CompatibleERC20InitTester.sol index 939d69baf..07cb6e539 100644 --- a/contracts/Mocks/Tokens/LSP7CompatibleERC20InitTester.sol +++ b/contracts/Mocks/Tokens/LSP7CompatibleERC20InitTester.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.4; // modules -import {LSP7DigitalAsset} from "../../LSP7DigitalAsset/LSP7DigitalAsset.sol"; import { LSP7CompatibleERC20InitAbstract } from "../../LSP7DigitalAsset/extensions/LSP7CompatibleERC20InitAbstract.sol"; diff --git a/contracts/Mocks/Tokens/LSP7CompatibleERC20Tester.sol b/contracts/Mocks/Tokens/LSP7CompatibleERC20Tester.sol index b768346ca..9e7429006 100644 --- a/contracts/Mocks/Tokens/LSP7CompatibleERC20Tester.sol +++ b/contracts/Mocks/Tokens/LSP7CompatibleERC20Tester.sol @@ -6,7 +6,6 @@ pragma solidity ^0.8.4; import { LSP7CompatibleERC20 } from "../../LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol"; -import {LSP7DigitalAsset} from "../../LSP7DigitalAsset/LSP7DigitalAsset.sol"; contract LSP7CompatibleERC20Tester is LSP7CompatibleERC20 { constructor( diff --git a/contracts/Mocks/Tokens/LSP8CompatibleERC721Tester.sol b/contracts/Mocks/Tokens/LSP8CompatibleERC721Tester.sol index e90af1e27..ce8517bf5 100644 --- a/contracts/Mocks/Tokens/LSP8CompatibleERC721Tester.sol +++ b/contracts/Mocks/Tokens/LSP8CompatibleERC721Tester.sol @@ -3,9 +3,6 @@ pragma solidity ^0.8.4; // modules -import { - LSP8IdentifiableDigitalAsset -} from "../../LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol"; import { LSP8CompatibleERC721 } from "../../LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol"; diff --git a/contracts/Mocks/Tokens/LSP8CompatibleERC721TesterInit.sol b/contracts/Mocks/Tokens/LSP8CompatibleERC721TesterInit.sol index edbc0f4bd..767826cbf 100644 --- a/contracts/Mocks/Tokens/LSP8CompatibleERC721TesterInit.sol +++ b/contracts/Mocks/Tokens/LSP8CompatibleERC721TesterInit.sol @@ -3,9 +3,6 @@ pragma solidity ^0.8.4; // modules -import { - LSP8IdentifiableDigitalAsset -} from "../../LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol"; import { LSP8CompatibleERC721InitAbstract } from "../../LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol"; diff --git a/contracts/Mocks/Tokens/RequireCallbackToken.sol b/contracts/Mocks/Tokens/RequireCallbackToken.sol index e91f1f6e1..abea751ae 100644 --- a/contracts/Mocks/Tokens/RequireCallbackToken.sol +++ b/contracts/Mocks/Tokens/RequireCallbackToken.sol @@ -2,7 +2,9 @@ pragma solidity ^0.8.4; -import "../FallbackExtensions/OnERC721ReceivedExtension.sol"; +import { + OnERC721ReceivedExtension +} from "../FallbackExtensions/OnERC721ReceivedExtension.sol"; /** * @dev This contract is used only for testing purposes diff --git a/contracts/Mocks/Tokens/TokenReceiverWithoutLSP1WithERC721Received.sol b/contracts/Mocks/Tokens/TokenReceiverWithoutLSP1WithERC721Received.sol index 5b9c97c90..fe714dafd 100644 --- a/contracts/Mocks/Tokens/TokenReceiverWithoutLSP1WithERC721Received.sol +++ b/contracts/Mocks/Tokens/TokenReceiverWithoutLSP1WithERC721Received.sol @@ -6,9 +6,6 @@ import { ERC721Holder } from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; -// constants -import {_INTERFACEID_LSP1} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; - contract TokenReceiverWithoutLSP1WithERC721Received is ERC721Holder { receive() external payable {} diff --git a/contracts/Mocks/Tokens/TokenReceiverWithoutLSP1WithERC721ReceivedInvalid.sol b/contracts/Mocks/Tokens/TokenReceiverWithoutLSP1WithERC721ReceivedInvalid.sol index d353d3128..a06e9eef0 100644 --- a/contracts/Mocks/Tokens/TokenReceiverWithoutLSP1WithERC721ReceivedInvalid.sol +++ b/contracts/Mocks/Tokens/TokenReceiverWithoutLSP1WithERC721ReceivedInvalid.sol @@ -6,9 +6,6 @@ import { ERC721Holder } from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; -// constants -import {_INTERFACEID_LSP1} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; - contract TokenReceiverWithoutLSP1WithERC721ReceivedInvalid is ERC721Holder { receive() external payable {} diff --git a/contracts/Mocks/Tokens/TokenReceiverWithoutLSP1WithERC721ReceivedRevert.sol b/contracts/Mocks/Tokens/TokenReceiverWithoutLSP1WithERC721ReceivedRevert.sol index 07563cde8..b3bbef6dc 100644 --- a/contracts/Mocks/Tokens/TokenReceiverWithoutLSP1WithERC721ReceivedRevert.sol +++ b/contracts/Mocks/Tokens/TokenReceiverWithoutLSP1WithERC721ReceivedRevert.sol @@ -6,9 +6,6 @@ import { ERC721Holder } from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; -// constants -import {_INTERFACEID_LSP1} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; - contract TokenReceiverWithoutLSP1WithERC721ReceivedRevert is ERC721Holder { receive() external payable {} diff --git a/contracts/Mocks/UPWithInstantAcceptOwnership.sol b/contracts/Mocks/UPWithInstantAcceptOwnership.sol index a1e7ed5f3..95b8f258b 100644 --- a/contracts/Mocks/UPWithInstantAcceptOwnership.sol +++ b/contracts/Mocks/UPWithInstantAcceptOwnership.sol @@ -11,9 +11,15 @@ import { import {LSP14Ownable2Step} from "../LSP14Ownable2Step/LSP14Ownable2Step.sol"; // constants -import "../LSP0ERC725Account/LSP0Constants.sol"; -import "../LSP9Vault/LSP9Constants.sol"; -import "../LSP14Ownable2Step/LSP14Constants.sol"; +import { + _TYPEID_LSP0_OwnershipTransferStarted +} from "../LSP0ERC725Account/LSP0Constants.sol"; +import { + _TYPEID_LSP9_OwnershipTransferStarted +} from "../LSP9Vault/LSP9Constants.sol"; +import { + _TYPEID_LSP14_OwnershipTransferStarted +} from "../LSP14Ownable2Step/LSP14Constants.sol"; /** * @dev This contract is used only for testing purposes diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateDataUpdater.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateDataUpdater.sol index d118a887a..fb3623df7 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateDataUpdater.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateDataUpdater.sol @@ -3,17 +3,9 @@ pragma solidity ^0.8.4; // interfaces import {ILSP6KeyManager} from "../../LSP6KeyManager/ILSP6KeyManager.sol"; -import { - IERC725X -} from "@erc725/smart-contracts/contracts/interfaces/IERC725X.sol"; -import { - IERC725Y -} from "@erc725/smart-contracts/contracts/interfaces/IERC725Y.sol"; import {LSP14Ownable2Step} from "../../LSP14Ownable2Step/LSP14Ownable2Step.sol"; // modules -import {ERC725Y} from "@erc725/smart-contracts/contracts/ERC725Y.sol"; -import {BytesLib} from "solidity-bytes-utils/contracts/BytesLib.sol"; import { ERC165Storage } from "@openzeppelin/contracts/utils/introspection/ERC165Storage.sol"; diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateGasConsumer.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateGasConsumer.sol index 6f01b3cc3..ffdd9aa90 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateGasConsumer.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateGasConsumer.sol @@ -24,6 +24,7 @@ contract UniversalReceiverDelegateGasConsumer is bytes32 /* typeId */, bytes memory /* data */ ) public payable virtual returns (bytes memory) { + // solhint-disable no-empty-blocks for (uint256 i = 0; ; i++) { // nothing } diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateTokenReentrant.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateTokenReentrant.sol index 24085433c..fe511af0a 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateTokenReentrant.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateTokenReentrant.sol @@ -9,19 +9,16 @@ import {ILSP6KeyManager} from "../../LSP6KeyManager/ILSP6KeyManager.sol"; // modules import {ERC725Y} from "@erc725/smart-contracts/contracts/ERC725Y.sol"; -import {BytesLib} from "solidity-bytes-utils/contracts/BytesLib.sol"; import { ERC165Storage } from "@openzeppelin/contracts/utils/introspection/ERC165Storage.sol"; // constants import { - _TYPEID_LSP7_TOKENSSENDER, _TYPEID_LSP7_TOKENSRECIPIENT } from "../../LSP7DigitalAsset/LSP7Constants.sol"; import { - _TYPEID_LSP8_TOKENSSENDER, _TYPEID_LSP8_TOKENSRECIPIENT } from "../../LSP8IdentifiableDigitalAsset/LSP8Constants.sol"; diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultMalicious.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultMalicious.sol index 79ae53228..c77b6e362 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultMalicious.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultMalicious.sol @@ -2,21 +2,14 @@ pragma solidity ^0.8.4; // interfaces -import {ILSP6KeyManager} from "../../LSP6KeyManager/ILSP6KeyManager.sol"; -import { - IERC725X -} from "@erc725/smart-contracts/contracts/interfaces/IERC725X.sol"; import { IERC725Y } from "@erc725/smart-contracts/contracts/interfaces/IERC725Y.sol"; -import {LSP14Ownable2Step} from "../../LSP14Ownable2Step/LSP14Ownable2Step.sol"; import { IERC725Y } from "@erc725/smart-contracts/contracts/interfaces/IERC725Y.sol"; // modules -import {ERC725Y} from "@erc725/smart-contracts/contracts/ERC725Y.sol"; -import {BytesLib} from "solidity-bytes-utils/contracts/BytesLib.sol"; import { ERC165Storage } from "@openzeppelin/contracts/utils/introspection/ERC165Storage.sol"; @@ -24,11 +17,16 @@ import {Address} from "@openzeppelin/contracts/utils/Address.sol"; // constants import { - _TYPEID_LSP7_TOKENSSENDER -} from "../../LSP7DigitalAsset/LSP7Constants.sol"; -import "../../LSP1UniversalReceiver/LSP1Constants.sol"; -import "../../LSP6KeyManager/LSP6Constants.sol"; -import "../../LSP17ContractExtension/LSP17Constants.sol"; + _INTERFACEID_LSP1, + _LSP1_UNIVERSAL_RECEIVER_DELEGATE_PREFIX +} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; +import { + _LSP6KEY_ADDRESSPERMISSIONS_PREFIX +} from "../../LSP6KeyManager/LSP6Constants.sol"; + +import { + _LSP17_EXTENSION_PREFIX +} from "../../LSP17ContractExtension/LSP17Constants.sol"; /** * @dev This contract is used only for testing diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantA.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantA.sol index dbd5bac55..b6df6d4be 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantA.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantA.sol @@ -16,11 +16,17 @@ import { // constants import {_INTERFACEID_LSP1} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; +import { + NativeTokensNotAccepted +} from "../../LSP1UniversalReceiver/LSP1Errors.sol"; /** * @dev This contract is used only for testing purposes */ -contract UniversalReceiverDelegateVaultReentrantA is ERC165Storage { +contract UniversalReceiverDelegateVaultReentrantA is + ILSP1UniversalReceiver, + ERC165Storage +{ constructor() { _registerInterface(_INTERFACEID_LSP1); } @@ -28,7 +34,11 @@ contract UniversalReceiverDelegateVaultReentrantA is ERC165Storage { function universalReceiver( bytes32 /* typeId */, bytes memory data - ) external returns (bytes memory) { + ) external payable returns (bytes memory) { + if (msg.value != 0) { + revert NativeTokensNotAccepted(); + } + bytes32[] memory keys = new bytes32[](1); bytes[] memory values = new bytes[](1); diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantB.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantB.sol index 893e6a4ed..228f08aed 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantB.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantB.sol @@ -17,10 +17,18 @@ import { // constants import {_INTERFACEID_LSP1} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; +// errors +import { + NativeTokensNotAccepted +} from "../../LSP1UniversalReceiver/LSP1Errors.sol"; + /** * @dev This contract is used only for testing purposes */ -contract UniversalReceiverDelegateVaultReentrantB is ERC165Storage { +contract UniversalReceiverDelegateVaultReentrantB is + ILSP1UniversalReceiver, + ERC165Storage +{ constructor() { _registerInterface(_INTERFACEID_LSP1); } @@ -28,7 +36,11 @@ contract UniversalReceiverDelegateVaultReentrantB is ERC165Storage { function universalReceiver( bytes32 /* typeId */, bytes memory data - ) external returns (bytes memory) { + ) external payable returns (bytes memory) { + if (msg.value != 0) { + revert NativeTokensNotAccepted(); + } + bytes32[] memory keys = new bytes32[](1); bytes[] memory values = new bytes[](1); diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultSetter.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultSetter.sol index f448e1b6b..8ac881316 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultSetter.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultSetter.sol @@ -5,9 +5,6 @@ pragma solidity ^0.8.4; import { IERC725Y } from "@erc725/smart-contracts/contracts/interfaces/IERC725Y.sol"; -import { - ILSP1UniversalReceiver -} from "../../LSP1UniversalReceiver/ILSP1UniversalReceiver.sol"; // modules import { diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md index 503d783e2..a1304e5e2 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md @@ -615,7 +615,7 @@ Returns true if this contract implements the interface defined by `interfaceId`. function tokenSupplyCap() external view returns (uint256); ``` -_The maximum supply amount of tokens allowed to exist is `_tokenSupplyCap`._ +_The maximum supply amount of tokens allowed to exist is `_TOKEN_SUPPLY_CAP`._ Get the maximum number of tokens that can exist to circulate. Once [`totalSupply`](#totalsupply) reaches reaches [`totalSuuplyCap`](#totalsuuplycap), it is not possible to mint more tokens. diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md index a69370888..f167191a5 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md @@ -535,7 +535,7 @@ Returns the list of `tokenIds` for the `tokenOwner` address. function tokenSupplyCap() external view returns (uint256); ``` -_The maximum supply amount of tokens allowed to exist is `_tokenSupplyCap`._ +_The maximum supply amount of tokens allowed to exist is `_TOKEN_SUPPLY_CAP`._ Get the maximum number of tokens that can exist to circulate. Once [`totalSupply`](#totalsupply) reaches reaches [`totalSuuplyCap`](#totalsuuplycap), it is not possible to mint more tokens. diff --git a/package-lock.json b/package-lock.json index 6ce1eb923..8d1136bc0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,7 +46,7 @@ "prettier": "^2.8.8", "prettier-plugin-solidity": "^1.1.3", "rollup-plugin-esbuild": "^5.0.0", - "solhint": "^3.3.6", + "solhint": "^3.6.2", "standard-version": "^9.3.1", "ts-node": "^10.2.0", "typechain": "^8.0.0", @@ -1043,43 +1043,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "peer": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, "node_modules/@eslint/eslintrc/node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -3246,15 +3209,6 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, "node_modules/@typescript-eslint/parser": { "version": "5.60.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.60.0.tgz", @@ -3387,15 +3341,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, "node_modules/@typescript-eslint/utils": { "version": "5.60.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.60.0.tgz", @@ -3587,6 +3532,7 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "peer": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -4078,10 +4024,13 @@ } }, "node_modules/antlr4": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.7.1.tgz", - "integrity": "sha512-haHyTW7Y9joE5MVs37P2lNYfU2RWBLfcRDD8OWldcdZm5TiCE91B5Xl1oWSwiDUSd4rlExpt2pu1fksYQjRBYQ==", - "dev": true + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.13.1.tgz", + "integrity": "sha512-kiXTspaRYvnIArgE97z5YVVf/cDVQABr3abFRR6mE7yesLMkgu4ujuyV/sgxafQ8wgve0DJQUJ38Z8tkgA2izA==", + "dev": true, + "engines": { + "node": ">=16" + } }, "node_modules/antlr4ts": { "version": "0.5.0-alpha.4", @@ -4296,7 +4245,6 @@ "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" } @@ -5015,39 +4963,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", - "dev": true, - "dependencies": { - "callsites": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", - "dev": true, - "dependencies": { - "caller-callsite": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -5373,18 +5288,6 @@ "node": ">=6" } }, - "node_modules/cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", - "dev": true, - "dependencies": { - "restore-cursor": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/cli-table3": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.2.tgz", @@ -5400,12 +5303,6 @@ "@colors/colors": "1.5.0" } }, - "node_modules/cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true - }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -6775,53 +6672,56 @@ } }, "node_modules/cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.5.tgz", + "integrity": "sha512-A5Xry3xfS96wy2qbiLkQLAg4JUrR2wvfybxj6yqLmrUfMAvhS3MZxIP2oQn0grgYIvJqzpeTEWu4vK0t+12NNw==", "dev": true, "dependencies": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/cosmiconfig/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/cosmiconfig/node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/cosmiconfig/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, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cosmiconfig/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==", + "node_modules/cosmiconfig/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, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=8" } }, "node_modules/crc-32": { @@ -7102,7 +7002,8 @@ "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 + "dev": true, + "peer": true }, "node_modules/defer-to-connect": { "version": "1.1.3", @@ -7181,15 +7082,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/del/node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, "node_modules/del/node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -7346,6 +7238,7 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, + "peer": true, "dependencies": { "esutils": "^2.0.2" }, @@ -8007,27 +7900,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/eslint-visitor-keys": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", @@ -8177,33 +8049,6 @@ "node": ">=8" } }, - "node_modules/eslint/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/eslint/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "peer": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -8272,16 +8117,6 @@ "node": ">=8" } }, - "node_modules/eslint/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, "node_modules/eslint/node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -8384,6 +8219,7 @@ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, + "peer": true, "dependencies": { "estraverse": "^5.1.0" }, @@ -8423,6 +8259,7 @@ "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" } @@ -10631,7 +10468,8 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "peer": true }, "node_modules/fast-safe-stringify": { "version": "2.1.1", @@ -10647,18 +10485,6 @@ "reusify": "^1.0.4" } }, - "node_modules/figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -11875,6 +11701,7 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "peer": true, "engines": { "node": ">=4" } @@ -11899,16 +11726,6 @@ "node": ">=8" } }, - "node_modules/globby/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/globrex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", @@ -13091,9 +12908,9 @@ ] }, "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true, "engines": { "node": ">= 4" @@ -13111,14 +12928,26 @@ "dev": true }, "node_modules/import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "dependencies": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, "engines": { "node": ">=4" } @@ -13137,6 +12966,7 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "peer": true, "engines": { "node": ">=0.8.19" } @@ -13171,103 +13001,6 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, - "node_modules/inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/inquirer/node_modules/ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/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, - "engines": { - "node": ">=6" - } - }, - "node_modules/inquirer/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, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/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, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/string-width/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, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/string-width/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, - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/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, - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/internal-slot": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", @@ -13482,15 +13215,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -14070,7 +13794,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "peer": true }, "node_modules/json-stringify-safe": { "version": "5.0.1", @@ -14414,8 +14139,7 @@ "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true, - "peer": true + "dev": true }, "node_modules/log-symbols": { "version": "4.1.0", @@ -15080,15 +14804,6 @@ "node": ">= 0.6" } }, - "node_modules/mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", @@ -15654,12 +15369,6 @@ "imul": "^1.0.0" } }, - "node_modules/mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==", - "dev": true - }, "node_modules/nan": { "version": "2.16.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz", @@ -15751,7 +15460,8 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "peer": true }, "node_modules/natural-compare-lite": { "version": "1.4.0", @@ -16186,18 +15896,6 @@ "wrappy": "1" } }, - "node_modules/onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", - "dev": true, - "dependencies": { - "mimic-fn": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -16434,12 +16132,6 @@ "node": ">=0.10.0" } }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "dev": true - }, "node_modules/path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", @@ -16704,15 +16396,6 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/promise": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", @@ -17127,15 +16810,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "dev": true, - "engines": { - "node": ">=6.5.0" - } - }, "node_modules/registry-auth-token": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", @@ -17368,19 +17042,6 @@ "lowercase-keys": "^1.0.0" } }, - "node_modules/restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", - "dev": true, - "dependencies": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", @@ -17749,9 +17410,9 @@ } }, "node_modules/semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -18030,7 +17691,6 @@ "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", @@ -18048,7 +17708,6 @@ "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" }, @@ -18064,7 +17723,6 @@ "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" }, @@ -18076,8 +17734,7 @@ "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 + "dev": true }, "node_modules/snapdragon": { "version": "0.8.2", @@ -18271,436 +17928,162 @@ } }, "node_modules/solhint": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.3.7.tgz", - "integrity": "sha512-NjjjVmXI3ehKkb3aNtRJWw55SUVJ8HMKKodwe0HnejA+k0d2kmhw7jvpa+MCTbcEgt8IWSwx0Hu6aCo/iYOZzQ==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.6.2.tgz", + "integrity": "sha512-85EeLbmkcPwD+3JR7aEMKsVC9YrRSxd4qkXuMzrlf7+z2Eqdfm1wHWq1ffTuo5aDhoZxp2I9yF3QkxZOxOL7aQ==", "dev": true, "dependencies": { - "@solidity-parser/parser": "^0.14.1", - "ajv": "^6.6.1", - "antlr4": "4.7.1", - "ast-parents": "0.0.1", - "chalk": "^2.4.2", - "commander": "2.18.0", - "cosmiconfig": "^5.0.7", - "eslint": "^5.6.0", - "fast-diff": "^1.1.2", - "glob": "^7.1.3", - "ignore": "^4.0.6", - "js-yaml": "^3.12.0", - "lodash": "^4.17.11", - "semver": "^6.3.0" + "@solidity-parser/parser": "^0.16.0", + "ajv": "^6.12.6", + "antlr4": "^4.11.0", + "ast-parents": "^0.0.1", + "chalk": "^4.1.2", + "commander": "^10.0.0", + "cosmiconfig": "^8.0.0", + "fast-diff": "^1.2.0", + "glob": "^8.0.3", + "ignore": "^5.2.4", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "pluralize": "^8.0.0", + "semver": "^7.5.2", + "strip-ansi": "^6.0.1", + "table": "^6.8.1", + "text-table": "^0.2.0" }, "bin": { "solhint": "solhint.js" }, "optionalDependencies": { - "prettier": "^1.14.3" + "prettier": "^2.8.3" } }, - "node_modules/solhint/node_modules/acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/solhint/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, - "engines": { - "node": ">=4" - } - }, - "node_modules/solhint/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, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/solhint/node_modules/astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/solhint/node_modules/commander": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.18.0.tgz", - "integrity": "sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ==", - "dev": true - }, - "node_modules/solhint/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 - }, - "node_modules/solhint/node_modules/eslint": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", - "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", + "node_modules/solhint/node_modules/@solidity-parser/parser": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.1.tgz", + "integrity": "sha512-PdhRFNhbTtu3x8Axm0uYpqOy/lODYQK+MlYSgqIsq2L8SFYEHJPHNUiOTAJbDGzNjjr1/n9AcIayxafR/fWmYw==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.9.1", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^4.0.3", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^5.0.1", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.7.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^6.2.2", - "js-yaml": "^3.13.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.11", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^6.14.0 || ^8.10.0 || >=9.10.0" - } - }, - "node_modules/solhint/node_modules/eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/solhint/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/solhint/node_modules/eslint/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/solhint/node_modules/espree": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", - "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", - "dev": true, - "dependencies": { - "acorn": "^6.0.7", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/solhint/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, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" + "antlr4ts": "^0.5.0-alpha.4" } }, - "node_modules/solhint/node_modules/estraverse": { + "node_modules/solhint/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/solhint/node_modules/file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "flat-cache": "^2.0.1" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/solhint/node_modules/flat-cache": { + "node_modules/solhint/node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - }, - "engines": { - "node": ">=4" + "balanced-match": "^1.0.0" } }, - "node_modules/solhint/node_modules/flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - }, - "node_modules/solhint/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "node_modules/solhint/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": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=6" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/solhint/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, - "engines": { - "node": ">=4" - } - }, - "node_modules/solhint/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, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/solhint/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, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/solhint/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "node_modules/solhint/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": { - "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/solhint/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, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/solhint/node_modules/prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", - "dev": true, - "optional": true, - "bin": { - "prettier": "bin-prettier.js" + "color-name": "~1.1.4" }, "engines": { - "node": ">=4" - } - }, - "node_modules/solhint/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" + "node": ">=7.0.0" } }, - "node_modules/solhint/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/solhint/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/solhint/node_modules/slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "node_modules/solhint/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "dev": true, - "dependencies": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, "engines": { - "node": ">=6" + "node": ">=14" } }, - "node_modules/solhint/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==", + "node_modules/solhint/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dev": true, "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": ">=6" - } - }, - "node_modules/solhint/node_modules/string-width/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, - "engines": { - "node": ">=6" - } - }, - "node_modules/solhint/node_modules/string-width/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, - "dependencies": { - "ansi-regex": "^4.1.0" + "node": ">=12" }, - "engines": { - "node": ">=6" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/solhint/node_modules/strip-ansi": { + "node_modules/solhint/node_modules/has-flag": { "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, - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/solhint/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==", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/solhint/node_modules/table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "node_modules/solhint/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "dependencies": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=6.0.0" + "node": ">=10" } }, - "node_modules/solhint/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==", + "node_modules/solhint/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": { - "prelude-ls": "~1.1.2" + "has-flag": "^4.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=8" } }, "node_modules/solidity-bytes-utils": { @@ -20232,11 +19615,10 @@ } }, "node_modules/table": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", - "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", + "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", @@ -20286,7 +19668,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "dev": true, - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -20302,8 +19683,7 @@ "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 + "dev": true }, "node_modules/tar": { "version": "4.4.19", @@ -22605,6 +21985,7 @@ "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" } @@ -22699,18 +22080,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, - "node_modules/write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "dependencies": { - "mkdirp": "^0.5.1" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/ws": { "version": "7.4.6", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", @@ -23568,31 +22937,6 @@ "type-fest": "^0.20.2" } }, - "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "peer": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "peer": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "peer": true - }, "type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -25157,14 +24501,6 @@ "natural-compare-lite": "^1.4.0", "semver": "^7.3.7", "tsutils": "^3.21.0" - }, - "dependencies": { - "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true - } } }, "@typescript-eslint/parser": { @@ -25236,12 +24572,6 @@ "merge2": "^1.4.1", "slash": "^3.0.0" } - }, - "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true } } }, @@ -25371,6 +24701,7 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "peer": true, "requires": {} }, "acorn-walk": { @@ -25735,9 +25066,9 @@ } }, "antlr4": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.7.1.tgz", - "integrity": "sha512-haHyTW7Y9joE5MVs37P2lNYfU2RWBLfcRDD8OWldcdZm5TiCE91B5Xl1oWSwiDUSd4rlExpt2pu1fksYQjRBYQ==", + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.13.1.tgz", + "integrity": "sha512-kiXTspaRYvnIArgE97z5YVVf/cDVQABr3abFRR6mE7yesLMkgu4ujuyV/sgxafQ8wgve0DJQUJ38Z8tkgA2izA==", "dev": true }, "antlr4ts": { @@ -25914,8 +25245,7 @@ "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 + "dev": true }, "async": { "version": "2.6.4", @@ -26496,30 +25826,6 @@ "get-intrinsic": "^1.0.2" } }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", - "dev": true, - "requires": { - "callsites": "^2.0.0" - } - }, - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", - "dev": true, - "requires": { - "caller-callsite": "^2.0.0" - } - }, - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==", - "dev": true - }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -26777,15 +26083,6 @@ "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, "cli-table3": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.2.tgz", @@ -26796,12 +26093,6 @@ "string-width": "^4.2.0" } }, - "cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true - }, "cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -27870,41 +27161,34 @@ } }, "cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.5.tgz", + "integrity": "sha512-A5Xry3xfS96wy2qbiLkQLAg4JUrR2wvfybxj6yqLmrUfMAvhS3MZxIP2oQn0grgYIvJqzpeTEWu4vK0t+12NNw==", "dev": true, "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" }, "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { - "sprintf-js": "~1.0.2" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "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 - }, - "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, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } } } }, @@ -28133,7 +27417,8 @@ "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 + "dev": true, + "peer": true }, "defer-to-connect": { "version": "1.1.3", @@ -28191,12 +27476,6 @@ "slash": "^3.0.0" } }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true - }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -28321,6 +27600,7 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, + "peer": true, "requires": { "esutils": "^2.0.2" } @@ -28909,24 +28189,6 @@ "dev": true, "peer": 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 - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "peer": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -28971,13 +28233,6 @@ "dev": true, "peer": true }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "peer": true - }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -29051,23 +28306,6 @@ "estraverse": "^5.2.0" } }, - "eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, "eslint-visitor-keys": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", @@ -29098,6 +28336,7 @@ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, + "peer": true, "requires": { "estraverse": "^5.1.0" } @@ -29127,7 +28366,8 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true + "dev": true, + "peer": true }, "etag": { "version": "1.8.1", @@ -31089,7 +30329,8 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "peer": true }, "fast-safe-stringify": { "version": "2.1.1", @@ -31105,15 +30346,6 @@ "reusify": "^1.0.4" } }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -32057,7 +31289,8 @@ "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "peer": true }, "globby": { "version": "10.0.2", @@ -32074,15 +31307,6 @@ "ignore": "^5.1.1", "merge2": "^1.2.3", "slash": "^3.0.0" - }, - "dependencies": { - "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "peer": true - } } }, "globrex": { @@ -32983,9 +32207,9 @@ "dev": true }, "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true }, "immediate": { @@ -33000,13 +32224,21 @@ "dev": true }, "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } } }, "imul": { @@ -33019,7 +32251,8 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true + "dev": true, + "peer": true }, "indent-string": { "version": "4.0.0", @@ -33048,83 +32281,6 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, - "inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", - "dev": true, - "requires": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": 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 - }, - "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 - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "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 - }, - "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, - "requires": { - "ansi-regex": "^3.0.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, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, "internal-slot": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", @@ -33285,12 +32441,6 @@ } } }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==", - "dev": true - }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -33713,7 +32863,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "peer": true }, "json-stringify-safe": { "version": "5.0.1", @@ -33977,8 +33128,7 @@ "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true, - "peer": true + "dev": true }, "log-symbols": { "version": "4.1.0", @@ -34499,12 +33649,6 @@ "mime-db": "1.52.0" } }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - }, "mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", @@ -34937,12 +34081,6 @@ "imul": "^1.0.0" } }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==", - "dev": true - }, "nan": { "version": "2.16.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz", @@ -35018,7 +34156,8 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "peer": true }, "natural-compare-lite": { "version": "1.4.0", @@ -35359,15 +34498,6 @@ "wrappy": "1" } }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -35551,12 +34681,6 @@ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "dev": true - }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", @@ -35731,12 +34855,6 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, "promise": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", @@ -36069,12 +35187,6 @@ "functions-have-names": "^1.2.2" } }, - "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "dev": true - }, "registry-auth-token": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", @@ -36251,16 +35363,6 @@ "lowercase-keys": "^1.0.0" } }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", @@ -36524,9 +35626,9 @@ "integrity": "sha512-O4OZEaNtkMd/K0i6js9SL+gqy0ZCBMgUvlSqHKi4IBdjhe7wB8pwztUk1BbZ1fmrvpwFrPbHzqd2w5pTcJH6LA==" }, "semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -36749,7 +35851,6 @@ "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", @@ -36761,7 +35862,6 @@ "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" } @@ -36771,7 +35871,6 @@ "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" } @@ -36780,8 +35879,7 @@ "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 + "dev": true } } }, @@ -36949,332 +36047,124 @@ } }, "solhint": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.3.7.tgz", - "integrity": "sha512-NjjjVmXI3ehKkb3aNtRJWw55SUVJ8HMKKodwe0HnejA+k0d2kmhw7jvpa+MCTbcEgt8IWSwx0Hu6aCo/iYOZzQ==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.6.2.tgz", + "integrity": "sha512-85EeLbmkcPwD+3JR7aEMKsVC9YrRSxd4qkXuMzrlf7+z2Eqdfm1wHWq1ffTuo5aDhoZxp2I9yF3QkxZOxOL7aQ==", "dev": true, "requires": { - "@solidity-parser/parser": "^0.14.1", - "ajv": "^6.6.1", - "antlr4": "4.7.1", - "ast-parents": "0.0.1", - "chalk": "^2.4.2", - "commander": "2.18.0", - "cosmiconfig": "^5.0.7", - "eslint": "^5.6.0", - "fast-diff": "^1.1.2", - "glob": "^7.1.3", - "ignore": "^4.0.6", - "js-yaml": "^3.12.0", - "lodash": "^4.17.11", - "prettier": "^1.14.3", - "semver": "^6.3.0" + "@solidity-parser/parser": "^0.16.0", + "ajv": "^6.12.6", + "antlr4": "^4.11.0", + "ast-parents": "^0.0.1", + "chalk": "^4.1.2", + "commander": "^10.0.0", + "cosmiconfig": "^8.0.0", + "fast-diff": "^1.2.0", + "glob": "^8.0.3", + "ignore": "^5.2.4", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "pluralize": "^8.0.0", + "prettier": "^2.8.3", + "semver": "^7.5.2", + "strip-ansi": "^6.0.1", + "table": "^6.8.1", + "text-table": "^0.2.0" }, "dependencies": { - "acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "dev": true - }, - "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 - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true - }, - "commander": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.18.0.tgz", - "integrity": "sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ==", - "dev": 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 - }, - "eslint": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", - "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.9.1", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^4.0.3", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^5.0.1", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.7.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^6.2.2", - "js-yaml": "^3.13.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.11", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - }, - "espree": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", - "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", + "@solidity-parser/parser": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.1.tgz", + "integrity": "sha512-PdhRFNhbTtu3x8Axm0uYpqOy/lODYQK+MlYSgqIsq2L8SFYEHJPHNUiOTAJbDGzNjjr1/n9AcIayxafR/fWmYw==", "dev": true, "requires": { - "acorn": "^6.0.7", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" + "antlr4ts": "^0.5.0-alpha.4" } }, - "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 - }, - "estraverse": { + "ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "flat-cache": "^2.0.1" + "color-convert": "^2.0.1" } }, - "flat-cache": { + "brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - } - }, - "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.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 - }, - "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==", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "balanced-match": "^1.0.0" } }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "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": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "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": { - "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" + "color-name": "~1.1.4" } }, - "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 - }, - "prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", - "dev": true, - "optional": true - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "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 }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "dev": true }, - "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.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==", + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "dependencies": { - "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 - }, - "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, - "requires": { - "ansi-regex": "^4.1.0" - } - } + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" } }, - "strip-ansi": { + "has-flag": { "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, - "requires": { - "ansi-regex": "^3.0.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==", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" + "brace-expansion": "^2.0.1" } }, - "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==", + "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": { - "prelude-ls": "~1.1.2" + "has-flag": "^4.0.0" } } } @@ -38474,11 +37364,10 @@ } }, "table": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", - "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", + "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", @@ -38492,7 +37381,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "dev": true, - "peer": true, "requires": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -38504,8 +37392,7 @@ "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 + "dev": true } } }, @@ -40267,7 +39154,8 @@ "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 + "dev": true, + "peer": true }, "wordwrap": { "version": "1.0.0", @@ -40342,15 +39230,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, "ws": { "version": "7.4.6", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", diff --git a/package.json b/package.json index 274c04d3d..47b2e7dd6 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "prettier": "^2.8.8", "prettier-plugin-solidity": "^1.1.3", "rollup-plugin-esbuild": "^5.0.0", - "solhint": "^3.3.6", + "solhint": "^3.6.2", "standard-version": "^9.3.1", "ts-node": "^10.2.0", "typechain": "^8.0.0", diff --git a/tests/LSP23LinkedContractsDeployment/LSP23LinkedContractsDeployment.test.ts b/tests/LSP23LinkedContractsDeployment/LSP23LinkedContractsDeployment.test.ts index a49ef6752..d0b2884a5 100644 --- a/tests/LSP23LinkedContractsDeployment/LSP23LinkedContractsDeployment.test.ts +++ b/tests/LSP23LinkedContractsDeployment/LSP23LinkedContractsDeployment.test.ts @@ -456,8 +456,8 @@ describe('UniversalProfileDeployer', function () { // CHECK that the `target()` of the KeyManager contract is the UP contract expect(await keyManagerInstance.target()).to.equal(upContract); - expect(await keyManagerInstance.firstParam()).to.deep.equal(firstAddress); - expect(await keyManagerInstance.lastParam()).to.deep.equal(lastAddress); + expect(await keyManagerInstance.FIRST_PARAM()).to.deep.equal(firstAddress); + expect(await keyManagerInstance.LAST_PARAM()).to.deep.equal(lastAddress); }); }); describe('for proxies deployment', function () { From f8b85f6fa1474b44f7315273786c441a7848a4d6 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Mon, 18 Sep 2023 13:56:43 +0100 Subject: [PATCH 10/55] build: add TS types for JSON Metadata of LSP3 and LSP4 --- README.md | 10 ++++++++-- constants.ts | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f79b2666e..7e76fd392 100644 --- a/README.md +++ b/README.md @@ -106,14 +106,20 @@ See the [issue related to Hardhat Typescript + ES Modules](https://hardhat.org/h ### Typescript types -The following additional typescript types are also available. +The following additional typescript types are also available, including types for the JSON format of the LSP3 Profile and LSP4 Digital Asset metadata. ```ts import { LSP2ArrayKey, LSPSupportedStandard, LSP6PermissionName, - LSPErrorInfo, + LSP3ProfileMetadataJSON, + LSP3ProfileMetadata, + LSP4DigitalAssetMetadataJSON, + LSP4DigitalAssetMetadata, + ImageMetadata, + LinkMetadata, + AssetMetadata, } from "@lukso/lsp-smart-contracts/constants"; ``` diff --git a/constants.ts b/constants.ts index 61688c84e..884c1a54b 100644 --- a/constants.ts +++ b/constants.ts @@ -90,6 +90,54 @@ export const OPERATION_TYPES = { export type LSP2ArrayKey = { length: string; index: string }; export type LSPSupportedStandard = { key: string; value: string }; +// JSON Metadata + +export type LSP3ProfileMetadataJSON = { + LSP3Profile: LSP3ProfileMetadata; +}; + +export type LSP3ProfileMetadata = { + name: string; + description: string; + profileImage?: ImageMetadata[]; + backgroundImage?: ImageMetadata[]; + tags?: string[]; + links?: LinkMetadata[]; + avatar?: AssetMetadata[]; +}; + +export type LSP4DigitalAssetMetadataJSON = { + LSP4Metadata: LSP4DigitalAssetMetadata; +}; + +export type LSP4DigitalAssetMetadata = { + description: string; + links: LinkMetadata[]; + images: ImageMetadata[][]; + assets: AssetMetadata[]; + icon: ImageMetadata[]; +}; + +export type ImageMetadata = { + width: number; + height: number; + hashFunction: string; + hash: string; + url: string; +}; + +export type LinkMetadata = { + title: string; + url: string; +}; + +export type AssetMetadata = { + hashFunction: string; + hash: string; + url: string; + fileType: string; +}; + /** * @dev list of ERC725Y keys from the LSP standards. * Can be used to detect if a contract implements a specific LSP Metadata standard From 7422ab053b27f1139dc8b917218bebd2407009b9 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Thu, 14 Sep 2023 15:56:20 +0100 Subject: [PATCH 11/55] fix: return `bytes32(0)` when permission value retrieved is not exactly 32 bytes long --- .../LSP6KeyManager/LSP6Modules/LSP6SetDataModule.sol | 10 +++++++--- contracts/LSP6KeyManager/LSP6Utils.sol | 7 +++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/contracts/LSP6KeyManager/LSP6Modules/LSP6SetDataModule.sol b/contracts/LSP6KeyManager/LSP6Modules/LSP6SetDataModule.sol index 78aa6c1a0..e89c1b382 100644 --- a/contracts/LSP6KeyManager/LSP6Modules/LSP6SetDataModule.sol +++ b/contracts/LSP6KeyManager/LSP6Modules/LSP6SetDataModule.sol @@ -431,12 +431,16 @@ abstract contract LSP6SetDataModule { address controlledContract, bytes32 inputPermissionDataKey ) internal view virtual returns (bytes32) { + // extract the address of the controller from the data key `AddressPermissions:Permissions:` + address controller = address(bytes20(inputPermissionDataKey << 96)); + + bytes32 controllerPermissions = ERC725Y(controlledContract) + .getPermissionsFor(controller); + return // if there is nothing stored under the data key, we are trying to ADD a new controller. // if there are already some permissions set under the data key, we are trying to CHANGE the permissions of a controller. - bytes32( - ERC725Y(controlledContract).getData(inputPermissionDataKey) - ) == bytes32(0) + controllerPermissions == bytes32(0) ? _PERMISSION_ADDCONTROLLER : _PERMISSION_EDITPERMISSIONS; } diff --git a/contracts/LSP6KeyManager/LSP6Utils.sol b/contracts/LSP6KeyManager/LSP6Utils.sol index 03f4516ac..ea76fe73b 100644 --- a/contracts/LSP6KeyManager/LSP6Utils.sol +++ b/contracts/LSP6KeyManager/LSP6Utils.sol @@ -50,6 +50,9 @@ library LSP6Utils { * @param caller The controller address to read the permissions from. * * @return A `bytes32` BitArray containing the permissions of a controller address. + * + * @custom:info If the raw value fetched from the ERC725Y storage of `target` is not 32 bytes long, this is considered + * like _"no permissions are set"_ and will return 32 x `0x00` bytes as `bytes32(0)`. */ function getPermissionsFor( IERC725Y target, @@ -62,6 +65,10 @@ library LSP6Utils { ) ); + if (permissions.length != 32) { + return bytes32(0); + } + return bytes32(permissions); } From b68326b07a3ac47894611412840e230dd97daa5d Mon Sep 17 00:00:00 2001 From: CJ42 Date: Thu, 14 Sep 2023 15:56:45 +0100 Subject: [PATCH 12/55] docs: update auto-generated docs for `LSP6Utils` --- docs/libraries/LSP6KeyManager/LSP6Utils.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/libraries/LSP6KeyManager/LSP6Utils.md b/docs/libraries/LSP6KeyManager/LSP6Utils.md index 5789174b7..5da90cae4 100644 --- a/docs/libraries/LSP6KeyManager/LSP6Utils.md +++ b/docs/libraries/LSP6KeyManager/LSP6Utils.md @@ -26,6 +26,13 @@ Internal functions cannot be called externally, whether from other smart contrac ### getPermissionsFor +:::info + +If the raw value fetched from the ERC725Y storage of `target` is not 32 bytes long, this is considered +like _"no permissions are set"_ and will return 32 x `0x00` bytes as `bytes32(0)`. + +::: + ```solidity function getPermissionsFor(contract IERC725Y target, address caller) internal view returns (bytes32); ``` From 00b3573be4b10947fcd7918e09c6f2395a666e9f Mon Sep 17 00:00:00 2001 From: CJ42 Date: Thu, 14 Sep 2023 15:57:02 +0100 Subject: [PATCH 13/55] test: add extra tests when permission value stored for a controller is not 32 bytes long --- .../PermissionChangeAddController.test.ts | 222 +++++++++++++++++- 1 file changed, 216 insertions(+), 6 deletions(-) diff --git a/tests/LSP6KeyManager/SetPermissions/PermissionChangeAddController.test.ts b/tests/LSP6KeyManager/SetPermissions/PermissionChangeAddController.test.ts index aac7e4dcb..01ffa480b 100644 --- a/tests/LSP6KeyManager/SetPermissions/PermissionChangeAddController.test.ts +++ b/tests/LSP6KeyManager/SetPermissions/PermissionChangeAddController.test.ts @@ -48,13 +48,97 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( let permissionArrayKeys: string[] = []; let permissionArrayValues: string[] = []; + // addresses with not 32 bytes long permissions value set + // used to check that the caller editing the permissions value for these controllers requires the permission ADDCONTROLLER, + const callerHasAllPermissionsTestCase = { + addressWith16BytesHexPermissionsLength: '', + addressWith40BytesHexPermsissionsLength: '', + }; + + const callerHasAddControllerTestCase = { + addressWith16BytesHexPermissionsLength: '', + addressWith40BytesHexPermsissionsLength: '', + }; + + const callerHasEditPermissionsTestCase = { + addressWith16BytesHexPermissionsLength: '', + addressWith40BytesHexPermsissionsLength: '', + }; + + const callerHasSetDataTestCase = { + addressWith16BytesHexPermissionsLength: '', + addressWith40BytesHexPermsissionsLength: '', + }; + before('setup', async () => { context = await buildContext(); + callerHasAllPermissionsTestCase.addressWith16BytesHexPermissionsLength = + new ethers.Wallet.createRandom().address.toLowerCase(); + + callerHasAllPermissionsTestCase.addressWith40BytesHexPermsissionsLength = + new ethers.Wallet.createRandom().address.toLowerCase(); + + callerHasAddControllerTestCase.addressWith16BytesHexPermissionsLength = + new ethers.Wallet.createRandom().address.toLowerCase(); + + callerHasAddControllerTestCase.addressWith40BytesHexPermsissionsLength = + new ethers.Wallet.createRandom().address.toLowerCase(); + + callerHasEditPermissionsTestCase.addressWith16BytesHexPermissionsLength = + new ethers.Wallet.createRandom().address.toLowerCase(); + + callerHasEditPermissionsTestCase.addressWith40BytesHexPermsissionsLength = + new ethers.Wallet.createRandom().address.toLowerCase(); + + callerHasSetDataTestCase.addressWith16BytesHexPermissionsLength = + new ethers.Wallet.createRandom().address.toLowerCase(); + + callerHasSetDataTestCase.addressWith40BytesHexPermsissionsLength = + new ethers.Wallet.createRandom().address.toLowerCase(); + + const firstSetupPermissionsKeys = [ + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + callerHasAllPermissionsTestCase.addressWith16BytesHexPermissionsLength.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + callerHasAllPermissionsTestCase.addressWith40BytesHexPermsissionsLength.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + callerHasAddControllerTestCase.addressWith16BytesHexPermissionsLength.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + callerHasAddControllerTestCase.addressWith40BytesHexPermsissionsLength.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + callerHasEditPermissionsTestCase.addressWith16BytesHexPermissionsLength.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + callerHasEditPermissionsTestCase.addressWith40BytesHexPermsissionsLength.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + callerHasSetDataTestCase.addressWith16BytesHexPermissionsLength.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + callerHasSetDataTestCase.addressWith40BytesHexPermsissionsLength.substring(2), + ]; + + // We need to setup these first from the start, as the setup and teardown in the tests reset the permissions via the Key Manager, + // as the Key Manager will revert with custom error `InvalidDataValuesForDataKeys(AddressPermissions:Permissions:, invalidPermissionValue)` + const firstSetupPermissionsValues = [ + // 16 bytes long hex string = not 32 bytes long = equivalent to No Permissions Set + '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + // 40 bytes long hex string = not 32 bytes long = equivalent to No Permissions Set + '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + // same for other controllers (just repeated) + '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + ]; + await setupKeyManager( context, - [ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2)], - [ALL_PERMISSIONS], + [ + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ...firstSetupPermissionsKeys, + ], + [ALL_PERMISSIONS, ...firstSetupPermissionsValues], ); }); @@ -100,7 +184,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( PERMISSIONS.SETDATA, // placeholder permission PERMISSIONS.TRANSFERVALUE, - // 0x0000... = similar to empty, or 'no permissions set' + // `bytes32(0)` = similar to empty, or 'no permissions set' '0x0000000000000000000000000000000000000000000000000000000000000000', ]; @@ -185,6 +269,36 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( expect(result).to.equal(value); }); + it('should be allowed to ADD a new controller if this address has a 16 bytes long bytes value already set under its permission', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + callerHasAllPermissionsTestCase.addressWith16BytesHexPermissionsLength.substring(2); + const value = PERMISSIONS.SETDATA; + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await context.keyManager.connect(context.owner).execute(payload); + expect(await context.universalProfile.getData(key)).to.equal(value); + }); + + it('should be allowed to ADD a new controller if this address has a 40 bytes long bytes value already set under its permission', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + callerHasAllPermissionsTestCase.addressWith40BytesHexPermsissionsLength.substring(2); + const value = PERMISSIONS.SETDATA; + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await context.keyManager.connect(context.owner).execute(payload); + expect(await context.universalProfile.getData(key)).to.equal(value); + }); + describe('when editing `AddressPermissions[]` array length', () => { it('should be allowed to increment the length', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions[]'].length; @@ -429,6 +543,36 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); }); + it('should be allowed to ADD a new controller if this address has a 16 bytes long bytes value already set under its permission', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + callerHasAddControllerTestCase.addressWith16BytesHexPermissionsLength.substring(2); + const value = PERMISSIONS.SETDATA; + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await context.keyManager.connect(canOnlyAddController).execute(payload); + expect(await context.universalProfile.getData(key)).to.equal(value); + }); + + it('should be allowed to ADD a new controller if this address has a 40 bytes long bytes value already set under its permission', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + callerHasAddControllerTestCase.addressWith40BytesHexPermsissionsLength.substring(2); + const value = PERMISSIONS.SETDATA; + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await context.keyManager.connect(canOnlyAddController).execute(payload); + expect(await context.universalProfile.getData(key)).to.equal(value); + }); + describe('when editing `AddressPermissions[]` array length', () => { it('should be allowed to increment the length', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions[]'].length; @@ -599,7 +743,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( ]); }); - it('should not be allowed to ADD a permission', async () => { + it('should not be allowed to ADD a new controller', async () => { const newController = ethers.Wallet.createRandom(); const key = @@ -618,7 +762,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( .withArgs(canOnlyEditPermissions.address, 'ADDCONTROLLER'); }); - it('should not be allowed to set (= ADD) a permission for an address that has 32 x 0 bytes (0x0000...0000) as permission value', async () => { + it('should not be allowed to ADD a new controller if this address had 32 x 0 bytes (0x0000...0000) already as permission value', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + addressWithZeroHexPermissions.address.substring(2); @@ -634,7 +778,40 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( .withArgs(canOnlyEditPermissions.address, 'ADDCONTROLLER'); }); - it('should be allowed to CHANGE a permission', async () => { + it('should not be allowed to ADD a new controller if this address has a 16 bytes long bytes value already set under its permission', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + callerHasEditPermissionsTestCase.addressWith16BytesHexPermissionsLength.substring(2); + + const value = PERMISSIONS.SETDATA; + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await expect(context.keyManager.connect(canOnlyEditPermissions).execute(payload)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyEditPermissions.address, 'ADDCONTROLLER'); + }); + + it('should not be allowed to ADD a new controller if this address has a 40 bytes long bytes value already set under its permission', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + callerHasEditPermissionsTestCase.addressWith40BytesHexPermsissionsLength.substring(2); + const value = PERMISSIONS.SETDATA; + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await expect(context.keyManager.connect(canOnlyEditPermissions).execute(payload)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyEditPermissions.address, 'ADDCONTROLLER'); + }); + + it('should be allowed to EDIT the existing permissions of a controller', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + addressToEditPermissions.address.substring(2); @@ -860,6 +1037,39 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( .withArgs(canOnlySetData.address, 'ADDCONTROLLER'); }); + it('should not be allowed to ADD a new controller if this address has a 16 bytes long bytes value already set under its permission', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + callerHasSetDataTestCase.addressWith16BytesHexPermissionsLength.substring(2); + + const value = PERMISSIONS.SETDATA; + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await expect(context.keyManager.connect(canOnlySetData).execute(payload)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlySetData.address, 'ADDCONTROLLER'); + }); + + it('should not be allowed to ADD a new controller if this address has a 40 bytes long bytes value already set under its permission', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + callerHasSetDataTestCase.addressWith40BytesHexPermsissionsLength.substring(2); + const value = PERMISSIONS.SETDATA; + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await expect(context.keyManager.connect(canOnlySetData).execute(payload)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlySetData.address, 'ADDCONTROLLER'); + }); + it('should not be allowed to EDIT a permission', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + From d59a2ff4712a5373ce72ba1ccd63b2d796f60cd9 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Tue, 19 Sep 2023 11:24:39 +0100 Subject: [PATCH 14/55] refactor!: re-change param name from `allowNonLSP1Recipient` to `force` --- .../LSP7DigitalAsset/ILSP7DigitalAsset.sol | 18 ++--- .../LSP7DigitalAsset/LSP7DigitalAssetCore.sol | 67 ++++++++----------- contracts/LSP7DigitalAsset/LSP7Errors.sol | 4 +- .../extensions/LSP7CappedSupply.sol | 4 +- .../LSP7CappedSupplyInitAbstract.sol | 4 +- .../extensions/LSP7CompatibleERC20.sol | 12 ++-- .../LSP7CompatibleERC20InitAbstract.sol | 12 ++-- .../presets/ILSP7Mintable.sol | 4 +- .../presets/LSP7CompatibleERC20Mintable.sol | 4 +- ...SP7CompatibleERC20MintableInitAbstract.sol | 4 +- .../LSP7DigitalAsset/presets/LSP7Mintable.sol | 4 +- .../presets/LSP7MintableInitAbstract.sol | 4 +- .../ILSP8IdentifiableDigitalAsset.sol | 20 +++--- .../LSP8Errors.sol | 4 +- .../LSP8IdentifiableDigitalAssetCore.sol | 45 +++++-------- .../extensions/LSP8CappedSupply.sol | 4 +- .../LSP8CappedSupplyInitAbstract.sol | 4 +- .../extensions/LSP8CompatibleERC721.sol | 14 ++-- .../LSP8CompatibleERC721InitAbstract.sol | 14 ++-- .../presets/ILSP8Mintable.sol | 4 +- .../presets/LSP8CompatibleERC721Mintable.sol | 8 +-- ...P8CompatibleERC721MintableInitAbstract.sol | 8 +-- .../presets/LSP8Mintable.sol | 8 +-- .../presets/LSP8MintableInitAbstract.sol | 8 +-- .../Tokens/LSP7CappedSupplyInitTester.sol | 2 +- .../Mocks/Tokens/LSP7CappedSupplyTester.sol | 2 +- .../Tokens/LSP7CompatibleERC20InitTester.sol | 2 +- .../Tokens/LSP7CompatibleERC20Tester.sol | 2 +- contracts/Mocks/Tokens/LSP7InitTester.sol | 4 +- contracts/Mocks/Tokens/LSP7Tester.sol | 4 +- .../Tokens/LSP8CompatibleERC721Tester.sol | 2 +- .../Tokens/LSP8CompatibleERC721TesterInit.sol | 2 +- contracts/Mocks/Tokens/LSP8InitTester.sol | 4 +- contracts/Mocks/Tokens/LSP8Tester.sol | 4 +- 34 files changed, 142 insertions(+), 168 deletions(-) diff --git a/contracts/LSP7DigitalAsset/ILSP7DigitalAsset.sol b/contracts/LSP7DigitalAsset/ILSP7DigitalAsset.sol index 93ec0792a..f7d29e86a 100644 --- a/contracts/LSP7DigitalAsset/ILSP7DigitalAsset.sol +++ b/contracts/LSP7DigitalAsset/ILSP7DigitalAsset.sol @@ -20,7 +20,7 @@ interface ILSP7DigitalAsset is IERC165, IERC725Y { * @param from The address which tokens were sent from (balance decreased by `-amount`). * @param to The address that received the tokens (balance increased by `+amount`). * @param amount The amount of tokens transferred. - * @param allowNonLSP1Recipient if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. + * @param force if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. * @param data Any additional data included by the caller during the transfer, and sent in the LSP1 hooks to the `from` and `to` addresses. */ event Transfer( @@ -28,7 +28,7 @@ interface ILSP7DigitalAsset is IERC165, IERC725Y { address indexed from, address indexed to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes data ); @@ -173,7 +173,7 @@ interface ILSP7DigitalAsset is IERC165, IERC725Y { * @param from The sender address. * @param to The recipient address. * @param amount The amount of tokens to transfer. - * @param allowNonLSP1Recipient When set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. + * @param force When set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. * @param data Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. * * @custom:requirements @@ -188,19 +188,19 @@ interface ILSP7DigitalAsset is IERC165, IERC725Y { * - if the transfer is triggered by an operator, either the {AuthorizedOperator} event will be emitted with the updated allowance or the {RevokedOperator} * event will be emitted if the operator has no more allowance left. * - * @custom:hint The `allowNonLSP1Recipient` parameter **MUST be set to `true`** to transfer tokens to Externally Owned Accounts (EOAs) + * @custom:hint The `force` parameter **MUST be set to `true`** to transfer tokens to Externally Owned Accounts (EOAs) * or contracts that do not implement the LSP1 Universal Receiver Standard. Otherwise the function will revert making the transfer fail. * - * @custom:info if the `to` address is a contract that implements LSP1, it will always be notified via its `universalReceiver(...)` function, regardless if `allowNonLSP1Recipient` is set to `true` or `false`. + * @custom:info if the `to` address is a contract that implements LSP1, it will always be notified via its `universalReceiver(...)` function, regardless if `force` is set to `true` or `false`. * * @custom:warning Be aware that when either the sender or the recipient can have logic that revert in their `universalReceiver(...)` function when being notified. - * This even if the `allowNonLSP1Recipient` was set to `true`. + * This even if the `force` was set to `true`. */ function transfer( address from, address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) external; @@ -212,7 +212,7 @@ interface ILSP7DigitalAsset is IERC165, IERC725Y { * @param from An array of sending addresses. * @param to An array of receiving addresses. * @param amount An array of amount of tokens to transfer for each `from -> to` transfer. - * @param allowNonLSP1Recipient For each transfer, when set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. + * @param force For each transfer, when set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. * @param data An array of additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. * * @custom:requirements @@ -228,7 +228,7 @@ interface ILSP7DigitalAsset is IERC165, IERC725Y { address[] memory from, address[] memory to, uint256[] memory amount, - bool[] memory allowNonLSP1Recipient, + bool[] memory force, bytes[] memory data ) external; } diff --git a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol index c878ef51c..d61a1adc2 100644 --- a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol +++ b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol @@ -171,7 +171,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { address from, address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) public virtual { if (from == to) revert LSP7CannotSendToSelf(); @@ -191,7 +191,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { _updateOperator(from, operator, operatorAmount - amount, ""); } - _transfer(from, to, amount, allowNonLSP1Recipient, data); + _transfer(from, to, amount, force, data); } /** @@ -201,14 +201,14 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { address[] memory from, address[] memory to, uint256[] memory amount, - bool[] memory allowNonLSP1Recipient, + bool[] memory force, bytes[] memory data ) public virtual { uint256 fromLength = from.length; if ( fromLength != to.length || fromLength != amount.length || - fromLength != allowNonLSP1Recipient.length || + fromLength != force.length || fromLength != data.length ) { revert LSP7InvalidTransferBatch(); @@ -216,13 +216,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { for (uint256 i = 0; i < fromLength; ) { // using the public transfer function to handle updates to operator authorized amounts - transfer( - from[i], - to[i], - amount[i], - allowNonLSP1Recipient[i], - data[i] - ); + transfer(from[i], to[i], amount[i], force[i], data[i]); unchecked { ++i; @@ -374,9 +368,9 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { /** * @dev Mints `amount` of tokens and transfers it to `to`. * - * @param to the address to mint tokens for. - * @param amount the amount of tokens to mint. - * @param allowNonLSP1Recipient a boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. + * @param to The address to mint tokens for. + * @param amount The amount of tokens to mint. + * @param force A boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. * @param data Additional data the caller wants included in the emitted {Transfer} event, and sent in the LSP1 hook to the `to` address. * * @custom:requirements @@ -387,7 +381,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { function _mint( address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) internal virtual { if (to == address(0)) { @@ -403,17 +397,10 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { _tokenOwnerBalances[to] += amount; - emit Transfer( - operator, - address(0), - to, - amount, - allowNonLSP1Recipient, - data - ); + emit Transfer(operator, address(0), to, amount, force, data); bytes memory lsp1Data = abi.encode(address(0), to, amount, data); - _notifyTokenReceiver(to, allowNonLSP1Recipient, lsp1Data); + _notifyTokenReceiver(to, force, lsp1Data); } /** @@ -425,8 +412,8 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { * * Any logic in the {_beforeTokenTransfer} function will run before updating the balances. * - * @param from the address to burn tokens from its balance. - * @param amount the amount of tokens to burn. + * @param from The address to burn tokens from its balance. + * @param amount The amount of tokens to burn. * @param data Additional data the caller wants included in the emitted event, and sent in the LSP1 hook to the `from` and `to` address. * * @custom:hint In dApps, you can know which address is burning tokens by listening for the `Transfer` event and filter with the zero address as `to`. @@ -492,10 +479,10 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { * * Any logic in the {_beforeTokenTransfer} function will run before updating the balances. * - * @param from the address to decrease the balance. - * @param to the address to increase the balance. - * @param amount the amount of tokens to transfer from `from` to `to`. - * @param allowNonLSP1Recipient a boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. + * @param from The address to decrease the balance. + * @param to The address to increase the balance. + * @param amount The amount of tokens to transfer from `from` to `to`. + * @param force A boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. * @param data Additional data the caller wants included in the emitted event, and sent in the LSP1 hook to the `from` and `to` address. * * @custom:requirements @@ -509,7 +496,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { address from, address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) internal virtual { if (from == address(0) || to == address(0)) { @@ -528,12 +515,12 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { _tokenOwnerBalances[from] -= amount; _tokenOwnerBalances[to] += amount; - emit Transfer(operator, from, to, amount, allowNonLSP1Recipient, data); + emit Transfer(operator, from, to, amount, force, data); bytes memory lsp1Data = abi.encode(from, to, amount, data); _notifyTokenSender(from, lsp1Data); - _notifyTokenReceiver(to, allowNonLSP1Recipient, lsp1Data); + _notifyTokenReceiver(to, force, lsp1Data); } /** @@ -607,17 +594,17 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { * @dev Attempt to notify the token receiver `to` about the `amount` tokens being received. * This is done by calling its {universalReceiver} function with the `_TYPEID_LSP7_TOKENSRECIPIENT` as typeId, if `to` is a contract that supports the LSP1 interface. * - * If `to` is is an EOA or a contract that does not support the LSP1 interface, the behaviour will depend on the `allowNonLSP1Recipient` boolean flag. - * - if `allowNonLSP1Recipient` is set to `true`, nothing will happen and no notification will be sent. - * - if `allowNonLSP1Recipient` is set to `false, the transaction will revert. + * If `to` is is an EOA or a contract that does not support the LSP1 interface, the behaviour will depend on the `force` boolean flag. + * - if `force` is set to `true`, nothing will happen and no notification will be sent. + * - if `force` is set to `false, the transaction will revert. * * @param to The address to call the {universalReceiver} function on. - * @param allowNonLSP1Recipient a boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. - * @param lsp1Data the data to be sent to the `to` address in the `universalReceiver(...)` call. + * @param force A boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. + * @param lsp1Data The data to be sent to the `to` address in the `universalReceiver(...)` call. */ function _notifyTokenReceiver( address to, - bool allowNonLSP1Recipient, + bool force, bytes memory lsp1Data ) internal virtual { if ( @@ -630,7 +617,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { _TYPEID_LSP7_TOKENSRECIPIENT, lsp1Data ); - } else if (!allowNonLSP1Recipient) { + } else if (!force) { if (to.code.length > 0) { revert LSP7NotifyTokenReceiverContractMissingLSP1Interface(to); } else { diff --git a/contracts/LSP7DigitalAsset/LSP7Errors.sol b/contracts/LSP7DigitalAsset/LSP7Errors.sol index b01947b81..02c1781ac 100644 --- a/contracts/LSP7DigitalAsset/LSP7Errors.sol +++ b/contracts/LSP7DigitalAsset/LSP7Errors.sol @@ -48,14 +48,14 @@ error LSP7InvalidTransferBatch(); /** * @dev reverts if the `tokenReceiver` does not implement LSP1 - * when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. + * when minting or transferring tokens with `bool force` set as `false`. */ error LSP7NotifyTokenReceiverContractMissingLSP1Interface( address tokenReceiver ); /** - * @dev reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. + * @dev reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. */ error LSP7NotifyTokenReceiverIsEOA(address tokenReceiver); diff --git a/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.sol b/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.sol index 1d4b06082..a7e92dedc 100644 --- a/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.sol +++ b/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.sol @@ -71,13 +71,13 @@ abstract contract LSP7CappedSupply is LSP7DigitalAsset { function _mint( address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) internal virtual override { if (totalSupply() + amount > tokenSupplyCap()) { revert LSP7CappedSupplyCannotMintOverCap(); } - super._mint(to, amount, allowNonLSP1Recipient, data); + super._mint(to, amount, force, data); } } diff --git a/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupplyInitAbstract.sol b/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupplyInitAbstract.sol index 66d0c8686..8e3eef30e 100644 --- a/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupplyInitAbstract.sol +++ b/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupplyInitAbstract.sol @@ -74,13 +74,13 @@ abstract contract LSP7CappedSupplyInitAbstract is LSP7DigitalAssetInitAbstract { function _mint( address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) internal virtual override { if (totalSupply() + amount > tokenSupplyCap()) { revert LSP7CappedSupplyCannotMintOverCap(); } - super._mint(to, amount, allowNonLSP1Recipient, data); + super._mint(to, amount, force, data); } } diff --git a/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol b/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol index d63562b0e..c77a8527d 100644 --- a/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol +++ b/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol @@ -76,7 +76,7 @@ abstract contract LSP7CompatibleERC20 is /** * @inheritdoc ILSP7CompatibleERC20 * - * @custom:info This function uses the `allowNonLSP1Recipient` parameter as `true` so that EOA and any contract can receive tokens. + * @custom:info This function uses the `force` parameter as `true` so that EOA and any contract can receive tokens. */ function transferFrom( address from, @@ -92,7 +92,7 @@ abstract contract LSP7CompatibleERC20 is /** * @inheritdoc ILSP7CompatibleERC20 * - * @custom:info This function uses the `allowNonLSP1Recipient` parameter as `true` so that EOA and any contract can receive tokens. + * @custom:info This function uses the `force` parameter as `true` so that EOA and any contract can receive tokens. */ function transfer( address to, @@ -126,11 +126,11 @@ abstract contract LSP7CompatibleERC20 is address from, address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) internal virtual override { emit Transfer(from, to, amount); - super._transfer(from, to, amount, allowNonLSP1Recipient, data); + super._transfer(from, to, amount, force, data); } /** @@ -141,11 +141,11 @@ abstract contract LSP7CompatibleERC20 is function _mint( address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) internal virtual override { emit Transfer(address(0), to, amount); - super._mint(to, amount, allowNonLSP1Recipient, data); + super._mint(to, amount, force, data); } /** diff --git a/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20InitAbstract.sol b/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20InitAbstract.sol index 2ab5adbe5..5c3665ada 100644 --- a/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20InitAbstract.sol +++ b/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20InitAbstract.sol @@ -83,7 +83,7 @@ abstract contract LSP7CompatibleERC20InitAbstract is /** * @inheritdoc ILSP7CompatibleERC20 * - * @custom:info This function uses the `allowNonLSP1Recipient` parameter as `true` so that EOA and any contract can receive tokens. + * @custom:info This function uses the `force` parameter as `true` so that EOA and any contract can receive tokens. */ function transferFrom( address from, @@ -99,7 +99,7 @@ abstract contract LSP7CompatibleERC20InitAbstract is /** * @inheritdoc ILSP7CompatibleERC20 * - * @custom:info This function uses the `allowNonLSP1Recipient` parameter as `true` so that EOA and any contract can receive tokens. + * @custom:info This function uses the `force` parameter as `true` so that EOA and any contract can receive tokens. */ function transfer( address to, @@ -133,11 +133,11 @@ abstract contract LSP7CompatibleERC20InitAbstract is address from, address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) internal virtual override { emit Transfer(from, to, amount); - super._transfer(from, to, amount, allowNonLSP1Recipient, data); + super._transfer(from, to, amount, force, data); } /** @@ -148,11 +148,11 @@ abstract contract LSP7CompatibleERC20InitAbstract is function _mint( address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) internal virtual override { emit Transfer(address(0), to, amount); - super._mint(to, amount, allowNonLSP1Recipient, data); + super._mint(to, amount, force, data); } /** diff --git a/contracts/LSP7DigitalAsset/presets/ILSP7Mintable.sol b/contracts/LSP7DigitalAsset/presets/ILSP7Mintable.sol index 7624bf8d6..08d7e267a 100644 --- a/contracts/LSP7DigitalAsset/presets/ILSP7Mintable.sol +++ b/contracts/LSP7DigitalAsset/presets/ILSP7Mintable.sol @@ -12,7 +12,7 @@ interface ILSP7Mintable is ILSP7DigitalAsset { /** * @param to The address to mint tokens * @param amount The amount to mint - * @param allowNonLSP1Recipient When set to TRUE, to may be any address but + * @param force When set to TRUE, to may be any address but * when set to FALSE to must be a contract that supports LSP1 UniversalReceiver * @param data Additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. * @dev Mints `amount` tokens and transfers it to `to`. @@ -26,7 +26,7 @@ interface ILSP7Mintable is ILSP7DigitalAsset { function mint( address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) external; } diff --git a/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol b/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol index dc25a81c3..cf8d2ab7b 100644 --- a/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol +++ b/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol @@ -27,9 +27,9 @@ contract LSP7CompatibleERC20Mintable is LSP7CompatibleERC20 { function mint( address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) public virtual onlyOwner { - _mint(to, amount, allowNonLSP1Recipient, data); + _mint(to, amount, force, data); } } diff --git a/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20MintableInitAbstract.sol b/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20MintableInitAbstract.sol index fe5b69b88..b0c77d31c 100644 --- a/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20MintableInitAbstract.sol +++ b/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20MintableInitAbstract.sol @@ -29,9 +29,9 @@ abstract contract LSP7CompatibleERC20MintableInitAbstract is function mint( address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) public virtual onlyOwner { - _mint(to, amount, allowNonLSP1Recipient, data); + _mint(to, amount, force, data); } } diff --git a/contracts/LSP7DigitalAsset/presets/LSP7Mintable.sol b/contracts/LSP7DigitalAsset/presets/LSP7Mintable.sol index a11d44804..d2c69149e 100644 --- a/contracts/LSP7DigitalAsset/presets/LSP7Mintable.sol +++ b/contracts/LSP7DigitalAsset/presets/LSP7Mintable.sol @@ -34,9 +34,9 @@ contract LSP7Mintable is LSP7DigitalAsset, ILSP7Mintable { function mint( address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) public virtual onlyOwner { - _mint(to, amount, allowNonLSP1Recipient, data); + _mint(to, amount, force, data); } } diff --git a/contracts/LSP7DigitalAsset/presets/LSP7MintableInitAbstract.sol b/contracts/LSP7DigitalAsset/presets/LSP7MintableInitAbstract.sol index 234577d4d..8b7a2cd5f 100644 --- a/contracts/LSP7DigitalAsset/presets/LSP7MintableInitAbstract.sol +++ b/contracts/LSP7DigitalAsset/presets/LSP7MintableInitAbstract.sol @@ -45,9 +45,9 @@ abstract contract LSP7MintableInitAbstract is function mint( address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) public virtual onlyOwner { - _mint(to, amount, allowNonLSP1Recipient, data); + _mint(to, amount, force, data); } } diff --git a/contracts/LSP8IdentifiableDigitalAsset/ILSP8IdentifiableDigitalAsset.sol b/contracts/LSP8IdentifiableDigitalAsset/ILSP8IdentifiableDigitalAsset.sol index 82c401837..babc53e27 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/ILSP8IdentifiableDigitalAsset.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/ILSP8IdentifiableDigitalAsset.sol @@ -20,7 +20,7 @@ interface ILSP8IdentifiableDigitalAsset is IERC165, IERC725Y { * @param from The previous owner of the `tokenId` * @param to The new owner of `tokenId` * @param tokenId The tokenId that was transferred - * @param allowNonLSP1Recipient If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. + * @param force If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. * @param data Any additional data the caller included by the caller during the transfer, and sent in the hooks to the `from` and `to` addresses. */ event Transfer( @@ -28,7 +28,7 @@ interface ILSP8IdentifiableDigitalAsset is IERC165, IERC725Y { address indexed from, address indexed to, bytes32 indexed tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ); @@ -182,13 +182,13 @@ interface ILSP8IdentifiableDigitalAsset is IERC165, IERC725Y { * * If operators are set for a specific `tokenId`, all the operators are revoked after the tokenId have been transferred. * - * The `allowNonLSP1Recipient` parameter MUST be set to `true` when transferring tokens to Externally Owned Accounts (EOAs) + * The `force` parameter MUST be set to `true` when transferring tokens to Externally Owned Accounts (EOAs) * or contracts that do not implement the LSP1 standard. * * @param from The address that owns the given `tokenId`. * @param to The address that will receive the `tokenId`. * @param tokenId The token ID to transfer. - * @param allowNonLSP1Recipient When set to `true`, the `to` address CAN be any addres. + * @param force When set to `true`, the `to` address CAN be any addres. * When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. * @param data Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. * @@ -202,19 +202,19 @@ interface ILSP8IdentifiableDigitalAsset is IERC165, IERC725Y { * @custom:events * - {Transfer} event when the `tokenId` is successfully transferred. * - * @custom:hint The `allowNonLSP1Recipient` parameter **MUST be set to `true`** to transfer tokens to Externally Owned Accounts (EOAs) + * @custom:hint The `force` parameter **MUST be set to `true`** to transfer tokens to Externally Owned Accounts (EOAs) * or contracts that do not implement the LSP1 Universal Receiver Standard. Otherwise the function will revert making the transfer fail. * - * @custom:info if the `to` address is a contract that implements LSP1, it will always be notified via its `universalReceiver(...)` function, regardless if `allowNonLSP1Recipient` is set to `true` or `false`. + * @custom:info if the `to` address is a contract that implements LSP1, it will always be notified via its `universalReceiver(...)` function, regardless if `force` is set to `true` or `false`. * * @custom:warning Be aware that when either the sender or the recipient can have logic that revert in their `universalReceiver(...)` function when being notified. - * This even if the `allowNonLSP1Recipient` was set to `true`. + * This even if the `force` was set to `true`. */ function transfer( address from, address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) external; @@ -225,7 +225,7 @@ interface ILSP8IdentifiableDigitalAsset is IERC165, IERC725Y { * @param from An array of sending addresses. * @param to An array of recipient addresses. * @param tokenId An array of token IDs to transfer. - * @param allowNonLSP1Recipient When set to `true`, `to` may be any address. + * @param force When set to `true`, `to` may be any address. * When set to `false`, `to` must be a contract that supports the LSP1 standard and not revert. * @param data Any additional data the caller wants included in the emitted event, and sent in the hooks to the `from` and `to` addresses. * @@ -245,7 +245,7 @@ interface ILSP8IdentifiableDigitalAsset is IERC165, IERC725Y { address[] memory from, address[] memory to, bytes32[] memory tokenId, - bool[] memory allowNonLSP1Recipient, + bool[] memory force, bytes[] memory data ) external; } diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8Errors.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8Errors.sol index c69ce9198..c5d6fe4e9 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8Errors.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8Errors.sol @@ -55,7 +55,7 @@ error LSP8InvalidTransferBatch(); /** * @dev reverts if the `tokenReceiver` does not implement LSP1 - * when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. + * when minting or transferring tokens with `bool force` set as `false`. */ error LSP8NotifyTokenReceiverContractMissingLSP1Interface( address tokenReceiver @@ -63,7 +63,7 @@ error LSP8NotifyTokenReceiverContractMissingLSP1Interface( /** * @dev reverts if the `tokenReceiver` is an EOA - * when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. + * when minting or transferring tokens with `bool force` set as `false`. */ error LSP8NotifyTokenReceiverIsEOA(address tokenReceiver); diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol index 09b940984..81bb7b8b4 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol @@ -236,7 +236,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is address from, address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) public virtual { address operator = msg.sender; @@ -245,7 +245,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is revert LSP8NotTokenOperator(tokenId, operator); } - _transfer(from, to, tokenId, allowNonLSP1Recipient, data); + _transfer(from, to, tokenId, force, data); } /** @@ -255,27 +255,21 @@ abstract contract LSP8IdentifiableDigitalAssetCore is address[] memory from, address[] memory to, bytes32[] memory tokenId, - bool[] memory allowNonLSP1Recipient, + bool[] memory force, bytes[] memory data ) public virtual { uint256 fromLength = from.length; if ( fromLength != to.length || fromLength != tokenId.length || - fromLength != allowNonLSP1Recipient.length || + fromLength != force.length || fromLength != data.length ) { revert LSP8InvalidTransferBatch(); } for (uint256 i = 0; i < fromLength; ) { - transfer( - from[i], - to[i], - tokenId[i], - allowNonLSP1Recipient[i], - data[i] - ); + transfer(from[i], to[i], tokenId[i], force[i], data[i]); unchecked { ++i; @@ -361,7 +355,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is * * @param to The address that will receive the minted `tokenId`. * @param tokenId The token ID to create (= mint). - * @param allowNonLSP1Recipient When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. + * @param force When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. * @param data Any additional data the caller wants included in the emitted event, and sent in the hook of the `to` address. * * @custom:events {Transfer} event with `address(0)` as `from` address. @@ -369,7 +363,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is function _mint( address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) internal virtual { if (to == address(0)) { @@ -390,17 +384,10 @@ abstract contract LSP8IdentifiableDigitalAssetCore is _ownedTokens[to].add(tokenId); _tokenOwners[tokenId] = to; - emit Transfer( - operator, - address(0), - to, - tokenId, - allowNonLSP1Recipient, - data - ); + emit Transfer(operator, address(0), to, tokenId, force, data); bytes memory lsp1Data = abi.encode(address(0), to, tokenId, data); - _notifyTokenReceiver(to, allowNonLSP1Recipient, lsp1Data); + _notifyTokenReceiver(to, force, lsp1Data); } /** @@ -460,7 +447,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is * @param from The sender address. * @param to The recipient address. * @param tokenId The token to transfer. - * @param allowNonLSP1Recipient When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. + * @param force When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. * @param data Additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. * * @custom:requirements @@ -475,7 +462,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is address from, address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) internal virtual { if (from == to) { @@ -501,12 +488,12 @@ abstract contract LSP8IdentifiableDigitalAssetCore is _ownedTokens[to].add(tokenId); _tokenOwners[tokenId] = to; - emit Transfer(operator, from, to, tokenId, allowNonLSP1Recipient, data); + emit Transfer(operator, from, to, tokenId, force, data); bytes memory lsp1Data = abi.encode(from, to, tokenId, data); _notifyTokenSender(from, lsp1Data); - _notifyTokenReceiver(to, allowNonLSP1Recipient, lsp1Data); + _notifyTokenReceiver(to, force, lsp1Data); } /** @@ -574,13 +561,13 @@ abstract contract LSP8IdentifiableDigitalAssetCore is /** * @dev An attempt is made to notify the token receiver about the `tokenId` changing owners - * using LSP1 interface. When allowNonLSP1Recipient is FALSE the token receiver MUST support LSP1. + * using LSP1 interface. When force is FALSE the token receiver MUST support LSP1. * * The receiver may revert when the token being sent is not wanted. */ function _notifyTokenReceiver( address to, - bool allowNonLSP1Recipient, + bool force, bytes memory lsp1Data ) internal virtual { if ( @@ -593,7 +580,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is _TYPEID_LSP8_TOKENSRECIPIENT, lsp1Data ); - } else if (!allowNonLSP1Recipient) { + } else if (!force) { if (to.code.length > 0) { revert LSP8NotifyTokenReceiverContractMissingLSP1Interface(to); } else { diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.sol index e0e4226f1..9dafac599 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.sol @@ -74,13 +74,13 @@ abstract contract LSP8CappedSupply is LSP8IdentifiableDigitalAsset { function _mint( address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) internal virtual override { if (totalSupply() + 1 > tokenSupplyCap()) { revert LSP8CappedSupplyCannotMintOverCap(); } - super._mint(to, tokenId, allowNonLSP1Recipient, data); + super._mint(to, tokenId, force, data); } } diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupplyInitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupplyInitAbstract.sol index 026ed2227..13b560841 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupplyInitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupplyInitAbstract.sol @@ -77,13 +77,13 @@ abstract contract LSP8CappedSupplyInitAbstract is function _mint( address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) internal virtual override { if (totalSupply() + 1 > tokenSupplyCap()) { revert LSP8CappedSupplyCannotMintOverCap(); } - super._mint(to, tokenId, allowNonLSP1Recipient, data); + super._mint(to, tokenId, force, data); } } diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol index 7f453b5e5..6dc651df8 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol @@ -173,7 +173,7 @@ abstract contract LSP8CompatibleERC721 is /** * @inheritdoc ILSP8CompatibleERC721 * - * @custom:info This function sets the `allowNonLSP1Recipient` parameter to `true` so that EOAs and any contract can receive the `tokenId`. + * @custom:info This function sets the `force` parameter to `true` so that EOAs and any contract can receive the `tokenId`. */ function transferFrom( address from, @@ -186,7 +186,7 @@ abstract contract LSP8CompatibleERC721 is /** * @inheritdoc ILSP8CompatibleERC721 * - * @custom:info This function sets the `allowNonLSP1Recipient` parameter to `true` so that EOAs and any contract can receive the `tokenId`. + * @custom:info This function sets the `force` parameter to `true` so that EOAs and any contract can receive the `tokenId`. */ function safeTransferFrom( address from, @@ -199,7 +199,7 @@ abstract contract LSP8CompatibleERC721 is /** * @inheritdoc ILSP8CompatibleERC721 * - * @custom:info This function sets the `allowNonLSP1Recipient` parameter to `true` so that EOAs and any contract can receive the `tokenId`. + * @custom:info This function sets the `force` parameter to `true` so that EOAs and any contract can receive the `tokenId`. */ function safeTransferFrom( address from, @@ -278,7 +278,7 @@ abstract contract LSP8CompatibleERC721 is address from, address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) internal virtual override { if ( @@ -289,7 +289,7 @@ abstract contract LSP8CompatibleERC721 is } emit Transfer(from, to, uint256(tokenId)); - super._transfer(from, to, tokenId, allowNonLSP1Recipient, data); + super._transfer(from, to, tokenId, force, data); } /** @@ -320,11 +320,11 @@ abstract contract LSP8CompatibleERC721 is function _mint( address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) internal virtual override { emit Transfer(address(0), to, uint256(tokenId)); - super._mint(to, tokenId, allowNonLSP1Recipient, data); + super._mint(to, tokenId, force, data); } /** diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol index 294e74091..5d562725c 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol @@ -181,7 +181,7 @@ abstract contract LSP8CompatibleERC721InitAbstract is /** * @inheritdoc ILSP8CompatibleERC721 * - * @custom:info This function sets the `allowNonLSP1Recipient` parameter to `true` so that EOAs and any contract can receive the `tokenId`. + * @custom:info This function sets the `force` parameter to `true` so that EOAs and any contract can receive the `tokenId`. */ function transferFrom( address from, @@ -194,7 +194,7 @@ abstract contract LSP8CompatibleERC721InitAbstract is /** * @inheritdoc ILSP8CompatibleERC721 * - * @custom:info This function sets the `allowNonLSP1Recipient` parameter to `true` so that EOAs and any contract can receive the `tokenId`. + * @custom:info This function sets the `force` parameter to `true` so that EOAs and any contract can receive the `tokenId`. */ function safeTransferFrom( address from, @@ -207,7 +207,7 @@ abstract contract LSP8CompatibleERC721InitAbstract is /** * @inheritdoc ILSP8CompatibleERC721 * - * @custom:info This function sets the `allowNonLSP1Recipient` parameter to `true` so that EOAs and any contract can receive the `tokenId`. + * @custom:info This function sets the `force` parameter to `true` so that EOAs and any contract can receive the `tokenId`. */ function safeTransferFrom( address from, @@ -286,7 +286,7 @@ abstract contract LSP8CompatibleERC721InitAbstract is address from, address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) internal virtual override { address operator = msg.sender; @@ -299,7 +299,7 @@ abstract contract LSP8CompatibleERC721InitAbstract is } emit Transfer(from, to, uint256(tokenId)); - super._transfer(from, to, tokenId, allowNonLSP1Recipient, data); + super._transfer(from, to, tokenId, force, data); } /** @@ -330,11 +330,11 @@ abstract contract LSP8CompatibleERC721InitAbstract is function _mint( address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) internal virtual override { emit Transfer(address(0), to, uint256(tokenId)); - super._mint(to, tokenId, allowNonLSP1Recipient, data); + super._mint(to, tokenId, force, data); } /** diff --git a/contracts/LSP8IdentifiableDigitalAsset/presets/ILSP8Mintable.sol b/contracts/LSP8IdentifiableDigitalAsset/presets/ILSP8Mintable.sol index da04c68a8..d6bc2e8bd 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/presets/ILSP8Mintable.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/presets/ILSP8Mintable.sol @@ -14,7 +14,7 @@ interface ILSP8Mintable is ILSP8IdentifiableDigitalAsset { /** * @param to The address to mint tokens * @param tokenId The tokenId to mint - * @param allowNonLSP1Recipient When set to TRUE, to may be any address but + * @param force When set to TRUE, to may be any address but * when set to FALSE to must be a contract that supports LSP1 UniversalReceiver * @param data Additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. * @dev Mints `amount` tokens and transfers it to `to`. @@ -28,7 +28,7 @@ interface ILSP8Mintable is ILSP8IdentifiableDigitalAsset { function mint( address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) external; } diff --git a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol index 872b06593..4c0c82596 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol @@ -22,21 +22,21 @@ contract LSP8CompatibleERC721Mintable is LSP8CompatibleERC721 { ) LSP8CompatibleERC721(name_, symbol_, newOwner_) {} /** - * @notice Minting tokenId `tokenId` for address `to` with the additional data `data` (Note: allow non-LSP1 recipient is set to `allowNonLSP1Recipient`). + * @notice Minting tokenId `tokenId` for address `to` with the additional data `data` (Note: allow non-LSP1 recipient is set to `force`). * * @dev Public {_mint} function only callable by the {owner}. * * @param to The address that will receive the minted `tokenId`. * @param tokenId The tokenId to mint. - * @param allowNonLSP1Recipient Set to `false` to ensure that you are minting for a recipient that implements LSP1, `false` otherwise for forcing the minting. + * @param force Set to `false` to ensure that you are minting for a recipient that implements LSP1, `false` otherwise for forcing the minting. * @param data Any addition data to be sent alongside the minting. */ function mint( address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) public virtual onlyOwner { - _mint(to, tokenId, allowNonLSP1Recipient, data); + _mint(to, tokenId, force, data); } } diff --git a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721MintableInitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721MintableInitAbstract.sol index 697d1bfb9..1b27875c0 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721MintableInitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721MintableInitAbstract.sol @@ -24,21 +24,21 @@ contract LSP8CompatibleERC721MintableInitAbstract is } /** - * @notice Minting tokenId `tokenId` for address `to` with the additional data `data` (Note: allow non-LSP1 recipient is set to `allowNonLSP1Recipient`). + * @notice Minting tokenId `tokenId` for address `to` with the additional data `data` (Note: allow non-LSP1 recipient is set to `force`). * * @dev Public {_mint} function only callable by the {owner}. * * @param to The address that will receive the minted `tokenId`. * @param tokenId The tokenId to mint. - * @param allowNonLSP1Recipient Set to `false` to ensure that you are minting for a recipient that implements LSP1, `false` otherwise for forcing the minting. + * @param force Set to `false` to ensure that you are minting for a recipient that implements LSP1, `false` otherwise for forcing the minting. * @param data Any addition data to be sent alongside the minting. */ function mint( address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) public virtual onlyOwner { - _mint(to, tokenId, allowNonLSP1Recipient, data); + _mint(to, tokenId, force, data); } } diff --git a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol index 43ac8e0a0..7182aad0b 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol @@ -29,21 +29,21 @@ contract LSP8Mintable is LSP8IdentifiableDigitalAsset, ILSP8Mintable { ) LSP8IdentifiableDigitalAsset(name_, symbol_, newOwner_) {} /** - * @notice Minting tokenId `tokenId` for address `to` with the additional data `data` (Note: allow non-LSP1 recipient is set to `allowNonLSP1Recipient`). + * @notice Minting tokenId `tokenId` for address `to` with the additional data `data` (Note: allow non-LSP1 recipient is set to `force`). * * @dev Public {_mint} function only callable by the {owner}. * * @param to The address that will receive the minted `tokenId`. * @param tokenId The tokenId to mint. - * @param allowNonLSP1Recipient Set to `false` to ensure that you are minting for a recipient that implements LSP1, `false` otherwise for forcing the minting. + * @param force Set to `false` to ensure that you are minting for a recipient that implements LSP1, `false` otherwise for forcing the minting. * @param data Any addition data to be sent alongside the minting. */ function mint( address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) public virtual onlyOwner { - _mint(to, tokenId, allowNonLSP1Recipient, data); + _mint(to, tokenId, force, data); } } diff --git a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInitAbstract.sol index 4e614fc0d..0c49af6d8 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInitAbstract.sol @@ -37,21 +37,21 @@ abstract contract LSP8MintableInitAbstract is } /** - * @notice Minting tokenId `tokenId` for address `to` with the additional data `data` (Note: allow non-LSP1 recipient is set to `allowNonLSP1Recipient`). + * @notice Minting tokenId `tokenId` for address `to` with the additional data `data` (Note: allow non-LSP1 recipient is set to `force`). * * @dev Public {_mint} function only callable by the {owner}. * * @param to The address that will receive the minted `tokenId`. * @param tokenId The tokenId to mint. - * @param allowNonLSP1Recipient Set to `false` to ensure that you are minting for a recipient that implements LSP1, `false` otherwise for forcing the minting. + * @param force Set to `false` to ensure that you are minting for a recipient that implements LSP1, `false` otherwise for forcing the minting. * @param data Any addition data to be sent alongside the minting. */ function mint( address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) public virtual onlyOwner { - _mint(to, tokenId, allowNonLSP1Recipient, data); + _mint(to, tokenId, force, data); } } diff --git a/contracts/Mocks/Tokens/LSP7CappedSupplyInitTester.sol b/contracts/Mocks/Tokens/LSP7CappedSupplyInitTester.sol index 8dbe9efd9..da0984f8f 100644 --- a/contracts/Mocks/Tokens/LSP7CappedSupplyInitTester.sol +++ b/contracts/Mocks/Tokens/LSP7CappedSupplyInitTester.sol @@ -22,7 +22,7 @@ contract LSP7CappedSupplyInitTester is LSP7CappedSupplyInitAbstract { } function mint(address to, uint256 amount) public { - // using allowNonLSP1Recipient=true so we can send to EOA in test + // using force=true so we can send to EOA in test _mint(to, amount, true, "token printer go brrr"); } diff --git a/contracts/Mocks/Tokens/LSP7CappedSupplyTester.sol b/contracts/Mocks/Tokens/LSP7CappedSupplyTester.sol index ec8c1cd68..5834fadfa 100644 --- a/contracts/Mocks/Tokens/LSP7CappedSupplyTester.sol +++ b/contracts/Mocks/Tokens/LSP7CappedSupplyTester.sol @@ -20,7 +20,7 @@ contract LSP7CappedSupplyTester is LSP7CappedSupply { {} function mint(address to, uint256 amount) public { - // using allowNonLSP1Recipient=true so we can send to EOA in test + // using force=true so we can send to EOA in test _mint(to, amount, true, "token printer go brrr"); } diff --git a/contracts/Mocks/Tokens/LSP7CompatibleERC20InitTester.sol b/contracts/Mocks/Tokens/LSP7CompatibleERC20InitTester.sol index 07cb6e539..fc1882a35 100644 --- a/contracts/Mocks/Tokens/LSP7CompatibleERC20InitTester.sol +++ b/contracts/Mocks/Tokens/LSP7CompatibleERC20InitTester.sol @@ -24,7 +24,7 @@ contract LSP7CompatibleERC20InitTester is LSP7CompatibleERC20InitAbstract { } function mint(address to, uint256 amount, bytes calldata data) public { - // using allowNonLSP1Recipient=true so we can send to EOA in test + // using force=true so we can send to EOA in test _mint(to, amount, true, data); } diff --git a/contracts/Mocks/Tokens/LSP7CompatibleERC20Tester.sol b/contracts/Mocks/Tokens/LSP7CompatibleERC20Tester.sol index 9e7429006..1bf28b352 100644 --- a/contracts/Mocks/Tokens/LSP7CompatibleERC20Tester.sol +++ b/contracts/Mocks/Tokens/LSP7CompatibleERC20Tester.sol @@ -15,7 +15,7 @@ contract LSP7CompatibleERC20Tester is LSP7CompatibleERC20 { ) LSP7CompatibleERC20(name_, symbol_, newOwner_) {} function mint(address to, uint256 amount, bytes calldata data) public { - // using allowNonLSP1Recipient=true so we can send to EOA in test + // using force=true so we can send to EOA in test _mint(to, amount, true, data); } diff --git a/contracts/Mocks/Tokens/LSP7InitTester.sol b/contracts/Mocks/Tokens/LSP7InitTester.sol index 2a95b0ae9..ad1a3b739 100644 --- a/contracts/Mocks/Tokens/LSP7InitTester.sol +++ b/contracts/Mocks/Tokens/LSP7InitTester.sol @@ -31,9 +31,9 @@ contract LSP7InitTester is function mint( address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) public { - _mint(to, amount, allowNonLSP1Recipient, data); + _mint(to, amount, force, data); } } diff --git a/contracts/Mocks/Tokens/LSP7Tester.sol b/contracts/Mocks/Tokens/LSP7Tester.sol index 4681979b2..411516e03 100644 --- a/contracts/Mocks/Tokens/LSP7Tester.sol +++ b/contracts/Mocks/Tokens/LSP7Tester.sol @@ -15,9 +15,9 @@ contract LSP7Tester is LSP7DigitalAsset, LSP7Burnable { function mint( address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) public { - _mint(to, amount, allowNonLSP1Recipient, data); + _mint(to, amount, force, data); } } diff --git a/contracts/Mocks/Tokens/LSP8CompatibleERC721Tester.sol b/contracts/Mocks/Tokens/LSP8CompatibleERC721Tester.sol index ce8517bf5..475c5e565 100644 --- a/contracts/Mocks/Tokens/LSP8CompatibleERC721Tester.sol +++ b/contracts/Mocks/Tokens/LSP8CompatibleERC721Tester.sol @@ -23,7 +23,7 @@ contract LSP8CompatibleERC721Tester is LSP8CompatibleERC721 { } function mint(address to, uint256 tokenId, bytes calldata data) public { - // using allowNonLSP1Recipient=true so we can send to EOA in test + // using force=true so we can send to EOA in test _mint(to, bytes32(tokenId), true, data); } diff --git a/contracts/Mocks/Tokens/LSP8CompatibleERC721TesterInit.sol b/contracts/Mocks/Tokens/LSP8CompatibleERC721TesterInit.sol index 767826cbf..0b1575b7f 100644 --- a/contracts/Mocks/Tokens/LSP8CompatibleERC721TesterInit.sol +++ b/contracts/Mocks/Tokens/LSP8CompatibleERC721TesterInit.sol @@ -32,7 +32,7 @@ contract LSP8CompatibleERC721InitTester is LSP8CompatibleERC721InitAbstract { } function mint(address to, uint256 tokenId, bytes calldata data) public { - // using allowNonLSP1Recipient=true so we can send to EOA in test + // using force=true so we can send to EOA in test _mint(to, bytes32(tokenId), true, data); } diff --git a/contracts/Mocks/Tokens/LSP8InitTester.sol b/contracts/Mocks/Tokens/LSP8InitTester.sol index 7d9fcb046..a5aa6d8c5 100644 --- a/contracts/Mocks/Tokens/LSP8InitTester.sol +++ b/contracts/Mocks/Tokens/LSP8InitTester.sol @@ -29,9 +29,9 @@ contract LSP8InitTester is function mint( address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) public { - _mint(to, tokenId, allowNonLSP1Recipient, data); + _mint(to, tokenId, force, data); } } diff --git a/contracts/Mocks/Tokens/LSP8Tester.sol b/contracts/Mocks/Tokens/LSP8Tester.sol index 0dbfd5138..66a7a6639 100644 --- a/contracts/Mocks/Tokens/LSP8Tester.sol +++ b/contracts/Mocks/Tokens/LSP8Tester.sol @@ -20,9 +20,9 @@ contract LSP8Tester is LSP8IdentifiableDigitalAsset, LSP8Burnable { function mint( address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes memory data ) public { - _mint(to, tokenId, allowNonLSP1Recipient, data); + _mint(to, tokenId, force, data); } } From 7b97ed9bef888d83a28aad00cc164f3046368349 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Tue, 19 Sep 2023 11:25:52 +0100 Subject: [PATCH 15/55] test: change back param name from `allowNonLSP1Recipient` to `force` --- .../Interactions/BatchExecute.test.ts | 2 +- .../LSP7CompatibleERC20.behaviour.ts | 84 ++++----- .../LSP7DigitalAsset.behaviour.ts | 162 ++++++++---------- .../LSP7Mintable.behaviour.ts | 2 +- .../LSP8CompatibleERC721.behaviour.ts | 34 +--- .../LSP8IdentifiableDigitalAsset.behaviour.ts | 151 +++++++--------- .../LSP8Mintable.behaviour.ts | 2 +- 7 files changed, 188 insertions(+), 249 deletions(-) diff --git a/tests/LSP6KeyManager/Interactions/BatchExecute.test.ts b/tests/LSP6KeyManager/Interactions/BatchExecute.test.ts index 336e5fe95..0e99eaa92 100644 --- a/tests/LSP6KeyManager/Interactions/BatchExecute.test.ts +++ b/tests/LSP6KeyManager/Interactions/BatchExecute.test.ts @@ -327,7 +327,7 @@ export const shouldBehaveLikeBatchExecute = ( [sender, sender, sender], // address[] memory from, recipients, // address[] memory to, amounts, // uint256[] memory amount, - [true, true, true], // bool[] memory allowNonLSP1Recipient, + [true, true, true], // bool[] memory force, ['0x', '0x', '0x'], // bytes[] memory data ]); diff --git a/tests/LSP7DigitalAsset/LSP7CompatibleERC20.behaviour.ts b/tests/LSP7DigitalAsset/LSP7CompatibleERC20.behaviour.ts index 49c673d57..831a6ad1e 100644 --- a/tests/LSP7DigitalAsset/LSP7CompatibleERC20.behaviour.ts +++ b/tests/LSP7DigitalAsset/LSP7CompatibleERC20.behaviour.ts @@ -422,7 +422,7 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( from: string; to: string; amount: BigNumber; - allowNonLSP1Recipient?: boolean; + force?: boolean; data?: string; }; @@ -450,7 +450,7 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( txParams.from, txParams.to, txParams.amount, - txParams.allowNonLSP1Recipient ?? true, + txParams.force ?? true, expectedData, ); @@ -810,13 +810,13 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( describe('when caller (msg.sender) is the `from` address', () => { describe('when `to` is an EOA', () => { - it('should allow transfering the tokens with `allowNonLSP1Recipient` param = true', async () => { + it('should allow transfering the tokens with `force` param = true', async () => { const txParams = { operator: context.accounts.owner, from: context.accounts.owner.address, to: context.accounts.tokenReceiver.address, amount: transferAmount, - allowNonLSP1Recipient: true, + force: true, data: expectedData, }; @@ -829,20 +829,20 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( txParams.from, txParams.to, txParams.amount, - txParams.allowNonLSP1Recipient, + txParams.force, txParams.data, ), expectedData, ); }); - it('should NOT allow transfering the tokens with `allowNonLSP1Recipient` param = false', async () => { + it('should NOT allow transfering the tokens with `force` param = false', async () => { const txParams = { operator: context.accounts.owner, from: context.accounts.owner.address, to: context.accounts.tokenReceiver.address, amount: transferAmount, - allowNonLSP1Recipient: false, + force: false, data: expectedData, }; @@ -856,7 +856,7 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( txParams.from, txParams.to, txParams.amount, - txParams.allowNonLSP1Recipient, + txParams.force, txParams.data, ), ) @@ -874,13 +874,13 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( describe('when `to` is a contract', () => { describe('when receiving contract supports LSP1', () => { - it('should allow transfering the tokens with `allowNonLSP1Recipient` param = true', async () => { + it('should allow transfering the tokens with `force` param = true', async () => { const txParams = { operator: context.accounts.owner, from: context.accounts.owner.address, to: deployedContracts.tokenReceiverWithLSP1.address, amount: transferAmount, - allowNonLSP1Recipient: true, + force: true, data: expectedData, }; @@ -893,20 +893,20 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( txParams.from, txParams.to, txParams.amount, - txParams.allowNonLSP1Recipient, + txParams.force, txParams.data, ), expectedData, ); }); - it('should allow transfering the tokens with `allowNonLSP1Recipient` param = false', async () => { + it('should allow transfering the tokens with `force` param = false', async () => { const txParams = { operator: context.accounts.owner, from: context.accounts.owner.address, to: deployedContracts.tokenReceiverWithLSP1.address, amount: transferAmount, - allowNonLSP1Recipient: false, + force: false, data: expectedData, }; @@ -919,7 +919,7 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( txParams.from, txParams.to, txParams.amount, - txParams.allowNonLSP1Recipient, + txParams.force, txParams.data, ), expectedData, @@ -928,13 +928,13 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( }); describe('when receiving contract does not support LSP1', () => { - it('should allow transfering the tokens with `allowNonLSP1Recipient` param = true', async () => { + it('should allow transfering the tokens with `force` param = true', async () => { const txParams = { operator: context.accounts.owner, from: context.accounts.owner.address, to: deployedContracts.tokenReceiverWithoutLSP1.address, amount: transferAmount, - allowNonLSP1Recipient: true, + force: true, data: expectedData, }; @@ -947,20 +947,20 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( txParams.from, txParams.to, txParams.amount, - txParams.allowNonLSP1Recipient, + txParams.force, txParams.data, ), expectedData, ); }); - it('should NOT allow transfering the tokens with `allowNonLSP1Recipient` param = false', async () => { + it('should NOT allow transfering the tokens with `force` param = false', async () => { const txParams = { operator: context.accounts.owner, from: context.accounts.owner.address, to: deployedContracts.tokenReceiverWithoutLSP1.address, amount: transferAmount, - allowNonLSP1Recipient: false, + force: false, data: expectedData, }; @@ -974,7 +974,7 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( txParams.from, txParams.to, txParams.amount, - txParams.allowNonLSP1Recipient, + txParams.force, txParams.data, ), ) @@ -994,13 +994,13 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( describe('when caller (msg.sender) is an operator (= Not the `from` address)', () => { describe('when `to` is an EOA', () => { - it('should allow transfering the tokens with `allowNonLSP1Recipient` param = true', async () => { + it('should allow transfering the tokens with `force` param = true', async () => { const txParams = { operator: context.accounts.operator, from: context.accounts.owner.address, to: context.accounts.tokenReceiver.address, amount: transferAmount, - allowNonLSP1Recipient: true, + force: true, data: expectedData, }; @@ -1013,20 +1013,20 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( txParams.from, txParams.to, txParams.amount, - txParams.allowNonLSP1Recipient, + txParams.force, txParams.data, ), expectedData, ); }); - it('should NOT allow transfering the tokens with `allowNonLSP1Recipient` param = false', async () => { + it('should NOT allow transfering the tokens with `force` param = false', async () => { const txParams = { operator: context.accounts.operator, from: context.accounts.owner.address, to: context.accounts.tokenReceiver.address, amount: transferAmount, - allowNonLSP1Recipient: false, + force: false, data: expectedData, }; @@ -1040,7 +1040,7 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( txParams.from, txParams.to, txParams.amount, - txParams.allowNonLSP1Recipient, + txParams.force, txParams.data, ), ) @@ -1058,13 +1058,13 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( describe('when `to` is a contract', () => { describe('when receiving contract supports LSP1', () => { - it('should allow transfering the tokens with `allowNonLSP1Recipient` param = true', async () => { + it('should allow transfering the tokens with `force` param = true', async () => { const txParams = { operator: context.accounts.operator, from: context.accounts.owner.address, to: deployedContracts.tokenReceiverWithLSP1.address, amount: transferAmount, - allowNonLSP1Recipient: true, + force: true, data: expectedData, }; @@ -1077,20 +1077,20 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( txParams.from, txParams.to, txParams.amount, - txParams.allowNonLSP1Recipient, + txParams.force, txParams.data, ), expectedData, ); }); - it('should allow transfering the tokens with `allowNonLSP1Recipient` param = false', async () => { + it('should allow transfering the tokens with `force` param = false', async () => { const txParams = { operator: context.accounts.operator, from: context.accounts.owner.address, to: deployedContracts.tokenReceiverWithLSP1.address, amount: transferAmount, - allowNonLSP1Recipient: false, + force: false, data: expectedData, }; @@ -1103,7 +1103,7 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( txParams.from, txParams.to, txParams.amount, - txParams.allowNonLSP1Recipient, + txParams.force, txParams.data, ), expectedData, @@ -1112,13 +1112,13 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( }); describe('when receiving contract does not support LSP1', () => { - it('should allow transfering the tokens with `allowNonLSP1Recipient` param = true', async () => { + it('should allow transfering the tokens with `force` param = true', async () => { const txParams = { operator: context.accounts.operator, from: context.accounts.owner.address, to: deployedContracts.tokenReceiverWithoutLSP1.address, amount: transferAmount, - allowNonLSP1Recipient: true, + force: true, data: expectedData, }; @@ -1131,20 +1131,20 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( txParams.from, txParams.to, txParams.amount, - txParams.allowNonLSP1Recipient, + txParams.force, txParams.data, ), expectedData, ); }); - it('should NOT allow transfering the tokens with `allowNonLSP1Recipient` param = false', async () => { + it('should NOT allow transfering the tokens with `force` param = false', async () => { const txParams = { operator: context.accounts.operator, from: context.accounts.owner.address, to: deployedContracts.tokenReceiverWithoutLSP1.address, amount: transferAmount, - allowNonLSP1Recipient: false, + force: false, data: expectedData, }; @@ -1158,7 +1158,7 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( txParams.from, txParams.to, txParams.amount, - txParams.allowNonLSP1Recipient, + txParams.force, txParams.data, ), ) @@ -1189,7 +1189,7 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( from: context.accounts.owner.address, to: deployedContracts.tokenReceiverWithoutLSP1.address, amount: ownerBalance.add(1), - allowNonLSP1Recipient: true, + force: true, data: expectedData, }; @@ -1203,7 +1203,7 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( txParams.from, txParams.to, txParams.amount, - txParams.allowNonLSP1Recipient, + txParams.force, txParams.data, ), ) @@ -1230,7 +1230,7 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( from: context.accounts.owner.address, to: deployedContracts.tokenReceiverWithoutLSP1.address, amount: ownerBalance.add(1), - allowNonLSP1Recipient: true, + force: true, data: expectedData, }; @@ -1244,7 +1244,7 @@ export const shouldBehaveLikeLSP7CompatibleERC20 = ( txParams.from, txParams.to, txParams.amount, - txParams.allowNonLSP1Recipient, + txParams.force, txParams.data, ), ) diff --git a/tests/LSP7DigitalAsset/LSP7DigitalAsset.behaviour.ts b/tests/LSP7DigitalAsset/LSP7DigitalAsset.behaviour.ts index e6f17645a..d965032e1 100644 --- a/tests/LSP7DigitalAsset/LSP7DigitalAsset.behaviour.ts +++ b/tests/LSP7DigitalAsset/LSP7DigitalAsset.behaviour.ts @@ -79,35 +79,35 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise { describe('when `amount == 0`', () => { - it('should revert if `allowNonLSP1Recipient == false`', async () => { + it('should revert if `force == false`', async () => { const txParams = { to: context.accounts.anotherTokenReceiver.address, amount: 0, - allowNonLSP1Recipient: false, + force: false, data: '0x', }; await expect( context.lsp7 .connect(context.accounts.anyone) - .mint(txParams.to, txParams.amount, txParams.allowNonLSP1Recipient, txParams.data), + .mint(txParams.to, txParams.amount, txParams.force, txParams.data), ) .to.be.revertedWithCustomError(context.lsp7, 'LSP7NotifyTokenReceiverIsEOA') .withArgs(txParams.to); }); - it('should pass if `allowNonLSP1Recipient == true`', async () => { + it('should pass if `force == true`', async () => { const txParams = { to: context.accounts.anotherTokenReceiver.address, amount: 0, - allowNonLSP1Recipient: true, + force: true, data: '0x', }; await expect( context.lsp7 .connect(context.accounts.anyone) - .mint(txParams.to, txParams.amount, txParams.allowNonLSP1Recipient, txParams.data), + .mint(txParams.to, txParams.amount, txParams.force, txParams.data), ) .to.emit(context.lsp7, 'Transfer') .withArgs( @@ -115,7 +115,7 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise Promise Promise Promise Promise { // pre-conditions @@ -846,12 +836,10 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise Promise { - const allowNonLSP1Recipient = true; + describe('when using force=true', () => { + const force = true; const data = ethers.utils.hexlify( - ethers.utils.toUtf8Bytes('doing a transfer with allowNonLSP1Recipient'), + ethers.utils.toUtf8Bytes('doing a transfer with force'), ); describe('when `to` is an EOA', () => { @@ -902,7 +890,7 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise Promise Promise Promise Promise Promise { - const allowNonLSP1Recipient = false; + describe('when force=false', () => { + const force = false; const data = ethers.utils.hexlify( - ethers.utils.toUtf8Bytes('doing a transfer without allowNonLSP1Recipient'), + ethers.utils.toUtf8Bytes('doing a transfer without force'), ); describe('when `to` is an EOA', () => { @@ -988,7 +976,7 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise Promise Promise Promise Promise Promise Promise Promise Promise Promise { - it('should revert with `allowNonLSP1Recipient == false`', async () => { + it('should revert with `force == false`', async () => { const caller = context.accounts.anyone; const txParams = { from: context.accounts.anyone.address, to: context.accounts.anotherTokenReceiver.address, amount: ethers.BigNumber.from(0), - allowNonLSP1Recipient: false, + force: false, data: '0x', }; @@ -1168,7 +1156,7 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise Promise { + it('should pass with `force == true`', async () => { const caller = context.accounts.anyone; const txParams = { from: context.accounts.anyone.address, to: context.accounts.anotherTokenReceiver.address, amount: ethers.BigNumber.from(0), - allowNonLSP1Recipient: true, + force: true, data: '0x', }; @@ -1198,7 +1186,7 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise Promise Promise Promise Promise { // pre-conditions @@ -1309,7 +1297,7 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise { @@ -1320,7 +1308,7 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise Promise { if (expectedError.args.length > 0) await expect( - context.lsp7 - .connect(operator) - .transferBatch(from, to, amount, allowNonLSP1Recipient, data), + context.lsp7.connect(operator).transferBatch(from, to, amount, force, data), ) .to.be.revertedWithCustomError(context.lsp7, expectedError.error) .withArgs(...expectedError.args); else await expect( - context.lsp7 - .connect(operator) - .transferBatch(from, to, amount, allowNonLSP1Recipient, data), + context.lsp7.connect(operator).transferBatch(from, to, amount, force, data), ).to.be.revertedWithCustomError(context.lsp7, expectedError.error); }; @@ -1388,9 +1372,9 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise { + describe('when force=true', () => { const data = ethers.utils.hexlify( - ethers.utils.toUtf8Bytes('doing a transfer with allowNonLSP1Recipient'), + ethers.utils.toUtf8Bytes('doing a transfer with force'), ); describe('when `to` is an EOA', () => { @@ -1400,7 +1384,7 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise Promise Promise Promise Promise { + describe('when force=false', () => { const data = ethers.utils.hexlify( - ethers.utils.toUtf8Bytes('doing a transfer without allowNonLSP1Recipient'), + ethers.utils.toUtf8Bytes('doing a transfer without force'), ); describe('when `to` is an EOA', () => { @@ -1501,7 +1485,7 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise Promise Promise Promise { + describe('when force is mixed(true/false) respectively', () => { const data = ethers.utils.hexlify( - ethers.utils.toUtf8Bytes('doing a transfer without allowNonLSP1Recipient'), + ethers.utils.toUtf8Bytes('doing a transfer without force'), ); describe('when `to` is an EOA', () => { @@ -1568,7 +1552,7 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise Promise Promise { - it('should pass regardless of allowNonLSP1Recipient params', async () => { + it('should pass regardless of force params', async () => { const txParams = { from: [context.accounts.owner.address, context.accounts.owner.address], to: [ @@ -1612,7 +1596,7 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise Promise Promise Promise Promise Promise { // pre-conditions @@ -749,14 +749,7 @@ export const shouldBehaveLikeLSP8CompatibleERC721 = ( context.lsp8CompatibleERC721, 'Transfer(address,address,address,bytes32,bool,bytes)', ) - .withArgs( - operator, - from, - to, - tokenIdAsBytes32(tokenId), - allowNonLSP1Recipient, - expectedData, - ); + .withArgs(operator, from, to, tokenIdAsBytes32(tokenId), force, expectedData); await expect(tx) .to.emit(context.lsp8CompatibleERC721, 'Transfer(address,address,uint256)') @@ -773,7 +766,7 @@ export const shouldBehaveLikeLSP8CompatibleERC721 = ( describe('transferFrom', () => { const transferFn = 'transferFrom'; - const allowNonLSP1Recipient = true; + const force = true; const expectedData = ethers.utils.hexlify(ethers.utils.toUtf8Bytes('')); describe('when the from address is the tokenId owner', () => { @@ -786,12 +779,7 @@ export const shouldBehaveLikeLSP8CompatibleERC721 = ( tokenId: mintedTokenId, }; - await transferSuccessScenario( - txParams, - transferFn, - allowNonLSP1Recipient, - expectedData, - ); + await transferSuccessScenario(txParams, transferFn, force, expectedData); }); }); @@ -805,12 +793,7 @@ export const shouldBehaveLikeLSP8CompatibleERC721 = ( tokenId: mintedTokenId, }; - await transferSuccessScenario( - txParams, - transferFn, - allowNonLSP1Recipient, - expectedData, - ); + await transferSuccessScenario(txParams, transferFn, force, expectedData); }); }); @@ -823,12 +806,7 @@ export const shouldBehaveLikeLSP8CompatibleERC721 = ( tokenId: mintedTokenId, }; - await transferSuccessScenario( - txParams, - transferFn, - allowNonLSP1Recipient, - expectedData, - ); + await transferSuccessScenario(txParams, transferFn, force, expectedData); }); }); }); diff --git a/tests/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.behaviour.ts b/tests/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.behaviour.ts index 05be3dd17..ecf3bb2f1 100644 --- a/tests/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.behaviour.ts +++ b/tests/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.behaviour.ts @@ -83,17 +83,12 @@ export const shouldBehaveLikeLSP8 = (buildContext: () => Promise Promise Promise Promise { // pre-conditions @@ -692,12 +677,10 @@ export const shouldBehaveLikeLSP8 = (buildContext: () => Promise Promise { - const allowNonLSP1Recipient = true; + describe('when using force=true', () => { + const force = true; const data = ethers.utils.hexlify( - ethers.utils.toUtf8Bytes('doing a transfer with allowNonLSP1Recipient'), + ethers.utils.toUtf8Bytes('doing a transfer with force'), ); describe('when `to` is an EOA', () => { @@ -750,7 +733,7 @@ export const shouldBehaveLikeLSP8 = (buildContext: () => Promise Promise Promise Promise Promise Promise Promise Promise { - const allowNonLSP1Recipient = false; + describe('when force=false', () => { + const force = false; const data = ethers.utils.hexlify( - ethers.utils.toUtf8Bytes('doing a transfer without allowNonLSP1Recipient'), + ethers.utils.toUtf8Bytes('doing a transfer without force'), ); describe('when `to` is an EOA', () => { @@ -860,7 +843,7 @@ export const shouldBehaveLikeLSP8 = (buildContext: () => Promise Promise Promise Promise Promise Promise Promise Promise Promise Promise Promise Promise Promise Promise { // pre-conditions @@ -1107,7 +1090,7 @@ export const shouldBehaveLikeLSP8 = (buildContext: () => Promise { @@ -1118,7 +1101,7 @@ export const shouldBehaveLikeLSP8 = (buildContext: () => Promise Promise { @@ -1164,18 +1147,12 @@ export const shouldBehaveLikeLSP8 = (buildContext: () => Promise 0) - await expect( - context.lsp8 - .connect(operator) - .transferBatch(from, to, tokenId, allowNonLSP1Recipient, data), - ) + await expect(context.lsp8.connect(operator).transferBatch(from, to, tokenId, force, data)) .to.be.revertedWithCustomError(context.lsp8, expectedError.error) .withArgs(...expectedError.args); else await expect( - context.lsp8 - .connect(operator) - .transferBatch(from, to, tokenId, allowNonLSP1Recipient, data), + context.lsp8.connect(operator).transferBatch(from, to, tokenId, force, data), ).to.be.revertedWithCustomError(context.lsp8, expectedError.error); }; @@ -1186,9 +1163,9 @@ export const shouldBehaveLikeLSP8 = (buildContext: () => Promise { + describe('when force=true', () => { const data = ethers.utils.hexlify( - ethers.utils.toUtf8Bytes('doing a transfer with allowNonLSP1Recipient'), + ethers.utils.toUtf8Bytes('doing a transfer with force'), ); describe('when `to` is an EOA', () => { @@ -1198,7 +1175,7 @@ export const shouldBehaveLikeLSP8 = (buildContext: () => Promise Promise Promise Promise Promise { + describe('when force=false', () => { const data = ethers.utils.hexlify( - ethers.utils.toUtf8Bytes('doing a transfer without allowNonLSP1Recipient'), + ethers.utils.toUtf8Bytes('doing a transfer without force'), ); describe('when `to` is an EOA', () => { @@ -1297,7 +1274,7 @@ export const shouldBehaveLikeLSP8 = (buildContext: () => Promise Promise Promise Promise { + describe('when force is mixed(true/false) respectively', () => { const data = ethers.utils.hexlify( - ethers.utils.toUtf8Bytes('doing a transfer without allowNonLSP1Recipient'), + ethers.utils.toUtf8Bytes('doing a transfer without force'), ); describe('when `to` is an EOA', () => { @@ -1364,7 +1341,7 @@ export const shouldBehaveLikeLSP8 = (buildContext: () => Promise Promise Promise { - it('should pass regardless of allowNonLSP1Recipient params', async () => { + it('should pass regardless of force params', async () => { const txParams = { from: [context.accounts.owner.address, context.accounts.owner.address], to: [ @@ -1408,7 +1385,7 @@ export const shouldBehaveLikeLSP8 = (buildContext: () => Promise Promise Promise Promise Promise Date: Tue, 19 Sep 2023 11:28:35 +0100 Subject: [PATCH 16/55] docs: regenerate `.md` docs with param `force` --- .../LSP7DigitalAsset/LSP7DigitalAsset.md | 92 +++++++-------- .../extensions/LSP7Burnable.md | 92 +++++++-------- .../extensions/LSP7CappedSupply.md | 80 ++++++------- .../extensions/LSP7CompatibleERC20.md | 66 +++++------ .../presets/LSP7CompatibleERC20Mintable.md | 80 ++++++------- .../LSP7DigitalAsset/presets/LSP7Mintable.md | 106 +++++++++--------- .../LSP8IdentifiableDigitalAsset.md | 76 ++++++------- .../extensions/LSP8Burnable.md | 76 ++++++------- .../extensions/LSP8CappedSupply.md | 64 +++++------ .../extensions/LSP8CompatibleERC721.md | 56 ++++----- .../extensions/LSP8Enumerable.md | 76 ++++++------- .../presets/LSP8CompatibleERC721Mintable.md | 72 ++++++------ .../presets/LSP8Mintable.md | 92 +++++++-------- 13 files changed, 514 insertions(+), 514 deletions(-) diff --git a/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md b/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md index 6f2fc0e21..be60e15ab 100644 --- a/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md +++ b/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md @@ -643,7 +643,7 @@ function transfer( address from, address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes data ) external nonpayable; ``` @@ -652,13 +652,13 @@ Transfers an `amount` of tokens from the `from` address to the `to` address and #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | The sender address. | -| `to` | `address` | The recipient address. | -| `amount` | `uint256` | The amount of tokens to transfer. | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | -| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. | +| Name | Type | Description | +| -------- | :-------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The sender address. | +| `to` | `address` | The recipient address. | +| `amount` | `uint256` | The amount of tokens to transfer. | +| `force` | `bool` | When set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | +| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. |
@@ -678,7 +678,7 @@ function transferBatch( address[] from, address[] to, uint256[] amount, - bool[] allowNonLSP1Recipient, + bool[] force, bytes[] data ) external nonpayable; ``` @@ -687,13 +687,13 @@ Same as [`transfer(...)`](#`transfer) but transfer multiple tokens based on the #### Parameters -| Name | Type | Description | -| ----------------------- | :---------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address[]` | An array of sending addresses. | -| `to` | `address[]` | An array of receiving addresses. | -| `amount` | `uint256[]` | An array of amount of tokens to transfer for each `from -> to` transfer. | -| `allowNonLSP1Recipient` | `bool[]` | For each transfer, when set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | -| `data` | `bytes[]` | An array of additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. | +| Name | Type | Description | +| -------- | :---------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address[]` | An array of sending addresses. | +| `to` | `address[]` | An array of receiving addresses. | +| `amount` | `uint256[]` | An array of amount of tokens to transfer for each `from -> to` transfer. | +| `force` | `bool[]` | For each transfer, when set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | +| `data` | `bytes[]` | An array of additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. |
@@ -809,7 +809,7 @@ If the amount is zero then the operator is being revoked, otherwise the operator function _mint( address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -826,12 +826,12 @@ Mints `amount` of tokens and transfers it to `to`. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ------------------------------------------------------------------------------------------------------------------------- | -| `to` | `address` | the address to mint tokens for. | -| `amount` | `uint256` | the amount of tokens to mint. | -| `allowNonLSP1Recipient` | `bool` | a boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | -| `data` | `bytes` | Additional data the caller wants included in the emitted {Transfer} event, and sent in the LSP1 hook to the `to` address. | +| Name | Type | Description | +| -------- | :-------: | ------------------------------------------------------------------------------------------------------------------------- | +| `to` | `address` | The address to mint tokens for. | +| `amount` | `uint256` | The amount of tokens to mint. | +| `force` | `bool` | A boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | +| `data` | `bytes` | Additional data the caller wants included in the emitted {Transfer} event, and sent in the LSP1 hook to the `to` address. |
@@ -865,8 +865,8 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r | Name | Type | Description | | -------- | :-------: | ------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | the address to burn tokens from its balance. | -| `amount` | `uint256` | the amount of tokens to burn. | +| `from` | `address` | The address to burn tokens from its balance. | +| `amount` | `uint256` | The amount of tokens to burn. | | `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the LSP1 hook to the `from` and `to` address. |
@@ -878,7 +878,7 @@ function _transfer( address from, address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -900,13 +900,13 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | the address to decrease the balance. | -| `to` | `address` | the address to increase the balance. | -| `amount` | `uint256` | the amount of tokens to transfer from `from` to `to`. | -| `allowNonLSP1Recipient` | `bool` | a boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | -| `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the LSP1 hook to the `from` and `to` address. | +| Name | Type | Description | +| -------- | :-------: | ------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The address to decrease the balance. | +| `to` | `address` | The address to increase the balance. | +| `amount` | `uint256` | The amount of tokens to transfer from `from` to `to`. | +| `force` | `bool` | A boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | +| `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the LSP1 hook to the `from` and `to` address. |
@@ -979,26 +979,26 @@ If `from` is an EOA or a contract that does not support the LSP1 interface, noth ```solidity function _notifyTokenReceiver( address to, - bool allowNonLSP1Recipient, + bool force, bytes lsp1Data ) internal nonpayable; ``` Attempt to notify the token receiver `to` about the `amount` tokens being received. This is done by calling its [`universalReceiver`](#universalreceiver) function with the `_TYPEID_LSP7_TOKENSRECIPIENT` as typeId, if `to` is a contract that supports the LSP1 interface. -If `to` is is an EOA or a contract that does not support the LSP1 interface, the behaviour will depend on the `allowNonLSP1Recipient` boolean flag. +If `to` is is an EOA or a contract that does not support the LSP1 interface, the behaviour will depend on the `force` boolean flag. -- if `allowNonLSP1Recipient` is set to `true`, nothing will happen and no notification will be sent. +- if `force` is set to `true`, nothing will happen and no notification will be sent. -- if `allowNonLSP1Recipient` is set to `false, the transaction will revert. +- if `force` is set to `false, the transaction will revert. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | --------------------------------------------------------------------------------------------------- | -| `to` | `address` | The address to call the {universalReceiver} function on. | -| `allowNonLSP1Recipient` | `bool` | a boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | -| `lsp1Data` | `bytes` | the data to be sent to the `to` address in the `universalReceiver(...)` call. | +| Name | Type | Description | +| ---------- | :-------: | --------------------------------------------------------------------------------------------------- | +| `to` | `address` | The address to call the {universalReceiver} function on. | +| `force` | `bool` | A boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | +| `lsp1Data` | `bytes` | The data to be sent to the `to` address in the `universalReceiver(...)` call. |
@@ -1174,7 +1174,7 @@ Emitted when `tokenOwner` disables `operator` for `amount` tokens and set its [` ::: ```solidity -event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool allowNonLSP1Recipient, bytes data); +event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool force, bytes data); ``` Emitted when the `from` transferred successfully `amount` of tokens to `to`. @@ -1187,7 +1187,7 @@ Emitted when the `from` transferred successfully `amount` of tokens to `to`. | `from` **`indexed`** | `address` | The address which tokens were sent from (balance decreased by `-amount`). | | `to` **`indexed`** | `address` | The address that received the tokens (balance increased by `+amount`). | | `amount` | `uint256` | The amount of tokens transferred. | -| `allowNonLSP1Recipient` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `force` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | | `data` | `bytes` | Any additional data included by the caller during the transfer, and sent in the LSP1 hooks to the `from` and `to` addresses. |
@@ -1521,7 +1521,7 @@ error LSP7NotifyTokenReceiverContractMissingLSP1Interface( ); ``` -reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1546,7 +1546,7 @@ reverts if the `tokenReceiver` does not implement LSP1 when minting or transferr error LSP7NotifyTokenReceiverIsEOA(address tokenReceiver); ``` -reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. #### Parameters diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md index cbd5d9599..4b9ae506f 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md @@ -668,7 +668,7 @@ function transfer( address from, address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes data ) external nonpayable; ``` @@ -677,13 +677,13 @@ Transfers an `amount` of tokens from the `from` address to the `to` address and #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | The sender address. | -| `to` | `address` | The recipient address. | -| `amount` | `uint256` | The amount of tokens to transfer. | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | -| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. | +| Name | Type | Description | +| -------- | :-------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The sender address. | +| `to` | `address` | The recipient address. | +| `amount` | `uint256` | The amount of tokens to transfer. | +| `force` | `bool` | When set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | +| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. |
@@ -703,7 +703,7 @@ function transferBatch( address[] from, address[] to, uint256[] amount, - bool[] allowNonLSP1Recipient, + bool[] force, bytes[] data ) external nonpayable; ``` @@ -712,13 +712,13 @@ Same as [`transfer(...)`](#`transfer) but transfer multiple tokens based on the #### Parameters -| Name | Type | Description | -| ----------------------- | :---------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address[]` | An array of sending addresses. | -| `to` | `address[]` | An array of receiving addresses. | -| `amount` | `uint256[]` | An array of amount of tokens to transfer for each `from -> to` transfer. | -| `allowNonLSP1Recipient` | `bool[]` | For each transfer, when set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | -| `data` | `bytes[]` | An array of additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. | +| Name | Type | Description | +| -------- | :---------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address[]` | An array of sending addresses. | +| `to` | `address[]` | An array of receiving addresses. | +| `amount` | `uint256[]` | An array of amount of tokens to transfer for each `from -> to` transfer. | +| `force` | `bool[]` | For each transfer, when set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | +| `data` | `bytes[]` | An array of additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. |
@@ -834,7 +834,7 @@ If the amount is zero then the operator is being revoked, otherwise the operator function _mint( address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -851,12 +851,12 @@ Mints `amount` of tokens and transfers it to `to`. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ------------------------------------------------------------------------------------------------------------------------- | -| `to` | `address` | the address to mint tokens for. | -| `amount` | `uint256` | the amount of tokens to mint. | -| `allowNonLSP1Recipient` | `bool` | a boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | -| `data` | `bytes` | Additional data the caller wants included in the emitted {Transfer} event, and sent in the LSP1 hook to the `to` address. | +| Name | Type | Description | +| -------- | :-------: | ------------------------------------------------------------------------------------------------------------------------- | +| `to` | `address` | The address to mint tokens for. | +| `amount` | `uint256` | The amount of tokens to mint. | +| `force` | `bool` | A boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | +| `data` | `bytes` | Additional data the caller wants included in the emitted {Transfer} event, and sent in the LSP1 hook to the `to` address. |
@@ -890,8 +890,8 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r | Name | Type | Description | | -------- | :-------: | ------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | the address to burn tokens from its balance. | -| `amount` | `uint256` | the amount of tokens to burn. | +| `from` | `address` | The address to burn tokens from its balance. | +| `amount` | `uint256` | The amount of tokens to burn. | | `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the LSP1 hook to the `from` and `to` address. |
@@ -903,7 +903,7 @@ function _transfer( address from, address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -925,13 +925,13 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | the address to decrease the balance. | -| `to` | `address` | the address to increase the balance. | -| `amount` | `uint256` | the amount of tokens to transfer from `from` to `to`. | -| `allowNonLSP1Recipient` | `bool` | a boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | -| `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the LSP1 hook to the `from` and `to` address. | +| Name | Type | Description | +| -------- | :-------: | ------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The address to decrease the balance. | +| `to` | `address` | The address to increase the balance. | +| `amount` | `uint256` | The amount of tokens to transfer from `from` to `to`. | +| `force` | `bool` | A boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | +| `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the LSP1 hook to the `from` and `to` address. |
@@ -1004,26 +1004,26 @@ If `from` is an EOA or a contract that does not support the LSP1 interface, noth ```solidity function _notifyTokenReceiver( address to, - bool allowNonLSP1Recipient, + bool force, bytes lsp1Data ) internal nonpayable; ``` Attempt to notify the token receiver `to` about the `amount` tokens being received. This is done by calling its [`universalReceiver`](#universalreceiver) function with the `_TYPEID_LSP7_TOKENSRECIPIENT` as typeId, if `to` is a contract that supports the LSP1 interface. -If `to` is is an EOA or a contract that does not support the LSP1 interface, the behaviour will depend on the `allowNonLSP1Recipient` boolean flag. +If `to` is is an EOA or a contract that does not support the LSP1 interface, the behaviour will depend on the `force` boolean flag. -- if `allowNonLSP1Recipient` is set to `true`, nothing will happen and no notification will be sent. +- if `force` is set to `true`, nothing will happen and no notification will be sent. -- if `allowNonLSP1Recipient` is set to `false, the transaction will revert. +- if `force` is set to `false, the transaction will revert. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | --------------------------------------------------------------------------------------------------- | -| `to` | `address` | The address to call the {universalReceiver} function on. | -| `allowNonLSP1Recipient` | `bool` | a boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | -| `lsp1Data` | `bytes` | the data to be sent to the `to` address in the `universalReceiver(...)` call. | +| Name | Type | Description | +| ---------- | :-------: | --------------------------------------------------------------------------------------------------- | +| `to` | `address` | The address to call the {universalReceiver} function on. | +| `force` | `bool` | A boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | +| `lsp1Data` | `bytes` | The data to be sent to the `to` address in the `universalReceiver(...)` call. |
@@ -1199,7 +1199,7 @@ Emitted when `tokenOwner` disables `operator` for `amount` tokens and set its [` ::: ```solidity -event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool allowNonLSP1Recipient, bytes data); +event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool force, bytes data); ``` Emitted when the `from` transferred successfully `amount` of tokens to `to`. @@ -1212,7 +1212,7 @@ Emitted when the `from` transferred successfully `amount` of tokens to `to`. | `from` **`indexed`** | `address` | The address which tokens were sent from (balance decreased by `-amount`). | | `to` **`indexed`** | `address` | The address that received the tokens (balance increased by `+amount`). | | `amount` | `uint256` | The amount of tokens transferred. | -| `allowNonLSP1Recipient` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `force` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | | `data` | `bytes` | Any additional data included by the caller during the transfer, and sent in the LSP1 hooks to the `from` and `to` addresses. |
@@ -1546,7 +1546,7 @@ error LSP7NotifyTokenReceiverContractMissingLSP1Interface( ); ``` -reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1571,7 +1571,7 @@ reverts if the `tokenReceiver` does not implement LSP1 when minting or transferr error LSP7NotifyTokenReceiverIsEOA(address tokenReceiver); ``` -reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. #### Parameters diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md index a1304e5e2..79ecb62fb 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md @@ -668,7 +668,7 @@ function transfer( address from, address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes data ) external nonpayable; ``` @@ -677,13 +677,13 @@ Transfers an `amount` of tokens from the `from` address to the `to` address and #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | The sender address. | -| `to` | `address` | The recipient address. | -| `amount` | `uint256` | The amount of tokens to transfer. | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | -| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. | +| Name | Type | Description | +| -------- | :-------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The sender address. | +| `to` | `address` | The recipient address. | +| `amount` | `uint256` | The amount of tokens to transfer. | +| `force` | `bool` | When set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | +| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. |
@@ -703,7 +703,7 @@ function transferBatch( address[] from, address[] to, uint256[] amount, - bool[] allowNonLSP1Recipient, + bool[] force, bytes[] data ) external nonpayable; ``` @@ -712,13 +712,13 @@ Same as [`transfer(...)`](#`transfer) but transfer multiple tokens based on the #### Parameters -| Name | Type | Description | -| ----------------------- | :---------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address[]` | An array of sending addresses. | -| `to` | `address[]` | An array of receiving addresses. | -| `amount` | `uint256[]` | An array of amount of tokens to transfer for each `from -> to` transfer. | -| `allowNonLSP1Recipient` | `bool[]` | For each transfer, when set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | -| `data` | `bytes[]` | An array of additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. | +| Name | Type | Description | +| -------- | :---------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address[]` | An array of sending addresses. | +| `to` | `address[]` | An array of receiving addresses. | +| `amount` | `uint256[]` | An array of amount of tokens to transfer for each `from -> to` transfer. | +| `force` | `bool[]` | For each transfer, when set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | +| `data` | `bytes[]` | An array of additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. |
@@ -834,7 +834,7 @@ If the amount is zero then the operator is being revoked, otherwise the operator function _mint( address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -874,8 +874,8 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r | Name | Type | Description | | -------- | :-------: | ------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | the address to burn tokens from its balance. | -| `amount` | `uint256` | the amount of tokens to burn. | +| `from` | `address` | The address to burn tokens from its balance. | +| `amount` | `uint256` | The amount of tokens to burn. | | `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the LSP1 hook to the `from` and `to` address. |
@@ -887,7 +887,7 @@ function _transfer( address from, address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -909,13 +909,13 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | the address to decrease the balance. | -| `to` | `address` | the address to increase the balance. | -| `amount` | `uint256` | the amount of tokens to transfer from `from` to `to`. | -| `allowNonLSP1Recipient` | `bool` | a boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | -| `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the LSP1 hook to the `from` and `to` address. | +| Name | Type | Description | +| -------- | :-------: | ------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The address to decrease the balance. | +| `to` | `address` | The address to increase the balance. | +| `amount` | `uint256` | The amount of tokens to transfer from `from` to `to`. | +| `force` | `bool` | A boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | +| `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the LSP1 hook to the `from` and `to` address. |
@@ -988,26 +988,26 @@ If `from` is an EOA or a contract that does not support the LSP1 interface, noth ```solidity function _notifyTokenReceiver( address to, - bool allowNonLSP1Recipient, + bool force, bytes lsp1Data ) internal nonpayable; ``` Attempt to notify the token receiver `to` about the `amount` tokens being received. This is done by calling its [`universalReceiver`](#universalreceiver) function with the `_TYPEID_LSP7_TOKENSRECIPIENT` as typeId, if `to` is a contract that supports the LSP1 interface. -If `to` is is an EOA or a contract that does not support the LSP1 interface, the behaviour will depend on the `allowNonLSP1Recipient` boolean flag. +If `to` is is an EOA or a contract that does not support the LSP1 interface, the behaviour will depend on the `force` boolean flag. -- if `allowNonLSP1Recipient` is set to `true`, nothing will happen and no notification will be sent. +- if `force` is set to `true`, nothing will happen and no notification will be sent. -- if `allowNonLSP1Recipient` is set to `false, the transaction will revert. +- if `force` is set to `false, the transaction will revert. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | --------------------------------------------------------------------------------------------------- | -| `to` | `address` | The address to call the {universalReceiver} function on. | -| `allowNonLSP1Recipient` | `bool` | a boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | -| `lsp1Data` | `bytes` | the data to be sent to the `to` address in the `universalReceiver(...)` call. | +| Name | Type | Description | +| ---------- | :-------: | --------------------------------------------------------------------------------------------------- | +| `to` | `address` | The address to call the {universalReceiver} function on. | +| `force` | `bool` | A boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | +| `lsp1Data` | `bytes` | The data to be sent to the `to` address in the `universalReceiver(...)` call. |
@@ -1183,7 +1183,7 @@ Emitted when `tokenOwner` disables `operator` for `amount` tokens and set its [` ::: ```solidity -event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool allowNonLSP1Recipient, bytes data); +event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool force, bytes data); ``` Emitted when the `from` transferred successfully `amount` of tokens to `to`. @@ -1196,7 +1196,7 @@ Emitted when the `from` transferred successfully `amount` of tokens to `to`. | `from` **`indexed`** | `address` | The address which tokens were sent from (balance decreased by `-amount`). | | `to` **`indexed`** | `address` | The address that received the tokens (balance increased by `+amount`). | | `amount` | `uint256` | The amount of tokens transferred. | -| `allowNonLSP1Recipient` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `force` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | | `data` | `bytes` | Any additional data included by the caller during the transfer, and sent in the LSP1 hooks to the `from` and `to` addresses. |
@@ -1572,7 +1572,7 @@ error LSP7NotifyTokenReceiverContractMissingLSP1Interface( ); ``` -reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1597,7 +1597,7 @@ reverts if the `tokenReceiver` does not implement LSP1 when minting or transferr error LSP7NotifyTokenReceiverIsEOA(address tokenReceiver); ``` -reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. #### Parameters diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md index bff5340d0..5add8d3b5 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md @@ -757,7 +757,7 @@ function transfer( address from, address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes data ) external nonpayable; ``` @@ -766,13 +766,13 @@ Transfers an `amount` of tokens from the `from` address to the `to` address and #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | The sender address. | -| `to` | `address` | The recipient address. | -| `amount` | `uint256` | The amount of tokens to transfer. | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | -| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. | +| Name | Type | Description | +| -------- | :-------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The sender address. | +| `to` | `address` | The recipient address. | +| `amount` | `uint256` | The amount of tokens to transfer. | +| `force` | `bool` | When set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | +| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. |
@@ -789,7 +789,7 @@ Transfers an `amount` of tokens from the `from` address to the `to` address and :::info -This function uses the `allowNonLSP1Recipient` parameter as `true` so that EOA and any contract can receive tokens. +This function uses the `force` parameter as `true` so that EOA and any contract can receive tokens. ::: @@ -831,7 +831,7 @@ function transferBatch( address[] from, address[] to, uint256[] amount, - bool[] allowNonLSP1Recipient, + bool[] force, bytes[] data ) external nonpayable; ``` @@ -840,13 +840,13 @@ Same as [`transfer(...)`](#`transfer) but transfer multiple tokens based on the #### Parameters -| Name | Type | Description | -| ----------------------- | :---------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address[]` | An array of sending addresses. | -| `to` | `address[]` | An array of receiving addresses. | -| `amount` | `uint256[]` | An array of amount of tokens to transfer for each `from -> to` transfer. | -| `allowNonLSP1Recipient` | `bool[]` | For each transfer, when set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | -| `data` | `bytes[]` | An array of additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. | +| Name | Type | Description | +| -------- | :---------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address[]` | An array of sending addresses. | +| `to` | `address[]` | An array of receiving addresses. | +| `amount` | `uint256[]` | An array of amount of tokens to transfer for each `from -> to` transfer. | +| `force` | `bool[]` | For each transfer, when set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | +| `data` | `bytes[]` | An array of additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. |
@@ -863,7 +863,7 @@ Same as [`transfer(...)`](#`transfer) but transfer multiple tokens based on the :::info -This function uses the `allowNonLSP1Recipient` parameter as `true` so that EOA and any contract can receive tokens. +This function uses the `force` parameter as `true` so that EOA and any contract can receive tokens. ::: @@ -997,7 +997,7 @@ function _updateOperator( function _mint( address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -1019,7 +1019,7 @@ function _transfer( address from, address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -1095,26 +1095,26 @@ If `from` is an EOA or a contract that does not support the LSP1 interface, noth ```solidity function _notifyTokenReceiver( address to, - bool allowNonLSP1Recipient, + bool force, bytes lsp1Data ) internal nonpayable; ``` Attempt to notify the token receiver `to` about the `amount` tokens being received. This is done by calling its [`universalReceiver`](#universalreceiver) function with the `_TYPEID_LSP7_TOKENSRECIPIENT` as typeId, if `to` is a contract that supports the LSP1 interface. -If `to` is is an EOA or a contract that does not support the LSP1 interface, the behaviour will depend on the `allowNonLSP1Recipient` boolean flag. +If `to` is is an EOA or a contract that does not support the LSP1 interface, the behaviour will depend on the `force` boolean flag. -- if `allowNonLSP1Recipient` is set to `true`, nothing will happen and no notification will be sent. +- if `force` is set to `true`, nothing will happen and no notification will be sent. -- if `allowNonLSP1Recipient` is set to `false, the transaction will revert. +- if `force` is set to `false, the transaction will revert. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | --------------------------------------------------------------------------------------------------- | -| `to` | `address` | The address to call the {universalReceiver} function on. | -| `allowNonLSP1Recipient` | `bool` | a boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | -| `lsp1Data` | `bytes` | the data to be sent to the `to` address in the `universalReceiver(...)` call. | +| Name | Type | Description | +| ---------- | :-------: | --------------------------------------------------------------------------------------------------- | +| `to` | `address` | The address to call the {universalReceiver} function on. | +| `force` | `bool` | A boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | +| `lsp1Data` | `bytes` | The data to be sent to the `to` address in the `universalReceiver(...)` call. |
@@ -1344,7 +1344,7 @@ Emitted when `value` tokens are moved from one account (`from`) to another (`to` ::: ```solidity -event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool allowNonLSP1Recipient, bytes data); +event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool force, bytes data); ``` Emitted when the `from` transferred successfully `amount` of tokens to `to`. @@ -1357,7 +1357,7 @@ Emitted when the `from` transferred successfully `amount` of tokens to `to`. | `from` **`indexed`** | `address` | The address which tokens were sent from (balance decreased by `-amount`). | | `to` **`indexed`** | `address` | The address that received the tokens (balance increased by `+amount`). | | `amount` | `uint256` | The amount of tokens transferred. | -| `allowNonLSP1Recipient` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `force` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | | `data` | `bytes` | Any additional data included by the caller during the transfer, and sent in the LSP1 hooks to the `from` and `to` addresses. |
@@ -1691,7 +1691,7 @@ error LSP7NotifyTokenReceiverContractMissingLSP1Interface( ); ``` -reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1716,7 +1716,7 @@ reverts if the `tokenReceiver` does not implement LSP1 when minting or transferr error LSP7NotifyTokenReceiverIsEOA(address tokenReceiver); ``` -reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. #### Parameters diff --git a/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md b/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md index b854b5904..052cc44df 100644 --- a/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md +++ b/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md @@ -482,7 +482,7 @@ Atomically increases the allowance granted to `operator` by the caller. This is function mint( address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes data ) external nonpayable; ``` @@ -491,12 +491,12 @@ Public [`_mint`](#_mint) function only callable by the [`owner`](#owner). #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ----------- | -| `to` | `address` | - | -| `amount` | `uint256` | - | -| `allowNonLSP1Recipient` | `bool` | - | -| `data` | `bytes` | - | +| Name | Type | Description | +| -------- | :-------: | ----------- | +| `to` | `address` | - | +| `amount` | `uint256` | - | +| `force` | `bool` | - | +| `data` | `bytes` | - |
@@ -795,7 +795,7 @@ function transfer( address from, address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes data ) external nonpayable; ``` @@ -804,13 +804,13 @@ Transfers an `amount` of tokens from the `from` address to the `to` address and #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | The sender address. | -| `to` | `address` | The recipient address. | -| `amount` | `uint256` | The amount of tokens to transfer. | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | -| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. | +| Name | Type | Description | +| -------- | :-------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The sender address. | +| `to` | `address` | The recipient address. | +| `amount` | `uint256` | The amount of tokens to transfer. | +| `force` | `bool` | When set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | +| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. |
@@ -827,7 +827,7 @@ Transfers an `amount` of tokens from the `from` address to the `to` address and :::info -This function uses the `allowNonLSP1Recipient` parameter as `true` so that EOA and any contract can receive tokens. +This function uses the `force` parameter as `true` so that EOA and any contract can receive tokens. ::: @@ -869,7 +869,7 @@ function transferBatch( address[] from, address[] to, uint256[] amount, - bool[] allowNonLSP1Recipient, + bool[] force, bytes[] data ) external nonpayable; ``` @@ -878,13 +878,13 @@ Same as [`transfer(...)`](#`transfer) but transfer multiple tokens based on the #### Parameters -| Name | Type | Description | -| ----------------------- | :---------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address[]` | An array of sending addresses. | -| `to` | `address[]` | An array of receiving addresses. | -| `amount` | `uint256[]` | An array of amount of tokens to transfer for each `from -> to` transfer. | -| `allowNonLSP1Recipient` | `bool[]` | For each transfer, when set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | -| `data` | `bytes[]` | An array of additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. | +| Name | Type | Description | +| -------- | :---------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address[]` | An array of sending addresses. | +| `to` | `address[]` | An array of receiving addresses. | +| `amount` | `uint256[]` | An array of amount of tokens to transfer for each `from -> to` transfer. | +| `force` | `bool[]` | For each transfer, when set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | +| `data` | `bytes[]` | An array of additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. |
@@ -901,7 +901,7 @@ Same as [`transfer(...)`](#`transfer) but transfer multiple tokens based on the :::info -This function uses the `allowNonLSP1Recipient` parameter as `true` so that EOA and any contract can receive tokens. +This function uses the `force` parameter as `true` so that EOA and any contract can receive tokens. ::: @@ -1035,7 +1035,7 @@ function _updateOperator( function _mint( address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -1057,7 +1057,7 @@ function _transfer( address from, address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -1133,26 +1133,26 @@ If `from` is an EOA or a contract that does not support the LSP1 interface, noth ```solidity function _notifyTokenReceiver( address to, - bool allowNonLSP1Recipient, + bool force, bytes lsp1Data ) internal nonpayable; ``` Attempt to notify the token receiver `to` about the `amount` tokens being received. This is done by calling its [`universalReceiver`](#universalreceiver) function with the `_TYPEID_LSP7_TOKENSRECIPIENT` as typeId, if `to` is a contract that supports the LSP1 interface. -If `to` is is an EOA or a contract that does not support the LSP1 interface, the behaviour will depend on the `allowNonLSP1Recipient` boolean flag. +If `to` is is an EOA or a contract that does not support the LSP1 interface, the behaviour will depend on the `force` boolean flag. -- if `allowNonLSP1Recipient` is set to `true`, nothing will happen and no notification will be sent. +- if `force` is set to `true`, nothing will happen and no notification will be sent. -- if `allowNonLSP1Recipient` is set to `false, the transaction will revert. +- if `force` is set to `false, the transaction will revert. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | --------------------------------------------------------------------------------------------------- | -| `to` | `address` | The address to call the {universalReceiver} function on. | -| `allowNonLSP1Recipient` | `bool` | a boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | -| `lsp1Data` | `bytes` | the data to be sent to the `to` address in the `universalReceiver(...)` call. | +| Name | Type | Description | +| ---------- | :-------: | --------------------------------------------------------------------------------------------------- | +| `to` | `address` | The address to call the {universalReceiver} function on. | +| `force` | `bool` | A boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | +| `lsp1Data` | `bytes` | The data to be sent to the `to` address in the `universalReceiver(...)` call. |
@@ -1382,7 +1382,7 @@ Emitted when `value` tokens are moved from one account (`from`) to another (`to` ::: ```solidity -event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool allowNonLSP1Recipient, bytes data); +event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool force, bytes data); ``` Emitted when the `from` transferred successfully `amount` of tokens to `to`. @@ -1395,7 +1395,7 @@ Emitted when the `from` transferred successfully `amount` of tokens to `to`. | `from` **`indexed`** | `address` | The address which tokens were sent from (balance decreased by `-amount`). | | `to` **`indexed`** | `address` | The address that received the tokens (balance increased by `+amount`). | | `amount` | `uint256` | The amount of tokens transferred. | -| `allowNonLSP1Recipient` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `force` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | | `data` | `bytes` | Any additional data included by the caller during the transfer, and sent in the LSP1 hooks to the `from` and `to` addresses. |
@@ -1729,7 +1729,7 @@ error LSP7NotifyTokenReceiverContractMissingLSP1Interface( ); ``` -reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1754,7 +1754,7 @@ reverts if the `tokenReceiver` does not implement LSP1 when minting or transferr error LSP7NotifyTokenReceiverIsEOA(address tokenReceiver); ``` -reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. #### Parameters diff --git a/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md b/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md index e3ee21c6a..7be6c980c 100644 --- a/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md +++ b/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md @@ -442,7 +442,7 @@ Atomically increases the allowance granted to `operator` by the caller. This is function mint( address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes data ) external nonpayable; ``` @@ -451,12 +451,12 @@ Public [`_mint`](#_mint) function only callable by the [`owner`](#owner). #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ----------- | -| `to` | `address` | - | -| `amount` | `uint256` | - | -| `allowNonLSP1Recipient` | `bool` | - | -| `data` | `bytes` | - | +| Name | Type | Description | +| -------- | :-------: | ----------- | +| `to` | `address` | - | +| `amount` | `uint256` | - | +| `force` | `bool` | - | +| `data` | `bytes` | - |
@@ -705,7 +705,7 @@ function transfer( address from, address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes data ) external nonpayable; ``` @@ -714,13 +714,13 @@ Transfers an `amount` of tokens from the `from` address to the `to` address and #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | The sender address. | -| `to` | `address` | The recipient address. | -| `amount` | `uint256` | The amount of tokens to transfer. | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | -| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. | +| Name | Type | Description | +| -------- | :-------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The sender address. | +| `to` | `address` | The recipient address. | +| `amount` | `uint256` | The amount of tokens to transfer. | +| `force` | `bool` | When set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | +| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. |
@@ -740,7 +740,7 @@ function transferBatch( address[] from, address[] to, uint256[] amount, - bool[] allowNonLSP1Recipient, + bool[] force, bytes[] data ) external nonpayable; ``` @@ -749,13 +749,13 @@ Same as [`transfer(...)`](#`transfer) but transfer multiple tokens based on the #### Parameters -| Name | Type | Description | -| ----------------------- | :---------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address[]` | An array of sending addresses. | -| `to` | `address[]` | An array of receiving addresses. | -| `amount` | `uint256[]` | An array of amount of tokens to transfer for each `from -> to` transfer. | -| `allowNonLSP1Recipient` | `bool[]` | For each transfer, when set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | -| `data` | `bytes[]` | An array of additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. | +| Name | Type | Description | +| -------- | :---------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address[]` | An array of sending addresses. | +| `to` | `address[]` | An array of receiving addresses. | +| `amount` | `uint256[]` | An array of amount of tokens to transfer for each `from -> to` transfer. | +| `force` | `bool[]` | For each transfer, when set to `true`, the `to` address CAN be any address. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | +| `data` | `bytes[]` | An array of additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. |
@@ -871,7 +871,7 @@ If the amount is zero then the operator is being revoked, otherwise the operator function _mint( address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -888,12 +888,12 @@ Mints `amount` of tokens and transfers it to `to`. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ------------------------------------------------------------------------------------------------------------------------- | -| `to` | `address` | the address to mint tokens for. | -| `amount` | `uint256` | the amount of tokens to mint. | -| `allowNonLSP1Recipient` | `bool` | a boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | -| `data` | `bytes` | Additional data the caller wants included in the emitted {Transfer} event, and sent in the LSP1 hook to the `to` address. | +| Name | Type | Description | +| -------- | :-------: | ------------------------------------------------------------------------------------------------------------------------- | +| `to` | `address` | The address to mint tokens for. | +| `amount` | `uint256` | The amount of tokens to mint. | +| `force` | `bool` | A boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | +| `data` | `bytes` | Additional data the caller wants included in the emitted {Transfer} event, and sent in the LSP1 hook to the `to` address. |
@@ -927,8 +927,8 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r | Name | Type | Description | | -------- | :-------: | ------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | the address to burn tokens from its balance. | -| `amount` | `uint256` | the amount of tokens to burn. | +| `from` | `address` | The address to burn tokens from its balance. | +| `amount` | `uint256` | The amount of tokens to burn. | | `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the LSP1 hook to the `from` and `to` address. |
@@ -940,7 +940,7 @@ function _transfer( address from, address to, uint256 amount, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -962,13 +962,13 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | the address to decrease the balance. | -| `to` | `address` | the address to increase the balance. | -| `amount` | `uint256` | the amount of tokens to transfer from `from` to `to`. | -| `allowNonLSP1Recipient` | `bool` | a boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | -| `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the LSP1 hook to the `from` and `to` address. | +| Name | Type | Description | +| -------- | :-------: | ------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The address to decrease the balance. | +| `to` | `address` | The address to increase the balance. | +| `amount` | `uint256` | The amount of tokens to transfer from `from` to `to`. | +| `force` | `bool` | A boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | +| `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the LSP1 hook to the `from` and `to` address. |
@@ -1041,26 +1041,26 @@ If `from` is an EOA or a contract that does not support the LSP1 interface, noth ```solidity function _notifyTokenReceiver( address to, - bool allowNonLSP1Recipient, + bool force, bytes lsp1Data ) internal nonpayable; ``` Attempt to notify the token receiver `to` about the `amount` tokens being received. This is done by calling its [`universalReceiver`](#universalreceiver) function with the `_TYPEID_LSP7_TOKENSRECIPIENT` as typeId, if `to` is a contract that supports the LSP1 interface. -If `to` is is an EOA or a contract that does not support the LSP1 interface, the behaviour will depend on the `allowNonLSP1Recipient` boolean flag. +If `to` is is an EOA or a contract that does not support the LSP1 interface, the behaviour will depend on the `force` boolean flag. -- if `allowNonLSP1Recipient` is set to `true`, nothing will happen and no notification will be sent. +- if `force` is set to `true`, nothing will happen and no notification will be sent. -- if `allowNonLSP1Recipient` is set to `false, the transaction will revert. +- if `force` is set to `false, the transaction will revert. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | --------------------------------------------------------------------------------------------------- | -| `to` | `address` | The address to call the {universalReceiver} function on. | -| `allowNonLSP1Recipient` | `bool` | a boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | -| `lsp1Data` | `bytes` | the data to be sent to the `to` address in the `universalReceiver(...)` call. | +| Name | Type | Description | +| ---------- | :-------: | --------------------------------------------------------------------------------------------------- | +| `to` | `address` | The address to call the {universalReceiver} function on. | +| `force` | `bool` | A boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. | +| `lsp1Data` | `bytes` | The data to be sent to the `to` address in the `universalReceiver(...)` call. |
@@ -1236,7 +1236,7 @@ Emitted when `tokenOwner` disables `operator` for `amount` tokens and set its [` ::: ```solidity -event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool allowNonLSP1Recipient, bytes data); +event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool force, bytes data); ``` Emitted when the `from` transferred successfully `amount` of tokens to `to`. @@ -1249,7 +1249,7 @@ Emitted when the `from` transferred successfully `amount` of tokens to `to`. | `from` **`indexed`** | `address` | The address which tokens were sent from (balance decreased by `-amount`). | | `to` **`indexed`** | `address` | The address that received the tokens (balance increased by `+amount`). | | `amount` | `uint256` | The amount of tokens transferred. | -| `allowNonLSP1Recipient` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `force` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | | `data` | `bytes` | Any additional data included by the caller during the transfer, and sent in the LSP1 hooks to the `from` and `to` addresses. |
@@ -1583,7 +1583,7 @@ error LSP7NotifyTokenReceiverContractMissingLSP1Interface( ); ``` -reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1608,7 +1608,7 @@ reverts if the `tokenReceiver` does not implement LSP1 when minting or transferr error LSP7NotifyTokenReceiverIsEOA(address tokenReceiver); ``` -reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. #### Parameters diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md b/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md index 53def3084..d99a9755f 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md @@ -563,22 +563,22 @@ function transfer( address from, address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) external nonpayable; ``` -Transfer a given `tokenId` token from the `from` address to the `to` address. If operators are set for a specific `tokenId`, all the operators are revoked after the tokenId have been transferred. The `allowNonLSP1Recipient` parameter MUST be set to `true` when transferring tokens to Externally Owned Accounts (EOAs) or contracts that do not implement the LSP1 standard. +Transfer a given `tokenId` token from the `from` address to the `to` address. If operators are set for a specific `tokenId`, all the operators are revoked after the tokenId have been transferred. The `force` parameter MUST be set to `true` when transferring tokens to Externally Owned Accounts (EOAs) or contracts that do not implement the LSP1 standard. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | The address that owns the given `tokenId`. | -| `to` | `address` | The address that will receive the `tokenId`. | -| `tokenId` | `bytes32` | The token ID to transfer. | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, the `to` address CAN be any addres. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | -| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. | +| Name | Type | Description | +| --------- | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The address that owns the given `tokenId`. | +| `to` | `address` | The address that will receive the `tokenId`. | +| `tokenId` | `bytes32` | The token ID to transfer. | +| `force` | `bool` | When set to `true`, the `to` address CAN be any addres. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | +| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. |
@@ -598,7 +598,7 @@ function transferBatch( address[] from, address[] to, bytes32[] tokenId, - bool[] allowNonLSP1Recipient, + bool[] force, bytes[] data ) external nonpayable; ``` @@ -607,13 +607,13 @@ Transfers multiple tokens at once based on the arrays of `from`, `to` and `token #### Parameters -| Name | Type | Description | -| ----------------------- | :---------: | ----------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address[]` | An array of sending addresses. | -| `to` | `address[]` | An array of recipient addresses. | -| `tokenId` | `bytes32[]` | An array of token IDs to transfer. | -| `allowNonLSP1Recipient` | `bool[]` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard and not revert. | -| `data` | `bytes[]` | Any additional data the caller wants included in the emitted event, and sent in the hooks to the `from` and `to` addresses. | +| Name | Type | Description | +| --------- | :---------: | ----------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address[]` | An array of sending addresses. | +| `to` | `address[]` | An array of recipient addresses. | +| `tokenId` | `bytes32[]` | An array of token IDs to transfer. | +| `force` | `bool[]` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard and not revert. | +| `data` | `bytes[]` | Any additional data the caller wants included in the emitted event, and sent in the hooks to the `from` and `to` addresses. |
@@ -787,7 +787,7 @@ When `tokenId` does not exist then revert with an error. function _mint( address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -804,12 +804,12 @@ Create `tokenId` by minting it and transfers it to `to`. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | -------------------------------------------------------------------------------------------------------------------------- | -| `to` | `address` | @param tokenId The token ID to create (= mint). | -| `tokenId` | `bytes32` | The token ID to create (= mint). | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. | -| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hook of the `to` address. | +| Name | Type | Description | +| --------- | :-------: | -------------------------------------------------------------------------------------------------------------------------- | +| `to` | `address` | @param tokenId The token ID to create (= mint). | +| `tokenId` | `bytes32` | The token ID to create (= mint). | +| `force` | `bool` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. | +| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hook of the `to` address. |
@@ -862,7 +862,7 @@ function _transfer( address from, address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -883,13 +883,13 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | -------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | The sender address. | -| `to` | `address` | @param tokenId The token to transfer. | -| `tokenId` | `bytes32` | The token to transfer. | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. | -| `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. | +| Name | Type | Description | +| --------- | :-------: | -------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The sender address. | +| `to` | `address` | @param tokenId The token to transfer. | +| `tokenId` | `bytes32` | The token to transfer. | +| `force` | `bool` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. | +| `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. |
@@ -955,13 +955,13 @@ LSP1 interface. ```solidity function _notifyTokenReceiver( address to, - bool allowNonLSP1Recipient, + bool force, bytes lsp1Data ) internal nonpayable; ``` An attempt is made to notify the token receiver about the `tokenId` changing owners -using LSP1 interface. When allowNonLSP1Recipient is FALSE the token receiver MUST support LSP1. +using LSP1 interface. When force is FALSE the token receiver MUST support LSP1. The receiver may revert when the token being sent is not wanted.
@@ -1139,7 +1139,7 @@ Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on i ::: ```solidity -event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool allowNonLSP1Recipient, bytes data); +event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool force, bytes data); ``` Emitted when `tokenId` token is transferred from the `from` to the `to` address. @@ -1152,7 +1152,7 @@ Emitted when `tokenId` token is transferred from the `from` to the `to` address. | `from` **`indexed`** | `address` | The previous owner of the `tokenId` | | `to` **`indexed`** | `address` | The new owner of `tokenId` | | `tokenId` **`indexed`** | `bytes32` | The tokenId that was transferred | -| `allowNonLSP1Recipient` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `force` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | | `data` | `bytes` | Any additional data the caller included by the caller during the transfer, and sent in the hooks to the `from` and `to` addresses. |
@@ -1501,7 +1501,7 @@ error LSP8NotifyTokenReceiverContractMissingLSP1Interface( ); ``` -reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1526,7 +1526,7 @@ reverts if the `tokenReceiver` does not implement LSP1 when minting or transferr error LSP8NotifyTokenReceiverIsEOA(address tokenReceiver); ``` -reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. #### Parameters diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md index 3b57aa369..4513f2285 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md @@ -589,22 +589,22 @@ function transfer( address from, address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) external nonpayable; ``` -Transfer a given `tokenId` token from the `from` address to the `to` address. If operators are set for a specific `tokenId`, all the operators are revoked after the tokenId have been transferred. The `allowNonLSP1Recipient` parameter MUST be set to `true` when transferring tokens to Externally Owned Accounts (EOAs) or contracts that do not implement the LSP1 standard. +Transfer a given `tokenId` token from the `from` address to the `to` address. If operators are set for a specific `tokenId`, all the operators are revoked after the tokenId have been transferred. The `force` parameter MUST be set to `true` when transferring tokens to Externally Owned Accounts (EOAs) or contracts that do not implement the LSP1 standard. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | The address that owns the given `tokenId`. | -| `to` | `address` | The address that will receive the `tokenId`. | -| `tokenId` | `bytes32` | The token ID to transfer. | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, the `to` address CAN be any addres. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | -| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. | +| Name | Type | Description | +| --------- | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The address that owns the given `tokenId`. | +| `to` | `address` | The address that will receive the `tokenId`. | +| `tokenId` | `bytes32` | The token ID to transfer. | +| `force` | `bool` | When set to `true`, the `to` address CAN be any addres. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | +| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. |
@@ -624,7 +624,7 @@ function transferBatch( address[] from, address[] to, bytes32[] tokenId, - bool[] allowNonLSP1Recipient, + bool[] force, bytes[] data ) external nonpayable; ``` @@ -633,13 +633,13 @@ Transfers multiple tokens at once based on the arrays of `from`, `to` and `token #### Parameters -| Name | Type | Description | -| ----------------------- | :---------: | ----------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address[]` | An array of sending addresses. | -| `to` | `address[]` | An array of recipient addresses. | -| `tokenId` | `bytes32[]` | An array of token IDs to transfer. | -| `allowNonLSP1Recipient` | `bool[]` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard and not revert. | -| `data` | `bytes[]` | Any additional data the caller wants included in the emitted event, and sent in the hooks to the `from` and `to` addresses. | +| Name | Type | Description | +| --------- | :---------: | ----------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address[]` | An array of sending addresses. | +| `to` | `address[]` | An array of recipient addresses. | +| `tokenId` | `bytes32[]` | An array of token IDs to transfer. | +| `force` | `bool[]` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard and not revert. | +| `data` | `bytes[]` | Any additional data the caller wants included in the emitted event, and sent in the hooks to the `from` and `to` addresses. |
@@ -813,7 +813,7 @@ When `tokenId` does not exist then revert with an error. function _mint( address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -830,12 +830,12 @@ Create `tokenId` by minting it and transfers it to `to`. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | -------------------------------------------------------------------------------------------------------------------------- | -| `to` | `address` | @param tokenId The token ID to create (= mint). | -| `tokenId` | `bytes32` | The token ID to create (= mint). | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. | -| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hook of the `to` address. | +| Name | Type | Description | +| --------- | :-------: | -------------------------------------------------------------------------------------------------------------------------- | +| `to` | `address` | @param tokenId The token ID to create (= mint). | +| `tokenId` | `bytes32` | The token ID to create (= mint). | +| `force` | `bool` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. | +| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hook of the `to` address. |
@@ -888,7 +888,7 @@ function _transfer( address from, address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -909,13 +909,13 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | -------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | The sender address. | -| `to` | `address` | @param tokenId The token to transfer. | -| `tokenId` | `bytes32` | The token to transfer. | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. | -| `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. | +| Name | Type | Description | +| --------- | :-------: | -------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The sender address. | +| `to` | `address` | @param tokenId The token to transfer. | +| `tokenId` | `bytes32` | The token to transfer. | +| `force` | `bool` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. | +| `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. |
@@ -981,13 +981,13 @@ LSP1 interface. ```solidity function _notifyTokenReceiver( address to, - bool allowNonLSP1Recipient, + bool force, bytes lsp1Data ) internal nonpayable; ``` An attempt is made to notify the token receiver about the `tokenId` changing owners -using LSP1 interface. When allowNonLSP1Recipient is FALSE the token receiver MUST support LSP1. +using LSP1 interface. When force is FALSE the token receiver MUST support LSP1. The receiver may revert when the token being sent is not wanted.
@@ -1165,7 +1165,7 @@ Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on i ::: ```solidity -event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool allowNonLSP1Recipient, bytes data); +event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool force, bytes data); ``` Emitted when `tokenId` token is transferred from the `from` to the `to` address. @@ -1178,7 +1178,7 @@ Emitted when `tokenId` token is transferred from the `from` to the `to` address. | `from` **`indexed`** | `address` | The previous owner of the `tokenId` | | `to` **`indexed`** | `address` | The new owner of `tokenId` | | `tokenId` **`indexed`** | `bytes32` | The tokenId that was transferred | -| `allowNonLSP1Recipient` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `force` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | | `data` | `bytes` | Any additional data the caller included by the caller during the transfer, and sent in the hooks to the `from` and `to` addresses. |
@@ -1527,7 +1527,7 @@ error LSP8NotifyTokenReceiverContractMissingLSP1Interface( ); ``` -reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1552,7 +1552,7 @@ reverts if the `tokenReceiver` does not implement LSP1 when minting or transferr error LSP8NotifyTokenReceiverIsEOA(address tokenReceiver); ``` -reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. #### Parameters diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md index f167191a5..8daa4dae5 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md @@ -588,22 +588,22 @@ function transfer( address from, address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) external nonpayable; ``` -Transfer a given `tokenId` token from the `from` address to the `to` address. If operators are set for a specific `tokenId`, all the operators are revoked after the tokenId have been transferred. The `allowNonLSP1Recipient` parameter MUST be set to `true` when transferring tokens to Externally Owned Accounts (EOAs) or contracts that do not implement the LSP1 standard. +Transfer a given `tokenId` token from the `from` address to the `to` address. If operators are set for a specific `tokenId`, all the operators are revoked after the tokenId have been transferred. The `force` parameter MUST be set to `true` when transferring tokens to Externally Owned Accounts (EOAs) or contracts that do not implement the LSP1 standard. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | The address that owns the given `tokenId`. | -| `to` | `address` | The address that will receive the `tokenId`. | -| `tokenId` | `bytes32` | The token ID to transfer. | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, the `to` address CAN be any addres. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | -| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. | +| Name | Type | Description | +| --------- | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The address that owns the given `tokenId`. | +| `to` | `address` | The address that will receive the `tokenId`. | +| `tokenId` | `bytes32` | The token ID to transfer. | +| `force` | `bool` | When set to `true`, the `to` address CAN be any addres. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | +| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. |
@@ -623,7 +623,7 @@ function transferBatch( address[] from, address[] to, bytes32[] tokenId, - bool[] allowNonLSP1Recipient, + bool[] force, bytes[] data ) external nonpayable; ``` @@ -632,13 +632,13 @@ Transfers multiple tokens at once based on the arrays of `from`, `to` and `token #### Parameters -| Name | Type | Description | -| ----------------------- | :---------: | ----------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address[]` | An array of sending addresses. | -| `to` | `address[]` | An array of recipient addresses. | -| `tokenId` | `bytes32[]` | An array of token IDs to transfer. | -| `allowNonLSP1Recipient` | `bool[]` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard and not revert. | -| `data` | `bytes[]` | Any additional data the caller wants included in the emitted event, and sent in the hooks to the `from` and `to` addresses. | +| Name | Type | Description | +| --------- | :---------: | ----------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address[]` | An array of sending addresses. | +| `to` | `address[]` | An array of recipient addresses. | +| `tokenId` | `bytes32[]` | An array of token IDs to transfer. | +| `force` | `bool[]` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard and not revert. | +| `data` | `bytes[]` | Any additional data the caller wants included in the emitted event, and sent in the hooks to the `from` and `to` addresses. |
@@ -812,7 +812,7 @@ When `tokenId` does not exist then revert with an error. function _mint( address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -872,7 +872,7 @@ function _transfer( address from, address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -893,13 +893,13 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | -------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | The sender address. | -| `to` | `address` | @param tokenId The token to transfer. | -| `tokenId` | `bytes32` | The token to transfer. | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. | -| `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. | +| Name | Type | Description | +| --------- | :-------: | -------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The sender address. | +| `to` | `address` | @param tokenId The token to transfer. | +| `tokenId` | `bytes32` | The token to transfer. | +| `force` | `bool` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. | +| `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. |
@@ -965,13 +965,13 @@ LSP1 interface. ```solidity function _notifyTokenReceiver( address to, - bool allowNonLSP1Recipient, + bool force, bytes lsp1Data ) internal nonpayable; ``` An attempt is made to notify the token receiver about the `tokenId` changing owners -using LSP1 interface. When allowNonLSP1Recipient is FALSE the token receiver MUST support LSP1. +using LSP1 interface. When force is FALSE the token receiver MUST support LSP1. The receiver may revert when the token being sent is not wanted.
@@ -1149,7 +1149,7 @@ Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on i ::: ```solidity -event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool allowNonLSP1Recipient, bytes data); +event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool force, bytes data); ``` Emitted when `tokenId` token is transferred from the `from` to the `to` address. @@ -1162,7 +1162,7 @@ Emitted when `tokenId` token is transferred from the `from` to the `to` address. | `from` **`indexed`** | `address` | The previous owner of the `tokenId` | | `to` **`indexed`** | `address` | The new owner of `tokenId` | | `tokenId` **`indexed`** | `bytes32` | The tokenId that was transferred | -| `allowNonLSP1Recipient` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `force` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | | `data` | `bytes` | Any additional data the caller included by the caller during the transfer, and sent in the hooks to the `from` and `to` addresses. |
@@ -1553,7 +1553,7 @@ error LSP8NotifyTokenReceiverContractMissingLSP1Interface( ); ``` -reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1578,7 +1578,7 @@ reverts if the `tokenReceiver` does not implement LSP1 when minting or transferr error LSP8NotifyTokenReceiverIsEOA(address tokenReceiver); ``` -reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. #### Parameters diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md index 85efdae38..ba096acc9 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md @@ -501,7 +501,7 @@ Remove access of `operator` for a given `tokenId`, disallowing it to transfer `t :::info -This function sets the `allowNonLSP1Recipient` parameter to `true` so that EOAs and any contract can receive the `tokenId`. +This function sets the `force` parameter to `true` so that EOAs and any contract can receive the `tokenId`. ::: @@ -540,7 +540,7 @@ Safe Transfer function without optional data from the ERC721 standard interface. :::info -This function sets the `allowNonLSP1Recipient` parameter to `true` so that EOAs and any contract can receive the `tokenId`. +This function sets the `force` parameter to `true` so that EOAs and any contract can receive the `tokenId`. ::: @@ -882,22 +882,22 @@ function transfer( address from, address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) external nonpayable; ``` -Transfer a given `tokenId` token from the `from` address to the `to` address. If operators are set for a specific `tokenId`, all the operators are revoked after the tokenId have been transferred. The `allowNonLSP1Recipient` parameter MUST be set to `true` when transferring tokens to Externally Owned Accounts (EOAs) or contracts that do not implement the LSP1 standard. +Transfer a given `tokenId` token from the `from` address to the `to` address. If operators are set for a specific `tokenId`, all the operators are revoked after the tokenId have been transferred. The `force` parameter MUST be set to `true` when transferring tokens to Externally Owned Accounts (EOAs) or contracts that do not implement the LSP1 standard. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | The address that owns the given `tokenId`. | -| `to` | `address` | The address that will receive the `tokenId`. | -| `tokenId` | `bytes32` | The token ID to transfer. | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, the `to` address CAN be any addres. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | -| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. | +| Name | Type | Description | +| --------- | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The address that owns the given `tokenId`. | +| `to` | `address` | The address that will receive the `tokenId`. | +| `tokenId` | `bytes32` | The token ID to transfer. | +| `force` | `bool` | When set to `true`, the `to` address CAN be any addres. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | +| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. |
@@ -917,7 +917,7 @@ function transferBatch( address[] from, address[] to, bytes32[] tokenId, - bool[] allowNonLSP1Recipient, + bool[] force, bytes[] data ) external nonpayable; ``` @@ -926,13 +926,13 @@ Transfers multiple tokens at once based on the arrays of `from`, `to` and `token #### Parameters -| Name | Type | Description | -| ----------------------- | :---------: | ----------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address[]` | An array of sending addresses. | -| `to` | `address[]` | An array of recipient addresses. | -| `tokenId` | `bytes32[]` | An array of token IDs to transfer. | -| `allowNonLSP1Recipient` | `bool[]` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard and not revert. | -| `data` | `bytes[]` | Any additional data the caller wants included in the emitted event, and sent in the hooks to the `from` and `to` addresses. | +| Name | Type | Description | +| --------- | :---------: | ----------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address[]` | An array of sending addresses. | +| `to` | `address[]` | An array of recipient addresses. | +| `tokenId` | `bytes32[]` | An array of token IDs to transfer. | +| `force` | `bool[]` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard and not revert. | +| `data` | `bytes[]` | Any additional data the caller wants included in the emitted event, and sent in the hooks to the `from` and `to` addresses. |
@@ -949,7 +949,7 @@ Transfers multiple tokens at once based on the arrays of `from`, `to` and `token :::info -This function sets the `allowNonLSP1Recipient` parameter to `true` so that EOAs and any contract can receive the `tokenId`. +This function sets the `force` parameter to `true` so that EOAs and any contract can receive the `tokenId`. ::: @@ -1143,7 +1143,7 @@ When `tokenId` does not exist then revert with an error. function _mint( address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -1165,7 +1165,7 @@ function _transfer( address from, address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -1234,13 +1234,13 @@ LSP1 interface. ```solidity function _notifyTokenReceiver( address to, - bool allowNonLSP1Recipient, + bool force, bytes lsp1Data ) internal nonpayable; ``` An attempt is made to notify the token receiver about the `tokenId` changing owners -using LSP1 interface. When allowNonLSP1Recipient is FALSE the token receiver MUST support LSP1. +using LSP1 interface. When force is FALSE the token receiver MUST support LSP1. The receiver may revert when the token being sent is not wanted.
@@ -1544,7 +1544,7 @@ Emitted when `value` tokens are moved from one account (`from`) to another (`to` ::: ```solidity -event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool allowNonLSP1Recipient, bytes data); +event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool force, bytes data); ``` Emitted when `tokenId` token is transferred from the `from` to the `to` address. @@ -1557,7 +1557,7 @@ Emitted when `tokenId` token is transferred from the `from` to the `to` address. | `from` **`indexed`** | `address` | The previous owner of the `tokenId` | | `to` **`indexed`** | `address` | The new owner of `tokenId` | | `tokenId` **`indexed`** | `bytes32` | The tokenId that was transferred | -| `allowNonLSP1Recipient` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `force` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | | `data` | `bytes` | Any additional data the caller included by the caller during the transfer, and sent in the hooks to the `from` and `to` addresses. |
@@ -1906,7 +1906,7 @@ error LSP8NotifyTokenReceiverContractMissingLSP1Interface( ); ``` -reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1931,7 +1931,7 @@ reverts if the `tokenReceiver` does not implement LSP1 when minting or transferr error LSP8NotifyTokenReceiverIsEOA(address tokenReceiver); ``` -reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. #### Parameters diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md index 46edaa81d..93ab8392a 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md @@ -594,22 +594,22 @@ function transfer( address from, address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) external nonpayable; ``` -Transfer a given `tokenId` token from the `from` address to the `to` address. If operators are set for a specific `tokenId`, all the operators are revoked after the tokenId have been transferred. The `allowNonLSP1Recipient` parameter MUST be set to `true` when transferring tokens to Externally Owned Accounts (EOAs) or contracts that do not implement the LSP1 standard. +Transfer a given `tokenId` token from the `from` address to the `to` address. If operators are set for a specific `tokenId`, all the operators are revoked after the tokenId have been transferred. The `force` parameter MUST be set to `true` when transferring tokens to Externally Owned Accounts (EOAs) or contracts that do not implement the LSP1 standard. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | The address that owns the given `tokenId`. | -| `to` | `address` | The address that will receive the `tokenId`. | -| `tokenId` | `bytes32` | The token ID to transfer. | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, the `to` address CAN be any addres. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | -| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. | +| Name | Type | Description | +| --------- | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The address that owns the given `tokenId`. | +| `to` | `address` | The address that will receive the `tokenId`. | +| `tokenId` | `bytes32` | The token ID to transfer. | +| `force` | `bool` | When set to `true`, the `to` address CAN be any addres. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | +| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. |
@@ -629,7 +629,7 @@ function transferBatch( address[] from, address[] to, bytes32[] tokenId, - bool[] allowNonLSP1Recipient, + bool[] force, bytes[] data ) external nonpayable; ``` @@ -638,13 +638,13 @@ Transfers multiple tokens at once based on the arrays of `from`, `to` and `token #### Parameters -| Name | Type | Description | -| ----------------------- | :---------: | ----------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address[]` | An array of sending addresses. | -| `to` | `address[]` | An array of recipient addresses. | -| `tokenId` | `bytes32[]` | An array of token IDs to transfer. | -| `allowNonLSP1Recipient` | `bool[]` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard and not revert. | -| `data` | `bytes[]` | Any additional data the caller wants included in the emitted event, and sent in the hooks to the `from` and `to` addresses. | +| Name | Type | Description | +| --------- | :---------: | ----------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address[]` | An array of sending addresses. | +| `to` | `address[]` | An array of recipient addresses. | +| `tokenId` | `bytes32[]` | An array of token IDs to transfer. | +| `force` | `bool[]` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard and not revert. | +| `data` | `bytes[]` | Any additional data the caller wants included in the emitted event, and sent in the hooks to the `from` and `to` addresses. |
@@ -818,7 +818,7 @@ When `tokenId` does not exist then revert with an error. function _mint( address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -835,12 +835,12 @@ Create `tokenId` by minting it and transfers it to `to`. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | -------------------------------------------------------------------------------------------------------------------------- | -| `to` | `address` | @param tokenId The token ID to create (= mint). | -| `tokenId` | `bytes32` | The token ID to create (= mint). | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. | -| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hook of the `to` address. | +| Name | Type | Description | +| --------- | :-------: | -------------------------------------------------------------------------------------------------------------------------- | +| `to` | `address` | @param tokenId The token ID to create (= mint). | +| `tokenId` | `bytes32` | The token ID to create (= mint). | +| `force` | `bool` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. | +| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hook of the `to` address. |
@@ -893,7 +893,7 @@ function _transfer( address from, address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -914,13 +914,13 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | -------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | The sender address. | -| `to` | `address` | @param tokenId The token to transfer. | -| `tokenId` | `bytes32` | The token to transfer. | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. | -| `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. | +| Name | Type | Description | +| --------- | :-------: | -------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The sender address. | +| `to` | `address` | @param tokenId The token to transfer. | +| `tokenId` | `bytes32` | The token to transfer. | +| `force` | `bool` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. | +| `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. |
@@ -982,13 +982,13 @@ LSP1 interface. ```solidity function _notifyTokenReceiver( address to, - bool allowNonLSP1Recipient, + bool force, bytes lsp1Data ) internal nonpayable; ``` An attempt is made to notify the token receiver about the `tokenId` changing owners -using LSP1 interface. When allowNonLSP1Recipient is FALSE the token receiver MUST support LSP1. +using LSP1 interface. When force is FALSE the token receiver MUST support LSP1. The receiver may revert when the token being sent is not wanted.
@@ -1166,7 +1166,7 @@ Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on i ::: ```solidity -event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool allowNonLSP1Recipient, bytes data); +event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool force, bytes data); ``` Emitted when `tokenId` token is transferred from the `from` to the `to` address. @@ -1179,7 +1179,7 @@ Emitted when `tokenId` token is transferred from the `from` to the `to` address. | `from` **`indexed`** | `address` | The previous owner of the `tokenId` | | `to` **`indexed`** | `address` | The new owner of `tokenId` | | `tokenId` **`indexed`** | `bytes32` | The tokenId that was transferred | -| `allowNonLSP1Recipient` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `force` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | | `data` | `bytes` | Any additional data the caller included by the caller during the transfer, and sent in the hooks to the `from` and `to` addresses. |
@@ -1528,7 +1528,7 @@ error LSP8NotifyTokenReceiverContractMissingLSP1Interface( ); ``` -reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1553,7 +1553,7 @@ reverts if the `tokenReceiver` does not implement LSP1 when minting or transferr error LSP8NotifyTokenReceiverIsEOA(address tokenReceiver); ``` -reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. #### Parameters diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md index b495bd998..e5fc7392c 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md @@ -375,23 +375,23 @@ Returns whether `operator` address is an operator for a given `tokenId`. function mint( address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) external nonpayable; ``` -_Minting tokenId `tokenId` for address `to` with the additional data `data` (Note: allow non-LSP1 recipient is set to `allowNonLSP1Recipient`)._ +_Minting tokenId `tokenId` for address `to` with the additional data `data` (Note: allow non-LSP1 recipient is set to `force`)._ Public [`_mint`](#_mint) function only callable by the [`owner`](#owner). #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ------------------------------------------------------------------------------------------------------------------------------ | -| `to` | `address` | The address that will receive the minted `tokenId`. | -| `tokenId` | `bytes32` | The tokenId to mint. | -| `allowNonLSP1Recipient` | `bool` | Set to `false` to ensure that you are minting for a recipient that implements LSP1, `false` otherwise for forcing the minting. | -| `data` | `bytes` | Any addition data to be sent alongside the minting. | +| Name | Type | Description | +| --------- | :-------: | ------------------------------------------------------------------------------------------------------------------------------ | +| `to` | `address` | The address that will receive the minted `tokenId`. | +| `tokenId` | `bytes32` | The tokenId to mint. | +| `force` | `bool` | Set to `false` to ensure that you are minting for a recipient that implements LSP1, `false` otherwise for forcing the minting. | +| `data` | `bytes` | Any addition data to be sent alongside the minting. |
@@ -541,7 +541,7 @@ Remove access of `operator` for a given `tokenId`, disallowing it to transfer `t :::info -This function sets the `allowNonLSP1Recipient` parameter to `true` so that EOAs and any contract can receive the `tokenId`. +This function sets the `force` parameter to `true` so that EOAs and any contract can receive the `tokenId`. ::: @@ -580,7 +580,7 @@ Safe Transfer function without optional data from the ERC721 standard interface. :::info -This function sets the `allowNonLSP1Recipient` parameter to `true` so that EOAs and any contract can receive the `tokenId`. +This function sets the `force` parameter to `true` so that EOAs and any contract can receive the `tokenId`. ::: @@ -922,22 +922,22 @@ function transfer( address from, address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) external nonpayable; ``` -Transfer a given `tokenId` token from the `from` address to the `to` address. If operators are set for a specific `tokenId`, all the operators are revoked after the tokenId have been transferred. The `allowNonLSP1Recipient` parameter MUST be set to `true` when transferring tokens to Externally Owned Accounts (EOAs) or contracts that do not implement the LSP1 standard. +Transfer a given `tokenId` token from the `from` address to the `to` address. If operators are set for a specific `tokenId`, all the operators are revoked after the tokenId have been transferred. The `force` parameter MUST be set to `true` when transferring tokens to Externally Owned Accounts (EOAs) or contracts that do not implement the LSP1 standard. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | The address that owns the given `tokenId`. | -| `to` | `address` | The address that will receive the `tokenId`. | -| `tokenId` | `bytes32` | The token ID to transfer. | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, the `to` address CAN be any addres. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | -| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. | +| Name | Type | Description | +| --------- | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The address that owns the given `tokenId`. | +| `to` | `address` | The address that will receive the `tokenId`. | +| `tokenId` | `bytes32` | The token ID to transfer. | +| `force` | `bool` | When set to `true`, the `to` address CAN be any addres. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | +| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. |
@@ -957,7 +957,7 @@ function transferBatch( address[] from, address[] to, bytes32[] tokenId, - bool[] allowNonLSP1Recipient, + bool[] force, bytes[] data ) external nonpayable; ``` @@ -966,13 +966,13 @@ Transfers multiple tokens at once based on the arrays of `from`, `to` and `token #### Parameters -| Name | Type | Description | -| ----------------------- | :---------: | ----------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address[]` | An array of sending addresses. | -| `to` | `address[]` | An array of recipient addresses. | -| `tokenId` | `bytes32[]` | An array of token IDs to transfer. | -| `allowNonLSP1Recipient` | `bool[]` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard and not revert. | -| `data` | `bytes[]` | Any additional data the caller wants included in the emitted event, and sent in the hooks to the `from` and `to` addresses. | +| Name | Type | Description | +| --------- | :---------: | ----------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address[]` | An array of sending addresses. | +| `to` | `address[]` | An array of recipient addresses. | +| `tokenId` | `bytes32[]` | An array of token IDs to transfer. | +| `force` | `bool[]` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard and not revert. | +| `data` | `bytes[]` | Any additional data the caller wants included in the emitted event, and sent in the hooks to the `from` and `to` addresses. |
@@ -989,7 +989,7 @@ Transfers multiple tokens at once based on the arrays of `from`, `to` and `token :::info -This function sets the `allowNonLSP1Recipient` parameter to `true` so that EOAs and any contract can receive the `tokenId`. +This function sets the `force` parameter to `true` so that EOAs and any contract can receive the `tokenId`. ::: @@ -1183,7 +1183,7 @@ When `tokenId` does not exist then revert with an error. function _mint( address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -1205,7 +1205,7 @@ function _transfer( address from, address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -1274,13 +1274,13 @@ LSP1 interface. ```solidity function _notifyTokenReceiver( address to, - bool allowNonLSP1Recipient, + bool force, bytes lsp1Data ) internal nonpayable; ``` An attempt is made to notify the token receiver about the `tokenId` changing owners -using LSP1 interface. When allowNonLSP1Recipient is FALSE the token receiver MUST support LSP1. +using LSP1 interface. When force is FALSE the token receiver MUST support LSP1. The receiver may revert when the token being sent is not wanted.
@@ -1584,7 +1584,7 @@ Emitted when `value` tokens are moved from one account (`from`) to another (`to` ::: ```solidity -event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool allowNonLSP1Recipient, bytes data); +event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool force, bytes data); ``` Emitted when `tokenId` token is transferred from the `from` to the `to` address. @@ -1597,7 +1597,7 @@ Emitted when `tokenId` token is transferred from the `from` to the `to` address. | `from` **`indexed`** | `address` | The previous owner of the `tokenId` | | `to` **`indexed`** | `address` | The new owner of `tokenId` | | `tokenId` **`indexed`** | `bytes32` | The tokenId that was transferred | -| `allowNonLSP1Recipient` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `force` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | | `data` | `bytes` | Any additional data the caller included by the caller during the transfer, and sent in the hooks to the `from` and `to` addresses. |
@@ -1946,7 +1946,7 @@ error LSP8NotifyTokenReceiverContractMissingLSP1Interface( ); ``` -reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1971,7 +1971,7 @@ reverts if the `tokenReceiver` does not implement LSP1 when minting or transferr error LSP8NotifyTokenReceiverIsEOA(address tokenReceiver); ``` -reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. #### Parameters diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md index 1e54c36b0..e380ffef1 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md @@ -292,23 +292,23 @@ Returns whether `operator` address is an operator for a given `tokenId`. function mint( address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) external nonpayable; ``` -_Minting tokenId `tokenId` for address `to` with the additional data `data` (Note: allow non-LSP1 recipient is set to `allowNonLSP1Recipient`)._ +_Minting tokenId `tokenId` for address `to` with the additional data `data` (Note: allow non-LSP1 recipient is set to `force`)._ Public [`_mint`](#_mint) function only callable by the [`owner`](#owner). #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ------------------------------------------------------------------------------------------------------------------------------ | -| `to` | `address` | The address that will receive the minted `tokenId`. | -| `tokenId` | `bytes32` | The tokenId to mint. | -| `allowNonLSP1Recipient` | `bool` | Set to `false` to ensure that you are minting for a recipient that implements LSP1, `false` otherwise for forcing the minting. | -| `data` | `bytes` | Any addition data to be sent alongside the minting. | +| Name | Type | Description | +| --------- | :-------: | ------------------------------------------------------------------------------------------------------------------------------ | +| `to` | `address` | The address that will receive the minted `tokenId`. | +| `tokenId` | `bytes32` | The tokenId to mint. | +| `force` | `bool` | Set to `false` to ensure that you are minting for a recipient that implements LSP1, `false` otherwise for forcing the minting. | +| `data` | `bytes` | Any addition data to be sent alongside the minting. |
@@ -621,22 +621,22 @@ function transfer( address from, address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) external nonpayable; ``` -Transfer a given `tokenId` token from the `from` address to the `to` address. If operators are set for a specific `tokenId`, all the operators are revoked after the tokenId have been transferred. The `allowNonLSP1Recipient` parameter MUST be set to `true` when transferring tokens to Externally Owned Accounts (EOAs) or contracts that do not implement the LSP1 standard. +Transfer a given `tokenId` token from the `from` address to the `to` address. If operators are set for a specific `tokenId`, all the operators are revoked after the tokenId have been transferred. The `force` parameter MUST be set to `true` when transferring tokens to Externally Owned Accounts (EOAs) or contracts that do not implement the LSP1 standard. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | The address that owns the given `tokenId`. | -| `to` | `address` | The address that will receive the `tokenId`. | -| `tokenId` | `bytes32` | The token ID to transfer. | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, the `to` address CAN be any addres. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | -| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. | +| Name | Type | Description | +| --------- | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The address that owns the given `tokenId`. | +| `to` | `address` | The address that will receive the `tokenId`. | +| `tokenId` | `bytes32` | The token ID to transfer. | +| `force` | `bool` | When set to `true`, the `to` address CAN be any addres. When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard. | +| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses. |
@@ -656,7 +656,7 @@ function transferBatch( address[] from, address[] to, bytes32[] tokenId, - bool[] allowNonLSP1Recipient, + bool[] force, bytes[] data ) external nonpayable; ``` @@ -665,13 +665,13 @@ Transfers multiple tokens at once based on the arrays of `from`, `to` and `token #### Parameters -| Name | Type | Description | -| ----------------------- | :---------: | ----------------------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address[]` | An array of sending addresses. | -| `to` | `address[]` | An array of recipient addresses. | -| `tokenId` | `bytes32[]` | An array of token IDs to transfer. | -| `allowNonLSP1Recipient` | `bool[]` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard and not revert. | -| `data` | `bytes[]` | Any additional data the caller wants included in the emitted event, and sent in the hooks to the `from` and `to` addresses. | +| Name | Type | Description | +| --------- | :---------: | ----------------------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address[]` | An array of sending addresses. | +| `to` | `address[]` | An array of recipient addresses. | +| `tokenId` | `bytes32[]` | An array of token IDs to transfer. | +| `force` | `bool[]` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard and not revert. | +| `data` | `bytes[]` | Any additional data the caller wants included in the emitted event, and sent in the hooks to the `from` and `to` addresses. |
@@ -845,7 +845,7 @@ When `tokenId` does not exist then revert with an error. function _mint( address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -862,12 +862,12 @@ Create `tokenId` by minting it and transfers it to `to`. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | -------------------------------------------------------------------------------------------------------------------------- | -| `to` | `address` | @param tokenId The token ID to create (= mint). | -| `tokenId` | `bytes32` | The token ID to create (= mint). | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. | -| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hook of the `to` address. | +| Name | Type | Description | +| --------- | :-------: | -------------------------------------------------------------------------------------------------------------------------- | +| `to` | `address` | @param tokenId The token ID to create (= mint). | +| `tokenId` | `bytes32` | The token ID to create (= mint). | +| `force` | `bool` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. | +| `data` | `bytes` | Any additional data the caller wants included in the emitted event, and sent in the hook of the `to` address. |
@@ -920,7 +920,7 @@ function _transfer( address from, address to, bytes32 tokenId, - bool allowNonLSP1Recipient, + bool force, bytes data ) internal nonpayable; ``` @@ -941,13 +941,13 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | -------------------------------------------------------------------------------------------------------------------------- | -| `from` | `address` | The sender address. | -| `to` | `address` | @param tokenId The token to transfer. | -| `tokenId` | `bytes32` | The token to transfer. | -| `allowNonLSP1Recipient` | `bool` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. | -| `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. | +| Name | Type | Description | +| --------- | :-------: | -------------------------------------------------------------------------------------------------------------------------- | +| `from` | `address` | The sender address. | +| `to` | `address` | @param tokenId The token to transfer. | +| `tokenId` | `bytes32` | The token to transfer. | +| `force` | `bool` | When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. | +| `data` | `bytes` | Additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses. |
@@ -1013,13 +1013,13 @@ LSP1 interface. ```solidity function _notifyTokenReceiver( address to, - bool allowNonLSP1Recipient, + bool force, bytes lsp1Data ) internal nonpayable; ``` An attempt is made to notify the token receiver about the `tokenId` changing owners -using LSP1 interface. When allowNonLSP1Recipient is FALSE the token receiver MUST support LSP1. +using LSP1 interface. When force is FALSE the token receiver MUST support LSP1. The receiver may revert when the token being sent is not wanted.
@@ -1197,7 +1197,7 @@ Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on i ::: ```solidity -event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool allowNonLSP1Recipient, bytes data); +event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool force, bytes data); ``` Emitted when `tokenId` token is transferred from the `from` to the `to` address. @@ -1210,7 +1210,7 @@ Emitted when `tokenId` token is transferred from the `from` to the `to` address. | `from` **`indexed`** | `address` | The previous owner of the `tokenId` | | `to` **`indexed`** | `address` | The new owner of `tokenId` | | `tokenId` **`indexed`** | `bytes32` | The tokenId that was transferred | -| `allowNonLSP1Recipient` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `force` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | | `data` | `bytes` | Any additional data the caller included by the caller during the transfer, and sent in the hooks to the `from` and `to` addresses. |
@@ -1559,7 +1559,7 @@ error LSP8NotifyTokenReceiverContractMissingLSP1Interface( ); ``` -reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1584,7 +1584,7 @@ reverts if the `tokenReceiver` does not implement LSP1 when minting or transferr error LSP8NotifyTokenReceiverIsEOA(address tokenReceiver); ``` -reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`. +reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. #### Parameters From ad83a0b699d44b6b4a7b4fc895fdbca41c9412dd Mon Sep 17 00:00:00 2001 From: CJ42 Date: Fri, 15 Sep 2023 15:40:27 +0100 Subject: [PATCH 17/55] docs: add LSP17 Natspec about `msg.value` not forwarded to extension --- .../LSP0ERC725AccountCore.sol | 17 ++++++++++++--- .../LSP17Extendable.sol | 15 +++++++------ .../LSP17ContractExtension/LSP17Extension.sol | 8 +++---- .../LSP7DigitalAsset/LSP7DigitalAsset.sol | 6 ++---- .../LSP7DigitalAssetInitAbstract.sol | 6 ++---- .../LSP8IdentifiableDigitalAsset.sol | 6 ++---- ...P8IdentifiableDigitalAssetInitAbstract.sol | 6 ++---- contracts/LSP9Vault/LSP9VaultCore.sol | 17 ++++++++++++--- .../LSP0ERC725Account/LSP0ERC725Account.md | 21 ++++++++++++++++--- .../LSP17ContractExtension/LSP17Extendable.md | 21 +++++++++++++------ .../LSP17ContractExtension/LSP17Extension.md | 8 +++---- .../LSP7DigitalAsset/LSP7DigitalAsset.md | 10 ++++++--- .../extensions/LSP7Burnable.md | 10 ++++++--- .../extensions/LSP7CappedSupply.md | 10 ++++++--- .../extensions/LSP7CompatibleERC20.md | 10 ++++++--- .../presets/LSP7CompatibleERC20Mintable.md | 10 ++++++--- .../LSP7DigitalAsset/presets/LSP7Mintable.md | 10 ++++++--- .../LSP8IdentifiableDigitalAsset.md | 10 ++++++--- .../extensions/LSP8Burnable.md | 10 ++++++--- .../extensions/LSP8CappedSupply.md | 10 ++++++--- .../extensions/LSP8CompatibleERC721.md | 10 ++++++--- .../extensions/LSP8Enumerable.md | 10 ++++++--- .../presets/LSP8CompatibleERC721Mintable.md | 10 ++++++--- .../presets/LSP8Mintable.md | 10 ++++++--- docs/contracts/LSP9Vault/LSP9Vault.md | 21 ++++++++++++++++--- docs/contracts/UniversalProfile.md | 21 ++++++++++++++++--- 26 files changed, 213 insertions(+), 90 deletions(-) diff --git a/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol b/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol index 0585fee4e..44335ecd7 100644 --- a/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol +++ b/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol @@ -711,11 +711,22 @@ abstract contract LSP0ERC725AccountCore is /** * @dev Forwards the call to an extension mapped to a function selector. * - * Calls {_getExtension} to get the address of the extension mapped to the function selector being called on the account. If there is no extension, the `address(0)` will be returned. + * Calls {_getExtension} to get the address of the extension mapped to the function selector being + * called on the account. If there is no extension, the `address(0)` will be returned. * - * Reverts if there is no extension for the function being called, except for the bytes4(0) function selector, which passes even if there is no extension for it. + * Reverts if there is no extension for the function being called, except for the `bytes4(0)` function selector, which passes even if there is no extension for it. * - * If there is an extension for the function selector being called, it calls the extension with the CALL opcode, passing the `msg.data` appended with the 20 bytes of the `msg.sender` and 32 bytes of the `msg.value` + * If there is an extension for the function selector being called, it calls the extension with the + * `CALL` opcode, passing the `msg.data` appended with the 20 bytes of the {msg.sender} and 32 bytes of the `msg.value`. + * + * @custom:hint This function does not forward to the extension contract the `msg.value` received by the contract that inherits `LSP17Extendable`. + * If you would like to forward the `msg.value` to the extension contract, you can override the code of this internal function as follow: + * + * ```solidity + * (bool success, bytes memory result) = extension.call{value: msg.value}( + * abi.encodePacked(callData, msg.sender, msg.value) + * ); + * ``` */ function _fallbackLSP17Extendable( bytes calldata callData diff --git a/contracts/LSP17ContractExtension/LSP17Extendable.sol b/contracts/LSP17ContractExtension/LSP17Extendable.sol index 7311879d4..f2b70b873 100644 --- a/contracts/LSP17ContractExtension/LSP17Extendable.sol +++ b/contracts/LSP17ContractExtension/LSP17Extendable.sol @@ -70,18 +70,21 @@ abstract contract LSP17Extendable is ERC165 { * @dev Forwards the call to an extension mapped to a function selector. * * Calls {_getExtension} to get the address of the extension mapped to the function selector being - * called on the account. If there is no extension, the address(0) will be returned. + * called on the account. If there is no extension, the `address(0)` will be returned. * * Reverts if there is no extension for the function being called. * * If there is an extension for the function selector being called, it calls the extension with the - * CALL opcode, passing the {msg.data} appended with the 20 bytes of the {msg.sender} and - * 32 bytes of the {msg.value} + * `CALL` opcode, passing the `msg.data` appended with the 20 bytes of the {msg.sender} and 32 bytes of the `msg.value`. * - * Because the function uses assembly {return()/revert()} to terminate the call, it cannot be - * called before other codes in fallback(). + * @custom:hint This function does not forward to the extension contract the `msg.value` received by the contract that inherits `LSP17Extendable`. + * If you would like to forward the `msg.value` to the extension contract, you can override the code of this internal function as follow: * - * Otherwise, the codes after _fallbackLSP17Extendable() may never be reached. + * ```solidity + * (bool success, bytes memory result) = extension.call{value: msg.value}( + * abi.encodePacked(callData, msg.sender, msg.value) + * ); + * ``` */ function _fallbackLSP17Extendable( bytes calldata callData diff --git a/contracts/LSP17ContractExtension/LSP17Extension.sol b/contracts/LSP17ContractExtension/LSP17Extension.sol index d33c0eed8..dafbe52bc 100644 --- a/contracts/LSP17ContractExtension/LSP17Extension.sol +++ b/contracts/LSP17ContractExtension/LSP17Extension.sol @@ -26,8 +26,8 @@ abstract contract LSP17Extension is ERC165 { } /** - * @dev Returns the original msg.data passed to the extendable contract - * without the appended msg.sender and msg.value + * @dev Returns the original `msg.data` passed to the extendable contract + * without the appended `msg.sender` and `msg.value`. */ function _extendableMsgData() internal @@ -39,7 +39,7 @@ abstract contract LSP17Extension is ERC165 { } /** - * @dev Returns the original msg.sender calling the extendable contract + * @dev Returns the original `msg.sender` calling the extendable contract. */ function _extendableMsgSender() internal view virtual returns (address) { return @@ -49,7 +49,7 @@ abstract contract LSP17Extension is ERC165 { } /** - * @dev Returns the original msg.value sent to the extendable contract + * @dev Returns the original `msg.value` sent to the extendable contract. */ function _extendableMsgValue() internal view virtual returns (uint256) { return uint256(bytes32(msg.data[msg.data.length - 32:])); diff --git a/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol b/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol index 85e877afd..d6e517f64 100644 --- a/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol +++ b/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol @@ -103,10 +103,8 @@ abstract contract LSP7DigitalAsset is * CALL opcode, passing the {msg.data} appended with the 20 bytes of the {msg.sender} and * 32 bytes of the {msg.value} * - * Because the function uses assembly {return()/revert()} to terminate the call, it cannot be - * called before other codes in fallback(). - * - * Otherwise, the codes after _fallbackLSP17Extendable() may never be reached. + * @custom:info The LSP7 Token contract should not hold any native tokens. Any native tokens received by the contract + * will be forwarded to the extension address mapped to the selector from `msg.sig`. */ function _fallbackLSP17Extendable( bytes calldata callData diff --git a/contracts/LSP7DigitalAsset/LSP7DigitalAssetInitAbstract.sol b/contracts/LSP7DigitalAsset/LSP7DigitalAssetInitAbstract.sol index 33295a77b..6540973fc 100644 --- a/contracts/LSP7DigitalAsset/LSP7DigitalAssetInitAbstract.sol +++ b/contracts/LSP7DigitalAsset/LSP7DigitalAssetInitAbstract.sol @@ -98,10 +98,8 @@ abstract contract LSP7DigitalAssetInitAbstract is * CALL opcode, passing the {msg.data} appended with the 20 bytes of the {msg.sender} and * 32 bytes of the {msg.value} * - * Because the function uses assembly {return()/revert()} to terminate the call, it cannot be - * called before other codes in fallback(). - * - * Otherwise, the codes after _fallbackLSP17Extendable() may never be reached. + * @custom:info The LSP7 Token contract should not hold any native tokens. Any native tokens received by the contract + * will be forwarded to the extension address mapped to the selector from `msg.sig`. */ function _fallbackLSP17Extendable( bytes calldata callData diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol index 42d996a48..75c0423ed 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol @@ -104,10 +104,8 @@ abstract contract LSP8IdentifiableDigitalAsset is * CALL opcode, passing the {msg.data} appended with the 20 bytes of the {msg.sender} and * 32 bytes of the {msg.value} * - * Because the function uses assembly {return()/revert()} to terminate the call, it cannot be - * called before other codes in fallback(). - * - * Otherwise, the codes after _fallbackLSP17Extendable() may never be reached. + * @custom:info The LSP8 Token contract should not hold any native tokens. Any native tokens received by the contract + * will be forwarded to the extension address mapped to the selector from `msg.sig`. */ function _fallbackLSP17Extendable( bytes calldata callData diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetInitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetInitAbstract.sol index 8cb9de384..2febcbc87 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetInitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetInitAbstract.sol @@ -104,10 +104,8 @@ abstract contract LSP8IdentifiableDigitalAssetInitAbstract is * CALL opcode, passing the {msg.data} appended with the 20 bytes of the {msg.sender} and * 32 bytes of the {msg.value} * - * Because the function uses assembly {return()/revert()} to terminate the call, it cannot be - * called before other codes in fallback(). - * - * Otherwise, the codes after _fallbackLSP17Extendable() may never be reached. + * @custom:info The LSP8 Token contract should not hold any native tokens. Any native tokens received by the contract + * will be forwarded to the extension address mapped to the selector from `msg.sig`. */ function _fallbackLSP17Extendable( bytes calldata callData diff --git a/contracts/LSP9Vault/LSP9VaultCore.sol b/contracts/LSP9Vault/LSP9VaultCore.sol index d6158c740..225518887 100644 --- a/contracts/LSP9Vault/LSP9VaultCore.sol +++ b/contracts/LSP9Vault/LSP9VaultCore.sol @@ -505,11 +505,22 @@ contract LSP9VaultCore is /** * @dev Forwards the call to an extension mapped to a function selector. * - * Calls {_getExtension} to get the address of the extension mapped to the function selector being called on the account. If there is no extension, the `address(0)` will be returned. + * Calls {_getExtension} to get the address of the extension mapped to the function selector being + * called on the account. If there is no extension, the `address(0)` will be returned. * - * Reverts if there is no extension for the function being called, except for the bytes4(0) function selector, which passes even if there is no extension for it. + * Reverts if there is no extension for the function being called, except for the `bytes4(0)` function selector, which passes even if there is no extension for it. * - * If there is an extension for the function selector being called, it calls the extension with the CALL opcode, passing the `msg.data` appended with the 20 bytes of the `msg.sender` and 32 bytes of the `msg.value` + * If there is an extension for the function selector being called, it calls the extension with the + * `CALL` opcode, passing the `msg.data` appended with the 20 bytes of the {msg.sender} and 32 bytes of the `msg.value`. + * + * @custom:hint This function does not forward to the extension contract the `msg.value` received by the contract that inherits `LSP17Extendable`. + * If you would like to forward the `msg.value` to the extension contract, you can override the code of this internal function as follow: + * + * ```solidity + * (bool success, bytes memory result) = extension.call{value: msg.value}( + * abi.encodePacked(callData, msg.sender, msg.value) + * ); + * ``` */ function _fallbackLSP17Extendable( bytes calldata callData diff --git a/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md b/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md index 09d1b6dce..a49f56ccc 100644 --- a/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md +++ b/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md @@ -1149,6 +1149,19 @@ Returns the extension address stored under the following data key: ### \_fallbackLSP17Extendable +:::tip Hint + +This function does not forward to the extension contract the `msg.value` received by the contract that inherits `LSP17Extendable`. +If you would like to forward the `msg.value` to the extension contract, you can override the code of this internal function as follow: + +```solidity +(bool success, bytes memory result) = extension.call{value: msg.value}( + abi.encodePacked(callData, msg.sender, msg.value) +); +``` + +::: + ```solidity function _fallbackLSP17Extendable( bytes callData @@ -1156,9 +1169,11 @@ function _fallbackLSP17Extendable( ``` Forwards the call to an extension mapped to a function selector. -Calls [`_getExtension`](#_getextension) to get the address of the extension mapped to the function selector being called on the account. If there is no extension, the `address(0)` will be returned. -Reverts if there is no extension for the function being called, except for the bytes4(0) function selector, which passes even if there is no extension for it. -If there is an extension for the function selector being called, it calls the extension with the CALL opcode, passing the `msg.data` appended with the 20 bytes of the `msg.sender` and 32 bytes of the `msg.value` +Calls [`_getExtension`](#_getextension) to get the address of the extension mapped to the function selector being +called on the account. If there is no extension, the `address(0)` will be returned. +Reverts if there is no extension for the function being called, except for the `bytes4(0)` function selector, which passes even if there is no extension for it. +If there is an extension for the function selector being called, it calls the extension with the +`CALL` opcode, passing the `msg.data` appended with the 20 bytes of the [`msg.sender`](#msg.sender) and 32 bytes of the `msg.value`.
diff --git a/docs/contracts/LSP17ContractExtension/LSP17Extendable.md b/docs/contracts/LSP17ContractExtension/LSP17Extendable.md index 2a5ab320f..1c1702416 100644 --- a/docs/contracts/LSP17ContractExtension/LSP17Extendable.md +++ b/docs/contracts/LSP17ContractExtension/LSP17Extendable.md @@ -93,6 +93,19 @@ Up to the implementor contract to return an extension based on a function select ### \_fallbackLSP17Extendable +:::tip Hint + +This function does not forward to the extension contract the `msg.value` received by the contract that inherits `LSP17Extendable`. +If you would like to forward the `msg.value` to the extension contract, you can override the code of this internal function as follow: + +```solidity +(bool success, bytes memory result) = extension.call{value: msg.value}( + abi.encodePacked(callData, msg.sender, msg.value) +); +``` + +::: + ```solidity function _fallbackLSP17Extendable( bytes callData @@ -101,13 +114,9 @@ function _fallbackLSP17Extendable( Forwards the call to an extension mapped to a function selector. Calls [`_getExtension`](#_getextension) to get the address of the extension mapped to the function selector being -called on the account. If there is no extension, the address(0) will be returned. +called on the account. If there is no extension, the `address(0)` will be returned. Reverts if there is no extension for the function being called. If there is an extension for the function selector being called, it calls the extension with the -CALL opcode, passing the [`msg.data`](#msg.data) appended with the 20 bytes of the [`msg.sender`](#msg.sender) and -32 bytes of the [`msg.value`](#msg.value) -Because the function uses assembly [`return()/revert()`](#return) to terminate the call, it cannot be -called before other codes in fallback(). -Otherwise, the codes after \_fallbackLSP17Extendable() may never be reached. +`CALL` opcode, passing the `msg.data` appended with the 20 bytes of the [`msg.sender`](#msg.sender) and 32 bytes of the `msg.value`.
diff --git a/docs/contracts/LSP17ContractExtension/LSP17Extension.md b/docs/contracts/LSP17ContractExtension/LSP17Extension.md index 89aeee841..fd53b38f1 100644 --- a/docs/contracts/LSP17ContractExtension/LSP17Extension.md +++ b/docs/contracts/LSP17ContractExtension/LSP17Extension.md @@ -66,8 +66,8 @@ Internal functions cannot be called externally, whether from other smart contrac function _extendableMsgData() internal view returns (bytes); ``` -Returns the original msg.data passed to the extendable contract -without the appended msg.sender and msg.value +Returns the original `msg.data` passed to the extendable contract +without the appended `msg.sender` and `msg.value`.
@@ -77,7 +77,7 @@ without the appended msg.sender and msg.value function _extendableMsgSender() internal view returns (address); ``` -Returns the original msg.sender calling the extendable contract +Returns the original `msg.sender` calling the extendable contract.
@@ -87,6 +87,6 @@ Returns the original msg.sender calling the extendable contract function _extendableMsgValue() internal view returns (uint256); ``` -Returns the original msg.value sent to the extendable contract +Returns the original `msg.value` sent to the extendable contract.
diff --git a/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md b/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md index be60e15ab..eb78e271a 100644 --- a/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md +++ b/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md @@ -1034,6 +1034,13 @@ Returns the extension address stored under the following data key: ### \_fallbackLSP17Extendable +:::info + +The LSP7 Token contract should not hold any native tokens. Any native tokens received by the contract +will be forwarded to the extension address mapped to the selector from `msg.sig`. + +::: + ```solidity function _fallbackLSP17Extendable( bytes callData @@ -1047,9 +1054,6 @@ Reverts if there is no extension for the function being called. If there is an extension for the function selector being called, it calls the extension with the CALL opcode, passing the [`msg.data`](#msg.data) appended with the 20 bytes of the [`msg.sender`](#msg.sender) and 32 bytes of the [`msg.value`](#msg.value) -Because the function uses assembly [`return()/revert()`](#return) to terminate the call, it cannot be -called before other codes in fallback(). -Otherwise, the codes after \_fallbackLSP17Extendable() may never be reached.
diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md index 4b9ae506f..75e286eb6 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md @@ -1059,6 +1059,13 @@ Returns the extension address stored under the following data key: ### \_fallbackLSP17Extendable +:::info + +The LSP7 Token contract should not hold any native tokens. Any native tokens received by the contract +will be forwarded to the extension address mapped to the selector from `msg.sig`. + +::: + ```solidity function _fallbackLSP17Extendable( bytes callData @@ -1072,9 +1079,6 @@ Reverts if there is no extension for the function being called. If there is an extension for the function selector being called, it calls the extension with the CALL opcode, passing the [`msg.data`](#msg.data) appended with the 20 bytes of the [`msg.sender`](#msg.sender) and 32 bytes of the [`msg.value`](#msg.value) -Because the function uses assembly [`return()/revert()`](#return) to terminate the call, it cannot be -called before other codes in fallback(). -Otherwise, the codes after \_fallbackLSP17Extendable() may never be reached.
diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md index 79ecb62fb..405a2233d 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md @@ -1043,6 +1043,13 @@ Returns the extension address stored under the following data key: ### \_fallbackLSP17Extendable +:::info + +The LSP7 Token contract should not hold any native tokens. Any native tokens received by the contract +will be forwarded to the extension address mapped to the selector from `msg.sig`. + +::: + ```solidity function _fallbackLSP17Extendable( bytes callData @@ -1056,9 +1063,6 @@ Reverts if there is no extension for the function being called. If there is an extension for the function selector being called, it calls the extension with the CALL opcode, passing the [`msg.data`](#msg.data) appended with the 20 bytes of the [`msg.sender`](#msg.sender) and 32 bytes of the [`msg.value`](#msg.value) -Because the function uses assembly [`return()/revert()`](#return) to terminate the call, it cannot be -called before other codes in fallback(). -Otherwise, the codes after \_fallbackLSP17Extendable() may never be reached.
diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md index 5add8d3b5..61d68ae45 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md @@ -1150,6 +1150,13 @@ Returns the extension address stored under the following data key: ### \_fallbackLSP17Extendable +:::info + +The LSP7 Token contract should not hold any native tokens. Any native tokens received by the contract +will be forwarded to the extension address mapped to the selector from `msg.sig`. + +::: + ```solidity function _fallbackLSP17Extendable( bytes callData @@ -1163,9 +1170,6 @@ Reverts if there is no extension for the function being called. If there is an extension for the function selector being called, it calls the extension with the CALL opcode, passing the [`msg.data`](#msg.data) appended with the 20 bytes of the [`msg.sender`](#msg.sender) and 32 bytes of the [`msg.value`](#msg.value) -Because the function uses assembly [`return()/revert()`](#return) to terminate the call, it cannot be -called before other codes in fallback(). -Otherwise, the codes after \_fallbackLSP17Extendable() may never be reached.
diff --git a/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md b/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md index 052cc44df..cd80c23f3 100644 --- a/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md +++ b/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md @@ -1188,6 +1188,13 @@ Returns the extension address stored under the following data key: ### \_fallbackLSP17Extendable +:::info + +The LSP7 Token contract should not hold any native tokens. Any native tokens received by the contract +will be forwarded to the extension address mapped to the selector from `msg.sig`. + +::: + ```solidity function _fallbackLSP17Extendable( bytes callData @@ -1201,9 +1208,6 @@ Reverts if there is no extension for the function being called. If there is an extension for the function selector being called, it calls the extension with the CALL opcode, passing the [`msg.data`](#msg.data) appended with the 20 bytes of the [`msg.sender`](#msg.sender) and 32 bytes of the [`msg.value`](#msg.value) -Because the function uses assembly [`return()/revert()`](#return) to terminate the call, it cannot be -called before other codes in fallback(). -Otherwise, the codes after \_fallbackLSP17Extendable() may never be reached.
diff --git a/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md b/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md index 7be6c980c..52c57a89c 100644 --- a/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md +++ b/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md @@ -1096,6 +1096,13 @@ Returns the extension address stored under the following data key: ### \_fallbackLSP17Extendable +:::info + +The LSP7 Token contract should not hold any native tokens. Any native tokens received by the contract +will be forwarded to the extension address mapped to the selector from `msg.sig`. + +::: + ```solidity function _fallbackLSP17Extendable( bytes callData @@ -1109,9 +1116,6 @@ Reverts if there is no extension for the function being called. If there is an extension for the function selector being called, it calls the extension with the CALL opcode, passing the [`msg.data`](#msg.data) appended with the 20 bytes of the [`msg.sender`](#msg.sender) and 32 bytes of the [`msg.value`](#msg.value) -Because the function uses assembly [`return()/revert()`](#return) to terminate the call, it cannot be -called before other codes in fallback(). -Otherwise, the codes after \_fallbackLSP17Extendable() may never be reached.
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md b/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md index d99a9755f..573b1df68 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md @@ -998,6 +998,13 @@ Returns the extension address stored under the following data key: ### \_fallbackLSP17Extendable +:::info + +The LSP8 Token contract should not hold any native tokens. Any native tokens received by the contract +will be forwarded to the extension address mapped to the selector from `msg.sig`. + +::: + ```solidity function _fallbackLSP17Extendable( bytes callData @@ -1011,9 +1018,6 @@ Reverts if there is no extension for the function being called. If there is an extension for the function selector being called, it calls the extension with the CALL opcode, passing the [`msg.data`](#msg.data) appended with the 20 bytes of the [`msg.sender`](#msg.sender) and 32 bytes of the [`msg.value`](#msg.value) -Because the function uses assembly [`return()/revert()`](#return) to terminate the call, it cannot be -called before other codes in fallback(). -Otherwise, the codes after \_fallbackLSP17Extendable() may never be reached.
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md index 4513f2285..68713e949 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md @@ -1024,6 +1024,13 @@ Returns the extension address stored under the following data key: ### \_fallbackLSP17Extendable +:::info + +The LSP8 Token contract should not hold any native tokens. Any native tokens received by the contract +will be forwarded to the extension address mapped to the selector from `msg.sig`. + +::: + ```solidity function _fallbackLSP17Extendable( bytes callData @@ -1037,9 +1044,6 @@ Reverts if there is no extension for the function being called. If there is an extension for the function selector being called, it calls the extension with the CALL opcode, passing the [`msg.data`](#msg.data) appended with the 20 bytes of the [`msg.sender`](#msg.sender) and 32 bytes of the [`msg.value`](#msg.value) -Because the function uses assembly [`return()/revert()`](#return) to terminate the call, it cannot be -called before other codes in fallback(). -Otherwise, the codes after \_fallbackLSP17Extendable() may never be reached.
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md index 8daa4dae5..6c75b59c4 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md @@ -1008,6 +1008,13 @@ Returns the extension address stored under the following data key: ### \_fallbackLSP17Extendable +:::info + +The LSP8 Token contract should not hold any native tokens. Any native tokens received by the contract +will be forwarded to the extension address mapped to the selector from `msg.sig`. + +::: + ```solidity function _fallbackLSP17Extendable( bytes callData @@ -1021,9 +1028,6 @@ Reverts if there is no extension for the function being called. If there is an extension for the function selector being called, it calls the extension with the CALL opcode, passing the [`msg.data`](#msg.data) appended with the 20 bytes of the [`msg.sender`](#msg.sender) and 32 bytes of the [`msg.value`](#msg.value) -Because the function uses assembly [`return()/revert()`](#return) to terminate the call, it cannot be -called before other codes in fallback(). -Otherwise, the codes after \_fallbackLSP17Extendable() may never be reached.
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md index ba096acc9..228a7a274 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md @@ -1277,6 +1277,13 @@ Returns the extension address stored under the following data key: ### \_fallbackLSP17Extendable +:::info + +The LSP8 Token contract should not hold any native tokens. Any native tokens received by the contract +will be forwarded to the extension address mapped to the selector from `msg.sig`. + +::: + ```solidity function _fallbackLSP17Extendable( bytes callData @@ -1290,9 +1297,6 @@ Reverts if there is no extension for the function being called. If there is an extension for the function selector being called, it calls the extension with the CALL opcode, passing the [`msg.data`](#msg.data) appended with the 20 bytes of the [`msg.sender`](#msg.sender) and 32 bytes of the [`msg.value`](#msg.value) -Because the function uses assembly [`return()/revert()`](#return) to terminate the call, it cannot be -called before other codes in fallback(). -Otherwise, the codes after \_fallbackLSP17Extendable() may never be reached.
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md index 93ab8392a..d4636235b 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md @@ -1025,6 +1025,13 @@ Returns the extension address stored under the following data key: ### \_fallbackLSP17Extendable +:::info + +The LSP8 Token contract should not hold any native tokens. Any native tokens received by the contract +will be forwarded to the extension address mapped to the selector from `msg.sig`. + +::: + ```solidity function _fallbackLSP17Extendable( bytes callData @@ -1038,9 +1045,6 @@ Reverts if there is no extension for the function being called. If there is an extension for the function selector being called, it calls the extension with the CALL opcode, passing the [`msg.data`](#msg.data) appended with the 20 bytes of the [`msg.sender`](#msg.sender) and 32 bytes of the [`msg.value`](#msg.value) -Because the function uses assembly [`return()/revert()`](#return) to terminate the call, it cannot be -called before other codes in fallback(). -Otherwise, the codes after \_fallbackLSP17Extendable() may never be reached.
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md index e5fc7392c..9e6460b10 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md @@ -1317,6 +1317,13 @@ Returns the extension address stored under the following data key: ### \_fallbackLSP17Extendable +:::info + +The LSP8 Token contract should not hold any native tokens. Any native tokens received by the contract +will be forwarded to the extension address mapped to the selector from `msg.sig`. + +::: + ```solidity function _fallbackLSP17Extendable( bytes callData @@ -1330,9 +1337,6 @@ Reverts if there is no extension for the function being called. If there is an extension for the function selector being called, it calls the extension with the CALL opcode, passing the [`msg.data`](#msg.data) appended with the 20 bytes of the [`msg.sender`](#msg.sender) and 32 bytes of the [`msg.value`](#msg.value) -Because the function uses assembly [`return()/revert()`](#return) to terminate the call, it cannot be -called before other codes in fallback(). -Otherwise, the codes after \_fallbackLSP17Extendable() may never be reached.
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md index e380ffef1..ec01dd97e 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md @@ -1056,6 +1056,13 @@ Returns the extension address stored under the following data key: ### \_fallbackLSP17Extendable +:::info + +The LSP8 Token contract should not hold any native tokens. Any native tokens received by the contract +will be forwarded to the extension address mapped to the selector from `msg.sig`. + +::: + ```solidity function _fallbackLSP17Extendable( bytes callData @@ -1069,9 +1076,6 @@ Reverts if there is no extension for the function being called. If there is an extension for the function selector being called, it calls the extension with the CALL opcode, passing the [`msg.data`](#msg.data) appended with the 20 bytes of the [`msg.sender`](#msg.sender) and 32 bytes of the [`msg.value`](#msg.value) -Because the function uses assembly [`return()/revert()`](#return) to terminate the call, it cannot be -called before other codes in fallback(). -Otherwise, the codes after \_fallbackLSP17Extendable() may never be reached.
diff --git a/docs/contracts/LSP9Vault/LSP9Vault.md b/docs/contracts/LSP9Vault/LSP9Vault.md index c836e0130..f314f378e 100644 --- a/docs/contracts/LSP9Vault/LSP9Vault.md +++ b/docs/contracts/LSP9Vault/LSP9Vault.md @@ -1113,6 +1113,19 @@ Returns the extension address stored under the following data key: ### \_fallbackLSP17Extendable +:::tip Hint + +This function does not forward to the extension contract the `msg.value` received by the contract that inherits `LSP17Extendable`. +If you would like to forward the `msg.value` to the extension contract, you can override the code of this internal function as follow: + +```solidity +(bool success, bytes memory result) = extension.call{value: msg.value}( + abi.encodePacked(callData, msg.sender, msg.value) +); +``` + +::: + ```solidity function _fallbackLSP17Extendable( bytes callData @@ -1120,9 +1133,11 @@ function _fallbackLSP17Extendable( ``` Forwards the call to an extension mapped to a function selector. -Calls [`_getExtension`](#_getextension) to get the address of the extension mapped to the function selector being called on the account. If there is no extension, the `address(0)` will be returned. -Reverts if there is no extension for the function being called, except for the bytes4(0) function selector, which passes even if there is no extension for it. -If there is an extension for the function selector being called, it calls the extension with the CALL opcode, passing the `msg.data` appended with the 20 bytes of the `msg.sender` and 32 bytes of the `msg.value` +Calls [`_getExtension`](#_getextension) to get the address of the extension mapped to the function selector being +called on the account. If there is no extension, the `address(0)` will be returned. +Reverts if there is no extension for the function being called, except for the `bytes4(0)` function selector, which passes even if there is no extension for it. +If there is an extension for the function selector being called, it calls the extension with the +`CALL` opcode, passing the `msg.data` appended with the 20 bytes of the [`msg.sender`](#msg.sender) and 32 bytes of the `msg.value`.
diff --git a/docs/contracts/UniversalProfile.md b/docs/contracts/UniversalProfile.md index ed5fcdbe8..dfcadcad8 100644 --- a/docs/contracts/UniversalProfile.md +++ b/docs/contracts/UniversalProfile.md @@ -1092,6 +1092,19 @@ Returns the extension address stored under the following data key: ### \_fallbackLSP17Extendable +:::tip Hint + +This function does not forward to the extension contract the `msg.value` received by the contract that inherits `LSP17Extendable`. +If you would like to forward the `msg.value` to the extension contract, you can override the code of this internal function as follow: + +```solidity +(bool success, bytes memory result) = extension.call{value: msg.value}( + abi.encodePacked(callData, msg.sender, msg.value) +); +``` + +::: + ```solidity function _fallbackLSP17Extendable( bytes callData @@ -1099,9 +1112,11 @@ function _fallbackLSP17Extendable( ``` Forwards the call to an extension mapped to a function selector. -Calls [`_getExtension`](#_getextension) to get the address of the extension mapped to the function selector being called on the account. If there is no extension, the `address(0)` will be returned. -Reverts if there is no extension for the function being called, except for the bytes4(0) function selector, which passes even if there is no extension for it. -If there is an extension for the function selector being called, it calls the extension with the CALL opcode, passing the `msg.data` appended with the 20 bytes of the `msg.sender` and 32 bytes of the `msg.value` +Calls [`_getExtension`](#_getextension) to get the address of the extension mapped to the function selector being +called on the account. If there is no extension, the `address(0)` will be returned. +Reverts if there is no extension for the function being called, except for the `bytes4(0)` function selector, which passes even if there is no extension for it. +If there is an extension for the function selector being called, it calls the extension with the +`CALL` opcode, passing the `msg.data` appended with the 20 bytes of the [`msg.sender`](#msg.sender) and 32 bytes of the `msg.value`.
From 3a8219a4184d8ff39662e681bc04e2448e2e413f Mon Sep 17 00:00:00 2001 From: CJ42 Date: Thu, 14 Sep 2023 11:45:21 +0100 Subject: [PATCH 18/55] docs: document `lsp20VerifyCall` about allowing read-only permissions verification --- contracts/LSP6KeyManager/LSP6KeyManagerCore.sol | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol index 3270053fa..369a390ca 100644 --- a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol +++ b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol @@ -305,6 +305,16 @@ abstract contract LSP6KeyManagerCore is /** * @inheritdoc ILSP20 + * + * @custom:hint This function can call by any other address than the {`target`}. + * This allows to verify permissions in a _"read-only"_ manner. + * + * Anyone can call this function to verify if the `caller` has the right permissions to perform the abi-encoded function call `data` + * on the {`target`} contract (while sending `msgValue` alongside the call). + * + * If the permissions have been verified successfully and `caller` is authorized, one of the following two LSP20 magic value will be returned: + * - `0x9bf04b00`: LSP20 magic value **without** post verification (last byte is `0x00`). + * - `0x9bf04b01`: LSP20 magic value **with** post-verification (last byte is `0x01`). */ function lsp20VerifyCall( address caller, @@ -332,8 +342,8 @@ abstract contract LSP6KeyManagerCore is ? _LSP20_VERIFY_CALL_MAGIC_VALUE_WITHOUT_POST_VERIFICATION : _LSP20_VERIFY_CALL_MAGIC_VALUE_WITH_POST_VERIFICATION; } - // If a different address is invoking the verification, do not change the state - // and do read-only verification + /// @dev If a different address is invoking the verification, + /// do not change the state or emit the event to allow read-only verification else { bool isReentrantCall = _reentrancyStatus; From 5a1b49dc46cf3cdcf1b0740788cc21c08c0570c7 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Thu, 14 Sep 2023 11:46:28 +0100 Subject: [PATCH 19/55] test: fix incorrectly written test for `_verifyPermissions` function --- contracts/LSP6KeyManager/LSP6KeyManagerCore.sol | 4 ++++ .../KeyManager/KeyManagerInternalsTester.sol | 10 +++++++++- .../LSP6KeyManager/internals/Execute.internal.ts | 16 ++++++++++------ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol index 369a390ca..aae6cc91d 100644 --- a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol +++ b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.5; +import "hardhat/console.sol"; + // interfaces import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol"; import { @@ -551,6 +553,8 @@ abstract contract LSP6KeyManagerCore is bytes memory data ) = abi.decode(payload[4:], (uint256, address, uint256, bytes)); + console.log("breakpoint"); + LSP6ExecuteModule._verifyCanExecute( _target, from, diff --git a/contracts/Mocks/KeyManager/KeyManagerInternalsTester.sol b/contracts/Mocks/KeyManager/KeyManagerInternalsTester.sol index b16538adc..dde9bfa47 100644 --- a/contracts/Mocks/KeyManager/KeyManagerInternalsTester.sol +++ b/contracts/Mocks/KeyManager/KeyManagerInternalsTester.sol @@ -117,7 +117,15 @@ contract KeyManagerInternalTester is LSP6KeyManager { address from, uint256 msgValue, bytes calldata payload - ) public view { + ) public { super._verifyPermissions(from, msgValue, payload); + + // This event is emitted just for a sake of not marking this function as `view`, + // as Hardhat has a bug that does not catch error that occured from failed `abi.decode` + // inside view functions. + // See these issues in the Github repository of Hardhat: + // - https://github.com/NomicFoundation/hardhat/issues/3084 + // - https://github.com/NomicFoundation/hardhat/issues/3475 + emit PermissionsVerified(from, msgValue, bytes4(payload)); } } diff --git a/tests/LSP6KeyManager/internals/Execute.internal.ts b/tests/LSP6KeyManager/internals/Execute.internal.ts index 066cbcd8b..9541523d6 100644 --- a/tests/LSP6KeyManager/internals/Execute.internal.ts +++ b/tests/LSP6KeyManager/internals/Execute.internal.ts @@ -43,7 +43,7 @@ export const testExecuteInternals = (buildContext: () => Promise { + it('should revert if the address param is not left padded with 12 x `00` bytes', async () => { const executeParameters = { operationType: OPERATION_TYPES.CALL, to: context.accounts[3].address, @@ -68,11 +68,15 @@ export const testExecuteInternals = (buildContext: () => Promise Date: Thu, 14 Sep 2023 12:01:25 +0100 Subject: [PATCH 20/55] docs: add notice in docs for read-only permissions verification via `lsp20VerifyCall` --- contracts/LSP6KeyManager/LSP6KeyManagerCore.sol | 4 ---- docs/contracts/LSP6KeyManager/LSP6KeyManager.md | 9 +++++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol index aae6cc91d..369a390ca 100644 --- a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol +++ b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol @@ -1,8 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.5; -import "hardhat/console.sol"; - // interfaces import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol"; import { @@ -553,8 +551,6 @@ abstract contract LSP6KeyManagerCore is bytes memory data ) = abi.decode(payload[4:], (uint256, address, uint256, bytes)); - console.log("breakpoint"); - LSP6ExecuteModule._verifyCanExecute( _target, from, diff --git a/docs/contracts/LSP6KeyManager/LSP6KeyManager.md b/docs/contracts/LSP6KeyManager/LSP6KeyManager.md index 621dc560d..95e13300c 100644 --- a/docs/contracts/LSP6KeyManager/LSP6KeyManager.md +++ b/docs/contracts/LSP6KeyManager/LSP6KeyManager.md @@ -337,6 +337,15 @@ Checks if a signature was signed by a controller that has the permission `SIGN`. ::: +:::tip Hint + +This function can call by any other address than the {`target`}. This allows to verify permissions in a _"read-only"_ manner. Anyone can call this function to verify if the `caller` has the right permissions to perform the abi-encoded function call `data` on the {`target`} contract (while sending `msgValue` alongside the call). If the permissions have been verified successfully and `caller` is authorized, one of the following two LSP20 magic value will be returned: + +- `0x9bf04b00`: LSP20 magic value **without** post verification (last byte is `0x00`). +- `0x9bf04b01`: LSP20 magic value **with** post-verification (last byte is `0x01`). + +::: + ```solidity function lsp20VerifyCall( address caller, From b01e73cc855d1b9619a0d9ba4187b63b5db07cda Mon Sep 17 00:00:00 2001 From: CJ42 Date: Fri, 22 Sep 2023 17:04:09 +0100 Subject: [PATCH 21/55] chore: use `Apache-2.0` license across all `.sol` files --- contracts/Factories/Create2Factory.sol | 2 +- contracts/LSP11BasicSocialRecovery/LSP11Constants.sol | 2 +- contracts/LSP11BasicSocialRecovery/LSP11Errors.sol | 2 +- contracts/LSP14Ownable2Step/ILSP14Ownable2Step.sol | 2 +- contracts/LSP14Ownable2Step/LSP14Constants.sol | 2 +- contracts/LSP14Ownable2Step/LSP14Errors.sol | 2 +- contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol | 2 +- contracts/LSP16UniversalFactory/LSP16UniversalFactory.sol | 2 +- contracts/LSP17ContractExtension/LSP17Errors.sol | 2 +- contracts/LSP1UniversalReceiver/ILSP1UniversalReceiver.sol | 2 +- .../LSP1UniversalReceiverDelegateUP.sol | 2 +- .../LSP1UniversalReceiverDelegateVault.sol | 2 +- contracts/LSP20CallVerification/ILSP20CallVerifier.sol | 2 +- contracts/LSP20CallVerification/LSP20Constants.sol | 2 +- contracts/LSP20CallVerification/LSP20Errors.sol | 2 +- .../ILSP23LinkedContractsFactory.sol | 2 +- contracts/LSP23LinkedContractsFactory/IPostDeploymentModule.sol | 2 +- contracts/LSP23LinkedContractsFactory/LSP23Errors.sol | 2 +- .../LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol | 2 +- .../modules/UniversalProfileInitPostDeploymentModule.sol | 2 +- .../modules/UniversalProfilePostDeploymentModule.sol | 2 +- contracts/LSP25ExecuteRelayCall/LSP25Constants.sol | 2 +- contracts/LSP3ProfileMetadata/LSP3Constants.sol | 2 +- contracts/LSP4DigitalAssetMetadata/ILSP4Compatibility.sol | 2 +- contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol | 2 +- contracts/LSP4DigitalAssetMetadata/LSP4Constants.sol | 2 +- contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.sol | 2 +- .../LSP4DigitalAssetMetadataInitAbstract.sol | 2 +- contracts/LSP6KeyManager/LSP6Constants.sol | 2 +- contracts/LSP7DigitalAsset/ILSP7DigitalAsset.sol | 2 +- contracts/LSP7DigitalAsset/LSP7Constants.sol | 2 +- contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol | 2 +- contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol | 2 +- contracts/LSP7DigitalAsset/LSP7DigitalAssetInitAbstract.sol | 2 +- contracts/LSP7DigitalAsset/LSP7Errors.sol | 2 +- contracts/LSP7DigitalAsset/extensions/ILSP7CompatibleERC20.sol | 2 +- contracts/LSP7DigitalAsset/extensions/LSP7Burnable.sol | 2 +- .../LSP7DigitalAsset/extensions/LSP7BurnableInitAbstract.sol | 2 +- contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.sol | 2 +- .../extensions/LSP7CappedSupplyInitAbstract.sol | 2 +- contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol | 2 +- .../extensions/LSP7CompatibleERC20InitAbstract.sol | 2 +- contracts/LSP7DigitalAsset/presets/ILSP7Mintable.sol | 2 +- .../LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol | 2 +- .../presets/LSP7CompatibleERC20MintableInit.sol | 2 +- .../presets/LSP7CompatibleERC20MintableInitAbstract.sol | 2 +- contracts/LSP7DigitalAsset/presets/LSP7Mintable.sol | 2 +- contracts/LSP7DigitalAsset/presets/LSP7MintableInit.sol | 2 +- contracts/LSP7DigitalAsset/presets/LSP7MintableInitAbstract.sol | 2 +- .../ILSP8IdentifiableDigitalAsset.sol | 2 +- contracts/LSP8IdentifiableDigitalAsset/LSP8Constants.sol | 2 +- contracts/LSP8IdentifiableDigitalAsset/LSP8Errors.sol | 2 +- .../LSP8IdentifiableDigitalAsset.sol | 2 +- .../LSP8IdentifiableDigitalAssetCore.sol | 2 +- .../LSP8IdentifiableDigitalAssetInitAbstract.sol | 2 +- .../extensions/ILSP8CompatibleERC721.sol | 2 +- .../LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.sol | 2 +- .../extensions/LSP8BurnableInitAbstract.sol | 2 +- .../extensions/LSP8CappedSupply.sol | 2 +- .../extensions/LSP8CappedSupplyInitAbstract.sol | 2 +- .../extensions/LSP8CompatibleERC721.sol | 2 +- .../extensions/LSP8CompatibleERC721InitAbstract.sol | 2 +- .../LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.sol | 2 +- .../extensions/LSP8EnumerableInitAbstract.sol | 2 +- .../LSP8IdentifiableDigitalAsset/presets/ILSP8Mintable.sol | 2 +- .../presets/LSP8CompatibleERC721Mintable.sol | 2 +- .../presets/LSP8CompatibleERC721MintableInit.sol | 2 +- .../presets/LSP8CompatibleERC721MintableInitAbstract.sol | 2 +- contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol | 2 +- .../LSP8IdentifiableDigitalAsset/presets/LSP8MintableInit.sol | 2 +- .../presets/LSP8MintableInitAbstract.sol | 2 +- contracts/LSP9Vault/LSP9Constants.sol | 2 +- contracts/LSP9Vault/LSP9Errors.sol | 2 +- contracts/Mocks/Executor.sol | 2 +- contracts/Mocks/ExecutorLSP20.sol | 2 +- contracts/Mocks/GenericExecutor.sol | 2 +- contracts/Mocks/GenericExecutorWithBalanceOfFunction.sol | 2 +- contracts/Mocks/ImplementationTester.sol | 2 +- contracts/Mocks/KeyManagerInitWithExtraParams.sol | 2 +- contracts/Mocks/KeyManagerWithExtraParams.sol | 2 +- contracts/Mocks/LSP2UtilsLibraryTester.sol | 2 +- contracts/Mocks/MaliciousERC1271Wallet.sol | 2 +- contracts/Mocks/Reentrancy/BatchReentrancyRelayer.sol | 2 +- contracts/Mocks/Reentrancy/LSP20ReentrantContract.sol | 2 +- contracts/Mocks/Reentrancy/ReentrantContract.sol | 2 +- contracts/Mocks/Reentrancy/SingleReentrancyRelayer.sol | 2 +- contracts/Mocks/Reentrancy/ThreeReentrancy.sol | 2 +- contracts/Mocks/Tokens/LSP4CompatibilityTester.sol | 2 +- contracts/Mocks/Tokens/LSP7CappedSupplyInitTester.sol | 2 +- contracts/Mocks/Tokens/LSP7CappedSupplyTester.sol | 2 +- contracts/Mocks/Tokens/LSP7CompatibleERC20InitTester.sol | 2 +- contracts/Mocks/Tokens/LSP7CompatibleERC20Tester.sol | 2 +- contracts/Mocks/Tokens/LSP7InitTester.sol | 2 +- contracts/Mocks/Tokens/LSP7MintWhenDeployed.sol | 2 +- contracts/Mocks/Tokens/LSP7Tester.sol | 2 +- contracts/Mocks/Tokens/LSP8BurnableInitTester.sol | 2 +- contracts/Mocks/Tokens/LSP8BurnableTester.sol | 2 +- contracts/Mocks/Tokens/LSP8CappedSupplyInitTester.sol | 2 +- contracts/Mocks/Tokens/LSP8CappedSupplyTester.sol | 2 +- contracts/Mocks/Tokens/LSP8CompatibleERC721Tester.sol | 2 +- contracts/Mocks/Tokens/LSP8CompatibleERC721TesterInit.sol | 2 +- contracts/Mocks/Tokens/LSP8EnumerableInitTester.sol | 2 +- contracts/Mocks/Tokens/LSP8EnumerableTester.sol | 2 +- contracts/Mocks/Tokens/LSP8InitTester.sol | 2 +- contracts/Mocks/Tokens/LSP8Tester.sol | 2 +- contracts/Mocks/Tokens/RequireCallbackToken.sol | 2 +- .../UniversalReceiverDelegateVaultReentrantA.sol | 2 +- .../UniversalReceiverDelegateVaultReentrantB.sol | 2 +- .../UniversalReceivers/UniversalReceiverDelegateVaultSetter.sol | 2 +- tests/foundry/GasTests/LSP6s/LSP6ExecuteRC.sol | 2 +- tests/foundry/GasTests/LSP6s/LSP6ExecuteUC.sol | 2 +- tests/foundry/GasTests/LSP6s/LSP6SetDataRC.sol | 2 +- tests/foundry/GasTests/LSP6s/LSP6SetDataUC.sol | 2 +- tests/foundry/GasTests/UniversalProfileTestsHelper.sol | 2 +- tests/foundry/GasTests/execute/RestrictedController.sol | 2 +- tests/foundry/GasTests/execute/UnrestrictedController.sol | 2 +- .../LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.t.sol | 2 +- tests/foundry/LSP11BasicSocialRecovery/LSP11Mock.sol | 2 +- tests/foundry/LSP14Ownable2Step/TwoStepOwnership.sol | 2 +- tests/foundry/LSP14Ownable2Step/TwoStepRenounceOwnership.sol | 2 +- tests/foundry/LSP16UniversalFactory/LSP16UniversalProfile.t.sol | 2 +- tests/foundry/LSP2ERC725YJSONSchema/LSP2Utils.t.sol | 2 +- tests/foundry/LSP6KeyManager/LSP6SetDataTest.t.sol | 2 +- tests/foundry/LSP6KeyManager/LSP6Utils.t.sol | 2 +- 124 files changed, 124 insertions(+), 124 deletions(-) diff --git a/contracts/Factories/Create2Factory.sol b/contracts/Factories/Create2Factory.sol index 2f77452d9..05cc2052d 100644 --- a/contracts/Factories/Create2Factory.sol +++ b/contracts/Factories/Create2Factory.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // DO NOT TOUCH diff --git a/contracts/LSP11BasicSocialRecovery/LSP11Constants.sol b/contracts/LSP11BasicSocialRecovery/LSP11Constants.sol index 65b9a2cf9..66ceb1657 100644 --- a/contracts/LSP11BasicSocialRecovery/LSP11Constants.sol +++ b/contracts/LSP11BasicSocialRecovery/LSP11Constants.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; // --- ERC165 interface ids diff --git a/contracts/LSP11BasicSocialRecovery/LSP11Errors.sol b/contracts/LSP11BasicSocialRecovery/LSP11Errors.sol index 599289aad..6c6951c2b 100644 --- a/contracts/LSP11BasicSocialRecovery/LSP11Errors.sol +++ b/contracts/LSP11BasicSocialRecovery/LSP11Errors.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; // --- Errors diff --git a/contracts/LSP14Ownable2Step/ILSP14Ownable2Step.sol b/contracts/LSP14Ownable2Step/ILSP14Ownable2Step.sol index f41b2845b..6b0410934 100644 --- a/contracts/LSP14Ownable2Step/ILSP14Ownable2Step.sol +++ b/contracts/LSP14Ownable2Step/ILSP14Ownable2Step.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; /** diff --git a/contracts/LSP14Ownable2Step/LSP14Constants.sol b/contracts/LSP14Ownable2Step/LSP14Constants.sol index 130d41a46..7e889eb7f 100644 --- a/contracts/LSP14Ownable2Step/LSP14Constants.sol +++ b/contracts/LSP14Ownable2Step/LSP14Constants.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; bytes4 constant _INTERFACEID_LSP14 = 0x94be5999; diff --git a/contracts/LSP14Ownable2Step/LSP14Errors.sol b/contracts/LSP14Ownable2Step/LSP14Errors.sol index 45c8526c5..55a004a40 100644 --- a/contracts/LSP14Ownable2Step/LSP14Errors.sol +++ b/contracts/LSP14Ownable2Step/LSP14Errors.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; /** diff --git a/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol b/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol index 6bd2f3716..53f96f11a 100644 --- a/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol +++ b/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // interfaces diff --git a/contracts/LSP16UniversalFactory/LSP16UniversalFactory.sol b/contracts/LSP16UniversalFactory/LSP16UniversalFactory.sol index a2cf5e67d..7c7f469ab 100644 --- a/contracts/LSP16UniversalFactory/LSP16UniversalFactory.sol +++ b/contracts/LSP16UniversalFactory/LSP16UniversalFactory.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // libraries diff --git a/contracts/LSP17ContractExtension/LSP17Errors.sol b/contracts/LSP17ContractExtension/LSP17Errors.sol index 3a2d7da49..a39ef197c 100644 --- a/contracts/LSP17ContractExtension/LSP17Errors.sol +++ b/contracts/LSP17ContractExtension/LSP17Errors.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; /** diff --git a/contracts/LSP1UniversalReceiver/ILSP1UniversalReceiver.sol b/contracts/LSP1UniversalReceiver/ILSP1UniversalReceiver.sol index 4e8ba6834..8243fec20 100644 --- a/contracts/LSP1UniversalReceiver/ILSP1UniversalReceiver.sol +++ b/contracts/LSP1UniversalReceiver/ILSP1UniversalReceiver.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; /** diff --git a/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol b/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol index e272690ab..8527981a3 100644 --- a/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol +++ b/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // interfaces diff --git a/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol b/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol index e88ed8d45..34f6144bd 100644 --- a/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol +++ b/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // interfaces diff --git a/contracts/LSP20CallVerification/ILSP20CallVerifier.sol b/contracts/LSP20CallVerification/ILSP20CallVerifier.sol index 5ac63eb6d..2f31efe1e 100644 --- a/contracts/LSP20CallVerification/ILSP20CallVerifier.sol +++ b/contracts/LSP20CallVerification/ILSP20CallVerifier.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; /** diff --git a/contracts/LSP20CallVerification/LSP20Constants.sol b/contracts/LSP20CallVerification/LSP20Constants.sol index ea3b2b1d9..65dff7f87 100644 --- a/contracts/LSP20CallVerification/LSP20Constants.sol +++ b/contracts/LSP20CallVerification/LSP20Constants.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // bytes4(keccak256("LSP20CallVerification")) diff --git a/contracts/LSP20CallVerification/LSP20Errors.sol b/contracts/LSP20CallVerification/LSP20Errors.sol index 15e417a89..264f2971e 100644 --- a/contracts/LSP20CallVerification/LSP20Errors.sol +++ b/contracts/LSP20CallVerification/LSP20Errors.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; /** diff --git a/contracts/LSP23LinkedContractsFactory/ILSP23LinkedContractsFactory.sol b/contracts/LSP23LinkedContractsFactory/ILSP23LinkedContractsFactory.sol index dd3eeb28d..e01c94213 100644 --- a/contracts/LSP23LinkedContractsFactory/ILSP23LinkedContractsFactory.sol +++ b/contracts/LSP23LinkedContractsFactory/ILSP23LinkedContractsFactory.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; interface ILSP23LinkedContractsFactory { diff --git a/contracts/LSP23LinkedContractsFactory/IPostDeploymentModule.sol b/contracts/LSP23LinkedContractsFactory/IPostDeploymentModule.sol index dda7d22d6..98746811f 100644 --- a/contracts/LSP23LinkedContractsFactory/IPostDeploymentModule.sol +++ b/contracts/LSP23LinkedContractsFactory/IPostDeploymentModule.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; interface IPostDeploymentModule { diff --git a/contracts/LSP23LinkedContractsFactory/LSP23Errors.sol b/contracts/LSP23LinkedContractsFactory/LSP23Errors.sol index 0bbb109ab..c1a661ae8 100644 --- a/contracts/LSP23LinkedContractsFactory/LSP23Errors.sol +++ b/contracts/LSP23LinkedContractsFactory/LSP23Errors.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; /** diff --git a/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol b/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol index 1e641943b..de93f3a24 100644 --- a/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol +++ b/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; diff --git a/contracts/LSP23LinkedContractsFactory/modules/UniversalProfileInitPostDeploymentModule.sol b/contracts/LSP23LinkedContractsFactory/modules/UniversalProfileInitPostDeploymentModule.sol index 90a905181..6e94fe845 100644 --- a/contracts/LSP23LinkedContractsFactory/modules/UniversalProfileInitPostDeploymentModule.sol +++ b/contracts/LSP23LinkedContractsFactory/modules/UniversalProfileInitPostDeploymentModule.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; import { diff --git a/contracts/LSP23LinkedContractsFactory/modules/UniversalProfilePostDeploymentModule.sol b/contracts/LSP23LinkedContractsFactory/modules/UniversalProfilePostDeploymentModule.sol index 5baf9566d..7e2f861ff 100644 --- a/contracts/LSP23LinkedContractsFactory/modules/UniversalProfilePostDeploymentModule.sol +++ b/contracts/LSP23LinkedContractsFactory/modules/UniversalProfilePostDeploymentModule.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; import { diff --git a/contracts/LSP25ExecuteRelayCall/LSP25Constants.sol b/contracts/LSP25ExecuteRelayCall/LSP25Constants.sol index 5b0a4b5df..a71e3202d 100644 --- a/contracts/LSP25ExecuteRelayCall/LSP25Constants.sol +++ b/contracts/LSP25ExecuteRelayCall/LSP25Constants.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // --- ERC165 interface ids diff --git a/contracts/LSP3ProfileMetadata/LSP3Constants.sol b/contracts/LSP3ProfileMetadata/LSP3Constants.sol index 724e259f8..30f137e28 100644 --- a/contracts/LSP3ProfileMetadata/LSP3Constants.sol +++ b/contracts/LSP3ProfileMetadata/LSP3Constants.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // bytes10(keccak256('SupportedStandards')) + bytes2(0) + bytes20(keccak256('LSP3Profile')) diff --git a/contracts/LSP4DigitalAssetMetadata/ILSP4Compatibility.sol b/contracts/LSP4DigitalAssetMetadata/ILSP4Compatibility.sol index 5fcd791b7..ede2d60a7 100644 --- a/contracts/LSP4DigitalAssetMetadata/ILSP4Compatibility.sol +++ b/contracts/LSP4DigitalAssetMetadata/ILSP4Compatibility.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol b/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol index e2c394a18..fe661e18e 100644 --- a/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol +++ b/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // interfaces diff --git a/contracts/LSP4DigitalAssetMetadata/LSP4Constants.sol b/contracts/LSP4DigitalAssetMetadata/LSP4Constants.sol index 2ce7a1a4b..09547e37a 100644 --- a/contracts/LSP4DigitalAssetMetadata/LSP4Constants.sol +++ b/contracts/LSP4DigitalAssetMetadata/LSP4Constants.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // --- ERC725Y entries diff --git a/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.sol b/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.sol index 7fff22763..e9e562d47 100644 --- a/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.sol +++ b/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // modules diff --git a/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadataInitAbstract.sol b/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadataInitAbstract.sol index 59ba3a837..b64e6c1b0 100644 --- a/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadataInitAbstract.sol +++ b/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadataInitAbstract.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // modules diff --git a/contracts/LSP6KeyManager/LSP6Constants.sol b/contracts/LSP6KeyManager/LSP6Constants.sol index faeba9d97..8d4fba6a0 100644 --- a/contracts/LSP6KeyManager/LSP6Constants.sol +++ b/contracts/LSP6KeyManager/LSP6Constants.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // --- ERC165 interface ids diff --git a/contracts/LSP7DigitalAsset/ILSP7DigitalAsset.sol b/contracts/LSP7DigitalAsset/ILSP7DigitalAsset.sol index f7d29e86a..8cb969b93 100644 --- a/contracts/LSP7DigitalAsset/ILSP7DigitalAsset.sol +++ b/contracts/LSP7DigitalAsset/ILSP7DigitalAsset.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/LSP7DigitalAsset/LSP7Constants.sol b/contracts/LSP7DigitalAsset/LSP7Constants.sol index 7c73dd4eb..bfbba9e1b 100644 --- a/contracts/LSP7DigitalAsset/LSP7Constants.sol +++ b/contracts/LSP7DigitalAsset/LSP7Constants.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // --- ERC165 interface ids diff --git a/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol b/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol index d6e517f64..3a742d677 100644 --- a/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol +++ b/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // interfaces diff --git a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol index d61a1adc2..ee1bca998 100644 --- a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol +++ b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // interfaces diff --git a/contracts/LSP7DigitalAsset/LSP7DigitalAssetInitAbstract.sol b/contracts/LSP7DigitalAsset/LSP7DigitalAssetInitAbstract.sol index 6540973fc..b27c6fa98 100644 --- a/contracts/LSP7DigitalAsset/LSP7DigitalAssetInitAbstract.sol +++ b/contracts/LSP7DigitalAsset/LSP7DigitalAssetInitAbstract.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // interfaces diff --git a/contracts/LSP7DigitalAsset/LSP7Errors.sol b/contracts/LSP7DigitalAsset/LSP7Errors.sol index 02c1781ac..93559fd6e 100644 --- a/contracts/LSP7DigitalAsset/LSP7Errors.sol +++ b/contracts/LSP7DigitalAsset/LSP7Errors.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // --- Errors diff --git a/contracts/LSP7DigitalAsset/extensions/ILSP7CompatibleERC20.sol b/contracts/LSP7DigitalAsset/extensions/ILSP7CompatibleERC20.sol index a4c2eb361..38cdb68c6 100644 --- a/contracts/LSP7DigitalAsset/extensions/ILSP7CompatibleERC20.sol +++ b/contracts/LSP7DigitalAsset/extensions/ILSP7CompatibleERC20.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.sol b/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.sol index f28967ccf..40a2289f7 100644 --- a/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.sol +++ b/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // modules diff --git a/contracts/LSP7DigitalAsset/extensions/LSP7BurnableInitAbstract.sol b/contracts/LSP7DigitalAsset/extensions/LSP7BurnableInitAbstract.sol index 7b542d189..8dd541eb8 100644 --- a/contracts/LSP7DigitalAsset/extensions/LSP7BurnableInitAbstract.sol +++ b/contracts/LSP7DigitalAsset/extensions/LSP7BurnableInitAbstract.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // modules diff --git a/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.sol b/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.sol index a7e92dedc..6d3eb98f9 100644 --- a/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.sol +++ b/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupplyInitAbstract.sol b/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupplyInitAbstract.sol index 8e3eef30e..86acdb471 100644 --- a/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupplyInitAbstract.sol +++ b/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupplyInitAbstract.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol b/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol index c77a8527d..b9b0e473e 100644 --- a/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol +++ b/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.12; // interfaces diff --git a/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20InitAbstract.sol b/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20InitAbstract.sol index 5c3665ada..4b64a16d3 100644 --- a/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20InitAbstract.sol +++ b/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20InitAbstract.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.12; // interfaces diff --git a/contracts/LSP7DigitalAsset/presets/ILSP7Mintable.sol b/contracts/LSP7DigitalAsset/presets/ILSP7Mintable.sol index 08d7e267a..7ec9c5615 100644 --- a/contracts/LSP7DigitalAsset/presets/ILSP7Mintable.sol +++ b/contracts/LSP7DigitalAsset/presets/ILSP7Mintable.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol b/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol index cf8d2ab7b..4595ed749 100644 --- a/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol +++ b/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.12; import {LSP7CompatibleERC20} from "../extensions/LSP7CompatibleERC20.sol"; diff --git a/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20MintableInit.sol b/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20MintableInit.sol index 7bf424ce6..f75b4b758 100644 --- a/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20MintableInit.sol +++ b/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20MintableInit.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.12; // modules diff --git a/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20MintableInitAbstract.sol b/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20MintableInitAbstract.sol index b0c77d31c..95b0bee2c 100644 --- a/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20MintableInitAbstract.sol +++ b/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20MintableInitAbstract.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.12; // modules diff --git a/contracts/LSP7DigitalAsset/presets/LSP7Mintable.sol b/contracts/LSP7DigitalAsset/presets/LSP7Mintable.sol index d2c69149e..952030f06 100644 --- a/contracts/LSP7DigitalAsset/presets/LSP7Mintable.sol +++ b/contracts/LSP7DigitalAsset/presets/LSP7Mintable.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/LSP7DigitalAsset/presets/LSP7MintableInit.sol b/contracts/LSP7DigitalAsset/presets/LSP7MintableInit.sol index 21bb6e87e..d3e395f26 100644 --- a/contracts/LSP7DigitalAsset/presets/LSP7MintableInit.sol +++ b/contracts/LSP7DigitalAsset/presets/LSP7MintableInit.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/LSP7DigitalAsset/presets/LSP7MintableInitAbstract.sol b/contracts/LSP7DigitalAsset/presets/LSP7MintableInitAbstract.sol index 8b7a2cd5f..0720d9bf6 100644 --- a/contracts/LSP7DigitalAsset/presets/LSP7MintableInitAbstract.sol +++ b/contracts/LSP7DigitalAsset/presets/LSP7MintableInitAbstract.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/LSP8IdentifiableDigitalAsset/ILSP8IdentifiableDigitalAsset.sol b/contracts/LSP8IdentifiableDigitalAsset/ILSP8IdentifiableDigitalAsset.sol index babc53e27..53aec6be2 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/ILSP8IdentifiableDigitalAsset.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/ILSP8IdentifiableDigitalAsset.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8Constants.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8Constants.sol index 72c71c754..eea9db83a 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8Constants.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8Constants.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // --- ERC165 interface ids diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8Errors.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8Errors.sol index c5d6fe4e9..d3f170005 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8Errors.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8Errors.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // --- Errors diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol index 75c0423ed..9e210d62d 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // interfaces diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol index 81bb7b8b4..7a41e367b 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // interfaces diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetInitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetInitAbstract.sol index 2febcbc87..51b3452f9 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetInitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetInitAbstract.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // interfaces diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/ILSP8CompatibleERC721.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/ILSP8CompatibleERC721.sol index e5b32faf4..6548fee57 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/ILSP8CompatibleERC721.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/ILSP8CompatibleERC721.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // interfaces diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.sol index de28b0b02..88bdd216d 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; import { diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8BurnableInitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8BurnableInitAbstract.sol index 2c5c92a5b..064aefd3b 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8BurnableInitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8BurnableInitAbstract.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; import { diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.sol index 9dafac599..102f4b819 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupplyInitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupplyInitAbstract.sol index 13b560841..6fab6a033 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupplyInitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupplyInitAbstract.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol index 6dc651df8..07738be5e 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.12; // interfaces diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol index 5d562725c..b524cd111 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.12; // interfaces diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.sol index 2e100bb13..4a25009ca 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8EnumerableInitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8EnumerableInitAbstract.sol index c4513bb93..18ca0e8fc 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8EnumerableInitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8EnumerableInitAbstract.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/LSP8IdentifiableDigitalAsset/presets/ILSP8Mintable.sol b/contracts/LSP8IdentifiableDigitalAsset/presets/ILSP8Mintable.sol index d6bc2e8bd..946d022b8 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/presets/ILSP8Mintable.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/presets/ILSP8Mintable.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol index 4c0c82596..482394e5b 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.12; import {LSP8CompatibleERC721} from "../extensions/LSP8CompatibleERC721.sol"; diff --git a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721MintableInit.sol b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721MintableInit.sol index 9bb1b63ab..2472662c6 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721MintableInit.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721MintableInit.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.12; // modules diff --git a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721MintableInitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721MintableInitAbstract.sol index 1b27875c0..e36d1d2af 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721MintableInitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721MintableInitAbstract.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.12; // modules diff --git a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol index 7182aad0b..2b9e389fb 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInit.sol b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInit.sol index 749ced640..58a43eb0f 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInit.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInit.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInitAbstract.sol index 0c49af6d8..004a0f5af 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInitAbstract.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/LSP9Vault/LSP9Constants.sol b/contracts/LSP9Vault/LSP9Constants.sol index 72299c813..f17ed7a04 100644 --- a/contracts/LSP9Vault/LSP9Constants.sol +++ b/contracts/LSP9Vault/LSP9Constants.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // --- ERC165 interface ids diff --git a/contracts/LSP9Vault/LSP9Errors.sol b/contracts/LSP9Vault/LSP9Errors.sol index 60ab7e520..38bf3a90a 100644 --- a/contracts/LSP9Vault/LSP9Errors.sol +++ b/contracts/LSP9Vault/LSP9Errors.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; /** diff --git a/contracts/Mocks/Executor.sol b/contracts/Mocks/Executor.sol index 340963a7c..2a234ad65 100644 --- a/contracts/Mocks/Executor.sol +++ b/contracts/Mocks/Executor.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // interfaces diff --git a/contracts/Mocks/ExecutorLSP20.sol b/contracts/Mocks/ExecutorLSP20.sol index 0d26cbb6d..ac77e27c1 100644 --- a/contracts/Mocks/ExecutorLSP20.sol +++ b/contracts/Mocks/ExecutorLSP20.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // interfaces diff --git a/contracts/Mocks/GenericExecutor.sol b/contracts/Mocks/GenericExecutor.sol index a51a81e42..2c9d040da 100644 --- a/contracts/Mocks/GenericExecutor.sol +++ b/contracts/Mocks/GenericExecutor.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; /** diff --git a/contracts/Mocks/GenericExecutorWithBalanceOfFunction.sol b/contracts/Mocks/GenericExecutorWithBalanceOfFunction.sol index 17f477694..9bb9f038e 100644 --- a/contracts/Mocks/GenericExecutorWithBalanceOfFunction.sol +++ b/contracts/Mocks/GenericExecutorWithBalanceOfFunction.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; /** diff --git a/contracts/Mocks/ImplementationTester.sol b/contracts/Mocks/ImplementationTester.sol index cc516941f..0cd7b6579 100644 --- a/contracts/Mocks/ImplementationTester.sol +++ b/contracts/Mocks/ImplementationTester.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; import { diff --git a/contracts/Mocks/KeyManagerInitWithExtraParams.sol b/contracts/Mocks/KeyManagerInitWithExtraParams.sol index 206b125bf..af9631860 100644 --- a/contracts/Mocks/KeyManagerInitWithExtraParams.sol +++ b/contracts/Mocks/KeyManagerInitWithExtraParams.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; import {LSP6KeyManagerInit} from "../LSP6KeyManager/LSP6KeyManagerInit.sol"; diff --git a/contracts/Mocks/KeyManagerWithExtraParams.sol b/contracts/Mocks/KeyManagerWithExtraParams.sol index c65588687..be27c4ffd 100644 --- a/contracts/Mocks/KeyManagerWithExtraParams.sol +++ b/contracts/Mocks/KeyManagerWithExtraParams.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; import {LSP6KeyManager} from "../LSP6KeyManager/LSP6KeyManager.sol"; diff --git a/contracts/Mocks/LSP2UtilsLibraryTester.sol b/contracts/Mocks/LSP2UtilsLibraryTester.sol index f1471dba2..289fc9542 100644 --- a/contracts/Mocks/LSP2UtilsLibraryTester.sol +++ b/contracts/Mocks/LSP2UtilsLibraryTester.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; import {LSP2Utils} from "../LSP2ERC725YJSONSchema/LSP2Utils.sol"; diff --git a/contracts/Mocks/MaliciousERC1271Wallet.sol b/contracts/Mocks/MaliciousERC1271Wallet.sol index 504006d97..7e264ec01 100644 --- a/contracts/Mocks/MaliciousERC1271Wallet.sol +++ b/contracts/Mocks/MaliciousERC1271Wallet.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; import {GenericExecutor} from "./GenericExecutor.sol"; diff --git a/contracts/Mocks/Reentrancy/BatchReentrancyRelayer.sol b/contracts/Mocks/Reentrancy/BatchReentrancyRelayer.sol index 32a01c962..4c6385f9e 100644 --- a/contracts/Mocks/Reentrancy/BatchReentrancyRelayer.sol +++ b/contracts/Mocks/Reentrancy/BatchReentrancyRelayer.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // interfaces diff --git a/contracts/Mocks/Reentrancy/LSP20ReentrantContract.sol b/contracts/Mocks/Reentrancy/LSP20ReentrantContract.sol index 4f779d7a8..e5e7e5586 100644 --- a/contracts/Mocks/Reentrancy/LSP20ReentrantContract.sol +++ b/contracts/Mocks/Reentrancy/LSP20ReentrantContract.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // interfaces diff --git a/contracts/Mocks/Reentrancy/ReentrantContract.sol b/contracts/Mocks/Reentrancy/ReentrantContract.sol index 70732bedf..b916e98c9 100644 --- a/contracts/Mocks/Reentrancy/ReentrantContract.sol +++ b/contracts/Mocks/Reentrancy/ReentrantContract.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // interfaces diff --git a/contracts/Mocks/Reentrancy/SingleReentrancyRelayer.sol b/contracts/Mocks/Reentrancy/SingleReentrancyRelayer.sol index f1e067636..0e24078de 100644 --- a/contracts/Mocks/Reentrancy/SingleReentrancyRelayer.sol +++ b/contracts/Mocks/Reentrancy/SingleReentrancyRelayer.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // interfaces diff --git a/contracts/Mocks/Reentrancy/ThreeReentrancy.sol b/contracts/Mocks/Reentrancy/ThreeReentrancy.sol index 2715082e4..d93f422de 100644 --- a/contracts/Mocks/Reentrancy/ThreeReentrancy.sol +++ b/contracts/Mocks/Reentrancy/ThreeReentrancy.sol @@ -1,5 +1,5 @@ // solhint-disable one-contract-per-file -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; import { diff --git a/contracts/Mocks/Tokens/LSP4CompatibilityTester.sol b/contracts/Mocks/Tokens/LSP4CompatibilityTester.sol index 9ca432621..3edb6de8b 100644 --- a/contracts/Mocks/Tokens/LSP4CompatibilityTester.sol +++ b/contracts/Mocks/Tokens/LSP4CompatibilityTester.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/Mocks/Tokens/LSP7CappedSupplyInitTester.sol b/contracts/Mocks/Tokens/LSP7CappedSupplyInitTester.sol index da0984f8f..286d08d22 100644 --- a/contracts/Mocks/Tokens/LSP7CappedSupplyInitTester.sol +++ b/contracts/Mocks/Tokens/LSP7CappedSupplyInitTester.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/Mocks/Tokens/LSP7CappedSupplyTester.sol b/contracts/Mocks/Tokens/LSP7CappedSupplyTester.sol index 5834fadfa..252d985ce 100644 --- a/contracts/Mocks/Tokens/LSP7CappedSupplyTester.sol +++ b/contracts/Mocks/Tokens/LSP7CappedSupplyTester.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/Mocks/Tokens/LSP7CompatibleERC20InitTester.sol b/contracts/Mocks/Tokens/LSP7CompatibleERC20InitTester.sol index fc1882a35..996b173a9 100644 --- a/contracts/Mocks/Tokens/LSP7CompatibleERC20InitTester.sol +++ b/contracts/Mocks/Tokens/LSP7CompatibleERC20InitTester.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/Mocks/Tokens/LSP7CompatibleERC20Tester.sol b/contracts/Mocks/Tokens/LSP7CompatibleERC20Tester.sol index 1bf28b352..21b1e4891 100644 --- a/contracts/Mocks/Tokens/LSP7CompatibleERC20Tester.sol +++ b/contracts/Mocks/Tokens/LSP7CompatibleERC20Tester.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/Mocks/Tokens/LSP7InitTester.sol b/contracts/Mocks/Tokens/LSP7InitTester.sol index ad1a3b739..5759191f6 100644 --- a/contracts/Mocks/Tokens/LSP7InitTester.sol +++ b/contracts/Mocks/Tokens/LSP7InitTester.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/Mocks/Tokens/LSP7MintWhenDeployed.sol b/contracts/Mocks/Tokens/LSP7MintWhenDeployed.sol index f21c3df60..7c4e15a5f 100644 --- a/contracts/Mocks/Tokens/LSP7MintWhenDeployed.sol +++ b/contracts/Mocks/Tokens/LSP7MintWhenDeployed.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; import {LSP7DigitalAsset} from "../../LSP7DigitalAsset/LSP7DigitalAsset.sol"; diff --git a/contracts/Mocks/Tokens/LSP7Tester.sol b/contracts/Mocks/Tokens/LSP7Tester.sol index 411516e03..ca0744ec8 100644 --- a/contracts/Mocks/Tokens/LSP7Tester.sol +++ b/contracts/Mocks/Tokens/LSP7Tester.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // modules diff --git a/contracts/Mocks/Tokens/LSP8BurnableInitTester.sol b/contracts/Mocks/Tokens/LSP8BurnableInitTester.sol index 6f3e42e1a..1d0d0109d 100644 --- a/contracts/Mocks/Tokens/LSP8BurnableInitTester.sol +++ b/contracts/Mocks/Tokens/LSP8BurnableInitTester.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/Mocks/Tokens/LSP8BurnableTester.sol b/contracts/Mocks/Tokens/LSP8BurnableTester.sol index c0b037d3d..ae492c50d 100644 --- a/contracts/Mocks/Tokens/LSP8BurnableTester.sol +++ b/contracts/Mocks/Tokens/LSP8BurnableTester.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/Mocks/Tokens/LSP8CappedSupplyInitTester.sol b/contracts/Mocks/Tokens/LSP8CappedSupplyInitTester.sol index d411dd7f3..93571c7b4 100644 --- a/contracts/Mocks/Tokens/LSP8CappedSupplyInitTester.sol +++ b/contracts/Mocks/Tokens/LSP8CappedSupplyInitTester.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/Mocks/Tokens/LSP8CappedSupplyTester.sol b/contracts/Mocks/Tokens/LSP8CappedSupplyTester.sol index 015aa92be..a05d2f09f 100644 --- a/contracts/Mocks/Tokens/LSP8CappedSupplyTester.sol +++ b/contracts/Mocks/Tokens/LSP8CappedSupplyTester.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/Mocks/Tokens/LSP8CompatibleERC721Tester.sol b/contracts/Mocks/Tokens/LSP8CompatibleERC721Tester.sol index 475c5e565..705a13515 100644 --- a/contracts/Mocks/Tokens/LSP8CompatibleERC721Tester.sol +++ b/contracts/Mocks/Tokens/LSP8CompatibleERC721Tester.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/Mocks/Tokens/LSP8CompatibleERC721TesterInit.sol b/contracts/Mocks/Tokens/LSP8CompatibleERC721TesterInit.sol index 0b1575b7f..7cb92bf08 100644 --- a/contracts/Mocks/Tokens/LSP8CompatibleERC721TesterInit.sol +++ b/contracts/Mocks/Tokens/LSP8CompatibleERC721TesterInit.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/Mocks/Tokens/LSP8EnumerableInitTester.sol b/contracts/Mocks/Tokens/LSP8EnumerableInitTester.sol index bfc536710..f809100ca 100644 --- a/contracts/Mocks/Tokens/LSP8EnumerableInitTester.sol +++ b/contracts/Mocks/Tokens/LSP8EnumerableInitTester.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/Mocks/Tokens/LSP8EnumerableTester.sol b/contracts/Mocks/Tokens/LSP8EnumerableTester.sol index 43b932e74..f2bde7f42 100644 --- a/contracts/Mocks/Tokens/LSP8EnumerableTester.sol +++ b/contracts/Mocks/Tokens/LSP8EnumerableTester.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/Mocks/Tokens/LSP8InitTester.sol b/contracts/Mocks/Tokens/LSP8InitTester.sol index a5aa6d8c5..9efdabfc2 100644 --- a/contracts/Mocks/Tokens/LSP8InitTester.sol +++ b/contracts/Mocks/Tokens/LSP8InitTester.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/Mocks/Tokens/LSP8Tester.sol b/contracts/Mocks/Tokens/LSP8Tester.sol index 66a7a6639..d6af853dc 100644 --- a/contracts/Mocks/Tokens/LSP8Tester.sol +++ b/contracts/Mocks/Tokens/LSP8Tester.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/Mocks/Tokens/RequireCallbackToken.sol b/contracts/Mocks/Tokens/RequireCallbackToken.sol index abea751ae..e7bacc99b 100644 --- a/contracts/Mocks/Tokens/RequireCallbackToken.sol +++ b/contracts/Mocks/Tokens/RequireCallbackToken.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantA.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantA.sol index b6df6d4be..de7c3e122 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantA.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantA.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // interfaces diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantB.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantB.sol index 228f08aed..9cb236ab2 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantB.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantB.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // interfaces diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultSetter.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultSetter.sol index 8ac881316..9a19b9b08 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultSetter.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultSetter.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // interfaces diff --git a/tests/foundry/GasTests/LSP6s/LSP6ExecuteRC.sol b/tests/foundry/GasTests/LSP6s/LSP6ExecuteRC.sol index 55ef7c7d3..805044d9c 100644 --- a/tests/foundry/GasTests/LSP6s/LSP6ExecuteRC.sol +++ b/tests/foundry/GasTests/LSP6s/LSP6ExecuteRC.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; import "../../../../contracts/LSP6KeyManager/LSP6KeyManager.sol"; diff --git a/tests/foundry/GasTests/LSP6s/LSP6ExecuteUC.sol b/tests/foundry/GasTests/LSP6s/LSP6ExecuteUC.sol index b72f24920..d1fc01615 100644 --- a/tests/foundry/GasTests/LSP6s/LSP6ExecuteUC.sol +++ b/tests/foundry/GasTests/LSP6s/LSP6ExecuteUC.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; import "forge-std/Test.sol"; diff --git a/tests/foundry/GasTests/LSP6s/LSP6SetDataRC.sol b/tests/foundry/GasTests/LSP6s/LSP6SetDataRC.sol index 2d325e159..f4f7aaa9d 100644 --- a/tests/foundry/GasTests/LSP6s/LSP6SetDataRC.sol +++ b/tests/foundry/GasTests/LSP6s/LSP6SetDataRC.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; import "forge-std/Test.sol"; diff --git a/tests/foundry/GasTests/LSP6s/LSP6SetDataUC.sol b/tests/foundry/GasTests/LSP6s/LSP6SetDataUC.sol index adba58552..9687c69f6 100644 --- a/tests/foundry/GasTests/LSP6s/LSP6SetDataUC.sol +++ b/tests/foundry/GasTests/LSP6s/LSP6SetDataUC.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; import "forge-std/Test.sol"; diff --git a/tests/foundry/GasTests/UniversalProfileTestsHelper.sol b/tests/foundry/GasTests/UniversalProfileTestsHelper.sol index 874331271..3cf8d39e2 100644 --- a/tests/foundry/GasTests/UniversalProfileTestsHelper.sol +++ b/tests/foundry/GasTests/UniversalProfileTestsHelper.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; import "forge-std/Test.sol"; diff --git a/tests/foundry/GasTests/execute/RestrictedController.sol b/tests/foundry/GasTests/execute/RestrictedController.sol index a8c0afbcf..34fb01a92 100644 --- a/tests/foundry/GasTests/execute/RestrictedController.sol +++ b/tests/foundry/GasTests/execute/RestrictedController.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; import "../LSP6s/LSP6ExecuteRC.sol"; diff --git a/tests/foundry/GasTests/execute/UnrestrictedController.sol b/tests/foundry/GasTests/execute/UnrestrictedController.sol index 29f9874ab..1f4bab4c1 100644 --- a/tests/foundry/GasTests/execute/UnrestrictedController.sol +++ b/tests/foundry/GasTests/execute/UnrestrictedController.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; import "../LSP6s/LSP6ExecuteUC.sol"; diff --git a/tests/foundry/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.t.sol b/tests/foundry/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.t.sol index 16edbc3c5..1e37dea63 100644 --- a/tests/foundry/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.t.sol +++ b/tests/foundry/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; import "forge-std/Test.sol"; diff --git a/tests/foundry/LSP11BasicSocialRecovery/LSP11Mock.sol b/tests/foundry/LSP11BasicSocialRecovery/LSP11Mock.sol index d1d35b1c6..02414f79f 100644 --- a/tests/foundry/LSP11BasicSocialRecovery/LSP11Mock.sol +++ b/tests/foundry/LSP11BasicSocialRecovery/LSP11Mock.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; import "../../../contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.sol"; diff --git a/tests/foundry/LSP14Ownable2Step/TwoStepOwnership.sol b/tests/foundry/LSP14Ownable2Step/TwoStepOwnership.sol index d5e6486a2..c1e152a47 100644 --- a/tests/foundry/LSP14Ownable2Step/TwoStepOwnership.sol +++ b/tests/foundry/LSP14Ownable2Step/TwoStepOwnership.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; import "forge-std/Test.sol"; diff --git a/tests/foundry/LSP14Ownable2Step/TwoStepRenounceOwnership.sol b/tests/foundry/LSP14Ownable2Step/TwoStepRenounceOwnership.sol index 0a00f8b4b..a017a9fe8 100644 --- a/tests/foundry/LSP14Ownable2Step/TwoStepRenounceOwnership.sol +++ b/tests/foundry/LSP14Ownable2Step/TwoStepRenounceOwnership.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; import "forge-std/Test.sol"; diff --git a/tests/foundry/LSP16UniversalFactory/LSP16UniversalProfile.t.sol b/tests/foundry/LSP16UniversalFactory/LSP16UniversalProfile.t.sol index 9371afd89..48d4c397b 100644 --- a/tests/foundry/LSP16UniversalFactory/LSP16UniversalProfile.t.sol +++ b/tests/foundry/LSP16UniversalFactory/LSP16UniversalProfile.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; import "forge-std/Test.sol"; diff --git a/tests/foundry/LSP2ERC725YJSONSchema/LSP2Utils.t.sol b/tests/foundry/LSP2ERC725YJSONSchema/LSP2Utils.t.sol index 0e217913e..677e6b409 100644 --- a/tests/foundry/LSP2ERC725YJSONSchema/LSP2Utils.t.sol +++ b/tests/foundry/LSP2ERC725YJSONSchema/LSP2Utils.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; import "forge-std/Test.sol"; diff --git a/tests/foundry/LSP6KeyManager/LSP6SetDataTest.t.sol b/tests/foundry/LSP6KeyManager/LSP6SetDataTest.t.sol index 75c862208..f8e4901f8 100644 --- a/tests/foundry/LSP6KeyManager/LSP6SetDataTest.t.sol +++ b/tests/foundry/LSP6KeyManager/LSP6SetDataTest.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; import "forge-std/Test.sol"; diff --git a/tests/foundry/LSP6KeyManager/LSP6Utils.t.sol b/tests/foundry/LSP6KeyManager/LSP6Utils.t.sol index 568a4f8af..2affc1f25 100644 --- a/tests/foundry/LSP6KeyManager/LSP6Utils.t.sol +++ b/tests/foundry/LSP6KeyManager/LSP6Utils.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; import "forge-std/Test.sol"; From a61ab9d639f4119ab333867048cd75ad482dbe3f Mon Sep 17 00:00:00 2001 From: CJ42 Date: Tue, 26 Sep 2023 09:29:11 +0100 Subject: [PATCH 22/55] docs: add Code4Rena audit report --- README.md | 1 + audits/README.md | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 audits/README.md diff --git a/README.md b/README.md index 7e76fd392..a5fff68d1 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,7 @@ The following audits and formal verification were conducted. All high-level issu - Runtime Verification - Formal Verification, 2023-02-20, Final Result: [RuntimeVerification_formalVerification_2023_02_20.pdf](./audits/RuntimeVerification_formalVerification_2023_02_20.pdf) - Trust Audit, 2023-04-13, Final Result: [Trust_audit_2023_04_13.pdf](./audits/Trust_audit_2023_04_13.pdf) - Watchpug Audit, 2023-04-21, Final Result: [Watchpug_audit_2023_04_21.pdf](./audits/Watchpug_audit_2023_04_21.pdf) +- Code4Rena Audit Contest, 2023-06-30 to 2023-07-14, Final Result: [See Code4Rena audit report on Code4rena.com website](https://code4rena.com/reports/2023-06-lukso) ## Contributors ✨ diff --git a/audits/README.md b/audits/README.md new file mode 100644 index 000000000..7871ca659 --- /dev/null +++ b/audits/README.md @@ -0,0 +1,3 @@ +# Smart Contracts Audits + +In addition to the audits reports in pdf available in this page, you can find the audit report of the **Code4Rena audit contest** at the following link: [https://code4rena.com/reports/2021-05-lukso](https://code4rena.com/reports/2021-05-lukso) From f1686d51fbe8cdd253fa678bd8a656e07514059f Mon Sep 17 00:00:00 2001 From: Yamen Merhi Date: Wed, 27 Sep 2023 10:36:54 +0300 Subject: [PATCH 23/55] chore: [C4] Add first batch of Gas optimization (#695) * chore: [C4] Add first batch of Gas optimization * chore: replace `= 0` assignment in iterators of LSP7/8 Core * chore: add more gas optimizations * docs: generate docs * chore: run prettier * docs: add latest docs * chore: resolve failing tesst * chore: suggested changes --------- Co-authored-by: CJ42 --- .../LSP0ERC725AccountCore.sol | 8 +- .../LSP1UniversalReceiverDelegateUP.sol | 2 +- .../LSP1UniversalReceiverDelegateVault.sol | 2 +- .../LSP20CallVerification.sol | 2 +- .../LSP25MultiChannelNonce.sol | 3 +- contracts/LSP2ERC725YJSONSchema/LSP2Utils.sol | 68 ------------- .../LSP6KeyManager/LSP6KeyManagerCore.sol | 95 ++++++++++++------- .../LSP6Modules/LSP6ExecuteModule.sol | 2 +- contracts/LSP6KeyManager/LSP6Utils.sol | 2 +- .../LSP7DigitalAsset/LSP7DigitalAssetCore.sol | 38 ++++---- .../LSP8IdentifiableDigitalAssetCore.sol | 35 +++---- .../LSP8CompatibleERC721InitAbstract.sol | 8 +- contracts/LSP9Vault/LSP9VaultCore.sol | 4 +- .../KeyManager/KeyManagerInternalsTester.sol | 2 +- .../LSP6KeyManager/LSP6KeyManager.md | 25 +++-- .../LSP2ERC725YJSONSchema/LSP2Utils.md | 44 --------- 16 files changed, 127 insertions(+), 213 deletions(-) diff --git a/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol b/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol index 44335ecd7..faaa839a4 100644 --- a/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol +++ b/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol @@ -146,7 +146,7 @@ abstract contract LSP0ERC725AccountCore is if (!success) { // Look for revert reason and bubble it up if present - if (result.length > 0) { + if (result.length != 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable no-inline-assembly /// @solidity memory-safe-assembly @@ -341,7 +341,7 @@ abstract contract LSP0ERC725AccountCore is // If the caller is the owner perform setData directly if (msg.sender == _owner) { - for (uint256 i = 0; i < dataKeys.length; ) { + for (uint256 i; i < dataKeys.length; ) { _setData(dataKeys[i], dataValues[i]); unchecked { @@ -356,7 +356,7 @@ abstract contract LSP0ERC725AccountCore is // Depending on the magicValue returned, a second call is done after setting data bool verifyAfter = _verifyCall(_owner); - for (uint256 i = 0; i < dataKeys.length; ) { + for (uint256 i; i < dataKeys.length; ) { _setData(dataKeys[i], dataValues[i]); unchecked { @@ -671,7 +671,7 @@ abstract contract LSP0ERC725AccountCore is address _owner = owner(); // If owner is a contract - if (_owner.code.length > 0) { + if (_owner.code.length != 0) { (bool success, bytes memory result) = _owner.staticcall( abi.encodeWithSelector( IERC1271.isValidSignature.selector, diff --git a/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol b/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol index 8527981a3..9746e154d 100644 --- a/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol +++ b/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol @@ -172,7 +172,7 @@ contract LSP1UniversalReceiverDelegateUP is ERC165, ILSP1UniversalReceiver { ) internal returns (bytes memory) { // CHECK balance only when the Token contract is already deployed, // not when tokens are being transferred on deployment through the `constructor` - if (notifier.code.length > 0) { + if (notifier.code.length != 0) { // if the amount sent is 0, then do not update the keys try ILSP7DigitalAsset(notifier).balanceOf(msg.sender) returns ( uint256 balance diff --git a/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol b/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol index 34f6144bd..e36960943 100644 --- a/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol +++ b/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol @@ -148,7 +148,7 @@ contract LSP1UniversalReceiverDelegateVault is ERC165, ILSP1UniversalReceiver { ) internal returns (bytes memory) { // CHECK balance only when the Token contract is already deployed, // not when tokens are being transferred on deployment through the `constructor` - if (notifier.code.length > 0) { + if (notifier.code.length != 0) { // if the amount sent is 0, then do not update the keys try ILSP7DigitalAsset(notifier).balanceOf(msg.sender) returns ( uint256 balance diff --git a/contracts/LSP20CallVerification/LSP20CallVerification.sol b/contracts/LSP20CallVerification/LSP20CallVerification.sol index 5c1477d24..0466a6809 100644 --- a/contracts/LSP20CallVerification/LSP20CallVerification.sol +++ b/contracts/LSP20CallVerification/LSP20CallVerification.sol @@ -89,7 +89,7 @@ abstract contract LSP20CallVerification { bytes memory returnedData ) internal pure virtual { // Look for revert reason and bubble it up if present - if (returnedData.length > 0) { + if (returnedData.length != 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable no-inline-assembly /// @solidity memory-safe-assembly diff --git a/contracts/LSP25ExecuteRelayCall/LSP25MultiChannelNonce.sol b/contracts/LSP25ExecuteRelayCall/LSP25MultiChannelNonce.sol index 15dbc1cb7..2d6c33598 100644 --- a/contracts/LSP25ExecuteRelayCall/LSP25MultiChannelNonce.sol +++ b/contracts/LSP25ExecuteRelayCall/LSP25MultiChannelNonce.sol @@ -56,8 +56,7 @@ abstract contract LSP25MultiChannelNonce { address from, uint128 channelId ) internal view virtual returns (uint256 idx) { - uint256 nonceInChannel = _nonceStore[from][channelId]; - return (uint256(channelId) << 128) | nonceInChannel; + return (uint256(channelId) << 128) | _nonceStore[from][channelId]; } /** diff --git a/contracts/LSP2ERC725YJSONSchema/LSP2Utils.sol b/contracts/LSP2ERC725YJSONSchema/LSP2Utils.sol index ff5d87553..06fd72f1d 100644 --- a/contracts/LSP2ERC725YJSONSchema/LSP2Utils.sol +++ b/contracts/LSP2ERC725YJSONSchema/LSP2Utils.sol @@ -308,74 +308,6 @@ library LSP2Utils { return true; } - /** - * @dev Verify if `data` is an abi-encoded array of addresses (`address[]`) encoded according to the ABI specs. - * - * @param data The bytes value to verify. - * - * @return `true` if the `data` represents an abi-encoded array of addresses, `false` otherwise. - */ - function isEncodedArrayOfAddresses( - bytes memory data - ) internal pure returns (bool) { - if (!isEncodedArray(data)) return false; - - uint256 offset = uint256(bytes32(data)); - uint256 arrayLength = data.toUint256(offset); - - uint256 pointer = offset + 32; - - for (uint256 ii = 0; ii < arrayLength; ) { - bytes32 key = data.toBytes32(pointer); - - // check that the leading bytes are zero bytes "00" - // NB: address type is padded on the left (unlike bytes20 type that is padded on the right) - if (bytes12(key) != bytes12(0)) return false; - - // increment the pointer - pointer += 32; - - unchecked { - ++ii; - } - } - - return true; - } - - /** - * @dev Verify if `data` is an abi-array of `bytes4` values (`bytes4[]`) encoded according to the ABI specs. - * - * @param data The bytes value to verify. - * - * @return `true` if the `data` represents an abi-encoded array of `bytes4`, `false` otherwise. - */ - function isBytes4EncodedArray( - bytes memory data - ) internal pure returns (bool) { - if (!isEncodedArray(data)) return false; - - uint256 offset = uint256(bytes32(data)); - uint256 arrayLength = data.toUint256(offset); - uint256 pointer = offset + 32; - - for (uint256 ii = 0; ii < arrayLength; ) { - bytes32 key = data.toBytes32(pointer); - - // check that the trailing bytes are zero bytes "00" - if (uint224(uint256(key)) != 0) return false; - - // increment the pointer - pointer += 32; - - unchecked { - ++ii; - } - } - - return true; - } - /** * @dev Verify if `data` is a valid array of value encoded as a `CompactBytesArray` according to the LSP2 `CompactBytesArray` valueType specification. * diff --git a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol index 369a390ca..f51fcf6c1 100644 --- a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol +++ b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol @@ -94,7 +94,9 @@ abstract contract LSP6KeyManagerCore is // Variables, methods and modifier used for ReentrancyGuard are taken from the link below and modified accordingly. // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.8/contracts/security/ReentrancyGuard.sol - bool internal _reentrancyStatus; + uint8 internal _reentrancyStatus; + uint8 internal constant _NOT_ENTERED = 1; + uint8 internal constant _ENTERED = 2; /** * @inheritdoc ILSP6 @@ -195,7 +197,7 @@ abstract contract LSP6KeyManagerCore is bytes[] memory results = new bytes[](payloads.length); uint256 totalValues; - for (uint256 ii = 0; ii < payloads.length; ) { + for (uint256 ii; ii < payloads.length; ) { if ((totalValues += values[ii]) > msg.value) { revert LSP6BatchInsufficientValueSent(totalValues, msg.value); } @@ -278,7 +280,7 @@ abstract contract LSP6KeyManagerCore is bytes[] memory results = new bytes[](payloads.length); uint256 totalValues; - for (uint256 ii = 0; ii < payloads.length; ) { + for (uint256 ii; ii < payloads.length; ) { if ((totalValues += values[ii]) > msg.value) { revert LSP6BatchInsufficientValueSent(totalValues, msg.value); } @@ -329,37 +331,43 @@ abstract contract LSP6KeyManagerCore is isSetData = true; } + address targetContract = _target; + // If target is invoking the verification, emit the event and change the reentrancy guard - if (msg.sender == _target) { - bool isReentrantCall = _nonReentrantBefore(isSetData, caller); + if (msg.sender == targetContract) { + uint8 reentrancyStatus = _nonReentrantBefore( + targetContract, + isSetData, + caller + ); - _verifyPermissions(caller, msgValue, data); + _verifyPermissions(targetContract, caller, msgValue, data); emit PermissionsVerified(caller, msgValue, bytes4(data)); // if it's a setData call, do not invoke the `lsp20VerifyCallResult(..)` function return - isSetData || isReentrantCall + isSetData || (reentrancyStatus == _ENTERED) ? _LSP20_VERIFY_CALL_MAGIC_VALUE_WITHOUT_POST_VERIFICATION : _LSP20_VERIFY_CALL_MAGIC_VALUE_WITH_POST_VERIFICATION; } /// @dev If a different address is invoking the verification, /// do not change the state or emit the event to allow read-only verification else { - bool isReentrantCall = _reentrancyStatus; + uint8 reentrancyStatus = _reentrancyStatus; - if (isReentrantCall) { + if (reentrancyStatus == _ENTERED) { _requirePermissions( caller, - ERC725Y(_target).getPermissionsFor(caller), + ERC725Y(targetContract).getPermissionsFor(caller), _PERMISSION_REENTRANCY ); } - _verifyPermissions(caller, msgValue, data); + _verifyPermissions(targetContract, caller, msgValue, data); // if it's a setData call, do not invoke the `lsp20VerifyCallResult(..)` function return - isSetData || isReentrantCall + isSetData || (reentrancyStatus == _ENTERED) ? _LSP20_VERIFY_CALL_MAGIC_VALUE_WITHOUT_POST_VERIFICATION : _LSP20_VERIFY_CALL_MAGIC_VALUE_WITH_POST_VERIFICATION; } @@ -396,14 +404,24 @@ abstract contract LSP6KeyManagerCore is isSetData = true; } - bool isReentrantCall = _nonReentrantBefore(isSetData, msg.sender); + address targetContract = _target; + + uint8 reentrancyStatus = _nonReentrantBefore( + targetContract, + isSetData, + msg.sender + ); - _verifyPermissions(msg.sender, msgValue, payload); + _verifyPermissions(targetContract, msg.sender, msgValue, payload); emit PermissionsVerified(msg.sender, msgValue, bytes4(payload)); - bytes memory result = _executePayload(msgValue, payload); + bytes memory result = _executePayload( + targetContract, + msgValue, + payload + ); - if (!isReentrantCall && !isSetData) { + if (reentrancyStatus == _NOT_ENTERED && !isSetData) { _nonReentrantAfter(); } @@ -435,6 +453,8 @@ abstract contract LSP6KeyManagerCore is revert InvalidPayload(payload); } + address targetContract = _target; + address signer = LSP25MultiChannelNonce ._recoverSignerFromLSP25Signature( signature, @@ -461,14 +481,22 @@ abstract contract LSP6KeyManagerCore is isSetData = true; } - bool isReentrantCall = _nonReentrantBefore(isSetData, signer); + uint8 reentrancyStatus = _nonReentrantBefore( + targetContract, + isSetData, + signer + ); - _verifyPermissions(signer, msgValue, payload); + _verifyPermissions(targetContract, signer, msgValue, payload); emit PermissionsVerified(signer, msgValue, bytes4(payload)); - bytes memory result = _executePayload(msgValue, payload); + bytes memory result = _executePayload( + targetContract, + msgValue, + payload + ); - if (!isReentrantCall && !isSetData) { + if (reentrancyStatus == _NOT_ENTERED && !isSetData) { _nonReentrantAfter(); } @@ -481,10 +509,11 @@ abstract contract LSP6KeyManagerCore is * @return bytes The data returned by the call made to the linked {target} contract. */ function _executePayload( + address targetContract, uint256 msgValue, bytes calldata payload ) internal virtual returns (bytes memory) { - (bool success, bytes memory returnData) = _target.call{ + (bool success, bytes memory returnData) = targetContract.call{ value: msgValue, gas: gasleft() }(payload); @@ -503,11 +532,12 @@ abstract contract LSP6KeyManagerCore is * @param payload The abi-encoded function call to execute on the {target} contract. */ function _verifyPermissions( + address targetContract, address from, uint256 msgValue, bytes calldata payload ) internal view virtual { - bytes32 permissions = ERC725Y(_target).getPermissionsFor(from); + bytes32 permissions = ERC725Y(targetContract).getPermissionsFor(from); if (permissions == bytes32(0)) revert NoPermissionsSet(from); bytes4 erc725Function = bytes4(payload); @@ -521,7 +551,7 @@ abstract contract LSP6KeyManagerCore is ); LSP6SetDataModule._verifyCanSetData( - _target, + targetContract, from, permissions, inputKey, @@ -535,7 +565,7 @@ abstract contract LSP6KeyManagerCore is .decode(payload[4:], (bytes32[], bytes[])); LSP6SetDataModule._verifyCanSetData( - _target, + targetContract, from, permissions, inputKeys, @@ -552,7 +582,7 @@ abstract contract LSP6KeyManagerCore is ) = abi.decode(payload[4:], (uint256, address, uint256, bytes)); LSP6ExecuteModule._verifyCanExecute( - _target, + targetContract, from, permissions, operationType, @@ -574,7 +604,7 @@ abstract contract LSP6KeyManagerCore is * @dev Initialise _reentrancyStatus to _NOT_ENTERED. */ function _setupLSP6ReentrancyGuard() internal virtual { - _reentrancyStatus = false; + _reentrancyStatus = 1; } /** @@ -583,20 +613,21 @@ abstract contract LSP6KeyManagerCore is * Used in the beginning of the `nonReentrant` modifier, before the method execution starts. */ function _nonReentrantBefore( + address targetContract, bool isSetData, address from - ) internal virtual returns (bool isReentrantCall) { - isReentrantCall = _reentrancyStatus; - if (isReentrantCall) { + ) internal virtual returns (uint8 reentrancyStatus) { + reentrancyStatus = _reentrancyStatus; + if (reentrancyStatus == _ENTERED) { // CHECK the caller has REENTRANCY permission _requirePermissions( from, - ERC725Y(_target).getPermissionsFor(from), + ERC725Y(targetContract).getPermissionsFor(from), _PERMISSION_REENTRANCY ); } else { if (!isSetData) { - _reentrancyStatus = true; + _reentrancyStatus = _ENTERED; } } } @@ -608,7 +639,7 @@ abstract contract LSP6KeyManagerCore is function _nonReentrantAfter() internal virtual { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) - _reentrancyStatus = false; + _reentrancyStatus = _NOT_ENTERED; } /** diff --git a/contracts/LSP6KeyManager/LSP6Modules/LSP6ExecuteModule.sol b/contracts/LSP6KeyManager/LSP6Modules/LSP6ExecuteModule.sol index 1747ca931..f3aab5d24 100644 --- a/contracts/LSP6KeyManager/LSP6Modules/LSP6ExecuteModule.sol +++ b/contracts/LSP6KeyManager/LSP6Modules/LSP6ExecuteModule.sol @@ -261,7 +261,7 @@ abstract contract LSP6ExecuteModule { isEmptyCall ); - for (uint256 ii = 0; ii < allowedCalls.length; ii += 34) { + for (uint256 ii; ii < allowedCalls.length; ii += 34) { /// @dev structure of an AllowedCall // /// AllowedCall = 0x00200000000ncafecafecafecafecafecafecafecafecafecafe5a5a5a5af1f1f1f1 diff --git a/contracts/LSP6KeyManager/LSP6Utils.sol b/contracts/LSP6KeyManager/LSP6Utils.sol index ea76fe73b..ccc9a2f38 100644 --- a/contracts/LSP6KeyManager/LSP6Utils.sol +++ b/contracts/LSP6KeyManager/LSP6Utils.sol @@ -213,7 +213,7 @@ library LSP6Utils { bytes32[] memory permissions ) internal pure returns (bytes32) { bytes32 result; - for (uint256 i = 0; i < permissions.length; i++) { + for (uint256 i; i < permissions.length; i++) { result |= permissions[i]; } return result; diff --git a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol index ee1bca998..a50ca839e 100644 --- a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol +++ b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol @@ -176,19 +176,21 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { ) public virtual { if (from == to) revert LSP7CannotSendToSelf(); - address operator = msg.sender; - if (operator != from) { - uint256 operatorAmount = _operatorAuthorizedAmount[from][operator]; + // if the caller is an operator + if (msg.sender != from) { + uint256 operatorAmount = _operatorAuthorizedAmount[from][ + msg.sender + ]; if (amount > operatorAmount) { revert LSP7AmountExceedsAuthorizedAmount( from, operatorAmount, - operator, + msg.sender, amount ); } - _updateOperator(from, operator, operatorAmount - amount, ""); + _updateOperator(from, msg.sender, operatorAmount - amount, ""); } _transfer(from, to, amount, force, data); @@ -214,7 +216,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { revert LSP7InvalidTransferBatch(); } - for (uint256 i = 0; i < fromLength; ) { + for (uint256 i; i < fromLength; ) { // using the public transfer function to handle updates to operator authorized amounts transfer(from[i], to[i], amount[i], force[i], data[i]); @@ -388,8 +390,6 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { revert LSP7CannotSendWithAddressZero(); } - address operator = msg.sender; - _beforeTokenTransfer(address(0), to, amount); // tokens being minted @@ -397,7 +397,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { _tokenOwnerBalances[to] += amount; - emit Transfer(operator, address(0), to, amount, force, data); + emit Transfer(msg.sender, address(0), to, amount, force, data); bytes memory lsp1Data = abi.encode(address(0), to, amount, data); _notifyTokenReceiver(to, force, lsp1Data); @@ -440,20 +440,22 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { revert LSP7AmountExceedsBalance(balance, from, amount); } - address operator = msg.sender; - if (operator != from) { + // if the caller is an operator + if (msg.sender != from) { uint256 authorizedAmount = _operatorAuthorizedAmount[from][ - operator + msg.sender ]; if (amount > authorizedAmount) { revert LSP7AmountExceedsAuthorizedAmount( from, authorizedAmount, - operator, + msg.sender, amount ); } - _operatorAuthorizedAmount[from][operator] -= amount; + _operatorAuthorizedAmount[from][msg.sender] = + authorizedAmount - + amount; } _beforeTokenTransfer(from, address(0), amount); @@ -463,7 +465,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { _tokenOwnerBalances[from] -= amount; - emit Transfer(operator, from, address(0), amount, false, data); + emit Transfer(msg.sender, from, address(0), amount, false, data); bytes memory lsp1Data = abi.encode(from, address(0), amount, data); _notifyTokenSender(from, lsp1Data); @@ -508,14 +510,12 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { revert LSP7AmountExceedsBalance(balance, from, amount); } - address operator = msg.sender; - _beforeTokenTransfer(from, to, amount); _tokenOwnerBalances[from] -= amount; _tokenOwnerBalances[to] += amount; - emit Transfer(operator, from, to, amount, force, data); + emit Transfer(msg.sender, from, to, amount, force, data); bytes memory lsp1Data = abi.encode(from, to, amount, data); @@ -618,7 +618,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { lsp1Data ); } else if (!force) { - if (to.code.length > 0) { + if (to.code.length != 0) { revert LSP7NotifyTokenReceiverContractMissingLSP1Interface(to); } else { revert LSP7NotifyTokenReceiverIsEOA(to); diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol index 7a41e367b..518bdb4f5 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol @@ -222,9 +222,8 @@ abstract contract LSP8IdentifiableDigitalAssetCore is address caller, bytes32 tokenId ) internal view virtual returns (bool) { - address tokenOwner = tokenOwnerOf(tokenId); - - return (caller == tokenOwner || _operators[tokenId].contains(caller)); + return (caller == tokenOwnerOf(tokenId) || + _operators[tokenId].contains(caller)); } // --- Transfer functionality @@ -239,10 +238,8 @@ abstract contract LSP8IdentifiableDigitalAssetCore is bool force, bytes memory data ) public virtual { - address operator = msg.sender; - - if (!_isOperatorOrOwner(operator, tokenId)) { - revert LSP8NotTokenOperator(tokenId, operator); + if (!_isOperatorOrOwner(msg.sender, tokenId)) { + revert LSP8NotTokenOperator(tokenId, msg.sender); } _transfer(from, to, tokenId, force, data); @@ -268,7 +265,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is revert LSP8InvalidTransferBatch(); } - for (uint256 i = 0; i < fromLength; ) { + for (uint256 i; i < fromLength; ) { transfer(from[i], to[i], tokenId[i], force[i], data[i]); unchecked { @@ -317,9 +314,10 @@ abstract contract LSP8IdentifiableDigitalAssetCore is ]; uint256 operatorListLength = operatorsForTokenId.length(); - for (uint256 i = 0; i < operatorListLength; ) { + address operator; + for (uint256 i; i < operatorListLength; ) { // we are emptying the list, always remove from index 0 - address operator = operatorsForTokenId.at(0); + operator = operatorsForTokenId.at(0); _revokeOperator(operator, tokenOwner, tokenId, ""); unchecked { @@ -374,17 +372,15 @@ abstract contract LSP8IdentifiableDigitalAssetCore is revert LSP8TokenIdAlreadyMinted(tokenId); } - address operator = msg.sender; - _beforeTokenTransfer(address(0), to, tokenId); // token being minted - _existingTokens += 1; + ++_existingTokens; _ownedTokens[to].add(tokenId); _tokenOwners[tokenId] = to; - emit Transfer(operator, address(0), to, tokenId, force, data); + emit Transfer(msg.sender, address(0), to, tokenId, force, data); bytes memory lsp1Data = abi.encode(address(0), to, tokenId, data); _notifyTokenReceiver(to, force, lsp1Data); @@ -412,19 +408,18 @@ abstract contract LSP8IdentifiableDigitalAssetCore is */ function _burn(bytes32 tokenId, bytes memory data) internal virtual { address tokenOwner = tokenOwnerOf(tokenId); - address operator = msg.sender; _beforeTokenTransfer(tokenOwner, address(0), tokenId); // token being burned - _existingTokens -= 1; + --_existingTokens; _clearOperators(tokenOwner, tokenId); _ownedTokens[tokenOwner].remove(tokenId); delete _tokenOwners[tokenId]; - emit Transfer(operator, tokenOwner, address(0), tokenId, false, data); + emit Transfer(msg.sender, tokenOwner, address(0), tokenId, false, data); bytes memory lsp1Data = abi.encode( tokenOwner, @@ -478,8 +473,6 @@ abstract contract LSP8IdentifiableDigitalAssetCore is revert LSP8CannotSendToAddressZero(); } - address operator = msg.sender; - _beforeTokenTransfer(from, to, tokenId); _clearOperators(from, tokenId); @@ -488,7 +481,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is _ownedTokens[to].add(tokenId); _tokenOwners[tokenId] = to; - emit Transfer(operator, from, to, tokenId, force, data); + emit Transfer(msg.sender, from, to, tokenId, force, data); bytes memory lsp1Data = abi.encode(from, to, tokenId, data); @@ -581,7 +574,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is lsp1Data ); } else if (!force) { - if (to.code.length > 0) { + if (to.code.length != 0) { revert LSP8NotifyTokenReceiverContractMissingLSP1Interface(to); } else { revert LSP8NotifyTokenReceiverIsEOA(to); diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol index b524cd111..42cd8f02e 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol @@ -289,13 +289,11 @@ abstract contract LSP8CompatibleERC721InitAbstract is bool force, bytes memory data ) internal virtual override { - address operator = msg.sender; - if ( - !isApprovedForAll(from, operator) && - !_isOperatorOrOwner(operator, tokenId) + !isApprovedForAll(from, msg.sender) && + !_isOperatorOrOwner(msg.sender, tokenId) ) { - revert LSP8NotTokenOperator(tokenId, operator); + revert LSP8NotTokenOperator(tokenId, msg.sender); } emit Transfer(from, to, uint256(tokenId)); diff --git a/contracts/LSP9Vault/LSP9VaultCore.sol b/contracts/LSP9Vault/LSP9VaultCore.sol index 225518887..15f8853da 100644 --- a/contracts/LSP9Vault/LSP9VaultCore.sol +++ b/contracts/LSP9Vault/LSP9VaultCore.sol @@ -92,7 +92,7 @@ contract LSP9VaultCore is * @custom:events {ValueReceived} when receiving native tokens. */ receive() external payable virtual { - if (msg.value > 0) emit ValueReceived(msg.sender, msg.value); + if (msg.value != 0) emit ValueReceived(msg.sender, msg.value); } /** @@ -147,7 +147,7 @@ contract LSP9VaultCore is if (!success) { // Look for revert reason and bubble it up if present - if (result.length > 0) { + if (result.length != 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable no-inline-assembly /// @solidity memory-safe-assembly diff --git a/contracts/Mocks/KeyManager/KeyManagerInternalsTester.sol b/contracts/Mocks/KeyManager/KeyManagerInternalsTester.sol index dde9bfa47..007a58dfb 100644 --- a/contracts/Mocks/KeyManager/KeyManagerInternalsTester.sol +++ b/contracts/Mocks/KeyManager/KeyManagerInternalsTester.sol @@ -118,7 +118,7 @@ contract KeyManagerInternalTester is LSP6KeyManager { uint256 msgValue, bytes calldata payload ) public { - super._verifyPermissions(from, msgValue, payload); + super._verifyPermissions(target(), from, msgValue, payload); // This event is emitted just for a sake of not marking this function as `view`, // as Hardhat has a bug that does not catch error that occured from failed `abi.decode` diff --git a/docs/contracts/LSP6KeyManager/LSP6KeyManager.md b/docs/contracts/LSP6KeyManager/LSP6KeyManager.md index 95e13300c..024890611 100644 --- a/docs/contracts/LSP6KeyManager/LSP6KeyManager.md +++ b/docs/contracts/LSP6KeyManager/LSP6KeyManager.md @@ -1124,6 +1124,7 @@ and conform to the signature format according to the LSP25 standard. ```solidity function _executePayload( + address targetContract, uint256 msgValue, bytes payload ) internal nonpayable returns (bytes); @@ -1133,10 +1134,11 @@ _Execute the `payload` passed to `execute(...)` or `executeRelayCall(...)`_ #### Parameters -| Name | Type | Description | -| ---------- | :-------: | ------------------------------------------------------------------ | -| `msgValue` | `uint256` | - | -| `payload` | `bytes` | The abi-encoded function call to execute on the {target} contract. | +| Name | Type | Description | +| ---------------- | :-------: | ------------------------------------------------------------------ | +| `targetContract` | `address` | - | +| `msgValue` | `uint256` | - | +| `payload` | `bytes` | The abi-encoded function call to execute on the {target} contract. | #### Returns @@ -1150,6 +1152,7 @@ _Execute the `payload` passed to `execute(...)` or `executeRelayCall(...)`_ ```solidity function _verifyPermissions( + address targetContract, address from, uint256 msgValue, bytes payload @@ -1160,11 +1163,12 @@ Verify if the `from` address is allowed to execute the `payload` on the [`target #### Parameters -| Name | Type | Description | -| ---------- | :-------: | ------------------------------------------------------------------- | -| `from` | `address` | Either the caller of {execute} or the signer of {executeRelayCall}. | -| `msgValue` | `uint256` | - | -| `payload` | `bytes` | The abi-encoded function call to execute on the {target} contract. | +| Name | Type | Description | +| ---------------- | :-------: | ------------------------------------------------------------------- | +| `targetContract` | `address` | - | +| `from` | `address` | Either the caller of {execute} or the signer of {executeRelayCall}. | +| `msgValue` | `uint256` | - | +| `payload` | `bytes` | The abi-encoded function call to execute on the {target} contract. |
@@ -1182,9 +1186,10 @@ Initialise \_reentrancyStatus to \_NOT_ENTERED. ```solidity function _nonReentrantBefore( + address targetContract, bool isSetData, address from -) internal nonpayable returns (bool isReentrantCall); +) internal nonpayable returns (uint8 reentrancyStatus); ``` Update the status from `_NON_ENTERED` to `_ENTERED` and checks if diff --git a/docs/libraries/LSP2ERC725YJSONSchema/LSP2Utils.md b/docs/libraries/LSP2ERC725YJSONSchema/LSP2Utils.md index 516377228..34debe873 100644 --- a/docs/libraries/LSP2ERC725YJSONSchema/LSP2Utils.md +++ b/docs/libraries/LSP2ERC725YJSONSchema/LSP2Utils.md @@ -361,50 +361,6 @@ Verify if `data` is an abi-encoded array.
-### isEncodedArrayOfAddresses - -```solidity -function isEncodedArrayOfAddresses(bytes data) internal pure returns (bool); -``` - -Verify if `data` is an abi-encoded array of addresses (`address[]`) encoded according to the ABI specs. - -#### Parameters - -| Name | Type | Description | -| ------ | :-----: | -------------------------- | -| `data` | `bytes` | The bytes value to verify. | - -#### Returns - -| Name | Type | Description | -| ---- | :----: | ------------------------------------------------------------------------------------- | -| `0` | `bool` | `true` if the `data` represents an abi-encoded array of addresses, `false` otherwise. | - -
- -### isBytes4EncodedArray - -```solidity -function isBytes4EncodedArray(bytes data) internal pure returns (bool); -``` - -Verify if `data` is an abi-array of `bytes4` values (`bytes4[]`) encoded according to the ABI specs. - -#### Parameters - -| Name | Type | Description | -| ------ | :-----: | -------------------------- | -| `data` | `bytes` | The bytes value to verify. | - -#### Returns - -| Name | Type | Description | -| ---- | :----: | ------------------------------------------------------------------------------------ | -| `0` | `bool` | `true` if the `data` represents an abi-encoded array of `bytes4`, `false` otherwise. | - -
- ### isCompactBytesArray ```solidity From ec5880078a889ce86531078332bc389c390d90e5 Mon Sep 17 00:00:00 2001 From: Yamen Merhi Date: Wed, 27 Sep 2023 13:12:46 +0300 Subject: [PATCH 24/55] chore: [C4] Add first batch of QA fixes (#693) * chore: apply first batch of QAs from Code4rena * test: add tests to UniversalProfile * test: add tests in LSP4 to ensure not value can be locked in contract via `setData` and `setDataBatch` * chore: add latest QA * chore: suggested changes * fix: re-fetch token owner after `_beforeTokenTransfer` hooks --------- Co-authored-by: CJ42 --- .../LSP0ERC725AccountCore.sol | 57 +++++++++++-------- .../LSP14Ownable2Step/ILSP14Ownable2Step.sol | 2 +- .../LSP20CallVerification.sol | 8 ++- .../LSP20CallVerification/LSP20Errors.sol | 6 ++ .../LSP6KeyManager/LSP6KeyManagerCore.sol | 27 ++------- .../LSP7DigitalAsset/LSP7DigitalAssetCore.sol | 14 ++--- .../LSP8IdentifiableDigitalAssetCore.sol | 13 +++++ .../LSP0ERC725Account/LSP0ERC725Account.md | 54 +++++++++++++++++- .../LSP14Ownable2Step/LSP14Ownable2Step.md | 2 +- .../LSP7DigitalAsset/LSP7DigitalAsset.md | 10 ++-- .../extensions/LSP7Burnable.md | 10 ++-- .../extensions/LSP7CappedSupply.md | 10 ++-- .../extensions/LSP7CompatibleERC20.md | 10 ++-- .../presets/LSP7CompatibleERC20Mintable.md | 10 ++-- .../LSP7DigitalAsset/presets/LSP7Mintable.md | 10 ++-- docs/contracts/LSP9Vault/LSP9Vault.md | 2 +- docs/contracts/UniversalProfile.md | 54 +++++++++++++++++- .../LSP20CallVerification.behaviour.ts | 24 ++++---- .../LSP20WithLSP14.behaviour.ts | 28 ++++----- .../LSP4DigitalAssetMetadata.behaviour.ts | 26 +++++++++ tests/UniversalProfile.behaviour.ts | 13 ++++- 21 files changed, 272 insertions(+), 118 deletions(-) diff --git a/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol b/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol index faaa839a4..acf930d68 100644 --- a/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol +++ b/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol @@ -39,7 +39,7 @@ import { _TYPEID_LSP0_OwnershipTransferStarted, _TYPEID_LSP0_OwnershipTransferred_SenderNotification, _TYPEID_LSP0_OwnershipTransferred_RecipientNotification -} from "../LSP0ERC725Account/LSP0Constants.sol"; +} from "./LSP0Constants.sol"; import { _INTERFACEID_LSP1, _LSP1_UNIVERSAL_RECEIVER_DELEGATE_PREFIX, @@ -56,7 +56,8 @@ import { // errors import { - ERC725Y_DataKeysValuesLengthMismatch + ERC725Y_DataKeysValuesLengthMismatch, + ERC725Y_DataKeysValuesEmptyArray } from "@erc725/smart-contracts/contracts/errors.sol"; import { NoExtensionFoundForFunctionSelector @@ -191,16 +192,16 @@ abstract contract LSP0ERC725AccountCore is emit ValueReceived(msg.sender, msg.value); } - address _owner = owner(); + address accountOwner = owner(); // If the caller is the owner perform execute directly - if (msg.sender == _owner) { + if (msg.sender == accountOwner) { return ERC725XCore._execute(operationType, target, value, data); } // If the caller is not the owner, call {lsp20VerifyCall} on the owner // Depending on the magicValue returned, a second call is done after execution - bool verifyAfter = LSP20CallVerification._verifyCall(_owner); + bool verifyAfter = LSP20CallVerification._verifyCall(accountOwner); // Perform the execution bytes memory result = ERC725XCore._execute( @@ -212,7 +213,10 @@ abstract contract LSP0ERC725AccountCore is // if verifyAfter is true, Call {lsp20VerifyCallResult} on the owner if (verifyAfter) { - LSP20CallVerification._verifyCallResult(_owner, abi.encode(result)); + LSP20CallVerification._verifyCallResult( + accountOwner, + abi.encode(result) + ); } return result; @@ -228,6 +232,9 @@ abstract contract LSP0ERC725AccountCore is * - If the operation type is `CREATE` (1) or `CREATE2` (2), `target` must be `address(0)`. * - If the operation type is `STATICCALL` (3) or `DELEGATECALL` (4), `value` transfer is disallowed and must be 0. * + * @custom:warning + * - The `msg.value` should not be trusted for any method called within the batch with `operationType`: `DELEGATECALL` (4). + * * @custom:events * - {Executed} event for each call that uses under `operationType`: `CALL` (0), `STATICCALL` (3) and `DELEGATECALL` (4). (each iteration) * - {ContractCreated} event, when a contract is created under `operationType`: `CREATE` (1) and `CREATE2` (2) (each iteration) @@ -243,10 +250,10 @@ abstract contract LSP0ERC725AccountCore is emit ValueReceived(msg.sender, msg.value); } - address _owner = owner(); + address accountOwner = owner(); // If the caller is the owner perform execute directly - if (msg.sender == _owner) { + if (msg.sender == accountOwner) { return ERC725XCore._executeBatch( operationsType, @@ -258,7 +265,7 @@ abstract contract LSP0ERC725AccountCore is // If the caller is not the owner, call {lsp20VerifyCall} on the owner // Depending on the magicValue returned, a second call is done after execution - bool verifyAfter = LSP20CallVerification._verifyCall(_owner); + bool verifyAfter = LSP20CallVerification._verifyCall(accountOwner); // Perform the execution bytes[] memory results = ERC725XCore._executeBatch( @@ -271,7 +278,7 @@ abstract contract LSP0ERC725AccountCore is // if verifyAfter is true, Call {lsp20VerifyCallResult} on the owner if (verifyAfter) { LSP20CallVerification._verifyCallResult( - _owner, + accountOwner, abi.encode(results) ); } @@ -296,23 +303,23 @@ abstract contract LSP0ERC725AccountCore is emit ValueReceived(msg.sender, msg.value); } - address _owner = owner(); + address accountOwner = owner(); // If the caller is the owner perform setData directly - if (msg.sender == _owner) { + if (msg.sender == accountOwner) { return _setData(dataKey, dataValue); } // If the caller is not the owner, call {lsp20VerifyCall} on the owner // Depending on the magicValue returned, a second call is done after setting data - bool verifyAfter = _verifyCall(_owner); + bool verifyAfter = _verifyCall(accountOwner); _setData(dataKey, dataValue); // If verifyAfter is true, Call {lsp20VerifyCallResult} on the owner // The setData function does not return, second parameter of {_verifyCallResult} will be empty if (verifyAfter) { - _verifyCallResult(_owner, ""); + _verifyCallResult(accountOwner, ""); } } @@ -337,10 +344,14 @@ abstract contract LSP0ERC725AccountCore is revert ERC725Y_DataKeysValuesLengthMismatch(); } - address _owner = owner(); + if (dataKeys.length == 0) { + revert ERC725Y_DataKeysValuesEmptyArray(); + } + + address accountOwner = owner(); // If the caller is the owner perform setData directly - if (msg.sender == _owner) { + if (msg.sender == accountOwner) { for (uint256 i; i < dataKeys.length; ) { _setData(dataKeys[i], dataValues[i]); @@ -354,7 +365,7 @@ abstract contract LSP0ERC725AccountCore is // If the caller is not the owner, call {lsp20VerifyCall} on the owner // Depending on the magicValue returned, a second call is done after setting data - bool verifyAfter = _verifyCall(_owner); + bool verifyAfter = _verifyCall(accountOwner); for (uint256 i; i < dataKeys.length; ) { _setData(dataKeys[i], dataValues[i]); @@ -367,7 +378,7 @@ abstract contract LSP0ERC725AccountCore is // If verifyAfter is true, Call {lsp20VerifyCallResult} on the owner // The setData function does not return, second parameter of {_verifyCallResult} will be empty if (verifyAfter) { - _verifyCallResult(_owner, ""); + _verifyCallResult(accountOwner, ""); } } @@ -572,7 +583,7 @@ abstract contract LSP0ERC725AccountCore is * * @custom:requirements Can be only called by the {owner} or by an authorised address that pass the verification check performed on the owner. * - * @custom:danger Leaves the contract without an owner. Once ownership of the contract has been renounced, any functions that are restricted to be called by the owner will be permanently inaccessible, making these functions not callable anymore and unusable. + * @custom:danger Leaves the contract without an owner. Once ownership of the contract has been renounced, any functions that are restricted to be called by the owner or an address allowed by the owner will be permanently inaccessible, making these functions not callable anymore and unusable. * */ function renounceOwnership() @@ -580,16 +591,16 @@ abstract contract LSP0ERC725AccountCore is virtual override(LSP14Ownable2Step, OwnableUnset) { - address _owner = owner(); + address accountOwner = owner(); // If the caller is the owner perform renounceOwnership directly - if (msg.sender == _owner) { + if (msg.sender == accountOwner) { return LSP14Ownable2Step._renounceOwnership(); } // If the caller is not the owner, call {lsp20VerifyCall} on the owner // Depending on the magicValue returned, a second call is done after transferring ownership - bool verifyAfter = _verifyCall(_owner); + bool verifyAfter = _verifyCall(accountOwner); address previousOwner = owner(); LSP14Ownable2Step._renounceOwnership(); @@ -604,7 +615,7 @@ abstract contract LSP0ERC725AccountCore is // If verifyAfter is true, Call {lsp20VerifyCallResult} on the owner // The transferOwnership function does not return, second parameter of {_verifyCallResult} will be empty if (verifyAfter) { - _verifyCallResult(_owner, ""); + _verifyCallResult(accountOwner, ""); } } diff --git a/contracts/LSP14Ownable2Step/ILSP14Ownable2Step.sol b/contracts/LSP14Ownable2Step/ILSP14Ownable2Step.sol index 6b0410934..00ded5eaf 100644 --- a/contracts/LSP14Ownable2Step/ILSP14Ownable2Step.sol +++ b/contracts/LSP14Ownable2Step/ILSP14Ownable2Step.sol @@ -59,7 +59,7 @@ interface ILSP14Ownable2Step { * @dev Transfer ownership of the contract from the current {owner()} to the {pendingOwner()}. * * Once this function is called: - * - The current {owner()} will loose access to the functions restricted to the {owner()} only. + * - The current {owner()} will lose access to the functions restricted to the {owner()} only. * - The {pendingOwner()} will gain access to the functions restricted to the {owner()} only. * * @notice `msg.sender` is accepting ownership of contract: `address(this)`. diff --git a/contracts/LSP20CallVerification/LSP20CallVerification.sol b/contracts/LSP20CallVerification/LSP20CallVerification.sol index 0466a6809..9f3780ca5 100644 --- a/contracts/LSP20CallVerification/LSP20CallVerification.sol +++ b/contracts/LSP20CallVerification/LSP20CallVerification.sol @@ -8,7 +8,8 @@ import {ILSP20CallVerifier as ILSP20} from "./ILSP20CallVerifier.sol"; // errors import { LSP20InvalidMagicValue, - LSP20CallingVerifierFailed + LSP20CallingVerifierFailed, + LSP20EOACannotVerifyCall } from "./LSP20Errors.sol"; /** @@ -26,6 +27,9 @@ abstract contract LSP20CallVerification { function _verifyCall( address logicVerifier ) internal virtual returns (bool verifyAfter) { + if (logicVerifier.code.length == 0) + revert LSP20EOACannotVerifyCall(logicVerifier); + (bool success, bytes memory returnedData) = logicVerifier.call( abi.encodeWithSelector( ILSP20.lsp20VerifyCall.selector, @@ -42,7 +46,7 @@ abstract contract LSP20CallVerification { if (bytes3(magicValue) != bytes3(ILSP20.lsp20VerifyCall.selector)) revert LSP20InvalidMagicValue(false, returnedData); - return magicValue[3] == 0x01 ? true : false; + return bytes1(magicValue[3]) == 0x01; } /** diff --git a/contracts/LSP20CallVerification/LSP20Errors.sol b/contracts/LSP20CallVerification/LSP20Errors.sol index 264f2971e..4ed0d42e0 100644 --- a/contracts/LSP20CallVerification/LSP20Errors.sol +++ b/contracts/LSP20CallVerification/LSP20Errors.sol @@ -13,3 +13,9 @@ error LSP20CallingVerifierFailed(bool postCall); * @param returnedData The data returned by the call to the logic verifier */ error LSP20InvalidMagicValue(bool postCall, bytes returnedData); + +/** + * @dev Reverts when the logic verifier is an Externally Owned Account (EOA) that cannot return the LSP20 magic value. + * @param logicVerifier The address of the logic verifier + */ +error LSP20EOACannotVerifyCall(address logicVerifier); diff --git a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol index f51fcf6c1..c8188b5e6 100644 --- a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol +++ b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol @@ -323,13 +323,8 @@ abstract contract LSP6KeyManagerCore is uint256 msgValue, bytes calldata data ) external virtual returns (bytes4) { - bool isSetData = false; - if ( - bytes4(data) == IERC725Y.setData.selector || - bytes4(data) == IERC725Y.setDataBatch.selector - ) { - isSetData = true; - } + bool isSetData = bytes4(data) == IERC725Y.setData.selector || + bytes4(data) == IERC725Y.setDataBatch.selector; address targetContract = _target; @@ -396,13 +391,8 @@ abstract contract LSP6KeyManagerCore is revert InvalidPayload(payload); } - bool isSetData = false; - if ( - bytes4(payload) == IERC725Y.setData.selector || - bytes4(payload) == IERC725Y.setDataBatch.selector - ) { - isSetData = true; - } + bool isSetData = bytes4(payload) == IERC725Y.setData.selector || + bytes4(payload) == IERC725Y.setDataBatch.selector; address targetContract = _target; @@ -473,13 +463,8 @@ abstract contract LSP6KeyManagerCore is LSP25MultiChannelNonce._verifyValidityTimestamps(validityTimestamps); - bool isSetData = false; - if ( - bytes4(payload) == IERC725Y.setData.selector || - bytes4(payload) == IERC725Y.setDataBatch.selector - ) { - isSetData = true; - } + bool isSetData = bytes4(payload) == IERC725Y.setData.selector || + bytes4(payload) == IERC725Y.setDataBatch.selector; uint8 reentrancyStatus = _nonReentrantBefore( targetContract, diff --git a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol index a50ca839e..edeeebac6 100644 --- a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol +++ b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol @@ -273,7 +273,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { * It has been added in the LSP7 contract implementation so that it can be used as a prevention mechanism * against the double spending allowance vulnerability. * - * @notice Decrease the allowance of `operator` by -`substractedAmount` + * @notice Decrease the allowance of `operator` by -`subtractedAmount` * * @dev Atomically decreases the allowance granted to `operator` by the caller. * This is an alternative approach to {authorizeOperator} that can be used as a mitigation @@ -281,29 +281,29 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { * * @custom:events * - {AuthorizedOperator} event indicating the updated allowance after decreasing it. - * - {RevokeOperator} event if `substractedAmount` is the full allowance, + * - {RevokeOperator} event if `subtractedAmount` is the full allowance, * indicating `operator` does not have any alauthorizedAmountForlowance left for `msg.sender`. * * @param operator the operator to decrease allowance for `msg.sender` - * @param substractedAmount the amount to decrease by in the operator's allowance. + * @param subtractedAmount the amount to decrease by in the operator's allowance. * * @custom:requirements * - `operator` cannot be the zero address. - * - `operator` must have allowance for the caller of at least `substractedAmount`. + * - `operator` must have allowance for the caller of at least `subtractedAmount`. */ function decreaseAllowance( address operator, - uint256 substractedAmount, + uint256 subtractedAmount, bytes memory operatorNotificationData ) public virtual { uint256 currentAllowance = authorizedAmountFor(operator, msg.sender); - if (currentAllowance < substractedAmount) { + if (currentAllowance < subtractedAmount) { revert LSP7DecreasedAllowanceBelowZero(); } uint256 newAllowance; unchecked { - newAllowance = currentAllowance - substractedAmount; + newAllowance = currentAllowance - subtractedAmount; _updateOperator( msg.sender, operator, diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol index 518bdb4f5..7691db56c 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol @@ -374,6 +374,11 @@ abstract contract LSP8IdentifiableDigitalAssetCore is _beforeTokenTransfer(address(0), to, tokenId); + // Check that `tokenId` was not minted inside the `_beforeTokenTransfer` hook + if (_exists(tokenId)) { + revert LSP8TokenIdAlreadyMinted(tokenId); + } + // token being minted ++_existingTokens; @@ -411,6 +416,10 @@ abstract contract LSP8IdentifiableDigitalAssetCore is _beforeTokenTransfer(tokenOwner, address(0), tokenId); + // Re-fetch and update `tokenOwner` in case `tokenId` + // was transferred inside the `_beforeTokenTransfer` hook + tokenOwner = tokenOwnerOf(tokenId); + // token being burned --_existingTokens; @@ -475,6 +484,10 @@ abstract contract LSP8IdentifiableDigitalAssetCore is _beforeTokenTransfer(from, to, tokenId); + // Re-fetch and update `tokenOwner` in case `tokenId` + // was transferred inside the `_beforeTokenTransfer` hook + tokenOwner = tokenOwnerOf(tokenId); + _clearOperators(from, tokenId); _ownedTokens[from].remove(tokenId); diff --git a/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md b/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md index a49f56ccc..d0b664f76 100644 --- a/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md +++ b/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md @@ -216,7 +216,7 @@ _`msg.sender` is accepting ownership of contract: `address(this)`._ Transfer ownership of the contract from the current [`owner()`](#owner) to the [`pendingOwner()`](#pendingowner). Once this function is called: -- The current [`owner()`](#owner) will loose access to the functions restricted to the [`owner()`](#owner) only. +- The current [`owner()`](#owner) will lose access to the functions restricted to the [`owner()`](#owner) only. - The [`pendingOwner()`](#pendingowner) will gain access to the functions restricted to the [`owner()`](#owner) only. @@ -350,6 +350,12 @@ Generic executor function to: ::: +:::caution Warning + +- The `msg.value` should not be trusted for any method called within the batch with `operationType`: `DELEGATECALL` (4). + +::: + ```solidity function executeBatch( uint256[] operationsType, @@ -588,7 +594,7 @@ The address that ownership of the contract is transferred to. This address may u :::danger -Leaves the contract without an owner. Once ownership of the contract has been renounced, any functions that are restricted to be called by the owner will be permanently inaccessible, making these functions not callable anymore and unusable. +Leaves the contract without an owner. Once ownership of the contract has been renounced, any functions that are restricted to be called by the owner or an address allowed by the owner will be permanently inaccessible, making these functions not callable anymore and unusable. ::: @@ -1680,6 +1686,25 @@ Reverts when the `operationTypeProvided` is none of the default operation types
+### ERC725Y_DataKeysValuesEmptyArray + +:::note References + +- Specification details: [**LSP-0-ERC725Account**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-0-ERC725Account.md#erc725y_datakeysvaluesemptyarray) +- Solidity implementation: [`LSP0ERC725Account.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP0ERC725Account/LSP0ERC725Account.sol) +- Error signature: `ERC725Y_DataKeysValuesEmptyArray()` +- Error hash: `0x97da5f95` + +::: + +```solidity +error ERC725Y_DataKeysValuesEmptyArray(); +``` + +Reverts when one of the array parameter provided to [`setDataBatch`](#setdatabatch) function is an empty array. + +
+ ### ERC725Y_DataKeysValuesLengthMismatch :::note References @@ -1745,6 +1770,31 @@ reverts when the call to the owner fail with no revert reason
+### LSP20EOACannotVerifyCall + +:::note References + +- Specification details: [**LSP-0-ERC725Account**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-0-ERC725Account.md#lsp20eoacannotverifycall) +- Solidity implementation: [`LSP0ERC725Account.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP0ERC725Account/LSP0ERC725Account.sol) +- Error signature: `LSP20EOACannotVerifyCall(address)` +- Error hash: `0x0c392301` + +::: + +```solidity +error LSP20EOACannotVerifyCall(address logicVerifier); +``` + +Reverts when the logic verifier is an Externally Owned Account (EOA) that cannot return the LSP20 magic value. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | --------------------------------- | +| `logicVerifier` | `address` | The address of the logic verifier | + +
+ ### LSP20InvalidMagicValue :::note References diff --git a/docs/contracts/LSP14Ownable2Step/LSP14Ownable2Step.md b/docs/contracts/LSP14Ownable2Step/LSP14Ownable2Step.md index a6e0464f0..cd4120269 100644 --- a/docs/contracts/LSP14Ownable2Step/LSP14Ownable2Step.md +++ b/docs/contracts/LSP14Ownable2Step/LSP14Ownable2Step.md @@ -98,7 +98,7 @@ _`msg.sender` is accepting ownership of contract: `address(this)`._ Transfer ownership of the contract from the current [`owner()`](#owner) to the [`pendingOwner()`](#pendingowner). Once this function is called: -- The current [`owner()`](#owner) will loose access to the functions restricted to the [`owner()`](#owner) only. +- The current [`owner()`](#owner) will lose access to the functions restricted to the [`owner()`](#owner) only. - The [`pendingOwner()`](#pendingowner) will gain access to the functions restricted to the [`owner()`](#owner) only. diff --git a/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md b/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md index eb78e271a..b40733a0f 100644 --- a/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md +++ b/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md @@ -206,12 +206,12 @@ This is a non-standard function, not part of the LSP7 standard interface. It has ```solidity function decreaseAllowance( address operator, - uint256 substractedAmount, + uint256 subtractedAmount, bytes operatorNotificationData ) external nonpayable; ``` -_Decrease the allowance of `operator` by -`substractedAmount`_ +_Decrease the allowance of `operator` by -`subtractedAmount`_ Atomically decreases the allowance granted to `operator` by the caller. This is an alternative approach to [`authorizeOperator`](#authorizeoperator) that can be used as a mitigation for the double spending allowance problem. @@ -220,7 +220,7 @@ Atomically decreases the allowance granted to `operator` by the caller. This is **Requirements:** - `operator` cannot be the zero address. -- `operator` must have allowance for the caller of at least `substractedAmount`. +- `operator` must have allowance for the caller of at least `subtractedAmount`. @@ -229,7 +229,7 @@ Atomically decreases the allowance granted to `operator` by the caller. This is **Emitted events:** - [`AuthorizedOperator`](#authorizedoperator) event indicating the updated allowance after decreasing it. -- [`RevokeOperator`](#revokeoperator) event if `substractedAmount` is the full allowance, indicating `operator` does not have any alauthorizedAmountForlowance left for `msg.sender`. +- [`RevokeOperator`](#revokeoperator) event if `subtractedAmount` is the full allowance, indicating `operator` does not have any alauthorizedAmountForlowance left for `msg.sender`. @@ -238,7 +238,7 @@ Atomically decreases the allowance granted to `operator` by the caller. This is | Name | Type | Description | | -------------------------- | :-------: | ------------------------------------------------------ | | `operator` | `address` | the operator to decrease allowance for `msg.sender` | -| `substractedAmount` | `uint256` | the amount to decrease by in the operator's allowance. | +| `subtractedAmount` | `uint256` | the amount to decrease by in the operator's allowance. | | `operatorNotificationData` | `bytes` | - |
diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md index 75e286eb6..14084bc92 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md @@ -231,12 +231,12 @@ This is a non-standard function, not part of the LSP7 standard interface. It has ```solidity function decreaseAllowance( address operator, - uint256 substractedAmount, + uint256 subtractedAmount, bytes operatorNotificationData ) external nonpayable; ``` -_Decrease the allowance of `operator` by -`substractedAmount`_ +_Decrease the allowance of `operator` by -`subtractedAmount`_ Atomically decreases the allowance granted to `operator` by the caller. This is an alternative approach to [`authorizeOperator`](#authorizeoperator) that can be used as a mitigation for the double spending allowance problem. @@ -245,7 +245,7 @@ Atomically decreases the allowance granted to `operator` by the caller. This is **Requirements:** - `operator` cannot be the zero address. -- `operator` must have allowance for the caller of at least `substractedAmount`. +- `operator` must have allowance for the caller of at least `subtractedAmount`. @@ -254,7 +254,7 @@ Atomically decreases the allowance granted to `operator` by the caller. This is **Emitted events:** - [`AuthorizedOperator`](#authorizedoperator) event indicating the updated allowance after decreasing it. -- [`RevokeOperator`](#revokeoperator) event if `substractedAmount` is the full allowance, indicating `operator` does not have any alauthorizedAmountForlowance left for `msg.sender`. +- [`RevokeOperator`](#revokeoperator) event if `subtractedAmount` is the full allowance, indicating `operator` does not have any alauthorizedAmountForlowance left for `msg.sender`. @@ -263,7 +263,7 @@ Atomically decreases the allowance granted to `operator` by the caller. This is | Name | Type | Description | | -------------------------- | :-------: | ------------------------------------------------------ | | `operator` | `address` | the operator to decrease allowance for `msg.sender` | -| `substractedAmount` | `uint256` | the amount to decrease by in the operator's allowance. | +| `subtractedAmount` | `uint256` | the amount to decrease by in the operator's allowance. | | `operatorNotificationData` | `bytes` | - |
diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md index 405a2233d..13868b9d0 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md @@ -204,12 +204,12 @@ This is a non-standard function, not part of the LSP7 standard interface. It has ```solidity function decreaseAllowance( address operator, - uint256 substractedAmount, + uint256 subtractedAmount, bytes operatorNotificationData ) external nonpayable; ``` -_Decrease the allowance of `operator` by -`substractedAmount`_ +_Decrease the allowance of `operator` by -`subtractedAmount`_ Atomically decreases the allowance granted to `operator` by the caller. This is an alternative approach to [`authorizeOperator`](#authorizeoperator) that can be used as a mitigation for the double spending allowance problem. @@ -218,7 +218,7 @@ Atomically decreases the allowance granted to `operator` by the caller. This is **Requirements:** - `operator` cannot be the zero address. -- `operator` must have allowance for the caller of at least `substractedAmount`. +- `operator` must have allowance for the caller of at least `subtractedAmount`. @@ -227,7 +227,7 @@ Atomically decreases the allowance granted to `operator` by the caller. This is **Emitted events:** - [`AuthorizedOperator`](#authorizedoperator) event indicating the updated allowance after decreasing it. -- [`RevokeOperator`](#revokeoperator) event if `substractedAmount` is the full allowance, indicating `operator` does not have any alauthorizedAmountForlowance left for `msg.sender`. +- [`RevokeOperator`](#revokeoperator) event if `subtractedAmount` is the full allowance, indicating `operator` does not have any alauthorizedAmountForlowance left for `msg.sender`. @@ -236,7 +236,7 @@ Atomically decreases the allowance granted to `operator` by the caller. This is | Name | Type | Description | | -------------------------- | :-------: | ------------------------------------------------------ | | `operator` | `address` | the operator to decrease allowance for `msg.sender` | -| `substractedAmount` | `uint256` | the amount to decrease by in the operator's allowance. | +| `subtractedAmount` | `uint256` | the amount to decrease by in the operator's allowance. | | `operatorNotificationData` | `bytes` | - |
diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md index 61d68ae45..8905143e7 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md @@ -270,12 +270,12 @@ This is a non-standard function, not part of the LSP7 standard interface. It has ```solidity function decreaseAllowance( address operator, - uint256 substractedAmount, + uint256 subtractedAmount, bytes operatorNotificationData ) external nonpayable; ``` -_Decrease the allowance of `operator` by -`substractedAmount`_ +_Decrease the allowance of `operator` by -`subtractedAmount`_ Atomically decreases the allowance granted to `operator` by the caller. This is an alternative approach to [`authorizeOperator`](#authorizeoperator) that can be used as a mitigation for the double spending allowance problem. @@ -284,7 +284,7 @@ Atomically decreases the allowance granted to `operator` by the caller. This is **Requirements:** - `operator` cannot be the zero address. -- `operator` must have allowance for the caller of at least `substractedAmount`. +- `operator` must have allowance for the caller of at least `subtractedAmount`. @@ -293,7 +293,7 @@ Atomically decreases the allowance granted to `operator` by the caller. This is **Emitted events:** - [`AuthorizedOperator`](#authorizedoperator) event indicating the updated allowance after decreasing it. -- [`RevokeOperator`](#revokeoperator) event if `substractedAmount` is the full allowance, indicating `operator` does not have any alauthorizedAmountForlowance left for `msg.sender`. +- [`RevokeOperator`](#revokeoperator) event if `subtractedAmount` is the full allowance, indicating `operator` does not have any alauthorizedAmountForlowance left for `msg.sender`. @@ -302,7 +302,7 @@ Atomically decreases the allowance granted to `operator` by the caller. This is | Name | Type | Description | | -------------------------- | :-------: | ------------------------------------------------------ | | `operator` | `address` | the operator to decrease allowance for `msg.sender` | -| `substractedAmount` | `uint256` | the amount to decrease by in the operator's allowance. | +| `subtractedAmount` | `uint256` | the amount to decrease by in the operator's allowance. | | `operatorNotificationData` | `bytes` | - |
diff --git a/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md b/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md index cd80c23f3..a80ed6335 100644 --- a/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md +++ b/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md @@ -275,12 +275,12 @@ This is a non-standard function, not part of the LSP7 standard interface. It has ```solidity function decreaseAllowance( address operator, - uint256 substractedAmount, + uint256 subtractedAmount, bytes operatorNotificationData ) external nonpayable; ``` -_Decrease the allowance of `operator` by -`substractedAmount`_ +_Decrease the allowance of `operator` by -`subtractedAmount`_ Atomically decreases the allowance granted to `operator` by the caller. This is an alternative approach to [`authorizeOperator`](#authorizeoperator) that can be used as a mitigation for the double spending allowance problem. @@ -289,7 +289,7 @@ Atomically decreases the allowance granted to `operator` by the caller. This is **Requirements:** - `operator` cannot be the zero address. -- `operator` must have allowance for the caller of at least `substractedAmount`. +- `operator` must have allowance for the caller of at least `subtractedAmount`. @@ -298,7 +298,7 @@ Atomically decreases the allowance granted to `operator` by the caller. This is **Emitted events:** - [`AuthorizedOperator`](#authorizedoperator) event indicating the updated allowance after decreasing it. -- [`RevokeOperator`](#revokeoperator) event if `substractedAmount` is the full allowance, indicating `operator` does not have any alauthorizedAmountForlowance left for `msg.sender`. +- [`RevokeOperator`](#revokeoperator) event if `subtractedAmount` is the full allowance, indicating `operator` does not have any alauthorizedAmountForlowance left for `msg.sender`. @@ -307,7 +307,7 @@ Atomically decreases the allowance granted to `operator` by the caller. This is | Name | Type | Description | | -------------------------- | :-------: | ------------------------------------------------------ | | `operator` | `address` | the operator to decrease allowance for `msg.sender` | -| `substractedAmount` | `uint256` | the amount to decrease by in the operator's allowance. | +| `subtractedAmount` | `uint256` | the amount to decrease by in the operator's allowance. | | `operatorNotificationData` | `bytes` | - |
diff --git a/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md b/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md index 52c57a89c..ddf2e1b70 100644 --- a/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md +++ b/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md @@ -235,12 +235,12 @@ This is a non-standard function, not part of the LSP7 standard interface. It has ```solidity function decreaseAllowance( address operator, - uint256 substractedAmount, + uint256 subtractedAmount, bytes operatorNotificationData ) external nonpayable; ``` -_Decrease the allowance of `operator` by -`substractedAmount`_ +_Decrease the allowance of `operator` by -`subtractedAmount`_ Atomically decreases the allowance granted to `operator` by the caller. This is an alternative approach to [`authorizeOperator`](#authorizeoperator) that can be used as a mitigation for the double spending allowance problem. @@ -249,7 +249,7 @@ Atomically decreases the allowance granted to `operator` by the caller. This is **Requirements:** - `operator` cannot be the zero address. -- `operator` must have allowance for the caller of at least `substractedAmount`. +- `operator` must have allowance for the caller of at least `subtractedAmount`. @@ -258,7 +258,7 @@ Atomically decreases the allowance granted to `operator` by the caller. This is **Emitted events:** - [`AuthorizedOperator`](#authorizedoperator) event indicating the updated allowance after decreasing it. -- [`RevokeOperator`](#revokeoperator) event if `substractedAmount` is the full allowance, indicating `operator` does not have any alauthorizedAmountForlowance left for `msg.sender`. +- [`RevokeOperator`](#revokeoperator) event if `subtractedAmount` is the full allowance, indicating `operator` does not have any alauthorizedAmountForlowance left for `msg.sender`. @@ -267,7 +267,7 @@ Atomically decreases the allowance granted to `operator` by the caller. This is | Name | Type | Description | | -------------------------- | :-------: | ------------------------------------------------------ | | `operator` | `address` | the operator to decrease allowance for `msg.sender` | -| `substractedAmount` | `uint256` | the amount to decrease by in the operator's allowance. | +| `subtractedAmount` | `uint256` | the amount to decrease by in the operator's allowance. | | `operatorNotificationData` | `bytes` | - |
diff --git a/docs/contracts/LSP9Vault/LSP9Vault.md b/docs/contracts/LSP9Vault/LSP9Vault.md index f314f378e..84821b6df 100644 --- a/docs/contracts/LSP9Vault/LSP9Vault.md +++ b/docs/contracts/LSP9Vault/LSP9Vault.md @@ -202,7 +202,7 @@ _`msg.sender` is accepting ownership of contract: `address(this)`._ Transfer ownership of the contract from the current [`owner()`](#owner) to the [`pendingOwner()`](#pendingowner). Once this function is called: -- The current [`owner()`](#owner) will loose access to the functions restricted to the [`owner()`](#owner) only. +- The current [`owner()`](#owner) will lose access to the functions restricted to the [`owner()`](#owner) only. - The [`pendingOwner()`](#pendingowner) will gain access to the functions restricted to the [`owner()`](#owner) only. diff --git a/docs/contracts/UniversalProfile.md b/docs/contracts/UniversalProfile.md index dfcadcad8..1516eb39e 100644 --- a/docs/contracts/UniversalProfile.md +++ b/docs/contracts/UniversalProfile.md @@ -159,7 +159,7 @@ _`msg.sender` is accepting ownership of contract: `address(this)`._ Transfer ownership of the contract from the current [`owner()`](#owner) to the [`pendingOwner()`](#pendingowner). Once this function is called: -- The current [`owner()`](#owner) will loose access to the functions restricted to the [`owner()`](#owner) only. +- The current [`owner()`](#owner) will lose access to the functions restricted to the [`owner()`](#owner) only. - The [`pendingOwner()`](#pendingowner) will gain access to the functions restricted to the [`owner()`](#owner) only. @@ -293,6 +293,12 @@ Generic executor function to: ::: +:::caution Warning + +- The `msg.value` should not be trusted for any method called within the batch with `operationType`: `DELEGATECALL` (4). + +::: + ```solidity function executeBatch( uint256[] operationsType, @@ -531,7 +537,7 @@ The address that ownership of the contract is transferred to. This address may u :::danger -Leaves the contract without an owner. Once ownership of the contract has been renounced, any functions that are restricted to be called by the owner will be permanently inaccessible, making these functions not callable anymore and unusable. +Leaves the contract without an owner. Once ownership of the contract has been renounced, any functions that are restricted to be called by the owner or an address allowed by the owner will be permanently inaccessible, making these functions not callable anymore and unusable. ::: @@ -1623,6 +1629,25 @@ Reverts when the `operationTypeProvided` is none of the default operation types
+### ERC725Y_DataKeysValuesEmptyArray + +:::note References + +- Specification details: [**UniversalProfile**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-3-UniversalProfile-Metadata.md#erc725y_datakeysvaluesemptyarray) +- Solidity implementation: [`UniversalProfile.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/UniversalProfile.sol) +- Error signature: `ERC725Y_DataKeysValuesEmptyArray()` +- Error hash: `0x97da5f95` + +::: + +```solidity +error ERC725Y_DataKeysValuesEmptyArray(); +``` + +Reverts when one of the array parameter provided to [`setDataBatch`](#setdatabatch) function is an empty array. + +
+ ### ERC725Y_DataKeysValuesLengthMismatch :::note References @@ -1688,6 +1713,31 @@ reverts when the call to the owner fail with no revert reason
+### LSP20EOACannotVerifyCall + +:::note References + +- Specification details: [**UniversalProfile**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-3-UniversalProfile-Metadata.md#lsp20eoacannotverifycall) +- Solidity implementation: [`UniversalProfile.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/UniversalProfile.sol) +- Error signature: `LSP20EOACannotVerifyCall(address)` +- Error hash: `0x0c392301` + +::: + +```solidity +error LSP20EOACannotVerifyCall(address logicVerifier); +``` + +Reverts when the logic verifier is an Externally Owned Account (EOA) that cannot return the LSP20 magic value. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | --------------------------------- | +| `logicVerifier` | `address` | The address of the logic verifier | + +
+ ### LSP20InvalidMagicValue :::note References diff --git a/tests/LSP20CallVerification/LSP20CallVerification.behaviour.ts b/tests/LSP20CallVerification/LSP20CallVerification.behaviour.ts index 89e2c3734..6ec1ff3d8 100644 --- a/tests/LSP20CallVerification/LSP20CallVerification.behaviour.ts +++ b/tests/LSP20CallVerification/LSP20CallVerification.behaviour.ts @@ -56,8 +56,8 @@ export const shouldBehaveLikeLSP20 = (buildContext: () => Promise Promise Promise Promise Promise Promise { @@ -209,14 +209,14 @@ export const shouldBehaveLikeLSP14WithLSP20 = ( .connect(previousOwner) .execute(OPERATION_TYPES.CALL, recipient.address, amount, '0x'), ) - .to.be.revertedWithCustomError(context.contract, 'LSP20InvalidMagicValue') - .withArgs(false, '0x'); + .to.be.revertedWithCustomError(context.contract, 'LSP20EOACannotVerifyCall') + .withArgs(newOwner.address); }); it('should revert when calling `renounceOwnership(...)`', async () => { await expect(context.contract.connect(previousOwner).renounceOwnership()) - .to.be.revertedWithCustomError(context.contract, 'LSP20InvalidMagicValue') - .withArgs(false, '0x'); + .to.be.revertedWithCustomError(context.contract, 'LSP20EOACannotVerifyCall') + .withArgs(newOwner.address); }); }); @@ -257,8 +257,8 @@ export const shouldBehaveLikeLSP14WithLSP20 = ( const tx = context.contract.connect(context.accounts[5]).renounceOwnership(); await expect(tx) - .to.be.revertedWithCustomError(context.contract, 'LSP20InvalidMagicValue') - .withArgs(false, '0x'); + .to.be.revertedWithCustomError(context.contract, 'LSP20EOACannotVerifyCall') + .withArgs(newOwner.address); }); }); @@ -468,8 +468,8 @@ export const shouldBehaveLikeLSP14WithLSP20 = ( const value = ethers.utils.hexlify(ethers.utils.toUtf8Bytes('Random Value')); await expect(context.contract.connect(context.deployParams.owner).setData(key, value)) - .to.be.revertedWithCustomError(context.contract, 'LSP20InvalidMagicValue') - .withArgs(false, '0x'); + .to.be.revertedWithCustomError(context.contract, 'LSP20EOACannotVerifyCall') + .withArgs(ethers.constants.AddressZero); }); it('transfer LYX via `execute(...)`', async () => { @@ -481,8 +481,8 @@ export const shouldBehaveLikeLSP14WithLSP20 = ( .connect(context.deployParams.owner) .execute(OPERATION_TYPES.CALL, recipient, amount, '0x'), ) - .to.be.revertedWithCustomError(context.contract, 'LSP20InvalidMagicValue') - .withArgs(false, '0x'); + .to.be.revertedWithCustomError(context.contract, 'LSP20EOACannotVerifyCall') + .withArgs(ethers.constants.AddressZero); }); }); }); diff --git a/tests/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.behaviour.ts b/tests/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.behaviour.ts index d56ea1e7a..dd552e53b 100644 --- a/tests/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.behaviour.ts +++ b/tests/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.behaviour.ts @@ -24,6 +24,32 @@ export const shouldBehaveLikeLSP4DigitalAssetMetadata = ( }); describe('when setting data on ERC725Y storage', () => { + describe('when sending value while setting data', () => { + it('should revert with `setData`', async () => { + const msgValue = ethers.utils.parseEther('2'); + const key = ethers.utils.keccak256(ethers.utils.toUtf8Bytes('My Key')); + const value = ethers.utils.hexlify(ethers.utils.randomBytes(256)); + + await expect( + context.contract + .connect(context.deployParams.owner) + .setData(key, value, { value: msgValue }), + ).to.be.revertedWithCustomError(context.contract, 'ERC725Y_MsgValueDisallowed'); + }); + + it('should revert with `setDataBatch`', async () => { + const msgValue = ethers.utils.parseEther('2'); + const key = [ethers.utils.keccak256(ethers.utils.toUtf8Bytes('My Key'))]; + const value = [ethers.utils.hexlify(ethers.utils.randomBytes(256))]; + + await expect( + context.contract + .connect(context.deployParams.owner) + .setDataBatch(key, value, { value: msgValue }), + ).to.be.revertedWithCustomError(context.contract, 'ERC725Y_MsgValueDisallowed'); + }); + }); + it('should revert when trying to edit Token Name', async () => { const key = ERC725YDataKeys.LSP4['LSP4TokenName']; const value = ethers.utils.hexlify(ethers.utils.toUtf8Bytes('Overriden Token Name')); diff --git a/tests/UniversalProfile.behaviour.ts b/tests/UniversalProfile.behaviour.ts index 4f0fedaaa..1831cc4ad 100644 --- a/tests/UniversalProfile.behaviour.ts +++ b/tests/UniversalProfile.behaviour.ts @@ -133,6 +133,15 @@ export const shouldBehaveLikeLSP3 = ( '0xdaea594e385fc724449e3118b2db7e86dfba1826', ]; + it('should fail when passing empty arrays of data keys / values', async () => { + const keys = []; + const values = []; + + await expect( + context.universalProfile.setDataBatch(keys, values), + ).to.be.revertedWithCustomError(context.universalProfile, 'ERC725Y_DataKeysValuesEmptyArray'); + }); + it('should set the 3 x keys for a basic UP setup => `LSP3Profile`, `LSP12IssuedAssets[]` and `LSP1UniversalReceiverDelegate`', async () => { const keys = [ ERC725YDataKeys.LSP3.LSP3Profile, @@ -431,8 +440,8 @@ export const shouldBehaveLikeLSP3 = ( await expect( context.universalProfile.connect(context.accounts[4]).batchCalls([setDataPayload]), ) - .to.be.revertedWithCustomError(context.universalProfile, 'LSP20InvalidMagicValue') - .withArgs(false, '0x'); + .to.be.revertedWithCustomError(context.universalProfile, 'LSP20EOACannotVerifyCall') + .withArgs(context.deployParams.owner.address); }); }); From e6fb55d9acc7bd63b9d66920f2f346ecf812c289 Mon Sep 17 00:00:00 2001 From: "b00ste.lyx" <62855857+b00ste@users.noreply.github.com> Date: Wed, 27 Sep 2023 13:25:38 +0300 Subject: [PATCH 25/55] fix: add `receive()` function in LSP7 & LSP8 to silent compiler warning (#711) * refactor: add `receive()` in LSP7 & LSP8 * docs: update token docs * test: update for the new behaivior --- .../LSP7DigitalAsset/LSP7DigitalAsset.sol | 14 ++++ .../LSP7DigitalAsset/LSP7DigitalAssetCore.sol | 11 ++-- .../LSP7DigitalAssetInitAbstract.sol | 14 ++++ contracts/LSP7DigitalAsset/LSP7Errors.sol | 9 +++ .../LSP8Errors.sol | 35 ++++++---- .../LSP8IdentifiableDigitalAsset.sol | 14 ++++ .../LSP8IdentifiableDigitalAssetCore.sol | 11 ++-- ...P8IdentifiableDigitalAssetInitAbstract.sol | 14 ++++ .../LSP7DigitalAsset/LSP7DigitalAsset.md | 40 +++++++++++ .../extensions/LSP7Burnable.md | 40 +++++++++++ .../extensions/LSP7CappedSupply.md | 40 +++++++++++ .../extensions/LSP7CompatibleERC20.md | 40 +++++++++++ .../presets/LSP7CompatibleERC20Mintable.md | 36 ++++++++++ .../LSP7DigitalAsset/presets/LSP7Mintable.md | 40 +++++++++++ .../LSP8IdentifiableDigitalAsset.md | 64 ++++++++++++++---- .../extensions/LSP8Burnable.md | 64 ++++++++++++++---- .../extensions/LSP8CappedSupply.md | 64 ++++++++++++++---- .../extensions/LSP8CompatibleERC721.md | 64 ++++++++++++++---- .../extensions/LSP8Enumerable.md | 64 ++++++++++++++---- .../presets/LSP8CompatibleERC721Mintable.md | 62 +++++++++++++---- .../presets/LSP8Mintable.md | 66 +++++++++++++++---- .../LSP17ExtendableTokens.behaviour.ts | 24 ------- .../LSP7DigitalAsset.behaviour.ts | 26 ++++++++ .../LSP8IdentifiableDigitalAsset.behaviour.ts | 26 ++++++++ 24 files changed, 751 insertions(+), 131 deletions(-) diff --git a/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol b/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol index 3a742d677..abe41cbb0 100644 --- a/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol +++ b/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol @@ -17,6 +17,7 @@ import {LSP2Utils} from "../LSP2ERC725YJSONSchema/LSP2Utils.sol"; // constants import {_INTERFACEID_LSP7} from "./LSP7Constants.sol"; +import {LSP7TokenContractCannotHoldValue} from "./LSP7Errors.sol"; import { _LSP17_EXTENSION_PREFIX @@ -91,6 +92,19 @@ abstract contract LSP7DigitalAsset is return _fallbackLSP17Extendable(callData); } + /** + * @dev Reverts whenever someone tries to send native tokens to a LSP7 contract. + * @notice LSP7 contract cannot receive native tokens. + */ + receive() external payable virtual { + // revert on empty calls with no value + if (msg.value == 0) { + revert InvalidFunctionSelector(hex"00000000"); + } + + revert LSP7TokenContractCannotHoldValue(); + } + /** * @dev Forwards the call with the received value to an extension mapped to a function selector. * diff --git a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol index edeeebac6..f58222cd3 100644 --- a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol +++ b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol @@ -555,13 +555,16 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { _INTERFACEID_LSP1 ) ) { - operator.call( - abi.encodeWithSelector( - ILSP1UniversalReceiver.universalReceiver.selector, + try + ILSP1UniversalReceiver(operator).universalReceiver( _TYPEID_LSP7_TOKENOPERATOR, lsp1Data ) - ); + { + return; + } catch { + return; + } } } diff --git a/contracts/LSP7DigitalAsset/LSP7DigitalAssetInitAbstract.sol b/contracts/LSP7DigitalAsset/LSP7DigitalAssetInitAbstract.sol index b27c6fa98..acd9e2751 100644 --- a/contracts/LSP7DigitalAsset/LSP7DigitalAssetInitAbstract.sol +++ b/contracts/LSP7DigitalAsset/LSP7DigitalAssetInitAbstract.sol @@ -18,6 +18,7 @@ import {LSP2Utils} from "../LSP2ERC725YJSONSchema/LSP2Utils.sol"; // constants import {_INTERFACEID_LSP7} from "./LSP7Constants.sol"; +import {LSP7TokenContractCannotHoldValue} from "./LSP7Errors.sol"; import { _LSP17_EXTENSION_PREFIX @@ -86,6 +87,19 @@ abstract contract LSP7DigitalAssetInitAbstract is return _fallbackLSP17Extendable(callData); } + /** + * @dev Reverts whenever someone tries to send native tokens to a LSP7 contract. + * @notice LSP7 contract cannot receive native tokens. + */ + receive() external payable virtual { + // revert on empty calls with no value + if (msg.value == 0) { + revert InvalidFunctionSelector(hex"00000000"); + } + + revert LSP7TokenContractCannotHoldValue(); + } + /** * @dev Forwards the call with the received value to an extension mapped to a function selector. * diff --git a/contracts/LSP7DigitalAsset/LSP7Errors.sol b/contracts/LSP7DigitalAsset/LSP7Errors.sol index 93559fd6e..cc9388941 100644 --- a/contracts/LSP7DigitalAsset/LSP7Errors.sol +++ b/contracts/LSP7DigitalAsset/LSP7Errors.sol @@ -68,3 +68,12 @@ error LSP7TokenOwnerCannotBeOperator(); * @dev Reverts when trying to decrease an operator's allowance to more than its current allowance. */ error LSP7DecreasedAllowanceBelowZero(); + +/** + * @dev Error occurs when sending native tokens to the LSP7 contract without sending any data. + * + * E.g. Sending value without passing a bytes4 function selector to call a LSP17 Extension. + * + * @notice LSP7 contract cannot receive native tokens. + */ +error LSP7TokenContractCannotHoldValue(); diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8Errors.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8Errors.sol index d3f170005..24bbe571c 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8Errors.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8Errors.sol @@ -4,57 +4,57 @@ pragma solidity ^0.8.4; // --- Errors /** - * @dev reverts when `tokenId` has not been minted. + * @dev Reverts when `tokenId` has not been minted. */ error LSP8NonExistentTokenId(bytes32 tokenId); /** - * @dev reverts when `caller` is not the `tokenOwner` of the `tokenId`. + * @dev Reverts when `caller` is not the `tokenOwner` of the `tokenId`. */ error LSP8NotTokenOwner(address tokenOwner, bytes32 tokenId, address caller); /** - * @dev reverts when `caller` is not an allowed operator for `tokenId`. + * @dev Reverts when `caller` is not an allowed operator for `tokenId`. */ error LSP8NotTokenOperator(bytes32 tokenId, address caller); /** - * @dev reverts when `operator` is already authorized for the `tokenId`. + * @dev Reverts when `operator` is already authorized for the `tokenId`. */ error LSP8OperatorAlreadyAuthorized(address operator, bytes32 tokenId); /** - * @dev reverts when trying to set the zero address as an operator. + * @dev Reverts when trying to set the zero address as an operator. */ error LSP8CannotUseAddressZeroAsOperator(); /** - * @dev reverts when trying to send token to the zero address. + * @dev Reverts when trying to send token to the zero address. */ error LSP8CannotSendToAddressZero(); /** - * @dev reverts when specifying the same address for `from` and `to` in a token transfer. + * @dev Reverts when specifying the same address for `from` and `to` in a token transfer. */ error LSP8CannotSendToSelf(); /** - * @dev reverts when `operator` is not an operator for the `tokenId`. + * @dev Reverts when `operator` is not an operator for the `tokenId`. */ error LSP8NonExistingOperator(address operator, bytes32 tokenId); /** - * @dev reverts when `tokenId` has already been minted. + * @dev Reverts when `tokenId` has already been minted. */ error LSP8TokenIdAlreadyMinted(bytes32 tokenId); /** - * @dev reverts when the parameters used for `transferBatch` have different lengths. + * @dev Reverts when the parameters used for `transferBatch` have different lengths. */ error LSP8InvalidTransferBatch(); /** - * @dev reverts if the `tokenReceiver` does not implement LSP1 + * @dev Reverts if the `tokenReceiver` does not implement LSP1 * when minting or transferring tokens with `bool force` set as `false`. */ error LSP8NotifyTokenReceiverContractMissingLSP1Interface( @@ -62,12 +62,21 @@ error LSP8NotifyTokenReceiverContractMissingLSP1Interface( ); /** - * @dev reverts if the `tokenReceiver` is an EOA + * @dev Reverts if the `tokenReceiver` is an EOA * when minting or transferring tokens with `bool force` set as `false`. */ error LSP8NotifyTokenReceiverIsEOA(address tokenReceiver); /** - * @dev reverts when trying to authorize or revoke the token's owner as an operator. + * @dev Reverts when trying to authorize or revoke the token's owner as an operator. */ error LSP8TokenOwnerCannotBeOperator(); + +/** + * @dev Error occurs when sending native tokens to the LSP8 contract without sending any data. + * + * E.g. Sending value without passing a bytes4 function selector to call a LSP17 Extension. + * + * @notice LSP8 contract cannot receive native tokens. + */ +error LSP8TokenContractCannotHoldValue(); diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol index 9e210d62d..9a3193796 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol @@ -20,6 +20,7 @@ import {LSP2Utils} from "../LSP2ERC725YJSONSchema/LSP2Utils.sol"; // constants import {_INTERFACEID_LSP8} from "./LSP8Constants.sol"; +import {LSP8TokenContractCannotHoldValue} from "./LSP8Errors.sol"; import { _LSP17_EXTENSION_PREFIX @@ -92,6 +93,19 @@ abstract contract LSP8IdentifiableDigitalAsset is return _fallbackLSP17Extendable(callData); } + /** + * @dev Reverts whenever someone tries to send native tokens to a LSP8 contract. + * @notice LSP8 contract cannot receive native tokens. + */ + receive() external payable virtual { + // revert on empty calls with no value + if (msg.value == 0) { + revert InvalidFunctionSelector(hex"00000000"); + } + + revert LSP8TokenContractCannotHoldValue(); + } + /** * @dev Forwards the call with the received value to an extension mapped to a function selector. * diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol index 7691db56c..97ac6b16f 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol @@ -534,13 +534,16 @@ abstract contract LSP8IdentifiableDigitalAssetCore is _INTERFACEID_LSP1 ) ) { - operator.call( - abi.encodeWithSelector( - ILSP1UniversalReceiver.universalReceiver.selector, + try + ILSP1UniversalReceiver(operator).universalReceiver( _TYPEID_LSP8_TOKENOPERATOR, lsp1Data ) - ); + { + return; + } catch { + return; + } } } diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetInitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetInitAbstract.sol index 51b3452f9..f6041d856 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetInitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetInitAbstract.sol @@ -20,6 +20,7 @@ import {LSP2Utils} from "../LSP2ERC725YJSONSchema/LSP2Utils.sol"; // constants import {_INTERFACEID_LSP8} from "./LSP8Constants.sol"; +import {LSP8TokenContractCannotHoldValue} from "./LSP8Errors.sol"; import { _LSP17_EXTENSION_PREFIX @@ -92,6 +93,19 @@ abstract contract LSP8IdentifiableDigitalAssetInitAbstract is return _fallbackLSP17Extendable(callData); } + /** + * @dev Reverts whenever someone tries to send native tokens to a LSP8 contract. + * @notice LSP8 contract cannot receive native tokens. + */ + receive() external payable virtual { + // revert on empty calls with no value + if (msg.value == 0) { + revert InvalidFunctionSelector(hex"00000000"); + } + + revert LSP8TokenContractCannotHoldValue(); + } + /** * @dev Forwards the call with the received value to an extension mapped to a function selector. * diff --git a/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md b/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md index b40733a0f..9b93c0984 100644 --- a/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md +++ b/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md @@ -58,6 +58,25 @@ This function is executed when:
+### receive + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#receive) +- Solidity implementation: [`LSP7DigitalAsset.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol) + +::: + +```solidity +receive() external payable; +``` + +_LSP7 contract cannot receive native tokens._ + +Reverts whenever someone tries to send native tokens to a LSP7 contract. + +
+ ### authorizeOperator :::note References @@ -1560,6 +1579,27 @@ reverts if the `tokenReceiver` is an EOA when minting or transferring tokens wit
+### LSP7TokenContractCannotHoldValue + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#lsp7tokencontractcannotholdvalue) +- Solidity implementation: [`LSP7DigitalAsset.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol) +- Error signature: `LSP7TokenContractCannotHoldValue()` +- Error hash: `0x388f5adc` + +::: + +```solidity +error LSP7TokenContractCannotHoldValue(); +``` + +_LSP7 contract cannot receive native tokens._ + +Error occurs when sending native tokens to the LSP7 contract without sending any data. E.g. Sending value without passing a bytes4 function selector to call a LSP17 Extension. + +
+ ### LSP7TokenOwnerCannotBeOperator :::note References diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md index 14084bc92..791796c97 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md @@ -56,6 +56,25 @@ This function is executed when:
+### receive + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#receive) +- Solidity implementation: [`LSP7Burnable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.sol) + +::: + +```solidity +receive() external payable; +``` + +_LSP7 contract cannot receive native tokens._ + +Reverts whenever someone tries to send native tokens to a LSP7 contract. + +
+ ### authorizeOperator :::note References @@ -1585,6 +1604,27 @@ reverts if the `tokenReceiver` is an EOA when minting or transferring tokens wit
+### LSP7TokenContractCannotHoldValue + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#lsp7tokencontractcannotholdvalue) +- Solidity implementation: [`LSP7Burnable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.sol) +- Error signature: `LSP7TokenContractCannotHoldValue()` +- Error hash: `0x388f5adc` + +::: + +```solidity +error LSP7TokenContractCannotHoldValue(); +``` + +_LSP7 contract cannot receive native tokens._ + +Error occurs when sending native tokens to the LSP7 contract without sending any data. E.g. Sending value without passing a bytes4 function selector to call a LSP17 Extension. + +
+ ### LSP7TokenOwnerCannotBeOperator :::note References diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md index 13868b9d0..51e5e5e61 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md @@ -56,6 +56,25 @@ This function is executed when:
+### receive + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#receive) +- Solidity implementation: [`LSP7CappedSupply.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.sol) + +::: + +```solidity +receive() external payable; +``` + +_LSP7 contract cannot receive native tokens._ + +Reverts whenever someone tries to send native tokens to a LSP7 contract. + +
+ ### authorizeOperator :::note References @@ -1611,6 +1630,27 @@ reverts if the `tokenReceiver` is an EOA when minting or transferring tokens wit
+### LSP7TokenContractCannotHoldValue + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#lsp7tokencontractcannotholdvalue) +- Solidity implementation: [`LSP7CappedSupply.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.sol) +- Error signature: `LSP7TokenContractCannotHoldValue()` +- Error hash: `0x388f5adc` + +::: + +```solidity +error LSP7TokenContractCannotHoldValue(); +``` + +_LSP7 contract cannot receive native tokens._ + +Error occurs when sending native tokens to the LSP7 contract without sending any data. E.g. Sending value without passing a bytes4 function selector to call a LSP17 Extension. + +
+ ### LSP7TokenOwnerCannotBeOperator :::note References diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md index 8905143e7..649bc8d60 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md @@ -56,6 +56,25 @@ This function is executed when:
+### receive + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#receive) +- Solidity implementation: [`LSP7CompatibleERC20.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol) + +::: + +```solidity +receive() external payable; +``` + +_LSP7 contract cannot receive native tokens._ + +Reverts whenever someone tries to send native tokens to a LSP7 contract. + +
+ ### allowance :::note References @@ -1730,6 +1749,27 @@ reverts if the `tokenReceiver` is an EOA when minting or transferring tokens wit
+### LSP7TokenContractCannotHoldValue + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#lsp7tokencontractcannotholdvalue) +- Solidity implementation: [`LSP7CompatibleERC20.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol) +- Error signature: `LSP7TokenContractCannotHoldValue()` +- Error hash: `0x388f5adc` + +::: + +```solidity +error LSP7TokenContractCannotHoldValue(); +``` + +_LSP7 contract cannot receive native tokens._ + +Error occurs when sending native tokens to the LSP7 contract without sending any data. E.g. Sending value without passing a bytes4 function selector to call a LSP17 Extension. + +
+ ### LSP7TokenOwnerCannotBeOperator :::note References diff --git a/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md b/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md index a80ed6335..e14dbe18d 100644 --- a/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md +++ b/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md @@ -61,6 +61,21 @@ fallback() external payable;
+### receive + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#receive) +- Solidity implementation: [`LSP7CompatibleERC20Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol) + +::: + +```solidity +receive() external payable; +``` + +
+ ### allowance :::note References @@ -1768,6 +1783,27 @@ reverts if the `tokenReceiver` is an EOA when minting or transferring tokens wit
+### LSP7TokenContractCannotHoldValue + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#lsp7tokencontractcannotholdvalue) +- Solidity implementation: [`LSP7CompatibleERC20Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol) +- Error signature: `LSP7TokenContractCannotHoldValue()` +- Error hash: `0x388f5adc` + +::: + +```solidity +error LSP7TokenContractCannotHoldValue(); +``` + +_LSP7 contract cannot receive native tokens._ + +Error occurs when sending native tokens to the LSP7 contract without sending any data. E.g. Sending value without passing a bytes4 function selector to call a LSP17 Extension. + +
+ ### LSP7TokenOwnerCannotBeOperator :::note References diff --git a/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md b/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md index ddf2e1b70..c3f22bcc6 100644 --- a/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md +++ b/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md @@ -87,6 +87,25 @@ This function is executed when:
+### receive + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#receive) +- Solidity implementation: [`LSP7Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/presets/LSP7Mintable.sol) + +::: + +```solidity +receive() external payable; +``` + +_LSP7 contract cannot receive native tokens._ + +Reverts whenever someone tries to send native tokens to a LSP7 contract. + +
+ ### authorizeOperator :::note References @@ -1622,6 +1641,27 @@ reverts if the `tokenReceiver` is an EOA when minting or transferring tokens wit
+### LSP7TokenContractCannotHoldValue + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#lsp7tokencontractcannotholdvalue) +- Solidity implementation: [`LSP7Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/presets/LSP7Mintable.sol) +- Error signature: `LSP7TokenContractCannotHoldValue()` +- Error hash: `0x388f5adc` + +::: + +```solidity +error LSP7TokenContractCannotHoldValue(); +``` + +_LSP7 contract cannot receive native tokens._ + +Error occurs when sending native tokens to the LSP7 contract without sending any data. E.g. Sending value without passing a bytes4 function selector to call a LSP17 Extension. + +
+ ### LSP7TokenOwnerCannotBeOperator :::note References diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md b/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md index 573b1df68..47bb4a37c 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md @@ -58,6 +58,25 @@ This function is executed when:
+### receive + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#receive) +- Solidity implementation: [`LSP8IdentifiableDigitalAsset.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol) + +::: + +```solidity +receive() external payable; +``` + +_LSP8 contract cannot receive native tokens._ + +Reverts whenever someone tries to send native tokens to a LSP8 contract. + +
+ ### authorizeOperator :::note References @@ -1323,7 +1342,7 @@ Reverts when trying to edit the data key `LSP4TokenSymbol` after the digital ass error LSP8CannotSendToAddressZero(); ``` -reverts when trying to send token to the zero address. +Reverts when trying to send token to the zero address.
@@ -1342,7 +1361,7 @@ reverts when trying to send token to the zero address. error LSP8CannotSendToSelf(); ``` -reverts when specifying the same address for `from` and `to` in a token transfer. +Reverts when specifying the same address for `from` and `to` in a token transfer.
@@ -1361,7 +1380,7 @@ reverts when specifying the same address for `from` and `to` in a token transfer error LSP8CannotUseAddressZeroAsOperator(); ``` -reverts when trying to set the zero address as an operator. +Reverts when trying to set the zero address as an operator.
@@ -1380,7 +1399,7 @@ reverts when trying to set the zero address as an operator. error LSP8InvalidTransferBatch(); ``` -reverts when the parameters used for `transferBatch` have different lengths. +Reverts when the parameters used for `transferBatch` have different lengths.
@@ -1399,7 +1418,7 @@ reverts when the parameters used for `transferBatch` have different lengths. error LSP8NonExistentTokenId(bytes32 tokenId); ``` -reverts when `tokenId` has not been minted. +Reverts when `tokenId` has not been minted. #### Parameters @@ -1424,7 +1443,7 @@ reverts when `tokenId` has not been minted. error LSP8NonExistingOperator(address operator, bytes32 tokenId); ``` -reverts when `operator` is not an operator for the `tokenId`. +Reverts when `operator` is not an operator for the `tokenId`. #### Parameters @@ -1450,7 +1469,7 @@ reverts when `operator` is not an operator for the `tokenId`. error LSP8NotTokenOperator(bytes32 tokenId, address caller); ``` -reverts when `caller` is not an allowed operator for `tokenId`. +Reverts when `caller` is not an allowed operator for `tokenId`. #### Parameters @@ -1476,7 +1495,7 @@ reverts when `caller` is not an allowed operator for `tokenId`. error LSP8NotTokenOwner(address tokenOwner, bytes32 tokenId, address caller); ``` -reverts when `caller` is not the `tokenOwner` of the `tokenId`. +Reverts when `caller` is not the `tokenOwner` of the `tokenId`. #### Parameters @@ -1505,7 +1524,7 @@ error LSP8NotifyTokenReceiverContractMissingLSP1Interface( ); ``` -reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. +Reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1530,7 +1549,7 @@ reverts if the `tokenReceiver` does not implement LSP1 when minting or transferr error LSP8NotifyTokenReceiverIsEOA(address tokenReceiver); ``` -reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. +Reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1555,7 +1574,7 @@ reverts if the `tokenReceiver` is an EOA when minting or transferring tokens wit error LSP8OperatorAlreadyAuthorized(address operator, bytes32 tokenId); ``` -reverts when `operator` is already authorized for the `tokenId`. +Reverts when `operator` is already authorized for the `tokenId`. #### Parameters @@ -1566,6 +1585,27 @@ reverts when `operator` is already authorized for the `tokenId`.
+### LSP8TokenContractCannotHoldValue + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokencontractcannotholdvalue) +- Solidity implementation: [`LSP8IdentifiableDigitalAsset.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol) +- Error signature: `LSP8TokenContractCannotHoldValue()` +- Error hash: `0x61f49442` + +::: + +```solidity +error LSP8TokenContractCannotHoldValue(); +``` + +_LSP8 contract cannot receive native tokens._ + +Error occurs when sending native tokens to the LSP8 contract without sending any data. E.g. Sending value without passing a bytes4 function selector to call a LSP17 Extension. + +
+ ### LSP8TokenOwnerCannotBeOperator :::note References @@ -1581,7 +1621,7 @@ reverts when `operator` is already authorized for the `tokenId`. error LSP8TokenOwnerCannotBeOperator(); ``` -reverts when trying to authorize or revoke the token's owner as an operator. +Reverts when trying to authorize or revoke the token's owner as an operator.
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md index 68713e949..6864202c2 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md @@ -56,6 +56,25 @@ This function is executed when:
+### receive + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#receive) +- Solidity implementation: [`LSP8Burnable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.sol) + +::: + +```solidity +receive() external payable; +``` + +_LSP8 contract cannot receive native tokens._ + +Reverts whenever someone tries to send native tokens to a LSP8 contract. + +
+ ### authorizeOperator :::note References @@ -1349,7 +1368,7 @@ Reverts when trying to edit the data key `LSP4TokenSymbol` after the digital ass error LSP8CannotSendToAddressZero(); ``` -reverts when trying to send token to the zero address. +Reverts when trying to send token to the zero address.
@@ -1368,7 +1387,7 @@ reverts when trying to send token to the zero address. error LSP8CannotSendToSelf(); ``` -reverts when specifying the same address for `from` and `to` in a token transfer. +Reverts when specifying the same address for `from` and `to` in a token transfer.
@@ -1387,7 +1406,7 @@ reverts when specifying the same address for `from` and `to` in a token transfer error LSP8CannotUseAddressZeroAsOperator(); ``` -reverts when trying to set the zero address as an operator. +Reverts when trying to set the zero address as an operator.
@@ -1406,7 +1425,7 @@ reverts when trying to set the zero address as an operator. error LSP8InvalidTransferBatch(); ``` -reverts when the parameters used for `transferBatch` have different lengths. +Reverts when the parameters used for `transferBatch` have different lengths.
@@ -1425,7 +1444,7 @@ reverts when the parameters used for `transferBatch` have different lengths. error LSP8NonExistentTokenId(bytes32 tokenId); ``` -reverts when `tokenId` has not been minted. +Reverts when `tokenId` has not been minted. #### Parameters @@ -1450,7 +1469,7 @@ reverts when `tokenId` has not been minted. error LSP8NonExistingOperator(address operator, bytes32 tokenId); ``` -reverts when `operator` is not an operator for the `tokenId`. +Reverts when `operator` is not an operator for the `tokenId`. #### Parameters @@ -1476,7 +1495,7 @@ reverts when `operator` is not an operator for the `tokenId`. error LSP8NotTokenOperator(bytes32 tokenId, address caller); ``` -reverts when `caller` is not an allowed operator for `tokenId`. +Reverts when `caller` is not an allowed operator for `tokenId`. #### Parameters @@ -1502,7 +1521,7 @@ reverts when `caller` is not an allowed operator for `tokenId`. error LSP8NotTokenOwner(address tokenOwner, bytes32 tokenId, address caller); ``` -reverts when `caller` is not the `tokenOwner` of the `tokenId`. +Reverts when `caller` is not the `tokenOwner` of the `tokenId`. #### Parameters @@ -1531,7 +1550,7 @@ error LSP8NotifyTokenReceiverContractMissingLSP1Interface( ); ``` -reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. +Reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1556,7 +1575,7 @@ reverts if the `tokenReceiver` does not implement LSP1 when minting or transferr error LSP8NotifyTokenReceiverIsEOA(address tokenReceiver); ``` -reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. +Reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1581,7 +1600,7 @@ reverts if the `tokenReceiver` is an EOA when minting or transferring tokens wit error LSP8OperatorAlreadyAuthorized(address operator, bytes32 tokenId); ``` -reverts when `operator` is already authorized for the `tokenId`. +Reverts when `operator` is already authorized for the `tokenId`. #### Parameters @@ -1592,6 +1611,27 @@ reverts when `operator` is already authorized for the `tokenId`.
+### LSP8TokenContractCannotHoldValue + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokencontractcannotholdvalue) +- Solidity implementation: [`LSP8Burnable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.sol) +- Error signature: `LSP8TokenContractCannotHoldValue()` +- Error hash: `0x61f49442` + +::: + +```solidity +error LSP8TokenContractCannotHoldValue(); +``` + +_LSP8 contract cannot receive native tokens._ + +Error occurs when sending native tokens to the LSP8 contract without sending any data. E.g. Sending value without passing a bytes4 function selector to call a LSP17 Extension. + +
+ ### LSP8TokenOwnerCannotBeOperator :::note References @@ -1607,7 +1647,7 @@ reverts when `operator` is already authorized for the `tokenId`. error LSP8TokenOwnerCannotBeOperator(); ``` -reverts when trying to authorize or revoke the token's owner as an operator. +Reverts when trying to authorize or revoke the token's owner as an operator.
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md index 6c75b59c4..e659b3842 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md @@ -56,6 +56,25 @@ This function is executed when:
+### receive + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#receive) +- Solidity implementation: [`LSP8CappedSupply.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.sol) + +::: + +```solidity +receive() external payable; +``` + +_LSP8 contract cannot receive native tokens._ + +Reverts whenever someone tries to send native tokens to a LSP8 contract. + +
+ ### authorizeOperator :::note References @@ -1333,7 +1352,7 @@ Reverts when trying to edit the data key `LSP4TokenSymbol` after the digital ass error LSP8CannotSendToAddressZero(); ``` -reverts when trying to send token to the zero address. +Reverts when trying to send token to the zero address.
@@ -1352,7 +1371,7 @@ reverts when trying to send token to the zero address. error LSP8CannotSendToSelf(); ``` -reverts when specifying the same address for `from` and `to` in a token transfer. +Reverts when specifying the same address for `from` and `to` in a token transfer.
@@ -1371,7 +1390,7 @@ reverts when specifying the same address for `from` and `to` in a token transfer error LSP8CannotUseAddressZeroAsOperator(); ``` -reverts when trying to set the zero address as an operator. +Reverts when trying to set the zero address as an operator.
@@ -1432,7 +1451,7 @@ Reverts when setting `0` for the [`tokenSupplyCap`](#tokensupplycap). The max to error LSP8InvalidTransferBatch(); ``` -reverts when the parameters used for `transferBatch` have different lengths. +Reverts when the parameters used for `transferBatch` have different lengths.
@@ -1451,7 +1470,7 @@ reverts when the parameters used for `transferBatch` have different lengths. error LSP8NonExistentTokenId(bytes32 tokenId); ``` -reverts when `tokenId` has not been minted. +Reverts when `tokenId` has not been minted. #### Parameters @@ -1476,7 +1495,7 @@ reverts when `tokenId` has not been minted. error LSP8NonExistingOperator(address operator, bytes32 tokenId); ``` -reverts when `operator` is not an operator for the `tokenId`. +Reverts when `operator` is not an operator for the `tokenId`. #### Parameters @@ -1502,7 +1521,7 @@ reverts when `operator` is not an operator for the `tokenId`. error LSP8NotTokenOperator(bytes32 tokenId, address caller); ``` -reverts when `caller` is not an allowed operator for `tokenId`. +Reverts when `caller` is not an allowed operator for `tokenId`. #### Parameters @@ -1528,7 +1547,7 @@ reverts when `caller` is not an allowed operator for `tokenId`. error LSP8NotTokenOwner(address tokenOwner, bytes32 tokenId, address caller); ``` -reverts when `caller` is not the `tokenOwner` of the `tokenId`. +Reverts when `caller` is not the `tokenOwner` of the `tokenId`. #### Parameters @@ -1557,7 +1576,7 @@ error LSP8NotifyTokenReceiverContractMissingLSP1Interface( ); ``` -reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. +Reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1582,7 +1601,7 @@ reverts if the `tokenReceiver` does not implement LSP1 when minting or transferr error LSP8NotifyTokenReceiverIsEOA(address tokenReceiver); ``` -reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. +Reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1607,7 +1626,7 @@ reverts if the `tokenReceiver` is an EOA when minting or transferring tokens wit error LSP8OperatorAlreadyAuthorized(address operator, bytes32 tokenId); ``` -reverts when `operator` is already authorized for the `tokenId`. +Reverts when `operator` is already authorized for the `tokenId`. #### Parameters @@ -1618,6 +1637,27 @@ reverts when `operator` is already authorized for the `tokenId`.
+### LSP8TokenContractCannotHoldValue + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokencontractcannotholdvalue) +- Solidity implementation: [`LSP8CappedSupply.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.sol) +- Error signature: `LSP8TokenContractCannotHoldValue()` +- Error hash: `0x61f49442` + +::: + +```solidity +error LSP8TokenContractCannotHoldValue(); +``` + +_LSP8 contract cannot receive native tokens._ + +Error occurs when sending native tokens to the LSP8 contract without sending any data. E.g. Sending value without passing a bytes4 function selector to call a LSP17 Extension. + +
+ ### LSP8TokenOwnerCannotBeOperator :::note References @@ -1633,7 +1673,7 @@ reverts when `operator` is already authorized for the `tokenId`. error LSP8TokenOwnerCannotBeOperator(); ``` -reverts when trying to authorize or revoke the token's owner as an operator. +Reverts when trying to authorize or revoke the token's owner as an operator.
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md index 228a7a274..beb1a520d 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md @@ -56,6 +56,25 @@ This function is executed when:
+### receive + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#receive) +- Solidity implementation: [`LSP8CompatibleERC721.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol) + +::: + +```solidity +receive() external payable; +``` + +_LSP8 contract cannot receive native tokens._ + +Reverts whenever someone tries to send native tokens to a LSP8 contract. + +
+ ### approve :::note References @@ -1728,7 +1747,7 @@ Reverts when trying to edit the data key `LSP4TokenSymbol` after the digital ass error LSP8CannotSendToAddressZero(); ``` -reverts when trying to send token to the zero address. +Reverts when trying to send token to the zero address.
@@ -1747,7 +1766,7 @@ reverts when trying to send token to the zero address. error LSP8CannotSendToSelf(); ``` -reverts when specifying the same address for `from` and `to` in a token transfer. +Reverts when specifying the same address for `from` and `to` in a token transfer.
@@ -1766,7 +1785,7 @@ reverts when specifying the same address for `from` and `to` in a token transfer error LSP8CannotUseAddressZeroAsOperator(); ``` -reverts when trying to set the zero address as an operator. +Reverts when trying to set the zero address as an operator.
@@ -1785,7 +1804,7 @@ reverts when trying to set the zero address as an operator. error LSP8InvalidTransferBatch(); ``` -reverts when the parameters used for `transferBatch` have different lengths. +Reverts when the parameters used for `transferBatch` have different lengths.
@@ -1804,7 +1823,7 @@ reverts when the parameters used for `transferBatch` have different lengths. error LSP8NonExistentTokenId(bytes32 tokenId); ``` -reverts when `tokenId` has not been minted. +Reverts when `tokenId` has not been minted. #### Parameters @@ -1829,7 +1848,7 @@ reverts when `tokenId` has not been minted. error LSP8NonExistingOperator(address operator, bytes32 tokenId); ``` -reverts when `operator` is not an operator for the `tokenId`. +Reverts when `operator` is not an operator for the `tokenId`. #### Parameters @@ -1855,7 +1874,7 @@ reverts when `operator` is not an operator for the `tokenId`. error LSP8NotTokenOperator(bytes32 tokenId, address caller); ``` -reverts when `caller` is not an allowed operator for `tokenId`. +Reverts when `caller` is not an allowed operator for `tokenId`. #### Parameters @@ -1881,7 +1900,7 @@ reverts when `caller` is not an allowed operator for `tokenId`. error LSP8NotTokenOwner(address tokenOwner, bytes32 tokenId, address caller); ``` -reverts when `caller` is not the `tokenOwner` of the `tokenId`. +Reverts when `caller` is not the `tokenOwner` of the `tokenId`. #### Parameters @@ -1910,7 +1929,7 @@ error LSP8NotifyTokenReceiverContractMissingLSP1Interface( ); ``` -reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. +Reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1935,7 +1954,7 @@ reverts if the `tokenReceiver` does not implement LSP1 when minting or transferr error LSP8NotifyTokenReceiverIsEOA(address tokenReceiver); ``` -reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. +Reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1960,7 +1979,7 @@ reverts if the `tokenReceiver` is an EOA when minting or transferring tokens wit error LSP8OperatorAlreadyAuthorized(address operator, bytes32 tokenId); ``` -reverts when `operator` is already authorized for the `tokenId`. +Reverts when `operator` is already authorized for the `tokenId`. #### Parameters @@ -1971,6 +1990,27 @@ reverts when `operator` is already authorized for the `tokenId`.
+### LSP8TokenContractCannotHoldValue + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokencontractcannotholdvalue) +- Solidity implementation: [`LSP8CompatibleERC721.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol) +- Error signature: `LSP8TokenContractCannotHoldValue()` +- Error hash: `0x61f49442` + +::: + +```solidity +error LSP8TokenContractCannotHoldValue(); +``` + +_LSP8 contract cannot receive native tokens._ + +Error occurs when sending native tokens to the LSP8 contract without sending any data. E.g. Sending value without passing a bytes4 function selector to call a LSP17 Extension. + +
+ ### LSP8TokenOwnerCannotBeOperator :::note References @@ -1986,7 +2026,7 @@ reverts when `operator` is already authorized for the `tokenId`. error LSP8TokenOwnerCannotBeOperator(); ``` -reverts when trying to authorize or revoke the token's owner as an operator. +Reverts when trying to authorize or revoke the token's owner as an operator.
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md index d4636235b..5b4667384 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md @@ -56,6 +56,25 @@ This function is executed when:
+### receive + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#receive) +- Solidity implementation: [`LSP8Enumerable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.sol) + +::: + +```solidity +receive() external payable; +``` + +_LSP8 contract cannot receive native tokens._ + +Reverts whenever someone tries to send native tokens to a LSP8 contract. + +
+ ### authorizeOperator :::note References @@ -1350,7 +1369,7 @@ Reverts when trying to edit the data key `LSP4TokenSymbol` after the digital ass error LSP8CannotSendToAddressZero(); ``` -reverts when trying to send token to the zero address. +Reverts when trying to send token to the zero address.
@@ -1369,7 +1388,7 @@ reverts when trying to send token to the zero address. error LSP8CannotSendToSelf(); ``` -reverts when specifying the same address for `from` and `to` in a token transfer. +Reverts when specifying the same address for `from` and `to` in a token transfer.
@@ -1388,7 +1407,7 @@ reverts when specifying the same address for `from` and `to` in a token transfer error LSP8CannotUseAddressZeroAsOperator(); ``` -reverts when trying to set the zero address as an operator. +Reverts when trying to set the zero address as an operator.
@@ -1407,7 +1426,7 @@ reverts when trying to set the zero address as an operator. error LSP8InvalidTransferBatch(); ``` -reverts when the parameters used for `transferBatch` have different lengths. +Reverts when the parameters used for `transferBatch` have different lengths.
@@ -1426,7 +1445,7 @@ reverts when the parameters used for `transferBatch` have different lengths. error LSP8NonExistentTokenId(bytes32 tokenId); ``` -reverts when `tokenId` has not been minted. +Reverts when `tokenId` has not been minted. #### Parameters @@ -1451,7 +1470,7 @@ reverts when `tokenId` has not been minted. error LSP8NonExistingOperator(address operator, bytes32 tokenId); ``` -reverts when `operator` is not an operator for the `tokenId`. +Reverts when `operator` is not an operator for the `tokenId`. #### Parameters @@ -1477,7 +1496,7 @@ reverts when `operator` is not an operator for the `tokenId`. error LSP8NotTokenOperator(bytes32 tokenId, address caller); ``` -reverts when `caller` is not an allowed operator for `tokenId`. +Reverts when `caller` is not an allowed operator for `tokenId`. #### Parameters @@ -1503,7 +1522,7 @@ reverts when `caller` is not an allowed operator for `tokenId`. error LSP8NotTokenOwner(address tokenOwner, bytes32 tokenId, address caller); ``` -reverts when `caller` is not the `tokenOwner` of the `tokenId`. +Reverts when `caller` is not the `tokenOwner` of the `tokenId`. #### Parameters @@ -1532,7 +1551,7 @@ error LSP8NotifyTokenReceiverContractMissingLSP1Interface( ); ``` -reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. +Reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1557,7 +1576,7 @@ reverts if the `tokenReceiver` does not implement LSP1 when minting or transferr error LSP8NotifyTokenReceiverIsEOA(address tokenReceiver); ``` -reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. +Reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1582,7 +1601,7 @@ reverts if the `tokenReceiver` is an EOA when minting or transferring tokens wit error LSP8OperatorAlreadyAuthorized(address operator, bytes32 tokenId); ``` -reverts when `operator` is already authorized for the `tokenId`. +Reverts when `operator` is already authorized for the `tokenId`. #### Parameters @@ -1593,6 +1612,27 @@ reverts when `operator` is already authorized for the `tokenId`.
+### LSP8TokenContractCannotHoldValue + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokencontractcannotholdvalue) +- Solidity implementation: [`LSP8Enumerable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.sol) +- Error signature: `LSP8TokenContractCannotHoldValue()` +- Error hash: `0x61f49442` + +::: + +```solidity +error LSP8TokenContractCannotHoldValue(); +``` + +_LSP8 contract cannot receive native tokens._ + +Error occurs when sending native tokens to the LSP8 contract without sending any data. E.g. Sending value without passing a bytes4 function selector to call a LSP17 Extension. + +
+ ### LSP8TokenOwnerCannotBeOperator :::note References @@ -1608,7 +1648,7 @@ reverts when `operator` is already authorized for the `tokenId`. error LSP8TokenOwnerCannotBeOperator(); ``` -reverts when trying to authorize or revoke the token's owner as an operator. +Reverts when trying to authorize or revoke the token's owner as an operator.
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md index 9e6460b10..687547fe6 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md @@ -61,6 +61,21 @@ fallback() external payable;
+### receive + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#receive) +- Solidity implementation: [`LSP8CompatibleERC721Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol) + +::: + +```solidity +receive() external payable; +``` + +
+ ### approve :::note References @@ -1768,7 +1783,7 @@ Reverts when trying to edit the data key `LSP4TokenSymbol` after the digital ass error LSP8CannotSendToAddressZero(); ``` -reverts when trying to send token to the zero address. +Reverts when trying to send token to the zero address.
@@ -1787,7 +1802,7 @@ reverts when trying to send token to the zero address. error LSP8CannotSendToSelf(); ``` -reverts when specifying the same address for `from` and `to` in a token transfer. +Reverts when specifying the same address for `from` and `to` in a token transfer.
@@ -1806,7 +1821,7 @@ reverts when specifying the same address for `from` and `to` in a token transfer error LSP8CannotUseAddressZeroAsOperator(); ``` -reverts when trying to set the zero address as an operator. +Reverts when trying to set the zero address as an operator.
@@ -1825,7 +1840,7 @@ reverts when trying to set the zero address as an operator. error LSP8InvalidTransferBatch(); ``` -reverts when the parameters used for `transferBatch` have different lengths. +Reverts when the parameters used for `transferBatch` have different lengths.
@@ -1844,7 +1859,7 @@ reverts when the parameters used for `transferBatch` have different lengths. error LSP8NonExistentTokenId(bytes32 tokenId); ``` -reverts when `tokenId` has not been minted. +Reverts when `tokenId` has not been minted. #### Parameters @@ -1869,7 +1884,7 @@ reverts when `tokenId` has not been minted. error LSP8NonExistingOperator(address operator, bytes32 tokenId); ``` -reverts when `operator` is not an operator for the `tokenId`. +Reverts when `operator` is not an operator for the `tokenId`. #### Parameters @@ -1895,7 +1910,7 @@ reverts when `operator` is not an operator for the `tokenId`. error LSP8NotTokenOperator(bytes32 tokenId, address caller); ``` -reverts when `caller` is not an allowed operator for `tokenId`. +Reverts when `caller` is not an allowed operator for `tokenId`. #### Parameters @@ -1921,7 +1936,7 @@ reverts when `caller` is not an allowed operator for `tokenId`. error LSP8NotTokenOwner(address tokenOwner, bytes32 tokenId, address caller); ``` -reverts when `caller` is not the `tokenOwner` of the `tokenId`. +Reverts when `caller` is not the `tokenOwner` of the `tokenId`. #### Parameters @@ -1950,7 +1965,7 @@ error LSP8NotifyTokenReceiverContractMissingLSP1Interface( ); ``` -reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. +Reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1975,7 +1990,7 @@ reverts if the `tokenReceiver` does not implement LSP1 when minting or transferr error LSP8NotifyTokenReceiverIsEOA(address tokenReceiver); ``` -reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. +Reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -2000,7 +2015,7 @@ reverts if the `tokenReceiver` is an EOA when minting or transferring tokens wit error LSP8OperatorAlreadyAuthorized(address operator, bytes32 tokenId); ``` -reverts when `operator` is already authorized for the `tokenId`. +Reverts when `operator` is already authorized for the `tokenId`. #### Parameters @@ -2011,6 +2026,27 @@ reverts when `operator` is already authorized for the `tokenId`.
+### LSP8TokenContractCannotHoldValue + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokencontractcannotholdvalue) +- Solidity implementation: [`LSP8CompatibleERC721Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol) +- Error signature: `LSP8TokenContractCannotHoldValue()` +- Error hash: `0x61f49442` + +::: + +```solidity +error LSP8TokenContractCannotHoldValue(); +``` + +_LSP8 contract cannot receive native tokens._ + +Error occurs when sending native tokens to the LSP8 contract without sending any data. E.g. Sending value without passing a bytes4 function selector to call a LSP17 Extension. + +
+ ### LSP8TokenIdAlreadyMinted :::note References @@ -2026,7 +2062,7 @@ reverts when `operator` is already authorized for the `tokenId`. error LSP8TokenIdAlreadyMinted(bytes32 tokenId); ``` -reverts when `tokenId` has already been minted. +Reverts when `tokenId` has already been minted. #### Parameters @@ -2051,7 +2087,7 @@ reverts when `tokenId` has already been minted. error LSP8TokenOwnerCannotBeOperator(); ``` -reverts when trying to authorize or revoke the token's owner as an operator. +Reverts when trying to authorize or revoke the token's owner as an operator.
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md index ec01dd97e..569610357 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md @@ -81,6 +81,25 @@ This function is executed when:
+### receive + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#receive) +- Solidity implementation: [`LSP8Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol) + +::: + +```solidity +receive() external payable; +``` + +_LSP8 contract cannot receive native tokens._ + +Reverts whenever someone tries to send native tokens to a LSP8 contract. + +
+ ### authorizeOperator :::note References @@ -1381,7 +1400,7 @@ Reverts when trying to edit the data key `LSP4TokenSymbol` after the digital ass error LSP8CannotSendToAddressZero(); ``` -reverts when trying to send token to the zero address. +Reverts when trying to send token to the zero address.
@@ -1400,7 +1419,7 @@ reverts when trying to send token to the zero address. error LSP8CannotSendToSelf(); ``` -reverts when specifying the same address for `from` and `to` in a token transfer. +Reverts when specifying the same address for `from` and `to` in a token transfer.
@@ -1419,7 +1438,7 @@ reverts when specifying the same address for `from` and `to` in a token transfer error LSP8CannotUseAddressZeroAsOperator(); ``` -reverts when trying to set the zero address as an operator. +Reverts when trying to set the zero address as an operator.
@@ -1438,7 +1457,7 @@ reverts when trying to set the zero address as an operator. error LSP8InvalidTransferBatch(); ``` -reverts when the parameters used for `transferBatch` have different lengths. +Reverts when the parameters used for `transferBatch` have different lengths.
@@ -1457,7 +1476,7 @@ reverts when the parameters used for `transferBatch` have different lengths. error LSP8NonExistentTokenId(bytes32 tokenId); ``` -reverts when `tokenId` has not been minted. +Reverts when `tokenId` has not been minted. #### Parameters @@ -1482,7 +1501,7 @@ reverts when `tokenId` has not been minted. error LSP8NonExistingOperator(address operator, bytes32 tokenId); ``` -reverts when `operator` is not an operator for the `tokenId`. +Reverts when `operator` is not an operator for the `tokenId`. #### Parameters @@ -1508,7 +1527,7 @@ reverts when `operator` is not an operator for the `tokenId`. error LSP8NotTokenOperator(bytes32 tokenId, address caller); ``` -reverts when `caller` is not an allowed operator for `tokenId`. +Reverts when `caller` is not an allowed operator for `tokenId`. #### Parameters @@ -1534,7 +1553,7 @@ reverts when `caller` is not an allowed operator for `tokenId`. error LSP8NotTokenOwner(address tokenOwner, bytes32 tokenId, address caller); ``` -reverts when `caller` is not the `tokenOwner` of the `tokenId`. +Reverts when `caller` is not the `tokenOwner` of the `tokenId`. #### Parameters @@ -1563,7 +1582,7 @@ error LSP8NotifyTokenReceiverContractMissingLSP1Interface( ); ``` -reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. +Reverts if the `tokenReceiver` does not implement LSP1 when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1588,7 +1607,7 @@ reverts if the `tokenReceiver` does not implement LSP1 when minting or transferr error LSP8NotifyTokenReceiverIsEOA(address tokenReceiver); ``` -reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. +Reverts if the `tokenReceiver` is an EOA when minting or transferring tokens with `bool force` set as `false`. #### Parameters @@ -1613,7 +1632,7 @@ reverts if the `tokenReceiver` is an EOA when minting or transferring tokens wit error LSP8OperatorAlreadyAuthorized(address operator, bytes32 tokenId); ``` -reverts when `operator` is already authorized for the `tokenId`. +Reverts when `operator` is already authorized for the `tokenId`. #### Parameters @@ -1624,6 +1643,27 @@ reverts when `operator` is already authorized for the `tokenId`.
+### LSP8TokenContractCannotHoldValue + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokencontractcannotholdvalue) +- Solidity implementation: [`LSP8Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol) +- Error signature: `LSP8TokenContractCannotHoldValue()` +- Error hash: `0x61f49442` + +::: + +```solidity +error LSP8TokenContractCannotHoldValue(); +``` + +_LSP8 contract cannot receive native tokens._ + +Error occurs when sending native tokens to the LSP8 contract without sending any data. E.g. Sending value without passing a bytes4 function selector to call a LSP17 Extension. + +
+ ### LSP8TokenIdAlreadyMinted :::note References @@ -1639,7 +1679,7 @@ reverts when `operator` is already authorized for the `tokenId`. error LSP8TokenIdAlreadyMinted(bytes32 tokenId); ``` -reverts when `tokenId` has already been minted. +Reverts when `tokenId` has already been minted. #### Parameters @@ -1664,7 +1704,7 @@ reverts when `tokenId` has already been minted. error LSP8TokenOwnerCannotBeOperator(); ``` -reverts when trying to authorize or revoke the token's owner as an operator. +Reverts when trying to authorize or revoke the token's owner as an operator.
diff --git a/tests/LSP17ContractExtension/LSP17ExtendableTokens.behaviour.ts b/tests/LSP17ContractExtension/LSP17ExtendableTokens.behaviour.ts index 095008e08..e6e20a87d 100644 --- a/tests/LSP17ContractExtension/LSP17ExtendableTokens.behaviour.ts +++ b/tests/LSP17ContractExtension/LSP17ExtendableTokens.behaviour.ts @@ -145,30 +145,6 @@ export const shouldBehaveLikeLSP17 = (buildContext: () => Promise { - describe('when making a call without any value', () => { - it('should revert', async () => { - await expect( - context.accounts[0].sendTransaction({ - to: context.contract.address, - }), - ).to.be.revertedWithCustomError(context.contract, 'InvalidFunctionSelector'); - }); - }); - - describe('when making a call with sending value', () => { - it('should revert', async () => { - const amountSent = 200; - await expect( - context.accounts[0].sendTransaction({ - to: context.contract.address, - value: amountSent, - }), - ).to.be.revertedWithCustomError(context.contract, 'InvalidFunctionSelector'); - }); - }); - }); - describe('when calling the contract with calldata', () => { describe("when calling method that doesn't exist", () => { describe('when there is no extension for the function called', () => { diff --git a/tests/LSP7DigitalAsset/LSP7DigitalAsset.behaviour.ts b/tests/LSP7DigitalAsset/LSP7DigitalAsset.behaviour.ts index d965032e1..5e57cc931 100644 --- a/tests/LSP7DigitalAsset/LSP7DigitalAsset.behaviour.ts +++ b/tests/LSP7DigitalAsset/LSP7DigitalAsset.behaviour.ts @@ -2144,6 +2144,32 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise { + describe('when making a call without any value', () => { + it('should revert', async () => { + await expect( + context.accounts.anyone.sendTransaction({ + to: context.lsp7.address, + }), + ) + .to.be.revertedWithCustomError(context.lsp7, 'InvalidFunctionSelector') + .withArgs('0x00000000'); + }); + }); + + describe('when making a call with sending value', () => { + it('should revert', async () => { + const amountSent = 200; + await expect( + context.accounts.anyone.sendTransaction({ + to: context.lsp7.address, + value: amountSent, + }), + ).to.be.revertedWithCustomError(context.lsp7, 'LSP7TokenContractCannotHoldValue'); + }); + }); + }); }; export type LSP7InitializeTestContext = { diff --git a/tests/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.behaviour.ts b/tests/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.behaviour.ts index ecf3bb2f1..df1c4a9af 100644 --- a/tests/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.behaviour.ts +++ b/tests/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.behaviour.ts @@ -1765,6 +1765,32 @@ export const shouldBehaveLikeLSP8 = (buildContext: () => Promise { + describe('when making a call without any value', () => { + it('should revert', async () => { + await expect( + context.accounts.anyone.sendTransaction({ + to: context.lsp8.address, + }), + ) + .to.be.revertedWithCustomError(context.lsp8, 'InvalidFunctionSelector') + .withArgs('0x00000000'); + }); + }); + + describe('when making a call with sending value', () => { + it('should revert', async () => { + const amountSent = 200; + await expect( + context.accounts.anyone.sendTransaction({ + to: context.lsp8.address, + value: amountSent, + }), + ).to.be.revertedWithCustomError(context.lsp8, 'LSP8TokenContractCannotHoldValue'); + }); + }); + }); }; export type LSP8InitializeTestContext = { From a8c730f608fdd585c94b69704272bdaec938a565 Mon Sep 17 00:00:00 2001 From: b00ste Date: Wed, 20 Sep 2023 14:58:02 +0300 Subject: [PATCH 26/55] feat: allow `endingTimestamp` to be 0 --- contracts/LSP25ExecuteRelayCall/LSP25MultiChannelNonce.sol | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contracts/LSP25ExecuteRelayCall/LSP25MultiChannelNonce.sol b/contracts/LSP25ExecuteRelayCall/LSP25MultiChannelNonce.sol index 2d6c33598..fb8c99015 100644 --- a/contracts/LSP25ExecuteRelayCall/LSP25MultiChannelNonce.sol +++ b/contracts/LSP25ExecuteRelayCall/LSP25MultiChannelNonce.sol @@ -113,6 +113,10 @@ abstract contract LSP25MultiChannelNonce { revert RelayCallBeforeStartTime(); } + // Allow `endingTimestamp` to be 0 + // Allow execution anytime past `startingTimestamp` + if (endingTimestamp == 0) return; + // solhint-disable-next-line not-rely-on-time if (block.timestamp > endingTimestamp) { revert RelayCallExpired(); From d6ef07ba1134329e6931bac6a6243d9b5ce8c5fb Mon Sep 17 00:00:00 2001 From: b00ste Date: Wed, 20 Sep 2023 14:58:17 +0300 Subject: [PATCH 27/55] test: add tests for new behavior --- .../Relay/ExecuteRelayCall.test.ts | 111 +++++++++++++++--- 1 file changed, 96 insertions(+), 15 deletions(-) diff --git a/tests/LSP6KeyManager/Relay/ExecuteRelayCall.test.ts b/tests/LSP6KeyManager/Relay/ExecuteRelayCall.test.ts index bf3efda48..ab6c0165e 100644 --- a/tests/LSP6KeyManager/Relay/ExecuteRelayCall.test.ts +++ b/tests/LSP6KeyManager/Relay/ExecuteRelayCall.test.ts @@ -727,11 +727,12 @@ export const shouldBehaveLikeExecuteRelayCall = ( startingTimestamp, endingTimestamp, ); + const randomNumber = 12345; const calldata = context.universalProfile.interface.encodeFunctionData('execute', [ - 0, + OPERATION_TYPES.CALL, targetContract.address, 0, - targetContract.interface.encodeFunctionData('setNumber', [nonce]), + targetContract.interface.encodeFunctionData('setNumber', [randomNumber]), ]); const value = 0; const signature = await signLSP6ExecuteRelayCall( @@ -747,7 +748,7 @@ export const shouldBehaveLikeExecuteRelayCall = ( .connect(relayer) .executeRelayCall(signature, nonce, validityTimestamps, calldata); - expect(await targetContract.getNumber()).to.equal(nonce); + expect(await targetContract.getNumber()).to.equal(randomNumber); }); }); @@ -825,11 +826,12 @@ export const shouldBehaveLikeExecuteRelayCall = ( startingTimestamp, endingTimestamp, ); + const randomNumber = 12345; const calldata = context.universalProfile.interface.encodeFunctionData('execute', [ - 0, + OPERATION_TYPES.CALL, targetContract.address, 0, - targetContract.interface.encodeFunctionData('setNumber', [nonce]), + targetContract.interface.encodeFunctionData('setNumber', [randomNumber]), ]); const value = 0; const signature = await signLSP6ExecuteRelayCall( @@ -845,7 +847,7 @@ export const shouldBehaveLikeExecuteRelayCall = ( .connect(relayer) .executeRelayCall(signature, nonce, validityTimestamps, calldata); - expect(await targetContract.getNumber()).to.equal(nonce); + expect(await targetContract.getNumber()).to.equal(randomNumber); }); }); @@ -862,11 +864,12 @@ export const shouldBehaveLikeExecuteRelayCall = ( startingTimestamp, endingTimestamp, ); + const randomNumber = 12345; const calldata = context.universalProfile.interface.encodeFunctionData('execute', [ - 0, + OPERATION_TYPES.CALL, targetContract.address, 0, - targetContract.interface.encodeFunctionData('setNumber', [nonce]), + targetContract.interface.encodeFunctionData('setNumber', [randomNumber]), ]); const value = 0; const signature = await signLSP6ExecuteRelayCall( @@ -884,7 +887,7 @@ export const shouldBehaveLikeExecuteRelayCall = ( .connect(relayer) .executeRelayCall(signature, nonce, validityTimestamps, calldata); - expect(await targetContract.getNumber()).to.equal(nonce); + expect(await targetContract.getNumber()).to.equal(randomNumber); }); }); }); @@ -964,11 +967,12 @@ export const shouldBehaveLikeExecuteRelayCall = ( startingTimestamp, endingTimestamp, ); + const randomNumber = 12345; const calldata = context.universalProfile.interface.encodeFunctionData('execute', [ - 0, + OPERATION_TYPES.CALL, targetContract.address, 0, - targetContract.interface.encodeFunctionData('setNumber', [nonce]), + targetContract.interface.encodeFunctionData('setNumber', [randomNumber]), ]); const value = 0; const signature = await signLSP6ExecuteRelayCall( @@ -986,7 +990,7 @@ export const shouldBehaveLikeExecuteRelayCall = ( .connect(relayer) .executeRelayCall(signature, nonce, validityTimestamps, calldata); - expect(await targetContract.getNumber()).to.equal(nonce); + expect(await targetContract.getNumber()).to.equal(randomNumber); }); }); }); @@ -995,11 +999,12 @@ export const shouldBehaveLikeExecuteRelayCall = ( it('passes', async () => { const nonce = await context.keyManager.callStatic.getNonce(signer.address, 14); const validityTimestamps = 0; + const randomNumber = 12345; const calldata = context.universalProfile.interface.encodeFunctionData('execute', [ - 0, + OPERATION_TYPES.CALL, targetContract.address, 0, - targetContract.interface.encodeFunctionData('setNumber', [nonce]), + targetContract.interface.encodeFunctionData('setNumber', [randomNumber]), ]); const value = 0; const signature = await signLSP6ExecuteRelayCall( @@ -1015,7 +1020,83 @@ export const shouldBehaveLikeExecuteRelayCall = ( .connect(relayer) .executeRelayCall(signature, nonce, validityTimestamps, calldata); - expect(await targetContract.getNumber()).to.equal(nonce); + expect(await targetContract.getNumber()).to.equal(randomNumber); + }); + }); + + describe('when `endingTimestamp == 0`', () => { + describe('`startingTimestamp` < now', () => { + it('passes', async () => { + const now = await time.latest(); + + const startingTimestamp = now - 100; + const endingTimestamp = 0; + + const nonce = await context.keyManager.callStatic.getNonce(signer.address, 14); + const validityTimestamps = createValidityTimestamps( + startingTimestamp, + endingTimestamp, + ); + const randomNumber = 12345; + const calldata = context.universalProfile.interface.encodeFunctionData('execute', [ + OPERATION_TYPES.CALL, + targetContract.address, + 0, + targetContract.interface.encodeFunctionData('setNumber', [randomNumber]), + ]); + const value = 0; + const signature = await signLSP6ExecuteRelayCall( + context.keyManager, + nonce.toString(), + validityTimestamps, + signerPrivateKey, + value, + calldata, + ); + + await context.keyManager + .connect(relayer) + .executeRelayCall(signature, nonce, validityTimestamps, calldata); + + expect(await targetContract.getNumber()).to.equal(randomNumber); + }); + }); + + describe('`startingTimestamp` > now', () => { + it('reverts', async () => { + const now = await time.latest(); + + const startingTimestamp = now + 100; + const endingTimestamp = 0; + + const nonce = await context.keyManager.callStatic.getNonce(signer.address, 14); + const validityTimestamps = createValidityTimestamps( + startingTimestamp, + endingTimestamp, + ); + const randomNumber = 12345; + const calldata = context.universalProfile.interface.encodeFunctionData('execute', [ + OPERATION_TYPES.CALL, + targetContract.address, + 0, + targetContract.interface.encodeFunctionData('setNumber', [randomNumber]), + ]); + const value = 0; + const signature = await signLSP6ExecuteRelayCall( + context.keyManager, + nonce.toString(), + validityTimestamps, + signerPrivateKey, + value, + calldata, + ); + + await expect( + context.keyManager + .connect(relayer) + .executeRelayCall(signature, nonce, validityTimestamps, calldata), + ).to.be.revertedWithCustomError(context.keyManager, 'RelayCallBeforeStartTime'); + }); }); }); }); From 67cb3333256e31a0c432a9bcd62f08e83e969222 Mon Sep 17 00:00:00 2001 From: Jean Cvllr <31145285+CJ42@users.noreply.github.com> Date: Wed, 27 Sep 2023 13:06:55 +0100 Subject: [PATCH 28/55] refactor!: set LSP8 TokenId Type on deployment / initialization (#712) * feat!: add tokenidType setting in `constructor` + prevent updating it via `_setData` * build: add constants for different types of LSP8 tokenIds * refactor: remove error check to allow setting additional future types of tokenIds * docs: auto-generate new docs for LSP8 * test: fix failing tests for Foundry and LSP1 * chore: fix linter errors and re-generate docs * docs: add leading `_` to param name + add Natspec --- README.md | 1 + constants.ts | 18 +++++++ .../LSP4DigitalAssetMetadata.sol | 2 +- .../LSP4DigitalAssetMetadataInitAbstract.sol | 2 +- .../LSP8Constants.sol | 11 +++++ .../LSP8Errors.sol | 7 +++ .../LSP8IdentifiableDigitalAsset.sol | 46 ++++++++++++++++-- ...P8IdentifiableDigitalAssetInitAbstract.sol | 47 +++++++++++++++++-- .../extensions/LSP8CompatibleERC721.sol | 10 ++-- .../LSP8CompatibleERC721InitAbstract.sol | 11 +++-- .../presets/LSP8CompatibleERC721Mintable.sol | 5 +- .../LSP8CompatibleERC721MintableInit.sol | 6 ++- ...P8CompatibleERC721MintableInitAbstract.sol | 10 +++- .../presets/LSP8Mintable.sol | 5 +- .../presets/LSP8MintableInit.sol | 10 +++- .../presets/LSP8MintableInitAbstract.sol | 6 ++- .../Mocks/Tokens/LSP8BurnableInitTester.sol | 6 ++- contracts/Mocks/Tokens/LSP8BurnableTester.sol | 5 +- .../Tokens/LSP8CappedSupplyInitTester.sol | 4 +- .../Mocks/Tokens/LSP8CappedSupplyTester.sol | 3 +- .../Tokens/LSP8CompatibleERC721Tester.sol | 3 +- .../Tokens/LSP8CompatibleERC721TesterInit.sol | 8 +++- .../Mocks/Tokens/LSP8EnumerableInitTester.sol | 6 ++- .../Mocks/Tokens/LSP8EnumerableTester.sol | 5 +- contracts/Mocks/Tokens/LSP8InitTester.sol | 6 ++- contracts/Mocks/Tokens/LSP8Tester.sol | 5 +- .../LSP8IdentifiableDigitalAsset.md | 22 ++++++++- .../extensions/LSP8Burnable.md | 22 ++++++++- .../extensions/LSP8CappedSupply.md | 22 ++++++++- .../extensions/LSP8CompatibleERC721.md | 19 ++++++++ .../extensions/LSP8Enumerable.md | 22 ++++++++- .../presets/LSP8CompatibleERC721Mintable.md | 37 ++++++++++++--- .../presets/LSP8Mintable.md | 40 +++++++++++++--- ...P1UniversalReceiverDelegateUP.behaviour.ts | 12 ++++- ...niversalReceiverDelegateVault.behaviour.ts | 12 ++++- .../Interactions/AllowedFunctions.test.ts | 2 + .../Interactions/AllowedFunctions.test.ts | 2 + .../LSP8CappedSupply.behaviour.ts | 1 + .../LSP8CompatibleERC721.behaviour.ts | 16 +++++++ .../LSP8Enumerable.behaviour.ts | 1 + .../LSP8IdentifiableDigitalAsset.behaviour.ts | 43 ++++++++++++++--- .../LSP8Mintable.behaviour.ts | 1 + .../proxy/LSP8BurnableInit.test.ts | 4 ++ .../proxy/LSP8CappedSupplyInit.test.ts | 5 +- .../proxy/LSP8CompatibleERC721Init.test.ts | 14 +++--- .../proxy/LSP8EnumerableInit.test.ts | 5 +- .../LSP8IdentifiableDigitalAssetInit.test.ts | 18 ++++--- .../proxy/LSP8MintableInit.test.ts | 8 +++- .../standard/LSP8Burnable.test.ts | 4 ++ .../standard/LSP8CappedSupply.test.ts | 3 ++ .../standard/LSP8CompatibleERC721.test.ts | 3 ++ .../standard/LSP8Enumerable.test.ts | 9 +++- .../LSP8IdentifiableDigitalAsset.test.ts | 12 +++-- .../standard/LSP8Mintable.test.ts | 3 ++ .../GasTests/execute/RestrictedController.sol | 6 ++- .../execute/UnrestrictedController.sol | 6 ++- 56 files changed, 523 insertions(+), 99 deletions(-) diff --git a/README.md b/README.md index a5fff68d1..42c6fd102 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ import { ERC725YDataKeys, PERMISSIONS, ALL_PERMISSIONS, + LSP8_TOKEN_ID_TYPES, LSP25_VERSION, ErrorSelectors, EventSigHashes, diff --git a/constants.ts b/constants.ts index 884c1a54b..2b7ff0a76 100644 --- a/constants.ts +++ b/constants.ts @@ -226,6 +226,9 @@ export const ERC725YDataKeys = { // AddressPermissions:AllowedCalls:
+ bytes2(0) 'AddressPermissions:AllowedCalls': '0x4b80742de2bf393a64c70000', }, + LSP8: { + LSP8TokenIdType: '0x715f248956de7ce65e94d9d836bfead479f7e70d69b718d47bfe7b00e05b4fe4', + }, LSP9: { SupportedStandards_LSP9: SupportedStandards.LSP9Vault.key, }, @@ -371,6 +374,21 @@ export const LSP1_TYPE_IDS = { '0xe32c7debcb817925ba4883fdbfc52797187f28f73f860641dab1a68d9b32902c', }; +// LSP8 +// ---------- + +/** + * @dev list of LSP8 Token ID types that can be used to create different types of NFTs. + * @see for details see: https://github.com/lukso-network/LIPs/blob/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokenidtype + */ +export const LSP8_TOKEN_ID_TYPES = { + NUMBER: 0, + STRING: 1, + UNIQUE_ID: 2, + HASH: 3, + ADDRESS: 4, +}; + // LSP25 // ---------- diff --git a/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.sol b/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.sol index e9e562d47..a57731572 100644 --- a/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.sol +++ b/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.sol @@ -51,7 +51,7 @@ abstract contract LSP4DigitalAssetMetadata is ERC725Y { /** * @dev The ERC725Y data keys `LSP4TokenName` and `LSP4TokenSymbol` cannot be changed - * via this function once the digital asset contract has been deployed. + * via this function once the digital asset contract has been deployed. * * @dev Save gas by emitting the {DataChanged} event with only the first 256 bytes of dataValue */ diff --git a/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadataInitAbstract.sol b/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadataInitAbstract.sol index b64e6c1b0..56603d4ff 100644 --- a/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadataInitAbstract.sol +++ b/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadataInitAbstract.sol @@ -55,7 +55,7 @@ abstract contract LSP4DigitalAssetMetadataInitAbstract is ERC725YInitAbstract { /** * @dev the ERC725Y data keys `LSP4TokenName` and `LSP4TokenSymbol` cannot be changed - * via this function once the digital asset contract has been deployed. + * via this function once the digital asset contract has been deployed. * * @dev Save gas by emitting the {DataChanged} event with only the first 256 bytes of dataValue */ diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8Constants.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8Constants.sol index eea9db83a..a117eeaf1 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8Constants.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8Constants.sol @@ -6,6 +6,9 @@ bytes4 constant _INTERFACEID_LSP8 = 0x1ae9ba1f; // --- ERC725Y Data Keys +// keccak256('LSP8TokenIdType') +bytes32 constant _LSP8_TOKENID_TYPE_KEY = 0x715f248956de7ce65e94d9d836bfead479f7e70d69b718d47bfe7b00e05b4fe4; + // bytes10(keccak256('LSP8MetadataAddress')) + bytes2(0) bytes12 constant _LSP8_METADATA_ADDRESS_KEY_PREFIX = 0x73dcc7c3c4096cdc7f8a0000; @@ -22,3 +25,11 @@ bytes32 constant _TYPEID_LSP8_TOKENSRECIPIENT = 0x0b084a55ebf70fd3c06fd755269dac // keccak256('LSP8Tokens_OperatorNotification') bytes32 constant _TYPEID_LSP8_TOKENOPERATOR = 0x8a1c15a8799f71b547e08e2bcb2e85257e81b0a07eee2ce6712549eef1f00970; + +// --- Types of token IDs + +uint256 constant _LSP8_TOKENID_TYPE_NUMBER = 0; +uint256 constant _LSP8_TOKENID_TYPE_STRING = 1; +uint256 constant _LSP8_TOKENID_TYPE_UNIQUE_ID = 2; +uint256 constant _LSP8_TOKENID_TYPE_HASH = 3; +uint256 constant _LSP8_TOKENID_TYPE_ADDRESS = 4; diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8Errors.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8Errors.sol index 24bbe571c..3a37b8ca3 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8Errors.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8Errors.sol @@ -80,3 +80,10 @@ error LSP8TokenOwnerCannotBeOperator(); * @notice LSP8 contract cannot receive native tokens. */ error LSP8TokenContractCannotHoldValue(); + +/** + * @dev Reverts when trying to edit the data key `LSP8TokenIdType` after the identifiable digital asset contract has been deployed. + * The `LSP8TokenIdType` data key is located inside the ERC725Y Data key-value store of the identifiable digital asset contract. + * It can be set only once inside the constructor/initializer when the identifiable digital asset contract is being deployed. + */ +error LSP8TokenIdTypeNotEditable(); diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol index 9a3193796..0143d4ae0 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol @@ -19,8 +19,13 @@ import {LSP17Extendable} from "../LSP17ContractExtension/LSP17Extendable.sol"; import {LSP2Utils} from "../LSP2ERC725YJSONSchema/LSP2Utils.sol"; // constants -import {_INTERFACEID_LSP8} from "./LSP8Constants.sol"; -import {LSP8TokenContractCannotHoldValue} from "./LSP8Errors.sol"; +import {_INTERFACEID_LSP8, _LSP8_TOKENID_TYPE_KEY} from "./LSP8Constants.sol"; + +// errors +import { + LSP8TokenContractCannotHoldValue, + LSP8TokenIdTypeNotEditable +} from "./LSP8Errors.sol"; import { _LSP17_EXTENSION_PREFIX @@ -51,16 +56,32 @@ abstract contract LSP8IdentifiableDigitalAsset is LSP17Extendable { /** - * @notice Sets the token-Metadata + * @notice Deploying a LSP8IdentifiableDigitalAsset with name `name_`, symbol `symbol_`, owned by address `newOwner_` + * with tokenId type `tokenIdType_`. + * + * @dev Deploy a `LSP8IdentifiableDigitalAsset` contract and set the tokenId type inside the ERC725Y storage of the contract. + * This will also set the token `name_` and `symbol_` under the ERC725Y data keys `LSP4TokenName` and `LSP4TokenSymbol`. + * * @param name_ The name of the token * @param symbol_ The symbol of the token * @param newOwner_ The owner of the the token-Metadata + * @param tokenIdType_ The type of tokenIds (= NFTs) that this contract will create. + * Available options are: NUMBER = `0`; STRING = `1`; UNIQUE_ID = `2`; HASH = `3`; ADDRESS = `4`. + * + * @custom:warning Make sure the tokenId type provided on deployment is correct, as it can only be set once + * and cannot be changed in the ERC725Y storage after the contract has been deployed. */ constructor( string memory name_, string memory symbol_, - address newOwner_ - ) LSP4DigitalAssetMetadata(name_, symbol_, newOwner_) {} + address newOwner_, + uint256 tokenIdType_ + ) LSP4DigitalAssetMetadata(name_, symbol_, newOwner_) { + LSP4DigitalAssetMetadata._setData( + _LSP8_TOKENID_TYPE_KEY, + abi.encode(tokenIdType_) + ); + } // fallback function @@ -190,4 +211,19 @@ abstract contract LSP8IdentifiableDigitalAsset is super.supportsInterface(interfaceId) || LSP17Extendable._supportsInterfaceInERC165Extension(interfaceId); } + + /** + * @inheritdoc LSP4DigitalAssetMetadata + * @dev The ERC725Y data key `_LSP8_TOKENID_TYPE_KEY` cannot be changed + * once the identifiable digital asset contract has been deployed. + */ + function _setData( + bytes32 dataKey, + bytes memory dataValue + ) internal virtual override { + if (dataKey == _LSP8_TOKENID_TYPE_KEY) { + revert LSP8TokenIdTypeNotEditable(); + } + LSP4DigitalAssetMetadata._setData(dataKey, dataValue); + } } diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetInitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetInitAbstract.sol index f6041d856..bfcbffa8b 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetInitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetInitAbstract.sol @@ -19,8 +19,13 @@ import {LSP17Extendable} from "../LSP17ContractExtension/LSP17Extendable.sol"; import {LSP2Utils} from "../LSP2ERC725YJSONSchema/LSP2Utils.sol"; // constants -import {_INTERFACEID_LSP8} from "./LSP8Constants.sol"; -import {LSP8TokenContractCannotHoldValue} from "./LSP8Errors.sol"; +import {_INTERFACEID_LSP8, _LSP8_TOKENID_TYPE_KEY} from "./LSP8Constants.sol"; + +// errors +import { + LSP8TokenContractCannotHoldValue, + LSP8TokenIdTypeNotEditable +} from "./LSP8Errors.sol"; import { _LSP17_EXTENSION_PREFIX @@ -50,16 +55,35 @@ abstract contract LSP8IdentifiableDigitalAssetInitAbstract is LSP8IdentifiableDigitalAssetCore, LSP17Extendable { + /** + * @dev Initialize a `LSP8IdentifiableDigitalAsset` contract and set the tokenId type inside the ERC725Y storage of the contract. + * This will also set the token `name_` and `symbol_` under the ERC725Y data keys `LSP4TokenName` and `LSP4TokenSymbol`. + * + * @param name_ The name of the token + * @param symbol_ The symbol of the token + * @param newOwner_ The owner of the the token-Metadata + * @param tokenIdType_ The type of tokenIds (= NFTs) that this contract will create. + * Available options are: NUMBER = `0`; STRING = `1`; UNIQUE_ID = `2`; HASH = `3`; ADDRESS = `4`. + * + * @custom:warning Make sure the tokenId type provided on deployment is correct, as it can only be set once + * and cannot be changed in the ERC725Y storage after the contract has been initialized. + */ function _initialize( string memory name_, string memory symbol_, - address newOwner_ - ) internal virtual override onlyInitializing { + address newOwner_, + uint256 tokenIdType_ + ) internal virtual onlyInitializing { LSP4DigitalAssetMetadataInitAbstract._initialize( name_, symbol_, newOwner_ ); + + LSP4DigitalAssetMetadataInitAbstract._setData( + _LSP8_TOKENID_TYPE_KEY, + abi.encode(tokenIdType_) + ); } // fallback function @@ -190,4 +214,19 @@ abstract contract LSP8IdentifiableDigitalAssetInitAbstract is super.supportsInterface(interfaceId) || LSP17Extendable._supportsInterfaceInERC165Extension(interfaceId); } + + /** + * @inheritdoc LSP4DigitalAssetMetadataInitAbstract + * @dev The ERC725Y data key `_LSP8_TOKENID_TYPE_KEY` cannot be changed + * once the identifiable digital asset contract has been deployed. + */ + function _setData( + bytes32 dataKey, + bytes memory dataValue + ) internal virtual override { + if (dataKey == _LSP8_TOKENID_TYPE_KEY) { + revert LSP8TokenIdTypeNotEditable(); + } + LSP4DigitalAssetMetadataInitAbstract._setData(dataKey, dataValue); + } } diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol index 07738be5e..6136f4cf1 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol @@ -23,7 +23,6 @@ import { } from "../../LSP4DigitalAssetMetadata/LSP4Compatibility.sol"; import { LSP8IdentifiableDigitalAsset, - LSP4DigitalAssetMetadata, ERC725YCore } from "../LSP8IdentifiableDigitalAsset.sol"; import { @@ -74,8 +73,9 @@ abstract contract LSP8CompatibleERC721 is constructor( string memory name_, string memory symbol_, - address newOwner_ - ) LSP8IdentifiableDigitalAsset(name_, symbol_, newOwner_) {} + address newOwner_, + uint256 tokenIdType_ + ) LSP8IdentifiableDigitalAsset(name_, symbol_, newOwner_, tokenIdType_) {} /** * @inheritdoc LSP8IdentifiableDigitalAsset @@ -407,12 +407,12 @@ abstract contract LSP8CompatibleERC721 is } /** - * @inheritdoc LSP4DigitalAssetMetadata + * @inheritdoc LSP8IdentifiableDigitalAsset */ function _setData( bytes32 key, bytes memory value - ) internal virtual override(LSP4DigitalAssetMetadata, ERC725YCore) { + ) internal virtual override(LSP8IdentifiableDigitalAsset, ERC725YCore) { super._setData(key, value); } } diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol index 42cd8f02e..851a0e361 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol @@ -23,7 +23,6 @@ import { } from "../../LSP4DigitalAssetMetadata/LSP4Compatibility.sol"; import { LSP8IdentifiableDigitalAssetInitAbstract, - LSP4DigitalAssetMetadataInitAbstract, ERC725YCore } from "../LSP8IdentifiableDigitalAssetInitAbstract.sol"; import { @@ -75,12 +74,14 @@ abstract contract LSP8CompatibleERC721InitAbstract is function _initialize( string memory name_, string memory symbol_, - address newOwner_ + address newOwner_, + uint256 tokenIdType_ ) internal virtual override onlyInitializing { LSP8IdentifiableDigitalAssetInitAbstract._initialize( name_, symbol_, - newOwner_ + newOwner_, + tokenIdType_ ); } @@ -415,7 +416,7 @@ abstract contract LSP8CompatibleERC721InitAbstract is } /** - * @inheritdoc LSP4DigitalAssetMetadataInitAbstract + * @inheritdoc LSP8IdentifiableDigitalAssetInitAbstract */ function _setData( bytes32 key, @@ -423,7 +424,7 @@ abstract contract LSP8CompatibleERC721InitAbstract is ) internal virtual - override(LSP4DigitalAssetMetadataInitAbstract, ERC725YCore) + override(LSP8IdentifiableDigitalAssetInitAbstract, ERC725YCore) { super._setData(key, value); } diff --git a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol index 482394e5b..cec967433 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol @@ -18,8 +18,9 @@ contract LSP8CompatibleERC721Mintable is LSP8CompatibleERC721 { constructor( string memory name_, string memory symbol_, - address newOwner_ - ) LSP8CompatibleERC721(name_, symbol_, newOwner_) {} + address newOwner_, + uint256 tokenIdType_ + ) LSP8CompatibleERC721(name_, symbol_, newOwner_, tokenIdType_) {} /** * @notice Minting tokenId `tokenId` for address `to` with the additional data `data` (Note: allow non-LSP1 recipient is set to `force`). diff --git a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721MintableInit.sol b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721MintableInit.sol index 2472662c6..7558bc368 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721MintableInit.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721MintableInit.sol @@ -30,12 +30,14 @@ contract LSP8CompatibleERC721MintableInit is function initialize( string memory name_, string memory symbol_, - address newOwner_ + address newOwner_, + uint256 tokenIdType_ ) external virtual initializer { LSP8CompatibleERC721MintableInitAbstract._initialize( name_, symbol_, - newOwner_ + newOwner_, + tokenIdType_ ); } } diff --git a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721MintableInitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721MintableInitAbstract.sol index e36d1d2af..58e7d31aa 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721MintableInitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721MintableInitAbstract.sol @@ -18,9 +18,15 @@ contract LSP8CompatibleERC721MintableInitAbstract is function _initialize( string memory name_, string memory symbol_, - address newOwner_ + address newOwner_, + uint256 tokenIdType_ ) internal virtual override onlyInitializing { - LSP8CompatibleERC721InitAbstract._initialize(name_, symbol_, newOwner_); + LSP8CompatibleERC721InitAbstract._initialize( + name_, + symbol_, + newOwner_, + tokenIdType_ + ); } /** diff --git a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol index 2b9e389fb..4a113bb47 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol @@ -25,8 +25,9 @@ contract LSP8Mintable is LSP8IdentifiableDigitalAsset, ILSP8Mintable { constructor( string memory name_, string memory symbol_, - address newOwner_ - ) LSP8IdentifiableDigitalAsset(name_, symbol_, newOwner_) {} + address newOwner_, + uint256 tokenIdType_ + ) LSP8IdentifiableDigitalAsset(name_, symbol_, newOwner_, tokenIdType_) {} /** * @notice Minting tokenId `tokenId` for address `to` with the additional data `data` (Note: allow non-LSP1 recipient is set to `force`). diff --git a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInit.sol b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInit.sol index 58a43eb0f..72532187e 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInit.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInit.sol @@ -27,8 +27,14 @@ contract LSP8MintableInit is LSP8MintableInitAbstract { function initialize( string memory name_, string memory symbol_, - address newOwner_ + address newOwner_, + uint256 tokenIdType_ ) external virtual initializer { - LSP8MintableInitAbstract._initialize(name_, symbol_, newOwner_); + LSP8MintableInitAbstract._initialize( + name_, + symbol_, + newOwner_, + tokenIdType_ + ); } } diff --git a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInitAbstract.sol index 004a0f5af..a7acd984b 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInitAbstract.sol @@ -27,12 +27,14 @@ abstract contract LSP8MintableInitAbstract is function _initialize( string memory name_, string memory symbol_, - address newOwner_ + address newOwner_, + uint256 tokenIdType_ ) internal virtual override onlyInitializing { LSP8IdentifiableDigitalAssetInitAbstract._initialize( name_, symbol_, - newOwner_ + newOwner_, + tokenIdType_ ); } diff --git a/contracts/Mocks/Tokens/LSP8BurnableInitTester.sol b/contracts/Mocks/Tokens/LSP8BurnableInitTester.sol index 1d0d0109d..0b63ce67b 100644 --- a/contracts/Mocks/Tokens/LSP8BurnableInitTester.sol +++ b/contracts/Mocks/Tokens/LSP8BurnableInitTester.sol @@ -14,12 +14,14 @@ contract LSP8BurnableInitTester is LSP8BurnableInitAbstract { function initialize( string memory name_, string memory symbol_, - address newOwner_ + address newOwner_, + uint256 tokenIdType_ ) public virtual initializer { LSP8IdentifiableDigitalAssetInitAbstract._initialize( name_, symbol_, - newOwner_ + newOwner_, + tokenIdType_ ); } } diff --git a/contracts/Mocks/Tokens/LSP8BurnableTester.sol b/contracts/Mocks/Tokens/LSP8BurnableTester.sol index ae492c50d..02c38dbb4 100644 --- a/contracts/Mocks/Tokens/LSP8BurnableTester.sol +++ b/contracts/Mocks/Tokens/LSP8BurnableTester.sol @@ -14,6 +14,7 @@ contract LSP8BurnableTester is LSP8Burnable { constructor( string memory name_, string memory symbol_, - address newOwner_ - ) LSP8IdentifiableDigitalAsset(name_, symbol_, newOwner_) {} + address newOwner_, + uint256 tokenIdType_ + ) LSP8IdentifiableDigitalAsset(name_, symbol_, newOwner_, tokenIdType_) {} } diff --git a/contracts/Mocks/Tokens/LSP8CappedSupplyInitTester.sol b/contracts/Mocks/Tokens/LSP8CappedSupplyInitTester.sol index 93571c7b4..ece6a3b52 100644 --- a/contracts/Mocks/Tokens/LSP8CappedSupplyInitTester.sol +++ b/contracts/Mocks/Tokens/LSP8CappedSupplyInitTester.sol @@ -15,12 +15,14 @@ contract LSP8CappedSupplyInitTester is LSP8CappedSupplyInitAbstract { string memory name_, string memory symbol_, address newOwner_, + uint256 tokenIdType_, uint256 tokenSupplyCap_ ) public virtual initializer { LSP8IdentifiableDigitalAssetInitAbstract._initialize( name_, symbol_, - newOwner_ + newOwner_, + tokenIdType_ ); LSP8CappedSupplyInitAbstract._initialize(tokenSupplyCap_); } diff --git a/contracts/Mocks/Tokens/LSP8CappedSupplyTester.sol b/contracts/Mocks/Tokens/LSP8CappedSupplyTester.sol index a05d2f09f..5ee6bea0c 100644 --- a/contracts/Mocks/Tokens/LSP8CappedSupplyTester.sol +++ b/contracts/Mocks/Tokens/LSP8CappedSupplyTester.sol @@ -15,9 +15,10 @@ contract LSP8CappedSupplyTester is LSP8CappedSupply { string memory name_, string memory symbol_, address newOwner_, + uint256 tokenIdType_, uint256 tokenSupplyCap_ ) - LSP8IdentifiableDigitalAsset(name_, symbol_, newOwner_) + LSP8IdentifiableDigitalAsset(name_, symbol_, newOwner_, tokenIdType_) LSP8CappedSupply(tokenSupplyCap_) {} diff --git a/contracts/Mocks/Tokens/LSP8CompatibleERC721Tester.sol b/contracts/Mocks/Tokens/LSP8CompatibleERC721Tester.sol index 705a13515..e713ebe63 100644 --- a/contracts/Mocks/Tokens/LSP8CompatibleERC721Tester.sol +++ b/contracts/Mocks/Tokens/LSP8CompatibleERC721Tester.sol @@ -17,8 +17,9 @@ contract LSP8CompatibleERC721Tester is LSP8CompatibleERC721 { string memory name_, string memory symbol_, address newOwner_, + uint256 tokenIdType_, bytes memory tokenURIValue_ - ) LSP8CompatibleERC721(name_, symbol_, newOwner_) { + ) LSP8CompatibleERC721(name_, symbol_, newOwner_, tokenIdType_) { _setData(_LSP4_METADATA_KEY, tokenURIValue_); } diff --git a/contracts/Mocks/Tokens/LSP8CompatibleERC721TesterInit.sol b/contracts/Mocks/Tokens/LSP8CompatibleERC721TesterInit.sol index 7cb92bf08..51689eb2e 100644 --- a/contracts/Mocks/Tokens/LSP8CompatibleERC721TesterInit.sol +++ b/contracts/Mocks/Tokens/LSP8CompatibleERC721TesterInit.sol @@ -24,9 +24,15 @@ contract LSP8CompatibleERC721InitTester is LSP8CompatibleERC721InitAbstract { string memory name_, string memory symbol_, address newOwner_, + uint256 tokenIdType_, bytes memory tokenURIValue_ ) public virtual initializer { - LSP8CompatibleERC721InitAbstract._initialize(name_, symbol_, newOwner_); + LSP8CompatibleERC721InitAbstract._initialize( + name_, + symbol_, + newOwner_, + tokenIdType_ + ); _setData(_LSP4_METADATA_KEY, tokenURIValue_); } diff --git a/contracts/Mocks/Tokens/LSP8EnumerableInitTester.sol b/contracts/Mocks/Tokens/LSP8EnumerableInitTester.sol index f809100ca..50aa38f66 100644 --- a/contracts/Mocks/Tokens/LSP8EnumerableInitTester.sol +++ b/contracts/Mocks/Tokens/LSP8EnumerableInitTester.sol @@ -14,12 +14,14 @@ contract LSP8EnumerableInitTester is LSP8EnumerableInitAbstract { function initialize( string memory name, string memory symbol, - address newOwner + address newOwner, + uint256 tokenIdType ) public virtual initializer { LSP8IdentifiableDigitalAssetInitAbstract._initialize( name, symbol, - newOwner + newOwner, + tokenIdType ); } diff --git a/contracts/Mocks/Tokens/LSP8EnumerableTester.sol b/contracts/Mocks/Tokens/LSP8EnumerableTester.sol index f2bde7f42..ef7d25858 100644 --- a/contracts/Mocks/Tokens/LSP8EnumerableTester.sol +++ b/contracts/Mocks/Tokens/LSP8EnumerableTester.sol @@ -14,8 +14,9 @@ contract LSP8EnumerableTester is LSP8Enumerable { constructor( string memory name, string memory symbol, - address newOwner - ) LSP8IdentifiableDigitalAsset(name, symbol, newOwner) {} + address newOwner, + uint256 tokenIdType + ) LSP8IdentifiableDigitalAsset(name, symbol, newOwner, tokenIdType) {} function mint(address to, bytes32 tokenId) public { _mint(to, tokenId, true, "token printer go brrr"); diff --git a/contracts/Mocks/Tokens/LSP8InitTester.sol b/contracts/Mocks/Tokens/LSP8InitTester.sol index 9efdabfc2..9f8e3245d 100644 --- a/contracts/Mocks/Tokens/LSP8InitTester.sol +++ b/contracts/Mocks/Tokens/LSP8InitTester.sol @@ -17,12 +17,14 @@ contract LSP8InitTester is function initialize( string memory name, string memory symbol, - address newOwner + address newOwner, + uint256 tokenIdType ) public initializer { LSP8IdentifiableDigitalAssetInitAbstract._initialize( name, symbol, - newOwner + newOwner, + tokenIdType ); } diff --git a/contracts/Mocks/Tokens/LSP8Tester.sol b/contracts/Mocks/Tokens/LSP8Tester.sol index d6af853dc..337cdc2b9 100644 --- a/contracts/Mocks/Tokens/LSP8Tester.sol +++ b/contracts/Mocks/Tokens/LSP8Tester.sol @@ -14,8 +14,9 @@ contract LSP8Tester is LSP8IdentifiableDigitalAsset, LSP8Burnable { constructor( string memory name, string memory symbol, - address newOwner - ) LSP8IdentifiableDigitalAsset(name, symbol, newOwner) {} + address newOwner, + uint256 tokenIdType + ) LSP8IdentifiableDigitalAsset(name, symbol, newOwner, tokenIdType) {} function mint( address to, diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md b/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md index 47bb4a37c..64eb7b0b8 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md @@ -721,7 +721,8 @@ mapping(bytes32 => bytes) _store function _setData(bytes32 dataKey, bytes dataValue) internal nonpayable; ``` -Save gas by emitting the [`DataChanged`](#datachanged) event with only the first 256 bytes of dataValue +The ERC725Y data key `_LSP8_TOKENID_TYPE_KEY` cannot be changed +once the identifiable digital asset contract has been deployed.
@@ -1606,6 +1607,25 @@ Error occurs when sending native tokens to the LSP8 contract without sending any
+### LSP8TokenIdTypeNotEditable + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokenidtypenoteditable) +- Solidity implementation: [`LSP8IdentifiableDigitalAsset.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol) +- Error signature: `LSP8TokenIdTypeNotEditable()` +- Error hash: `0x53bc1122` + +::: + +```solidity +error LSP8TokenIdTypeNotEditable(); +``` + +Reverts when trying to edit the data key `LSP8TokenIdType` after the identifiable digital asset contract has been deployed. The `LSP8TokenIdType` data key is located inside the ERC725Y Data key-value store of the identifiable digital asset contract. It can be set only once inside the constructor/initializer when the identifiable digital asset contract is being deployed. + +
+ ### LSP8TokenOwnerCannotBeOperator :::note References diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md index 6864202c2..acfdb68cd 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md @@ -747,7 +747,8 @@ mapping(bytes32 => bytes) _store function _setData(bytes32 dataKey, bytes dataValue) internal nonpayable; ``` -Save gas by emitting the [`DataChanged`](#datachanged) event with only the first 256 bytes of dataValue +The ERC725Y data key `_LSP8_TOKENID_TYPE_KEY` cannot be changed +once the identifiable digital asset contract has been deployed.
@@ -1632,6 +1633,25 @@ Error occurs when sending native tokens to the LSP8 contract without sending any
+### LSP8TokenIdTypeNotEditable + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokenidtypenoteditable) +- Solidity implementation: [`LSP8Burnable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.sol) +- Error signature: `LSP8TokenIdTypeNotEditable()` +- Error hash: `0x53bc1122` + +::: + +```solidity +error LSP8TokenIdTypeNotEditable(); +``` + +Reverts when trying to edit the data key `LSP8TokenIdType` after the identifiable digital asset contract has been deployed. The `LSP8TokenIdType` data key is located inside the ERC725Y Data key-value store of the identifiable digital asset contract. It can be set only once inside the constructor/initializer when the identifiable digital asset contract is being deployed. + +
+ ### LSP8TokenOwnerCannotBeOperator :::note References diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md index e659b3842..5946dd474 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md @@ -746,7 +746,8 @@ mapping(bytes32 => bytes) _store function _setData(bytes32 dataKey, bytes dataValue) internal nonpayable; ``` -Save gas by emitting the [`DataChanged`](#datachanged) event with only the first 256 bytes of dataValue +The ERC725Y data key `_LSP8_TOKENID_TYPE_KEY` cannot be changed +once the identifiable digital asset contract has been deployed.
@@ -1658,6 +1659,25 @@ Error occurs when sending native tokens to the LSP8 contract without sending any
+### LSP8TokenIdTypeNotEditable + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokenidtypenoteditable) +- Solidity implementation: [`LSP8CappedSupply.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.sol) +- Error signature: `LSP8TokenIdTypeNotEditable()` +- Error hash: `0x53bc1122` + +::: + +```solidity +error LSP8TokenIdTypeNotEditable(); +``` + +Reverts when trying to edit the data key `LSP8TokenIdType` after the identifiable digital asset contract has been deployed. The `LSP8TokenIdType` data key is located inside the ERC725Y Data key-value store of the identifiable digital asset contract. It can be set only once inside the constructor/initializer when the identifiable digital asset contract is being deployed. + +
+ ### LSP8TokenOwnerCannotBeOperator :::note References diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md index beb1a520d..d1693dda6 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md @@ -2011,6 +2011,25 @@ Error occurs when sending native tokens to the LSP8 contract without sending any
+### LSP8TokenIdTypeNotEditable + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokenidtypenoteditable) +- Solidity implementation: [`LSP8CompatibleERC721.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol) +- Error signature: `LSP8TokenIdTypeNotEditable()` +- Error hash: `0x53bc1122` + +::: + +```solidity +error LSP8TokenIdTypeNotEditable(); +``` + +Reverts when trying to edit the data key `LSP8TokenIdType` after the identifiable digital asset contract has been deployed. The `LSP8TokenIdType` data key is located inside the ERC725Y Data key-value store of the identifiable digital asset contract. It can be set only once inside the constructor/initializer when the identifiable digital asset contract is being deployed. + +
+ ### LSP8TokenOwnerCannotBeOperator :::note References diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md index 5b4667384..36bc2804e 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md @@ -752,7 +752,8 @@ mapping(bytes32 => bytes) _store function _setData(bytes32 dataKey, bytes dataValue) internal nonpayable; ``` -Save gas by emitting the [`DataChanged`](#datachanged) event with only the first 256 bytes of dataValue +The ERC725Y data key `_LSP8_TOKENID_TYPE_KEY` cannot be changed +once the identifiable digital asset contract has been deployed.
@@ -1633,6 +1634,25 @@ Error occurs when sending native tokens to the LSP8 contract without sending any
+### LSP8TokenIdTypeNotEditable + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokenidtypenoteditable) +- Solidity implementation: [`LSP8Enumerable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.sol) +- Error signature: `LSP8TokenIdTypeNotEditable()` +- Error hash: `0x53bc1122` + +::: + +```solidity +error LSP8TokenIdTypeNotEditable(); +``` + +Reverts when trying to edit the data key `LSP8TokenIdType` after the identifiable digital asset contract has been deployed. The `LSP8TokenIdType` data key is located inside the ERC725Y Data key-value store of the identifiable digital asset contract. It can be set only once inside the constructor/initializer when the identifiable digital asset contract is being deployed. + +
+ ### LSP8TokenOwnerCannotBeOperator :::note References diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md index 687547fe6..33d19c009 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md @@ -31,18 +31,24 @@ When marked as 'public', a method can be called both externally and internally, ::: ```solidity -constructor(string name_, string symbol_, address newOwner_); +constructor( + string name_, + string symbol_, + address newOwner_, + uint256 tokenIdType_ +); ``` _Deploying a `LSP8CompatibleERC721Mintable` token contract with: token name = `name_`, token symbol = `symbol_`, and address `newOwner_` as the token contract owner._ #### Parameters -| Name | Type | Description | -| ----------- | :-------: | -------------------------------- | -| `name_` | `string` | The name of the token. | -| `symbol_` | `string` | The symbol of the token. | -| `newOwner_` | `address` | The owner of the token contract. | +| Name | Type | Description | +| -------------- | :-------: | -------------------------------- | +| `name_` | `string` | The name of the token. | +| `symbol_` | `string` | The symbol of the token. | +| `newOwner_` | `address` | The owner of the token contract. | +| `tokenIdType_` | `uint256` | - |
@@ -2072,6 +2078,25 @@ Reverts when `tokenId` has already been minted.
+### LSP8TokenIdTypeNotEditable + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokenidtypenoteditable) +- Solidity implementation: [`LSP8CompatibleERC721Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol) +- Error signature: `LSP8TokenIdTypeNotEditable()` +- Error hash: `0x53bc1122` + +::: + +```solidity +error LSP8TokenIdTypeNotEditable(); +``` + +Reverts when trying to edit the data key `LSP8TokenIdType` after the identifiable digital asset contract has been deployed. The `LSP8TokenIdType` data key is located inside the ERC725Y Data key-value store of the identifiable digital asset contract. It can be set only once inside the constructor/initializer when the identifiable digital asset contract is being deployed. + +
+ ### LSP8TokenOwnerCannotBeOperator :::note References diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md index 569610357..e71fb2a68 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md @@ -31,18 +31,24 @@ When marked as 'public', a method can be called both externally and internally, ::: ```solidity -constructor(string name_, string symbol_, address newOwner_); +constructor( + string name_, + string symbol_, + address newOwner_, + uint256 tokenIdType_ +); ``` _Deploying a `LSP8Mintable` token contract with: token name = `name_`, token symbol = `symbol_`, and address `newOwner_` as the token contract owner._ #### Parameters -| Name | Type | Description | -| ----------- | :-------: | -------------------------------- | -| `name_` | `string` | The name of the token. | -| `symbol_` | `string` | The symbol of the token. | -| `newOwner_` | `address` | The owner of the token contract. | +| Name | Type | Description | +| -------------- | :-------: | -------------------------------- | +| `name_` | `string` | The name of the token. | +| `symbol_` | `string` | The symbol of the token. | +| `newOwner_` | `address` | The owner of the token contract. | +| `tokenIdType_` | `uint256` | - |
@@ -779,7 +785,8 @@ mapping(bytes32 => bytes) _store function _setData(bytes32 dataKey, bytes dataValue) internal nonpayable; ``` -Save gas by emitting the [`DataChanged`](#datachanged) event with only the first 256 bytes of dataValue +The ERC725Y data key `_LSP8_TOKENID_TYPE_KEY` cannot be changed +once the identifiable digital asset contract has been deployed.
@@ -1689,6 +1696,25 @@ Reverts when `tokenId` has already been minted.
+### LSP8TokenIdTypeNotEditable + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokenidtypenoteditable) +- Solidity implementation: [`LSP8Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol) +- Error signature: `LSP8TokenIdTypeNotEditable()` +- Error hash: `0x53bc1122` + +::: + +```solidity +error LSP8TokenIdTypeNotEditable(); +``` + +Reverts when trying to edit the data key `LSP8TokenIdType` after the identifiable digital asset contract has been deployed. The `LSP8TokenIdType` data key is located inside the ERC725Y Data key-value store of the identifiable digital asset contract. It can be set only once inside the constructor/initializer when the identifiable digital asset contract is being deployed. + +
+ ### LSP8TokenOwnerCannotBeOperator :::note References diff --git a/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP.behaviour.ts b/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP.behaviour.ts index adf8bc19c..e38f35450 100644 --- a/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP.behaviour.ts +++ b/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP.behaviour.ts @@ -30,7 +30,13 @@ import { import { ARRAY_LENGTH, LSP1_HOOK_PLACEHOLDER, abiCoder } from '../utils/helpers'; // constants -import { ERC725YDataKeys, INTERFACE_IDS, OPERATION_TYPES, LSP1_TYPE_IDS } from '../../constants'; +import { + ERC725YDataKeys, + INTERFACE_IDS, + OPERATION_TYPES, + LSP1_TYPE_IDS, + LSP8_TOKEN_ID_TYPES, +} from '../../constants'; // fixtures import { callPayload, getLSP5MapAndArrayKeysValue, setupKeyManager } from '../utils/fixtures'; @@ -1743,18 +1749,21 @@ export const shouldBehaveLikeLSP1Delegate = ( 'TokenAlpha', 'TA', context.accounts.random.address, + LSP8_TOKEN_ID_TYPES.UNIQUE_ID, ); lsp8TokenB = await new LSP8Tester__factory(context.accounts.random).deploy( 'TokenBeta', 'TB', context.accounts.random.address, + LSP8_TOKEN_ID_TYPES.UNIQUE_ID, ); lsp8TokenC = await new LSP8Tester__factory(context.accounts.random).deploy( 'TokenGamma', 'TA', context.accounts.random.address, + LSP8_TOKEN_ID_TYPES.UNIQUE_ID, ); }); @@ -3069,6 +3078,7 @@ export const shouldBehaveLikeLSP1Delegate = ( 'MyToken', 'MTK', context.universalProfile1.address, + LSP8_TOKEN_ID_TYPES.NUMBER, ); // Mint token for UP1 await LSP8.mint(context.universalProfile1.address, '0x' + '0'.repeat(64), true, '0x'); diff --git a/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault.behaviour.ts b/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault.behaviour.ts index 866dab1d6..c773e1e03 100644 --- a/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault.behaviour.ts +++ b/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault.behaviour.ts @@ -19,7 +19,13 @@ import { import { ARRAY_LENGTH, LSP1_HOOK_PLACEHOLDER, abiCoder } from '../utils/helpers'; // constants -import { ERC725YDataKeys, INTERFACE_IDS, OPERATION_TYPES, LSP1_TYPE_IDS } from '../../constants'; +import { + ERC725YDataKeys, + INTERFACE_IDS, + OPERATION_TYPES, + LSP1_TYPE_IDS, + LSP8_TOKEN_ID_TYPES, +} from '../../constants'; import { callPayload, getLSP5MapAndArrayKeysValue } from '../utils/fixtures'; import { BigNumber, BytesLike, Transaction } from 'ethers'; @@ -1151,18 +1157,21 @@ export const shouldBehaveLikeLSP1Delegate = (buildContext: () => Promise Promise Promise Promise { + it('should not allow to update the `LSP8TokenIdType` after deployment', async () => { + await expect( + context.lsp8CompatibleERC721.setData(ERC725YDataKeys.LSP8.LSP8TokenIdType, '0xdeadbeef'), + ).to.be.revertedWithCustomError(context.lsp8CompatibleERC721, 'LSP8TokenIdTypeNotEditable'); + }); + }); + + describe('when setting data', () => { + it('should not allow to update the `LSP8TokenIdType` after deployment', async () => { + await expect( + context.lsp8CompatibleERC721.setData(ERC725YDataKeys.LSP8.LSP8TokenIdType, '0xdeadbeef'), + ).to.be.revertedWithCustomError(context.lsp8CompatibleERC721, 'LSP8TokenIdTypeNotEditable'); + }); + }); + describe('when checking supported ERC165 interfaces', () => { it('should support ERC721', async () => { expect(await context.lsp8CompatibleERC721.supportsInterface(INTERFACE_IDS.ERC721)).to.equal( diff --git a/tests/LSP8IdentifiableDigitalAsset/LSP8Enumerable.behaviour.ts b/tests/LSP8IdentifiableDigitalAsset/LSP8Enumerable.behaviour.ts index 5c567be7f..0be64bb05 100644 --- a/tests/LSP8IdentifiableDigitalAsset/LSP8Enumerable.behaviour.ts +++ b/tests/LSP8IdentifiableDigitalAsset/LSP8Enumerable.behaviour.ts @@ -18,6 +18,7 @@ export type LSP8EnumerableDeployParams = { name: string; symbol: string; newOwner: string; + tokenIdType: number; }; export type LSP8EnumerableTestContext = { diff --git a/tests/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.behaviour.ts b/tests/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.behaviour.ts index df1c4a9af..7c726b6c5 100644 --- a/tests/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.behaviour.ts +++ b/tests/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.behaviour.ts @@ -42,6 +42,7 @@ export type LSP8DeployParams = { name: string; symbol: string; newOwner: string; + tokenIdType: number; }; export type LSP8TestContext = { @@ -58,12 +59,30 @@ export type ExpectedError = { const mintedTokenId = tokenIdAsBytes32(10); const neverMintedTokenId = tokenIdAsBytes32(1010110); -export const shouldBehaveLikeLSP8 = (buildContext: () => Promise) => { +export const shouldBehaveLikeLSP8 = ( + buildContext: (nftType: number) => Promise, +) => { let context: LSP8TestContext; let expectedTotalSupply = 0; before(async () => { - context = await buildContext(); + context = await buildContext(0); + }); + + describe('when setting data', () => { + it('should not allow to update the `LSP8TokenIdType` after deployment', async () => { + await expect( + context.lsp8.setData(ERC725YDataKeys.LSP8.LSP8TokenIdType, '0xdeadbeef'), + ).to.be.revertedWithCustomError(context.lsp8, 'LSP8TokenIdTypeNotEditable'); + }); + }); + + describe('when setting data', () => { + it('should not allow to update the `LSP8TokenIdType` after deployment', async () => { + await expect( + context.lsp8.setData(ERC725YDataKeys.LSP8.LSP8TokenIdType, '0xdeadbeef'), + ).to.be.revertedWithCustomError(context.lsp8, 'LSP8TokenIdTypeNotEditable'); + }); }); describe('when minting tokens', () => { @@ -625,7 +644,7 @@ export const shouldBehaveLikeLSP8 = (buildContext: () => Promise { - context = await buildContext(); + context = await buildContext(0); // mint a tokenId await context.lsp8.mint( @@ -1495,7 +1514,7 @@ export const shouldBehaveLikeLSP8 = (buildContext: () => Promise { beforeEach(async () => { - context = await buildContext(); + context = await buildContext(0); await context.lsp8.mint( context.accounts.owner.address, @@ -1697,7 +1716,7 @@ export const shouldBehaveLikeLSP8 = (buildContext: () => Promise { - context = await buildContext(); + context = await buildContext(0); oldOwner = context.accounts.owner; newOwner = context.accounts.anyone; }); @@ -1716,7 +1735,7 @@ export const shouldBehaveLikeLSP8 = (buildContext: () => Promise { beforeEach(async () => { - context = await buildContext(); + context = await buildContext(0); await context.lsp8.connect(oldOwner).transferOwnership(newOwner.address); }); @@ -1805,7 +1824,7 @@ export const shouldInitializeLikeLSP8 = ( let context: LSP8InitializeTestContext; before(async () => { - context = await buildContext(); + context = await buildContext(0); }); describe('when the contract was initialized', () => { @@ -1853,6 +1872,16 @@ export const shouldInitializeLikeLSP8 = ( .to.emit(context.lsp8, 'DataChanged') .withArgs(symbolKey, expectedSymbolValue); expect(await context.lsp8.getData(symbolKey)).to.equal(expectedSymbolValue); + + const lsp8TokenIdTypeDataKey = ERC725YDataKeys.LSP8['LSP8TokenIdType']; + const expectedTokenIdDataValue = abiCoder.encode( + ['uint256'], + [context.deployParams.tokenIdType], + ); + await expect(context.initializeTransaction) + .to.emit(context.lsp8, 'DataChanged') + .withArgs(lsp8TokenIdTypeDataKey, expectedTokenIdDataValue); + expect(await context.lsp8.getData(lsp8TokenIdTypeDataKey)).to.equal(expectedTokenIdDataValue); }); }); }; diff --git a/tests/LSP8IdentifiableDigitalAsset/LSP8Mintable.behaviour.ts b/tests/LSP8IdentifiableDigitalAsset/LSP8Mintable.behaviour.ts index 8afb19708..0c4d54e6a 100644 --- a/tests/LSP8IdentifiableDigitalAsset/LSP8Mintable.behaviour.ts +++ b/tests/LSP8IdentifiableDigitalAsset/LSP8Mintable.behaviour.ts @@ -28,6 +28,7 @@ export type LSP8MintableDeployParams = { name: string; symbol: string; newOwner: string; + tokenIdType: number; }; export type LSP8MintableTestContext = { diff --git a/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8BurnableInit.test.ts b/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8BurnableInit.test.ts index 208769948..f6d1cf7db 100644 --- a/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8BurnableInit.test.ts +++ b/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8BurnableInit.test.ts @@ -7,6 +7,7 @@ import { LSP8BurnableInitTester, LSP8BurnableInitTester__factory } from '../../. import { shouldInitializeLikeLSP8 } from '../LSP8IdentifiableDigitalAsset.behaviour'; import { deployProxy } from '../../utils/fixtures'; +import { LSP8_TOKEN_ID_TYPES } from '../../../constants'; type LSP8BurnableInitTestContext = { accounts: SignerWithAddress[]; @@ -15,6 +16,7 @@ type LSP8BurnableInitTestContext = { name: string; symbol: string; newOwner: string; + tokenIdType: number; }; }; @@ -25,6 +27,7 @@ describe('LSP8BurnableInit with proxy', () => { name: 'LSP8 Burnable - deployed with constructor', symbol: 'BRN', newOwner: accounts[0].address, + tokenIdType: LSP8_TOKEN_ID_TYPES.NUMBER, }; const lsp8BurnableImplementation = await new LSP8BurnableInitTester__factory( @@ -41,6 +44,7 @@ describe('LSP8BurnableInit with proxy', () => { context.deployParams.name, context.deployParams.symbol, context.deployParams.newOwner, + context.deployParams.tokenIdType, ); }; diff --git a/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8CappedSupplyInit.test.ts b/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8CappedSupplyInit.test.ts index 18dfb8c16..b1091b1b4 100644 --- a/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8CappedSupplyInit.test.ts +++ b/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8CappedSupplyInit.test.ts @@ -10,6 +10,7 @@ import { } from '../LSP8CappedSupply.behaviour'; import { deployProxy } from '../../utils/fixtures'; +import { LSP8_TOKEN_ID_TYPES } from '../../../constants'; describe('LSP8CappedSupplyInit with proxy', () => { const buildTestContext = async () => { @@ -18,6 +19,7 @@ describe('LSP8CappedSupplyInit with proxy', () => { name: 'LSP8 capped supply - deployed with proxy', symbol: 'CAP', newOwner: accounts.owner.address, + tokenIdType: LSP8_TOKEN_ID_TYPES.NUMBER, tokenSupplyCap: ethers.BigNumber.from('2'), }; const lsp8CappedSupplyInit = await new LSP8CappedSupplyInitTester__factory( @@ -30,10 +32,11 @@ describe('LSP8CappedSupplyInit with proxy', () => { }; const initializeProxy = async (context: LSP8CappedSupplyTestContext) => { - return context.lsp8CappedSupply['initialize(string,string,address,uint256)']( + return context.lsp8CappedSupply['initialize(string,string,address,uint256,uint256)']( context.deployParams.name, context.deployParams.symbol, context.deployParams.newOwner, + context.deployParams.tokenIdType, context.deployParams.tokenSupplyCap, ); }; diff --git a/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8CompatibleERC721Init.test.ts b/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8CompatibleERC721Init.test.ts index fc0229f59..cf444cca8 100644 --- a/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8CompatibleERC721Init.test.ts +++ b/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8CompatibleERC721Init.test.ts @@ -14,6 +14,7 @@ import { } from '../LSP8CompatibleERC721.behaviour'; import { deployProxy } from '../../utils/fixtures'; +import { LSP8_TOKEN_ID_TYPES } from '../../../constants'; describe('LSP8CompatibleERC721Init with proxy', () => { const buildTestContext = async (): Promise => { @@ -31,6 +32,7 @@ describe('LSP8CompatibleERC721Init with proxy', () => { name: 'LSP8 - deployed with constructor', symbol: 'NFT', newOwner: accounts.owner.address, + tokenIdType: LSP8_TOKEN_ID_TYPES.NUMBER, lsp4MetadataValue, }; @@ -47,10 +49,11 @@ describe('LSP8CompatibleERC721Init with proxy', () => { }; const initializeProxy = async (context: LSP8CompatibleERC721TestContext) => { - return context.lsp8CompatibleERC721['initialize(string,string,address,bytes)']( + return context.lsp8CompatibleERC721['initialize(string,string,address,uint256,bytes)']( context.deployParams.name, context.deployParams.symbol, context.deployParams.newOwner, + context.deployParams.tokenIdType, context.deployParams.lsp4MetadataValue, ); }; @@ -65,10 +68,11 @@ describe('LSP8CompatibleERC721Init with proxy', () => { const randomCaller = accounts[1]; await expect( - lsp8CompatibilityForERC721TesterInit['initialize(string,string,address,bytes)']( + lsp8CompatibilityForERC721TesterInit['initialize(string,string,address,uint256,bytes)']( 'XXXXXXXXXXX', 'XXX', randomCaller.address, + 0, '0x', ), ).to.be.revertedWith('Initializable: contract is already initialized'); @@ -84,11 +88,7 @@ describe('LSP8CompatibleERC721Init with proxy', () => { const randomCaller = accounts[1]; await expect( - lsp8CompatibleERC721MintableInit['initialize(string,string,address)']( - 'XXXXXXXXXXX', - 'XXX', - randomCaller.address, - ), + lsp8CompatibleERC721MintableInit.initialize('XXXXXXXXXXX', 'XXX', randomCaller.address, 0), ).to.be.revertedWith('Initializable: contract is already initialized'); }); }); diff --git a/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8EnumerableInit.test.ts b/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8EnumerableInit.test.ts index ba3ed1bc8..7aae65422 100644 --- a/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8EnumerableInit.test.ts +++ b/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8EnumerableInit.test.ts @@ -9,6 +9,7 @@ import { } from '../LSP8Enumerable.behaviour'; import { deployProxy } from '../../utils/fixtures'; +import { LSP8_TOKEN_ID_TYPES } from '../../../constants'; describe('LSP8EnumerableInit with proxy', () => { const buildTestContext = async () => { @@ -17,6 +18,7 @@ describe('LSP8EnumerableInit with proxy', () => { name: 'LSP8 Enumerable - deployed with proxy', symbol: 'LSP8 NMRBL', newOwner: accounts.owner.address, + tokenIdType: LSP8_TOKEN_ID_TYPES.NUMBER, }; const LSP8EnumerableInit: LSP8EnumerableInitTester = @@ -29,10 +31,11 @@ describe('LSP8EnumerableInit with proxy', () => { }; const initializeProxy = async (context: LSP8EnumerableTestContext) => { - return context.lsp8Enumerable['initialize(string,string,address)']( + return context.lsp8Enumerable['initialize(string,string,address,uint256)']( context.deployParams.name, context.deployParams.symbol, context.deployParams.newOwner, + context.deployParams.tokenIdType, ); }; diff --git a/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8IdentifiableDigitalAssetInit.test.ts b/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8IdentifiableDigitalAssetInit.test.ts index faaceab15..cc58c704e 100644 --- a/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8IdentifiableDigitalAssetInit.test.ts +++ b/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8IdentifiableDigitalAssetInit.test.ts @@ -18,12 +18,13 @@ import { import { deployProxy } from '../../utils/fixtures'; describe('LSP8IdentifiableDigitalAssetInit with proxy', () => { - const buildTestContext = async (): Promise => { + const buildTestContext = async (nftType: number): Promise => { const accounts = await getNamedAccounts(); const deployParams = { name: 'LSP8 - deployed with constructor', symbol: 'NFT', newOwner: accounts.owner.address, + tokenIdType: nftType, }; const lsp8TesterInit = await new LSP8InitTester__factory(accounts.owner).deploy(); @@ -35,7 +36,7 @@ describe('LSP8IdentifiableDigitalAssetInit with proxy', () => { const buildLSP4DigitalAssetMetadataTestContext = async (): Promise => { - const { lsp8 } = await buildTestContext(); + const { lsp8 } = await buildTestContext(0); const accounts = await ethers.getSigners(); const deployParams = { @@ -50,10 +51,11 @@ describe('LSP8IdentifiableDigitalAssetInit with proxy', () => { }; const initializeProxy = async (context: LSP8TestContext) => { - return context.lsp8['initialize(string,string,address)']( + return context.lsp8['initialize(string,string,address,uint256)']( context.deployParams.name, context.deployParams.symbol, context.deployParams.newOwner, + context.deployParams.tokenIdType, ); }; @@ -61,15 +63,16 @@ describe('LSP8IdentifiableDigitalAssetInit with proxy', () => { let context: LSP8TestContext; before(async () => { - context = await buildTestContext(); + context = await buildTestContext(0); }); it('should revert when initializing with address(0) as owner', async () => { await expect( - context.lsp8['initialize(string,string,address)']( + context.lsp8['initialize(string,string,address,uint256)']( context.deployParams.name, context.deployParams.symbol, ethers.constants.AddressZero, + 0, ), ).to.be.revertedWith('Ownable: new owner is the zero address'); }); @@ -100,17 +103,18 @@ describe('LSP8IdentifiableDigitalAssetInit with proxy', () => { shouldBehaveLikeLSP4DigitalAssetMetadata(async () => { const lsp4Context = await buildLSP4DigitalAssetMetadataTestContext(); - await lsp4Context.contract['initialize(string,string,address)']( + await lsp4Context.contract['initialize(string,string,address,uint256)']( 'LSP8 - deployed with proxy', 'NFT', lsp4Context.deployParams.owner.address, + 0, ); return lsp4Context; }); shouldBehaveLikeLSP8(() => - buildTestContext().then(async (context) => { + buildTestContext(0).then(async (context) => { await initializeProxy(context); return context; diff --git a/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8MintableInit.test.ts b/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8MintableInit.test.ts index 96cd82060..aa8062b55 100644 --- a/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8MintableInit.test.ts +++ b/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8MintableInit.test.ts @@ -10,6 +10,7 @@ import { } from '../LSP8Mintable.behaviour'; import { deployProxy } from '../../utils/fixtures'; +import { LSP8_TOKEN_ID_TYPES } from '../../../constants'; describe('LSP8MintableInit with proxy', () => { const buildTestContext = async () => { @@ -18,6 +19,7 @@ describe('LSP8MintableInit with proxy', () => { name: 'LSP8 Mintable - deployed with proxy', symbol: 'MNTBL', newOwner: accounts.owner.address, + tokenIdType: LSP8_TOKEN_ID_TYPES.NUMBER, }; const LSP8MintableInit: LSP8MintableInit = await new LSP8MintableInit__factory( @@ -31,10 +33,11 @@ describe('LSP8MintableInit with proxy', () => { }; const initializeProxy = async (context: LSP8MintableTestContext) => { - return context.lsp8Mintable['initialize(string,string,address)']( + return context.lsp8Mintable['initialize(string,string,address,uint256)']( context.deployParams.name, context.deployParams.symbol, context.deployParams.newOwner, + context.deployParams.tokenIdType, ); }; @@ -47,10 +50,11 @@ describe('LSP8MintableInit with proxy', () => { const randomCaller = accounts[1]; await expect( - lsp8Mintable['initialize(string,string,address)']( + lsp8Mintable['initialize(string,string,address,uint256)']( 'XXXXXXXXXXX', 'XXX', randomCaller.address, + 0, ), ).to.be.revertedWith('Initializable: contract is already initialized'); }); diff --git a/tests/LSP8IdentifiableDigitalAsset/standard/LSP8Burnable.test.ts b/tests/LSP8IdentifiableDigitalAsset/standard/LSP8Burnable.test.ts index e15e676f8..4170d7959 100644 --- a/tests/LSP8IdentifiableDigitalAsset/standard/LSP8Burnable.test.ts +++ b/tests/LSP8IdentifiableDigitalAsset/standard/LSP8Burnable.test.ts @@ -4,6 +4,7 @@ import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; import { LSP8BurnableTester, LSP8BurnableTester__factory } from '../../../types'; import { shouldInitializeLikeLSP8 } from '../LSP8IdentifiableDigitalAsset.behaviour'; +import { LSP8_TOKEN_ID_TYPES } from '../../../constants'; type LSP8BurnableTestContext = { accounts: SignerWithAddress[]; @@ -12,6 +13,7 @@ type LSP8BurnableTestContext = { name: string; symbol: string; newOwner: string; + tokenIdType: number; }; }; @@ -22,12 +24,14 @@ describe('LSP8Burnable with constructor', () => { name: 'LSP8 Burnable - deployed with constructor', symbol: 'BRN', newOwner: accounts[0].address, + tokenIdType: LSP8_TOKEN_ID_TYPES.NUMBER, }; const lsp8Burnable = await new LSP8BurnableTester__factory(accounts[0]).deploy( deployParams.name, deployParams.symbol, deployParams.newOwner, + deployParams.tokenIdType, ); return { accounts, lsp8Burnable, deployParams }; diff --git a/tests/LSP8IdentifiableDigitalAsset/standard/LSP8CappedSupply.test.ts b/tests/LSP8IdentifiableDigitalAsset/standard/LSP8CappedSupply.test.ts index c92f74a7d..9d3c85e41 100644 --- a/tests/LSP8IdentifiableDigitalAsset/standard/LSP8CappedSupply.test.ts +++ b/tests/LSP8IdentifiableDigitalAsset/standard/LSP8CappedSupply.test.ts @@ -8,6 +8,7 @@ import { LSP8CappedSupplyTestContext, getNamedAccounts, } from '../LSP8CappedSupply.behaviour'; +import { LSP8_TOKEN_ID_TYPES } from '../../../constants'; describe('LSP8CappedSupply with constructor', () => { const buildTestContext = async () => { @@ -16,12 +17,14 @@ describe('LSP8CappedSupply with constructor', () => { name: 'LSP8 capped supply - deployed with constructor', symbol: 'CAP', newOwner: accounts.owner.address, + tokenIdType: LSP8_TOKEN_ID_TYPES.NUMBER, tokenSupplyCap: ethers.BigNumber.from('2'), }; const lsp8CappedSupply = await new LSP8CappedSupplyTester__factory(accounts.owner).deploy( deployParams.name, deployParams.symbol, deployParams.newOwner, + deployParams.tokenIdType, deployParams.tokenSupplyCap, ); diff --git a/tests/LSP8IdentifiableDigitalAsset/standard/LSP8CompatibleERC721.test.ts b/tests/LSP8IdentifiableDigitalAsset/standard/LSP8CompatibleERC721.test.ts index f24298b47..e55499f8f 100644 --- a/tests/LSP8IdentifiableDigitalAsset/standard/LSP8CompatibleERC721.test.ts +++ b/tests/LSP8IdentifiableDigitalAsset/standard/LSP8CompatibleERC721.test.ts @@ -8,6 +8,7 @@ import { shouldInitializeLikeLSP8CompatibleERC721, LSP8CompatibleERC721TestContext, } from '../LSP8CompatibleERC721.behaviour'; +import { LSP8_TOKEN_ID_TYPES } from '../../../constants'; describe('LSP8CompatibleERC721 with constructor', () => { const buildTestContext = async (): Promise => { @@ -25,6 +26,7 @@ describe('LSP8CompatibleERC721 with constructor', () => { name: 'Compat for ERC721', symbol: 'NFT', newOwner: accounts.owner.address, + tokenIdType: LSP8_TOKEN_ID_TYPES.NUMBER, lsp4MetadataValue, }; @@ -34,6 +36,7 @@ describe('LSP8CompatibleERC721 with constructor', () => { deployParams.name, deployParams.symbol, deployParams.newOwner, + deployParams.tokenIdType, deployParams.lsp4MetadataValue, ); diff --git a/tests/LSP8IdentifiableDigitalAsset/standard/LSP8Enumerable.test.ts b/tests/LSP8IdentifiableDigitalAsset/standard/LSP8Enumerable.test.ts index ff35676d4..e78b97336 100644 --- a/tests/LSP8IdentifiableDigitalAsset/standard/LSP8Enumerable.test.ts +++ b/tests/LSP8IdentifiableDigitalAsset/standard/LSP8Enumerable.test.ts @@ -6,6 +6,7 @@ import { LSP8EnumerableTestContext, getNamedAccounts, } from '../LSP8Enumerable.behaviour'; +import { LSP8_TOKEN_ID_TYPES } from '../../../constants'; describe('LSP8Enumerable with constructor', () => { const buildTestContext = async () => { @@ -15,11 +16,17 @@ describe('LSP8Enumerable with constructor', () => { name: 'LSP8 Enumerable - deployed with constructor', symbol: 'LSP8 NMRBL', newOwner: accounts.owner.address, + tokenIdType: LSP8_TOKEN_ID_TYPES.NUMBER, }; const lsp8Enumerable: LSP8EnumerableTester = await new LSP8EnumerableTester__factory( accounts.owner, - ).deploy(deployParams.name, deployParams.symbol, deployParams.newOwner); + ).deploy( + deployParams.name, + deployParams.symbol, + deployParams.newOwner, + deployParams.tokenIdType, + ); return { accounts, lsp8Enumerable, deployParams }; }; diff --git a/tests/LSP8IdentifiableDigitalAsset/standard/LSP8IdentifiableDigitalAsset.test.ts b/tests/LSP8IdentifiableDigitalAsset/standard/LSP8IdentifiableDigitalAsset.test.ts index e1263a0e2..b1faa703c 100644 --- a/tests/LSP8IdentifiableDigitalAsset/standard/LSP8IdentifiableDigitalAsset.test.ts +++ b/tests/LSP8IdentifiableDigitalAsset/standard/LSP8IdentifiableDigitalAsset.test.ts @@ -19,19 +19,22 @@ import { LS4DigitalAssetMetadataTestContext, shouldBehaveLikeLSP4DigitalAssetMetadata, } from '../../LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.behaviour'; +import { LSP8_TOKEN_ID_TYPES } from '../../../constants'; describe('LSP8IdentifiableDigitalAsset with constructor', () => { - const buildTestContext = async (): Promise => { + const buildTestContext = async (nftType: number): Promise => { const accounts = await getNamedAccounts(); const deployParams = { name: 'LSP8 - deployed with constructor', symbol: 'NFT', newOwner: accounts.owner.address, + tokenIdType: nftType, }; const lsp8 = await new LSP8Tester__factory(accounts.owner).deploy( deployParams.name, deployParams.symbol, deployParams.newOwner, + deployParams.tokenIdType, ); return { accounts, lsp8, deployParams }; @@ -39,7 +42,7 @@ describe('LSP8IdentifiableDigitalAsset with constructor', () => { const buildLSP4DigitalAssetMetadataTestContext = async (): Promise => { - const { lsp8 } = await buildTestContext(); + const { lsp8 } = await buildTestContext(LSP8_TOKEN_ID_TYPES.NUMBER); const accounts = await ethers.getSigners(); const deployParams = { @@ -60,11 +63,13 @@ describe('LSP8IdentifiableDigitalAsset with constructor', () => { name: 'LSP8 - deployed with constructor', symbol: 'NFT', owner: accounts[0], + tokenIdType: LSP8_TOKEN_ID_TYPES.NUMBER, }; const contract = await new LSP8Tester__factory(accounts[0]).deploy( deployParams.name, deployParams.symbol, deployParams.owner.address, + deployParams.tokenIdType, ); return { accounts, contract, deployParams }; @@ -85,6 +90,7 @@ describe('LSP8IdentifiableDigitalAsset with constructor', () => { deployParams.name, deployParams.symbol, ethers.constants.AddressZero, + LSP8_TOKEN_ID_TYPES.NUMBER, ), ).to.be.revertedWith('Ownable: new owner is the zero address'); }); @@ -93,7 +99,7 @@ describe('LSP8IdentifiableDigitalAsset with constructor', () => { let context: LSP8TestContext; before(async () => { - context = await buildTestContext(); + context = await buildTestContext(0); }); shouldInitializeLikeLSP8(async () => { diff --git a/tests/LSP8IdentifiableDigitalAsset/standard/LSP8Mintable.test.ts b/tests/LSP8IdentifiableDigitalAsset/standard/LSP8Mintable.test.ts index 81409c007..79b77d849 100644 --- a/tests/LSP8IdentifiableDigitalAsset/standard/LSP8Mintable.test.ts +++ b/tests/LSP8IdentifiableDigitalAsset/standard/LSP8Mintable.test.ts @@ -1,3 +1,4 @@ +import { LSP8_TOKEN_ID_TYPES } from '../../../constants'; import { LSP8Mintable, LSP8Mintable__factory } from '../../../types'; import { shouldInitializeLikeLSP8 } from '../LSP8IdentifiableDigitalAsset.behaviour'; @@ -15,12 +16,14 @@ describe('LSP8Mintable with constructor', () => { name: 'LSP8 Mintable - deployed with constructor', symbol: 'LSP8 MNTBL', newOwner: accounts.owner.address, + tokenIdType: LSP8_TOKEN_ID_TYPES.NUMBER, }; const lsp8Mintable: LSP8Mintable = await new LSP8Mintable__factory(accounts.owner).deploy( deployParams.name, deployParams.symbol, deployParams.newOwner, + deployParams.tokenIdType, ); return { accounts, lsp8Mintable, deployParams }; diff --git a/tests/foundry/GasTests/execute/RestrictedController.sol b/tests/foundry/GasTests/execute/RestrictedController.sol index 34fb01a92..a7bf58cf0 100644 --- a/tests/foundry/GasTests/execute/RestrictedController.sol +++ b/tests/foundry/GasTests/execute/RestrictedController.sol @@ -19,6 +19,9 @@ import { _PERMISSION_CALL, _PERMISSION_TRANSFERVALUE } from "../../../../contracts/LSP6KeyManager/LSP6Constants.sol"; +import { + _LSP8_TOKENID_TYPE_NUMBER +} from "../../../../contracts/LSP8IdentifiableDigitalAsset/LSP8Constants.sol"; import "../UniversalProfileTestsHelper.sol"; contract ExecuteRestrictedController is UniversalProfileTestsHelper { @@ -438,7 +441,8 @@ contract ExecuteRestrictedController is UniversalProfileTestsHelper { indentifiableDigitalAsset = new LSP8Tester( "TestLSP8", "TSTLSP8", - digitalAssetsOwner + digitalAssetsOwner, + _LSP8_TOKENID_TYPE_NUMBER ); bytes32 tokenID = bytes32(uint256(1)); diff --git a/tests/foundry/GasTests/execute/UnrestrictedController.sol b/tests/foundry/GasTests/execute/UnrestrictedController.sol index 1f4bab4c1..49ca3b07a 100644 --- a/tests/foundry/GasTests/execute/UnrestrictedController.sol +++ b/tests/foundry/GasTests/execute/UnrestrictedController.sol @@ -17,6 +17,9 @@ import { _PERMISSION_REENTRANCY, _PERMISSION_SUPER_TRANSFERVALUE } from "../../../../contracts/LSP6KeyManager/LSP6Constants.sol"; +import { + _LSP8_TOKENID_TYPE_NUMBER +} from "../../../../contracts/LSP8IdentifiableDigitalAsset/LSP8Constants.sol"; import "../UniversalProfileTestsHelper.sol"; contract ExecuteUnrestrictedController is UniversalProfileTestsHelper { @@ -260,7 +263,8 @@ contract ExecuteUnrestrictedController is UniversalProfileTestsHelper { indentifiableDigitalAsset = new LSP8Tester( "TestLSP8", "TSTLSP8", - digitalAssetsOwner + digitalAssetsOwner, + _LSP8_TOKENID_TYPE_NUMBER ); bytes32 tokenID = bytes32(uint256(1)); From 1b50a5c31d73a2ee5cf582720f9ef9edf730cc02 Mon Sep 17 00:00:00 2001 From: Jean Cvllr <31145285+CJ42@users.noreply.github.com> Date: Wed, 27 Sep 2023 19:13:16 +0100 Subject: [PATCH 29/55] refactor: remove operator logic from internal `_burn` function in LSP7 (#726) --- .../LSP7DigitalAsset/LSP7DigitalAssetCore.sol | 108 +++++++++++------- .../extensions/LSP7Burnable.sol | 4 + .../extensions/LSP7BurnableInitAbstract.sol | 3 + .../LSP7DigitalAsset/LSP7DigitalAsset.md | 41 ++++++- .../extensions/LSP7Burnable.md | 41 ++++++- .../extensions/LSP7CappedSupply.md | 41 ++++++- .../extensions/LSP7CompatibleERC20.md | 30 ++++- .../presets/LSP7CompatibleERC20Mintable.md | 30 ++++- .../LSP7DigitalAsset/presets/LSP7Mintable.md | 41 ++++++- .../LSP7DigitalAsset.behaviour.ts | 70 +++++++++++- 10 files changed, 340 insertions(+), 69 deletions(-) diff --git a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol index f58222cd3..4c9d2176d 100644 --- a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol +++ b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol @@ -176,21 +176,12 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { ) public virtual { if (from == to) revert LSP7CannotSendToSelf(); - // if the caller is an operator if (msg.sender != from) { - uint256 operatorAmount = _operatorAuthorizedAmount[from][ - msg.sender - ]; - if (amount > operatorAmount) { - revert LSP7AmountExceedsAuthorizedAmount( - from, - operatorAmount, - msg.sender, - amount - ); - } - - _updateOperator(from, msg.sender, operatorAmount - amount, ""); + _spendAllowance({ + operator: msg.sender, + tokenOwner: from, + amountToSpend: amount + }); } _transfer(from, to, amount, force, data); @@ -237,8 +228,8 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { * This is an alternative approach to {authorizeOperator} that can be used as a mitigation * for the double spending allowance problem. * - * @param operator the operator to increase the allowance for `msg.sender` - * @param addedAmount the additional amount to add on top of the current operator's allowance + * @param operator The operator to increase the allowance for `msg.sender` + * @param addedAmount The additional amount to add on top of the current operator's allowance * * @custom:requirements * - `operator` cannot be the same address as `msg.sender` @@ -253,6 +244,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { ) public virtual { uint256 newAllowance = authorizedAmountFor(operator, msg.sender) + addedAmount; + _updateOperator( msg.sender, operator, @@ -284,8 +276,8 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { * - {RevokeOperator} event if `subtractedAmount` is the full allowance, * indicating `operator` does not have any alauthorizedAmountForlowance left for `msg.sender`. * - * @param operator the operator to decrease allowance for `msg.sender` - * @param subtractedAmount the amount to decrease by in the operator's allowance. + * @param operator The operator to decrease allowance for `msg.sender` + * @param subtractedAmount The amount to decrease by in the operator's allowance. * * @custom:requirements * - `operator` cannot be the zero address. @@ -325,6 +317,10 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { * If the amount is zero the operator is removed from the list of operators, otherwise he is added to the list of operators. * If the amount is zero then the operator is being revoked, otherwise the operator amount is being modified. * + * @param tokenOwner The address that will give `operator` an allowance for on its balance. + * @param operator The address to grant an allowance to spend. + * @param allowance The maximum amount of token that `operator` can spend from the `tokenOwner`'s balance. + * * @custom:events * - {RevokedOperator} event when operator's allowance is set to `0`. * - {AuthorizedOperator} event when operator's allowance is set to any other amount. @@ -336,7 +332,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { function _updateOperator( address tokenOwner, address operator, - uint256 amount, + uint256 allowance, bytes memory operatorNotificationData ) internal virtual { if (operator == address(0)) { @@ -347,14 +343,14 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { revert LSP7TokenOwnerCannotBeOperator(); } - _operatorAuthorizedAmount[tokenOwner][operator] = amount; + _operatorAuthorizedAmount[tokenOwner][operator] = allowance; - if (amount != 0) { + if (allowance != 0) { _operators[tokenOwner].add(operator); emit AuthorizedOperator( operator, tokenOwner, - amount, + allowance, operatorNotificationData ); } else { @@ -440,24 +436,6 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { revert LSP7AmountExceedsBalance(balance, from, amount); } - // if the caller is an operator - if (msg.sender != from) { - uint256 authorizedAmount = _operatorAuthorizedAmount[from][ - msg.sender - ]; - if (amount > authorizedAmount) { - revert LSP7AmountExceedsAuthorizedAmount( - from, - authorizedAmount, - msg.sender, - amount - ); - } - _operatorAuthorizedAmount[from][msg.sender] = - authorizedAmount - - amount; - } - _beforeTokenTransfer(from, address(0), amount); // tokens being burnt @@ -466,11 +444,61 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { _tokenOwnerBalances[from] -= amount; emit Transfer(msg.sender, from, address(0), amount, false, data); + emit Transfer({ + operator: msg.sender, + from: from, + to: address(0), + amount: amount, + force: false, + data: data + }); bytes memory lsp1Data = abi.encode(from, address(0), amount, data); _notifyTokenSender(from, lsp1Data); } + /** + * @dev Spend `amountToSpend` from the `operator`'s authorized on behalf of the `tokenOwner`. + * + * @param operator The address of the operator to decrease the allowance of. + * @param tokenOwner The address that granted an allowance on its balance to `operator`. + * @param amountToSpend The amount of tokens to substract in allowance of `operator`. + * + * @custom:events + * - {RevokedOperator} event when operator's allowance is set to `0`. + * - {AuthorizedOperator} event when operator's allowance is set to any other amount. + * + * @custom:requirements + * - The `amountToSpend` MUST be at least the allowance granted to `operator` (accessible via {`authorizedAmountFor}`) + * - `operator` cannot be the zero address. + * - `operator` cannot be the same address as `tokenOwner`. + */ + function _spendAllowance( + address operator, + address tokenOwner, + uint256 amountToSpend + ) internal virtual { + uint256 authorizedAmount = _operatorAuthorizedAmount[tokenOwner][ + operator + ]; + + if (amountToSpend > authorizedAmount) { + revert LSP7AmountExceedsAuthorizedAmount( + tokenOwner, + authorizedAmount, + operator, + amountToSpend + ); + } + + _updateOperator({ + tokenOwner: tokenOwner, + operator: operator, + allowance: authorizedAmount - amountToSpend, + operatorNotificationData: "" + }); + } + /** * @dev Transfer tokens from `from` to `to` by decreasing the balance of `from` by `-amount` and increasing the balance * of `to` by `+amount`. diff --git a/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.sol b/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.sol index 40a2289f7..e95130639 100644 --- a/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.sol +++ b/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.sol @@ -17,6 +17,10 @@ abstract contract LSP7Burnable is LSP7DigitalAsset { uint256 amount, bytes memory data ) public virtual { + if (msg.sender != from) { + _spendAllowance(msg.sender, from, amount); + } + _burn(from, amount, data); } } diff --git a/contracts/LSP7DigitalAsset/extensions/LSP7BurnableInitAbstract.sol b/contracts/LSP7DigitalAsset/extensions/LSP7BurnableInitAbstract.sol index 8dd541eb8..9915fafa7 100644 --- a/contracts/LSP7DigitalAsset/extensions/LSP7BurnableInitAbstract.sol +++ b/contracts/LSP7DigitalAsset/extensions/LSP7BurnableInitAbstract.sol @@ -19,6 +19,9 @@ abstract contract LSP7BurnableInitAbstract is LSP7DigitalAssetInitAbstract { uint256 amount, bytes memory data ) public virtual { + if (msg.sender != from) { + _spendAllowance(msg.sender, from, amount); + } _burn(from, amount, data); } } diff --git a/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md b/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md index 9b93c0984..101dc5629 100644 --- a/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md +++ b/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md @@ -256,8 +256,8 @@ Atomically decreases the allowance granted to `operator` by the caller. This is | Name | Type | Description | | -------------------------- | :-------: | ------------------------------------------------------ | -| `operator` | `address` | the operator to decrease allowance for `msg.sender` | -| `subtractedAmount` | `uint256` | the amount to decrease by in the operator's allowance. | +| `operator` | `address` | The operator to decrease allowance for `msg.sender` | +| `subtractedAmount` | `uint256` | The amount to decrease by in the operator's allowance. | | `operatorNotificationData` | `bytes` | - |
@@ -411,8 +411,8 @@ Atomically increases the allowance granted to `operator` by the caller. This is | Name | Type | Description | | -------------------------- | :-------: | ----------------------------------------------------------------------- | -| `operator` | `address` | the operator to increase the allowance for `msg.sender` | -| `addedAmount` | `uint256` | the additional amount to add on top of the current operator's allowance | +| `operator` | `address` | The operator to increase the allowance for `msg.sender` | +| `addedAmount` | `uint256` | The additional amount to add on top of the current operator's allowance | | `operatorNotificationData` | `bytes` | - |
@@ -811,7 +811,7 @@ Save gas by emitting the [`DataChanged`](#datachanged) event with only the first function _updateOperator( address tokenOwner, address operator, - uint256 amount, + uint256 allowance, bytes operatorNotificationData ) internal nonpayable; ``` @@ -820,6 +820,15 @@ Changes token `amount` the `operator` has access to from `tokenOwner` tokens. If the amount is zero the operator is removed from the list of operators, otherwise he is added to the list of operators. If the amount is zero then the operator is being revoked, otherwise the operator amount is being modified. +#### Parameters + +| Name | Type | Description | +| -------------------------- | :-------: | -------------------------------------------------------------------------------------- | +| `tokenOwner` | `address` | The address that will give `operator` an allowance for on its balance. | +| `operator` | `address` | The address to grant an allowance to spend. | +| `allowance` | `uint256` | The maximum amount of token that `operator` can spend from the `tokenOwner`'s balance. | +| `operatorNotificationData` | `bytes` | - | +
### \_mint @@ -890,6 +899,28 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r
+### \_spendAllowance + +```solidity +function _spendAllowance( + address operator, + address tokenOwner, + uint256 amountToSpend +) internal nonpayable; +``` + +Spend `amountToSpend` from the `operator`'s authorized on behalf of the `tokenOwner`. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ------------------------------------------------------------------- | +| `operator` | `address` | The address of the operator to decrease the allowance of. | +| `tokenOwner` | `address` | The address that granted an allowance on its balance to `operator`. | +| `amountToSpend` | `uint256` | The amount of tokens to substract in allowance of `operator`. | + +
+ ### \_transfer ```solidity diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md index 791796c97..2a2652731 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md @@ -281,8 +281,8 @@ Atomically decreases the allowance granted to `operator` by the caller. This is | Name | Type | Description | | -------------------------- | :-------: | ------------------------------------------------------ | -| `operator` | `address` | the operator to decrease allowance for `msg.sender` | -| `subtractedAmount` | `uint256` | the amount to decrease by in the operator's allowance. | +| `operator` | `address` | The operator to decrease allowance for `msg.sender` | +| `subtractedAmount` | `uint256` | The amount to decrease by in the operator's allowance. | | `operatorNotificationData` | `bytes` | - |
@@ -436,8 +436,8 @@ Atomically increases the allowance granted to `operator` by the caller. This is | Name | Type | Description | | -------------------------- | :-------: | ----------------------------------------------------------------------- | -| `operator` | `address` | the operator to increase the allowance for `msg.sender` | -| `addedAmount` | `uint256` | the additional amount to add on top of the current operator's allowance | +| `operator` | `address` | The operator to increase the allowance for `msg.sender` | +| `addedAmount` | `uint256` | The additional amount to add on top of the current operator's allowance | | `operatorNotificationData` | `bytes` | - |
@@ -836,7 +836,7 @@ Save gas by emitting the [`DataChanged`](#datachanged) event with only the first function _updateOperator( address tokenOwner, address operator, - uint256 amount, + uint256 allowance, bytes operatorNotificationData ) internal nonpayable; ``` @@ -845,6 +845,15 @@ Changes token `amount` the `operator` has access to from `tokenOwner` tokens. If the amount is zero the operator is removed from the list of operators, otherwise he is added to the list of operators. If the amount is zero then the operator is being revoked, otherwise the operator amount is being modified. +#### Parameters + +| Name | Type | Description | +| -------------------------- | :-------: | -------------------------------------------------------------------------------------- | +| `tokenOwner` | `address` | The address that will give `operator` an allowance for on its balance. | +| `operator` | `address` | The address to grant an allowance to spend. | +| `allowance` | `uint256` | The maximum amount of token that `operator` can spend from the `tokenOwner`'s balance. | +| `operatorNotificationData` | `bytes` | - | +
### \_mint @@ -915,6 +924,28 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r
+### \_spendAllowance + +```solidity +function _spendAllowance( + address operator, + address tokenOwner, + uint256 amountToSpend +) internal nonpayable; +``` + +Spend `amountToSpend` from the `operator`'s authorized on behalf of the `tokenOwner`. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ------------------------------------------------------------------- | +| `operator` | `address` | The address of the operator to decrease the allowance of. | +| `tokenOwner` | `address` | The address that granted an allowance on its balance to `operator`. | +| `amountToSpend` | `uint256` | The amount of tokens to substract in allowance of `operator`. | + +
+ ### \_transfer ```solidity diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md index 51e5e5e61..cc2501eae 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md @@ -254,8 +254,8 @@ Atomically decreases the allowance granted to `operator` by the caller. This is | Name | Type | Description | | -------------------------- | :-------: | ------------------------------------------------------ | -| `operator` | `address` | the operator to decrease allowance for `msg.sender` | -| `subtractedAmount` | `uint256` | the amount to decrease by in the operator's allowance. | +| `operator` | `address` | The operator to decrease allowance for `msg.sender` | +| `subtractedAmount` | `uint256` | The amount to decrease by in the operator's allowance. | | `operatorNotificationData` | `bytes` | - |
@@ -409,8 +409,8 @@ Atomically increases the allowance granted to `operator` by the caller. This is | Name | Type | Description | | -------------------------- | :-------: | ----------------------------------------------------------------------- | -| `operator` | `address` | the operator to increase the allowance for `msg.sender` | -| `addedAmount` | `uint256` | the additional amount to add on top of the current operator's allowance | +| `operator` | `address` | The operator to increase the allowance for `msg.sender` | +| `addedAmount` | `uint256` | The additional amount to add on top of the current operator's allowance | | `operatorNotificationData` | `bytes` | - |
@@ -836,7 +836,7 @@ Save gas by emitting the [`DataChanged`](#datachanged) event with only the first function _updateOperator( address tokenOwner, address operator, - uint256 amount, + uint256 allowance, bytes operatorNotificationData ) internal nonpayable; ``` @@ -845,6 +845,15 @@ Changes token `amount` the `operator` has access to from `tokenOwner` tokens. If the amount is zero the operator is removed from the list of operators, otherwise he is added to the list of operators. If the amount is zero then the operator is being revoked, otherwise the operator amount is being modified. +#### Parameters + +| Name | Type | Description | +| -------------------------- | :-------: | -------------------------------------------------------------------------------------- | +| `tokenOwner` | `address` | The address that will give `operator` an allowance for on its balance. | +| `operator` | `address` | The address to grant an allowance to spend. | +| `allowance` | `uint256` | The maximum amount of token that `operator` can spend from the `tokenOwner`'s balance. | +| `operatorNotificationData` | `bytes` | - | +
### \_mint @@ -899,6 +908,28 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r
+### \_spendAllowance + +```solidity +function _spendAllowance( + address operator, + address tokenOwner, + uint256 amountToSpend +) internal nonpayable; +``` + +Spend `amountToSpend` from the `operator`'s authorized on behalf of the `tokenOwner`. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ------------------------------------------------------------------- | +| `operator` | `address` | The address of the operator to decrease the allowance of. | +| `tokenOwner` | `address` | The address that granted an allowance on its balance to `operator`. | +| `amountToSpend` | `uint256` | The amount of tokens to substract in allowance of `operator`. | + +
+ ### \_transfer ```solidity diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md index 649bc8d60..b5892952b 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md @@ -320,8 +320,8 @@ Atomically decreases the allowance granted to `operator` by the caller. This is | Name | Type | Description | | -------------------------- | :-------: | ------------------------------------------------------ | -| `operator` | `address` | the operator to decrease allowance for `msg.sender` | -| `subtractedAmount` | `uint256` | the amount to decrease by in the operator's allowance. | +| `operator` | `address` | The operator to decrease allowance for `msg.sender` | +| `subtractedAmount` | `uint256` | The amount to decrease by in the operator's allowance. | | `operatorNotificationData` | `bytes` | - |
@@ -475,8 +475,8 @@ Atomically increases the allowance granted to `operator` by the caller. This is | Name | Type | Description | | -------------------------- | :-------: | ----------------------------------------------------------------------- | -| `operator` | `address` | the operator to increase the allowance for `msg.sender` | -| `addedAmount` | `uint256` | the additional amount to add on top of the current operator's allowance | +| `operator` | `address` | The operator to increase the allowance for `msg.sender` | +| `addedAmount` | `uint256` | The additional amount to add on top of the current operator's allowance | | `operatorNotificationData` | `bytes` | - |
@@ -1031,6 +1031,28 @@ function _burn(address from, uint256 amount, bytes data) internal nonpayable;
+### \_spendAllowance + +```solidity +function _spendAllowance( + address operator, + address tokenOwner, + uint256 amountToSpend +) internal nonpayable; +``` + +Spend `amountToSpend` from the `operator`'s authorized on behalf of the `tokenOwner`. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ------------------------------------------------------------------- | +| `operator` | `address` | The address of the operator to decrease the allowance of. | +| `tokenOwner` | `address` | The address that granted an allowance on its balance to `operator`. | +| `amountToSpend` | `uint256` | The amount of tokens to substract in allowance of `operator`. | + +
+ ### \_transfer ```solidity diff --git a/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md b/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md index e14dbe18d..8a5d97d56 100644 --- a/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md +++ b/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md @@ -321,8 +321,8 @@ Atomically decreases the allowance granted to `operator` by the caller. This is | Name | Type | Description | | -------------------------- | :-------: | ------------------------------------------------------ | -| `operator` | `address` | the operator to decrease allowance for `msg.sender` | -| `subtractedAmount` | `uint256` | the amount to decrease by in the operator's allowance. | +| `operator` | `address` | The operator to decrease allowance for `msg.sender` | +| `subtractedAmount` | `uint256` | The amount to decrease by in the operator's allowance. | | `operatorNotificationData` | `bytes` | - |
@@ -476,8 +476,8 @@ Atomically increases the allowance granted to `operator` by the caller. This is | Name | Type | Description | | -------------------------- | :-------: | ----------------------------------------------------------------------- | -| `operator` | `address` | the operator to increase the allowance for `msg.sender` | -| `addedAmount` | `uint256` | the additional amount to add on top of the current operator's allowance | +| `operator` | `address` | The operator to increase the allowance for `msg.sender` | +| `addedAmount` | `uint256` | The additional amount to add on top of the current operator's allowance | | `operatorNotificationData` | `bytes` | - |
@@ -1065,6 +1065,28 @@ function _burn(address from, uint256 amount, bytes data) internal nonpayable;
+### \_spendAllowance + +```solidity +function _spendAllowance( + address operator, + address tokenOwner, + uint256 amountToSpend +) internal nonpayable; +``` + +Spend `amountToSpend` from the `operator`'s authorized on behalf of the `tokenOwner`. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ------------------------------------------------------------------- | +| `operator` | `address` | The address of the operator to decrease the allowance of. | +| `tokenOwner` | `address` | The address that granted an allowance on its balance to `operator`. | +| `amountToSpend` | `uint256` | The amount of tokens to substract in allowance of `operator`. | + +
+ ### \_transfer ```solidity diff --git a/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md b/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md index c3f22bcc6..b9de110e4 100644 --- a/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md +++ b/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md @@ -285,8 +285,8 @@ Atomically decreases the allowance granted to `operator` by the caller. This is | Name | Type | Description | | -------------------------- | :-------: | ------------------------------------------------------ | -| `operator` | `address` | the operator to decrease allowance for `msg.sender` | -| `subtractedAmount` | `uint256` | the amount to decrease by in the operator's allowance. | +| `operator` | `address` | The operator to decrease allowance for `msg.sender` | +| `subtractedAmount` | `uint256` | The amount to decrease by in the operator's allowance. | | `operatorNotificationData` | `bytes` | - |
@@ -440,8 +440,8 @@ Atomically increases the allowance granted to `operator` by the caller. This is | Name | Type | Description | | -------------------------- | :-------: | ----------------------------------------------------------------------- | -| `operator` | `address` | the operator to increase the allowance for `msg.sender` | -| `addedAmount` | `uint256` | the additional amount to add on top of the current operator's allowance | +| `operator` | `address` | The operator to increase the allowance for `msg.sender` | +| `addedAmount` | `uint256` | The additional amount to add on top of the current operator's allowance | | `operatorNotificationData` | `bytes` | - |
@@ -873,7 +873,7 @@ Save gas by emitting the [`DataChanged`](#datachanged) event with only the first function _updateOperator( address tokenOwner, address operator, - uint256 amount, + uint256 allowance, bytes operatorNotificationData ) internal nonpayable; ``` @@ -882,6 +882,15 @@ Changes token `amount` the `operator` has access to from `tokenOwner` tokens. If the amount is zero the operator is removed from the list of operators, otherwise he is added to the list of operators. If the amount is zero then the operator is being revoked, otherwise the operator amount is being modified. +#### Parameters + +| Name | Type | Description | +| -------------------------- | :-------: | -------------------------------------------------------------------------------------- | +| `tokenOwner` | `address` | The address that will give `operator` an allowance for on its balance. | +| `operator` | `address` | The address to grant an allowance to spend. | +| `allowance` | `uint256` | The maximum amount of token that `operator` can spend from the `tokenOwner`'s balance. | +| `operatorNotificationData` | `bytes` | - | +
### \_mint @@ -952,6 +961,28 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r
+### \_spendAllowance + +```solidity +function _spendAllowance( + address operator, + address tokenOwner, + uint256 amountToSpend +) internal nonpayable; +``` + +Spend `amountToSpend` from the `operator`'s authorized on behalf of the `tokenOwner`. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ------------------------------------------------------------------- | +| `operator` | `address` | The address of the operator to decrease the allowance of. | +| `tokenOwner` | `address` | The address that granted an allowance on its balance to `operator`. | +| `amountToSpend` | `uint256` | The amount of tokens to substract in allowance of `operator`. | + +
+ ### \_transfer ```solidity diff --git a/tests/LSP7DigitalAsset/LSP7DigitalAsset.behaviour.ts b/tests/LSP7DigitalAsset/LSP7DigitalAsset.behaviour.ts index 5e57cc931..da3dc0141 100644 --- a/tests/LSP7DigitalAsset/LSP7DigitalAsset.behaviour.ts +++ b/tests/LSP7DigitalAsset/LSP7DigitalAsset.behaviour.ts @@ -1776,6 +1776,7 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise { describe('when using address(0) as `from` address', () => { it('should revert', async () => { @@ -1784,7 +1785,14 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise Promise { + const operator = context.accounts.operator; + const amount = operatorAllowance; + + const operatorsList = await context.lsp7.getOperatorsOf(context.accounts.owner.address); + expect(operatorsList).to.include(operator.address); + + await context.lsp7.connect(operator).burn(context.accounts.owner.address, amount, '0x'); + + const updatedOperatorList = await context.lsp7.getOperatorsOf( + context.accounts.owner.address, + ); + expect(updatedOperatorList.length).to.equal(operatorsList.length - 1); + expect(updatedOperatorList).to.not.include(operator.address); + }); + it('token owner balance should have decreased', async () => { const operator = context.accounts.operator; const amount = operatorAllowance; @@ -1981,6 +2005,20 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise { + const operator = context.accounts.operator; + const amount = operatorAllowance; + + const operatorsList = await context.lsp7.getOperatorsOf(context.accounts.owner.address); + expect(operatorsList).to.include(operator.address); + + await expect( + context.lsp7.connect(operator).burn(context.accounts.owner.address, amount, '0x'), + ) + .to.emit(context.lsp7, 'RevokedOperator') + .withArgs(operator.address, context.accounts.owner.address, '0x'); + }); }); describe('when burning part of its allowance', () => { @@ -2004,6 +2042,18 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise { + const amount = 10; + assert.isBelow(amount, operatorAllowance); + + const operator = context.accounts.operator; + + await context.lsp7.connect(operator).burn(context.accounts.owner.address, amount, '0x'); + + const operatorsList = await context.lsp7.getOperatorsOf(context.accounts.owner.address); + expect(operatorsList).to.include(operator.address); + }); + it('token owner balance should have decreased', async () => { const amount = 10; assert.isBelow(amount, operatorAllowance); @@ -2049,6 +2099,24 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise { + const amount = 10; + assert.isBelow(amount, operatorAllowance); + + const operator = context.accounts.operator; + + await expect( + context.lsp7.connect(operator).burn(context.accounts.owner.address, amount, '0x'), + ) + .to.emit(context.lsp7, 'AuthorizedOperator') + .withArgs( + operator.address, + context.accounts.owner.address, + operatorAllowance - amount, + '0x', + ); + }); }); describe('when burning more than its allowance', () => { From dd74b56af54cc01a5e28b50feac2ce6659403cda Mon Sep 17 00:00:00 2001 From: b00ste Date: Thu, 21 Sep 2023 17:02:07 +0300 Subject: [PATCH 30/55] feat: allow `renounceOwnership()` through LSP6 --- contracts/LSP6KeyManager/LSP6KeyManagerCore.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol index c8188b5e6..9f805a396 100644 --- a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol +++ b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol @@ -577,7 +577,8 @@ abstract contract LSP6KeyManagerCore is ); } else if ( erc725Function == ILSP14Ownable2Step.transferOwnership.selector || - erc725Function == ILSP14Ownable2Step.acceptOwnership.selector + erc725Function == ILSP14Ownable2Step.acceptOwnership.selector || + erc725Function == ILSP14Ownable2Step.renounceOwnership.selector ) { LSP6OwnershipModule._verifyOwnershipPermissions(from, permissions); } else { From 072c36708876cb1fecca4f3ff95a211baccff540 Mon Sep 17 00:00:00 2001 From: b00ste Date: Mon, 25 Sep 2023 15:58:48 +0300 Subject: [PATCH 31/55] test: fix tests to allow `renounceOwnership` through KM --- .../LSP6/Admin/PermissionChangeOwner.test.ts | 50 +++++- .../Admin/PermissionChangeOwner.test.ts | 150 ++++++++++++++---- .../LSP6ControlledToken.test.ts | 20 ++- 3 files changed, 175 insertions(+), 45 deletions(-) diff --git a/tests/LSP20CallVerification/LSP6/Admin/PermissionChangeOwner.test.ts b/tests/LSP20CallVerification/LSP6/Admin/PermissionChangeOwner.test.ts index da889fa28..9fb87df9a 100644 --- a/tests/LSP20CallVerification/LSP6/Admin/PermissionChangeOwner.test.ts +++ b/tests/LSP20CallVerification/LSP6/Admin/PermissionChangeOwner.test.ts @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { ethers } from 'hardhat'; -import { BigNumber } from 'ethers'; +import { ethers, network } from 'hardhat'; +import { BigNumber, ContractTransaction } from 'ethers'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; // constants @@ -318,12 +318,48 @@ export const shouldBehaveLikePermissionChangeOwner = ( }); describe('when calling `renounceOwnership(...)`', () => { - it('should revert even if caller has ALL PERMISSIONS`', async () => { - const payload = context.universalProfile.interface.getSighash('renounceOwnership'); + describe('caller has ALL PERMISSIONS`', async () => { + let renounceOwnershipFirstTx: ContractTransaction; + let renounceOwnershipSecondTx: ContractTransaction; - await expect(context.universalProfile.connect(context.owner).renounceOwnership()) - .to.be.revertedWithCustomError(context.keyManager, 'InvalidERC725Function') - .withArgs(payload); + before(async () => { + // 1st call + renounceOwnershipFirstTx = await context.universalProfile + .connect(context.owner) + .renounceOwnership(); + + // mine 200 blocks + await network.provider.send('hardhat_mine', [ethers.utils.hexValue(200)]); + + // 2nd call + renounceOwnershipSecondTx = await context.universalProfile + .connect(context.owner) + .renounceOwnership(); + }); + + it('should emit `RenounceOwnershipStarted` on first call', async () => { + await expect(renounceOwnershipFirstTx).to.emit( + context.universalProfile, + 'RenounceOwnershipStarted', + ); + }); + + it('should emit `OwnershipRenounced` on second call', async () => { + await expect(renounceOwnershipSecondTx).to.emit( + context.universalProfile, + 'OwnershipRenounced', + ); + }); + + it('should clear the `pendingOwner` and set it to `AddressZero`', async () => { + expect(await context.universalProfile.pendingOwner()).to.equal( + ethers.constants.AddressZero, + ); + }); + + it('should update the owner to `AddressZero`', async () => { + expect(await context.universalProfile.owner()).to.equal(ethers.constants.AddressZero); + }); }); }); }; diff --git a/tests/LSP6KeyManager/Admin/PermissionChangeOwner.test.ts b/tests/LSP6KeyManager/Admin/PermissionChangeOwner.test.ts index bbd3852fc..a21d617a2 100644 --- a/tests/LSP6KeyManager/Admin/PermissionChangeOwner.test.ts +++ b/tests/LSP6KeyManager/Admin/PermissionChangeOwner.test.ts @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { ethers } from 'hardhat'; -import { BigNumber } from 'ethers'; +import { ethers, network } from 'hardhat'; +import { BigNumber, ContractTransaction } from 'ethers'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; // constants @@ -335,46 +335,136 @@ export const shouldBehaveLikePermissionChangeOwner = ( describe('when calling `renounceOwnership(...)` via the KeyManager', () => { describe('when caller has ALL PERMISSIONS', () => { - it('should revert via `execute(...)`', async () => { - const payload = context.universalProfile.interface.getSighash('renounceOwnership'); + describe('using `execute(...)`', () => { + let renounceOwnershipFirstTx: ContractTransaction; + let renounceOwnershipSecondTx: ContractTransaction; - await expect(context.keyManager.connect(context.owner).execute(payload)) - .to.be.revertedWithCustomError(context.keyManager, 'InvalidERC725Function') - .withArgs(payload); + before(async () => { + const payload = context.universalProfile.interface.getSighash('renounceOwnership'); + + // 1st call + renounceOwnershipFirstTx = await newKeyManager.connect(context.owner).execute(payload); + + // mine 200 blocks + await network.provider.send('hardhat_mine', [ethers.utils.hexValue(200)]); + + // 2nd call + renounceOwnershipSecondTx = await newKeyManager.connect(context.owner).execute(payload); + }); + + it('should emit `RenounceOwnershipStarted` on first call', async () => { + await expect(renounceOwnershipFirstTx).to.emit( + context.universalProfile, + 'RenounceOwnershipStarted', + ); + }); + + it('should emit `OwnershipRenounced` on second call', async () => { + await expect(renounceOwnershipSecondTx).to.emit( + context.universalProfile, + 'OwnershipRenounced', + ); + }); + + it('should clear the `pendingOwner` and set it to `AddressZero`', async () => { + expect(await context.universalProfile.pendingOwner()).to.equal( + ethers.constants.AddressZero, + ); + }); + + it('should update the owner to `AddressZero`', async () => { + expect(await context.universalProfile.owner()).to.equal(ethers.constants.AddressZero); + }); }); - it('should revert via `executeRelayCall()`', async () => { - const HARDHAT_CHAINID = 31337; - const valueToSend = 0; + describe('using `executeRelayCall()`', () => { + let renounceOwnershipFirstTx: ContractTransaction; + let renounceOwnershipSecondTx: ContractTransaction; + + before(async () => { + // Build new context as `renounceOwnership()` was used in the previous context + // ------ Build new context ------ + context = await buildContext(); + await setupKeyManager(context, [], []); + // ------------------------------- + + // ------ General variables for relay call ------ + const payload = context.universalProfile.interface.getSighash('renounceOwnership'); + const eip191Signer = new EIP191Signer(); + const HARDHAT_CHAINID = 31337; + const validityTimestamps = 0; + const valueToSend = 0; + // ---------------------------------------------- + + // ------ 1st call ------ + const firstNonce = await context.keyManager.getNonce(context.owner.address, 0); + + const firstEncodedMessage = ethers.utils.solidityPack( + ['uint256', 'uint256', 'uint256', 'uint256', 'uint256', 'bytes'], + [LSP25_VERSION, HARDHAT_CHAINID, firstNonce, validityTimestamps, valueToSend, payload], + ); - const nonce = await context.keyManager.getNonce(context.owner.address, 0); + const firstSignature = await eip191Signer.signDataWithIntendedValidator( + context.keyManager.address, + firstEncodedMessage, + LOCAL_PRIVATE_KEYS.ACCOUNT0, + ).signature; - const validityTimestamps = 0; + renounceOwnershipFirstTx = await context.keyManager + .connect(context.owner) + .executeRelayCall(firstSignature, firstNonce, validityTimestamps, payload, { + value: valueToSend, + }); + // ---------------------- - const payload = context.universalProfile.interface.getSighash('renounceOwnership'); + // mine 200 blocks + await network.provider.send('hardhat_mine', [ethers.utils.hexValue(200)]); - const encodedMessage = ethers.utils.solidityPack( - ['uint256', 'uint256', 'uint256', 'uint256', 'uint256', 'bytes'], - [LSP25_VERSION, HARDHAT_CHAINID, nonce, validityTimestamps, valueToSend, payload], - ); + // ------ 2nd call ------ + const secondNonce = await context.keyManager.getNonce(context.owner.address, 0); - const eip191Signer = new EIP191Signer(); + const secondEncodedMessage = ethers.utils.solidityPack( + ['uint256', 'uint256', 'uint256', 'uint256', 'uint256', 'bytes'], + [LSP25_VERSION, HARDHAT_CHAINID, secondNonce, validityTimestamps, valueToSend, payload], + ); - const { signature } = await eip191Signer.signDataWithIntendedValidator( - context.keyManager.address, - encodedMessage, - LOCAL_PRIVATE_KEYS.ACCOUNT0, - ); + const secondSignature = await eip191Signer.signDataWithIntendedValidator( + context.keyManager.address, + secondEncodedMessage, + LOCAL_PRIVATE_KEYS.ACCOUNT0, + ).signature; - await expect( - context.keyManager + renounceOwnershipSecondTx = await context.keyManager .connect(context.owner) - .executeRelayCall(signature, nonce, validityTimestamps, payload, { + .executeRelayCall(secondSignature, secondNonce, validityTimestamps, payload, { value: valueToSend, - }), - ) - .to.be.revertedWithCustomError(context.keyManager, 'InvalidERC725Function') - .withArgs(payload); + }); + // ---------------------- + }); + + it('should emit `RenounceOwnershipStarted` on first call', async () => { + await expect(renounceOwnershipFirstTx).to.emit( + context.universalProfile, + 'RenounceOwnershipStarted', + ); + }); + + it('should emit `OwnershipRenounced` on second call', async () => { + await expect(renounceOwnershipSecondTx).to.emit( + context.universalProfile, + 'OwnershipRenounced', + ); + }); + + it('should clear the `pendingOwner` and set it to `AddressZero`', async () => { + expect(await context.universalProfile.pendingOwner()).to.equal( + ethers.constants.AddressZero, + ); + }); + + it('should update the owner to `AddressZero`', async () => { + expect(await context.universalProfile.owner()).to.equal(ethers.constants.AddressZero); + }); }); }); }); diff --git a/tests/LSP6KeyManager/LSP6ControlledToken.test.ts b/tests/LSP6KeyManager/LSP6ControlledToken.test.ts index 77f0c7626..c0a3e1fae 100644 --- a/tests/LSP6KeyManager/LSP6ControlledToken.test.ts +++ b/tests/LSP6KeyManager/LSP6ControlledToken.test.ts @@ -132,17 +132,21 @@ describe('When deploying LSP7 with LSP6 as owner', () => { }); describe('using renounceOwnership(..) in LSP7 through LSP6', () => { - it('should revert', async () => { + it('should pass', async () => { const renounceOwnershipPayload = context.token.interface.encodeFunctionData('renounceOwnership'); - await expect(context.keyManager.connect(context.owner).execute(renounceOwnershipPayload)) - .to.be.revertedWithCustomError(context.keyManager, 'InvalidERC725Function') - .withArgs(renounceOwnershipPayload); + await context.keyManager.connect(context.owner).execute(renounceOwnershipPayload); + + expect(await context.token.owner()).to.equal(ethers.constants.AddressZero); }); }); describe('using transferOwnership(..) in LSP7 through LSP6', () => { + before("previous token contract's ownership was renounced, build new context", async () => { + context = await buildContext(); + }); + it('should change the owner of LSP7 contract', async () => { const LSP7 = context.token as LSP7Mintable; const transferOwnershipPayload = LSP7.interface.encodeFunctionData('transferOwnership', [ @@ -173,7 +177,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { expect(await context.token.getData(key)).to.equal(value); }); - it("`mint(..)` -> should revert with 'caller is not the owner' error.", async () => { + it("`mint(..)` -> should revert with 'InvalidERC725Function' error.", async () => { const LSP7 = context.token as LSP7Mintable; const mintPayload = LSP7.interface.encodeFunctionData('mint', [ context.owner.address, @@ -216,9 +220,9 @@ describe('When deploying LSP7 with LSP6 as owner', () => { const renounceOwnershipPayload = context.token.interface.encodeFunctionData('renounceOwnership'); - await expect(context.keyManager.connect(context.owner).execute(renounceOwnershipPayload)) - .to.be.revertedWithCustomError(context.keyManager, 'InvalidERC725Function') - .withArgs(renounceOwnershipPayload); + await expect( + context.keyManager.connect(context.owner).execute(renounceOwnershipPayload), + ).to.be.revertedWith('Ownable: caller is not the owner'); }); it('should allow the new owner to call renounceOwnership(..)', async () => { From d62239e7031ef80c52fb35abe5ecf996a9340141 Mon Sep 17 00:00:00 2001 From: Jean Cvllr <31145285+CJ42@users.noreply.github.com> Date: Fri, 29 Sep 2023 17:05:31 +0100 Subject: [PATCH 32/55] ci: update gas benchmark CI to display gas diffs as well as the figures (#731) * build: write Hardhat task for gas benchmark * refactor: improve benchmark generation script with markdown * ci: update CI to generate gas comparison * build: add deployment cost in gas benchmark --- .github/workflows/benchmark.yml | 43 +- .gitignore | 2 +- hardhat.config.ts | 3 + scripts/ci/gas_benchmark.ts | 226 ++++++ scripts/ci/gas_benchmark_template.json | 204 +++++ tests/Benchmark.test.ts | 1023 ++++++++++++++++-------- 6 files changed, 1143 insertions(+), 358 deletions(-) create mode 100644 scripts/ci/gas_benchmark.ts create mode 100644 scripts/ci/gas_benchmark_template.json diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 0fb243e1f..edb5a2057 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -1,5 +1,7 @@ # This workflow benchmark the gas usage of Universal Profile for common interactions - +# It compare the gas cost of the changes made between: +# - a feature branch (where a PR is opened) +# - a target branch (where the PR will be merged) name: 🆙 📊 Universal Profile Benchmark on: @@ -22,7 +24,11 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: Checkout base branch + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.base.sha }} + fetch-depth: 0 - name: Use Node.js '16.15.0' uses: actions/setup-node@v2 @@ -37,11 +43,40 @@ jobs: run: npx hardhat compile - name: 🧪 Run Benchmark tests - run: npm run test:benchmark + # Rename the file to be able to generate benchmark JSON report + run: | + npm run test:benchmark + mv gas_benchmark_result.json gas_benchmark_before.json + + - name: Checkout current branch + uses: actions/checkout@v3 + # Do not run `git clean -ffdx && git reset --hard HEAD` to prevent removing `gas_benchmark_before.json` + with: + clean: false + + - name: Use Node.js '16.15.0' + uses: actions/setup-node@v2 + with: + node-version: "16.15.0" + cache: "npm" + + - name: 📦 Install dependencies + run: npm ci + + - name: 🏗️ Build contract artifacts + run: npx hardhat compile + + - name: 🧪 Run Benchmark tests + run: | + npm run test:benchmark + mv gas_benchmark_result.json gas_benchmark_after.json - name: 📊 Generate Benchmark Report + run: npx hardhat gas-benchmark --compare gas_benchmark_after.json --against gas_benchmark_before.json + + - name: 💬 Add Gas Report as comment in PR uses: peter-evans/create-or-update-comment@v2 with: token: ${{ secrets.GITHUB_TOKEN }} issue-number: ${{ github.event.pull_request.number }} - body-file: "./benchmark.md" + body-file: "./gas_benchmark.md" diff --git a/.gitignore b/.gitignore index 9b491c2bd..c1824b6ac 100644 --- a/.gitignore +++ b/.gitignore @@ -132,7 +132,7 @@ out/ forge-cache/ # generated gas benchmark -benchmark.md +gas_benchmark.md # Exclude build output folders /common diff --git a/hardhat.config.ts b/hardhat.config.ts index 78aeec4d1..175e5dad2 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -18,7 +18,10 @@ import '@nomicfoundation/hardhat-toolbox'; import 'hardhat-packager'; import 'hardhat-contract-sizer'; import 'hardhat-deploy'; + +// custom built hardhat plugins for CI import './scripts/ci/docs-generate'; +import './scripts/ci/gas_benchmark'; // Typescript types for web3.js import '@nomiclabs/hardhat-web3'; diff --git a/scripts/ci/gas_benchmark.ts b/scripts/ci/gas_benchmark.ts new file mode 100644 index 000000000..024a1b464 --- /dev/null +++ b/scripts/ci/gas_benchmark.ts @@ -0,0 +1,226 @@ +import fs from 'fs'; +import { task } from 'hardhat/config'; +import { Align, getMarkdownTable, Row } from 'markdown-table-ts'; + +task('gas-benchmark', 'Benchmark gas usage of the smart contracts based on predefined scenarios') + .addParam( + 'compare', + 'The `.json` file that contains the gas costs of the currently compiled contracts (e.g: current working branch)', + ) + .addParam( + 'against', + 'The `.json` file that contains the gas costs to compare against (e.g: the `develop` branch)', + ) + .setAction(async function (args) { + const currentBenchmark = JSON.parse(fs.readFileSync(args.compare, 'utf8')); + const baseBenchmark = JSON.parse(fs.readFileSync(args.against, 'utf8')); + + const deploymentCosts: Row[] = []; + + const casesEOAExecute: Row[] = []; + const casesEOASetData: Row[] = []; + const casesEOATokens: Row[] = []; + + const casesKeyManagerExecute: Row[] = []; + const casesKeyManagerSetData: Row[] = []; + + const formatNumber = (value: number) => { + return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); + }; + + const displayGasDiff = (gasDiff: number) => { + let emoji = ''; + + if (gasDiff > 0) { + emoji = '📈❌'; + } + + if (gasDiff < 0) { + emoji = '📉✅'; + } + + return `${formatNumber(gasDiff)} ${emoji}`; + }; + + // Deployment costs + for (const [key, value] of Object.entries(currentBenchmark['deployment_costs'])) { + const gasCost: any = value; + const gasDiff = gasCost - baseBenchmark['deployment_costs'][key]; + + deploymentCosts.push([key, value + ` (${displayGasDiff(gasDiff)})`]); + } + + const generatedDeploymentCostsTable = getMarkdownTable({ + table: { + head: ['Deployed contracts', '⛽ Deployment cost'], + body: deploymentCosts, + }, + alignment: [Align.Left], + }); + + // EOA - execute + for (const [key, value] of Object.entries( + currentBenchmark['runtime_costs']['EOA_owner']['execute'], + )) { + const gasDiff = + value['gas_cost'] - baseBenchmark['runtime_costs']['EOA_owner']['execute'][key]['gas_cost']; + + casesEOAExecute.push([ + value['description'], + value['gas_cost'] + ` (${displayGasDiff(gasDiff)})`, + ]); + } + + const generatedEOAExecuteTable = getMarkdownTable({ + table: { + head: ['`execute` scenarios - UP owned by 🔑 EOA', '⛽ Gas Usage'], + body: casesEOAExecute, + }, + alignment: [Align.Left], + }); + + // EOA - setData + for (const [key, value] of Object.entries( + currentBenchmark['runtime_costs']['EOA_owner']['setData'], + )) { + const gasDiff = + value['gas_cost'] - baseBenchmark['runtime_costs']['EOA_owner']['setData'][key]['gas_cost']; + + casesEOASetData.push([ + value['description'], + value['gas_cost'] + ` (${displayGasDiff(gasDiff)})`, + ]); + } + + const generatedEOASetDataTable = getMarkdownTable({ + table: { + head: ['`setData` scenarios - UP owned by 🔑 EOA', '⛽ Gas Usage'], + body: casesEOASetData, + }, + alignment: [Align.Left], + }); + + // EOA - Tokens + for (const [key, value] of Object.entries( + currentBenchmark['runtime_costs']['EOA_owner']['tokens'], + )) { + const gasDiff = + value['gas_cost'] - baseBenchmark['runtime_costs']['EOA_owner']['tokens'][key]['gas_cost']; + + casesEOATokens.push([ + value['description'], + value['gas_cost'] + ` (${displayGasDiff(gasDiff)})`, + ]); + } + + const generatedEOATokensTable = getMarkdownTable({ + table: { + head: ['`Tokens` scenarios - UP owned by 🔑 EOA', '⛽ Gas Usage'], + body: casesEOATokens, + }, + alignment: [Align.Left], + }); + + // Key Manager - execute + for (const [key, value] of Object.entries( + currentBenchmark['runtime_costs']['KeyManager_owner']['execute'], + )) { + const gasDiffMainController = + value['main_controller'] - + baseBenchmark['runtime_costs']['KeyManager_owner']['execute'][key]['main_controller']; + + const gasDiffRestrictedController = + value['restricted_controller'] - + baseBenchmark['runtime_costs']['KeyManager_owner']['execute'][key]['restricted_controller']; + + casesKeyManagerExecute.push([ + value['description'], + value['main_controller'] + ` (${displayGasDiff(gasDiffMainController)})`, + value['restricted_controller'] + ` (${displayGasDiff(gasDiffRestrictedController)})`, + ]); + } + + const generatedKeyManagerExecuteTable = getMarkdownTable({ + table: { + head: ['`execute` scenarios', '👑 main controller', '🛃 restricted controller'], + body: casesKeyManagerExecute, + }, + alignment: [Align.Left], + }); + + // Key Manager - setData + for (const [key, value] of Object.entries( + currentBenchmark['runtime_costs']['KeyManager_owner']['setData'], + )) { + const gasDiffMainController = + value['main_controller'] - + baseBenchmark['runtime_costs']['KeyManager_owner']['setData'][key]['main_controller']; + + const gasDiffRestrictedController = + value['restricted_controller'] - + baseBenchmark['runtime_costs']['KeyManager_owner']['setData'][key]['restricted_controller']; + + casesKeyManagerSetData.push([ + value['description'], + value['main_controller'] + ` (${displayGasDiff(gasDiffMainController)})`, + value['restricted_controller'] + ` (${displayGasDiff(gasDiffRestrictedController)})`, + ]); + } + + const generatedKeyManagerSetDataTable = getMarkdownTable({ + table: { + head: ['`setData` scenarios', '👑 main controller', '🛃 restricted controller'], + body: casesKeyManagerSetData, + }, + alignment: [Align.Left], + }); + + const markdownContent = ` +👋 Hello +⛽ I am the Gas Bot Reporter. I keep track of the gas costs of common interactions using Universal Profiles 🆙 ! +📊 Here is a summary of the gas cost with the code introduced by this PR. + +## ⛽📊 Gas Benchmark Report + +### Deployment Costs + +${generatedDeploymentCostsTable} + +### Runtime Costs + +
+UniversalProfile owned by an 🔑 EOA + +### 🔀 \`execute\` scenarios + +${generatedEOAExecuteTable} + +### 🗄️ \`setData\` scenarios + +${generatedEOASetDataTable} + +### 🗄️ \`Tokens\` scenarios + +${generatedEOATokensTable} + +
+ +
+UniversalProfile owned by a 🔒📄 LSP6KeyManager + +### 🔀 \`execute\` scenarios + +${generatedKeyManagerExecuteTable} + +### 🗄️ \`setData\` scenarios + +${generatedKeyManagerSetDataTable} + +
+ + `; + + const file = 'gas_benchmark.md'; + + fs.writeFileSync(file, markdownContent, 'utf8'); + }); diff --git a/scripts/ci/gas_benchmark_template.json b/scripts/ci/gas_benchmark_template.json new file mode 100644 index 000000000..6c7d794c6 --- /dev/null +++ b/scripts/ci/gas_benchmark_template.json @@ -0,0 +1,204 @@ +{ + "deployment_costs": { + "UniversalProfile": "", + "KeyManager": "", + "LSP1DelegateUP": "", + "LSP7Mintable": "", + "LSP8Mintable": "" + }, + "runtime_costs": { + "EOA_owner": { + "execute": { + "case_1": { + "description": "Transfer 1 LYX to an EOA without data", + "gas_cost": "" + }, + "case_2": { + "description": "Transfer 1 LYX to a UP without data", + "gas_cost": "" + }, + "case_3": { + "description": "Transfer 1 LYX to an EOA with 256 bytes of data", + "gas_cost": "" + }, + "case_4": { + "description": "Transfer 1 LYX to a UP with 256 bytes of data", + "gas_cost": "" + }, + "case_5": { + "description": "Transfer 0.1 LYX to 3x EOA without data", + "gas_cost": "" + }, + "case_6": { + "description": "Transfer 0.1 LYX to 3x UP without data", + "gas_cost": "" + }, + "case_7": { + "description": "Transfer 0.1 LYX to 3x EOA with 256 bytes of data", + "gas_cost": "" + }, + "case_8": { + "description": "Transfer 0.1 LYX to 3x UPs with 256 bytes of data", + "gas_cost": "" + } + }, + "setData": { + "case_1": { + "description": "Set a 20 bytes long value", + "gas_cost": "" + }, + "case_2": { + "description": "Set a 60 bytes long value", + "gas_cost": "" + }, + "case_3": { + "description": "Set a 160 bytes long value", + "gas_cost": "" + }, + "case_4": { + "description": "Set a 300 bytes long value", + "gas_cost": "" + }, + "case_5": { + "description": "Set a 600 bytes long value", + "gas_cost": "" + }, + "case_6": { + "description": "Change the value of a data key already set", + "gas_cost": "" + }, + "case_7": { + "description": "Remove the value of a data key already set", + "gas_cost": "" + }, + "case_8": { + "description": "Set 2 data keys of 20 bytes long value", + "gas_cost": "" + }, + "case_9": { + "description": "Set 2 data keys of 100 bytes long value", + "gas_cost": "" + }, + "case_10": { + "description": "Set 3 data keys of 20 bytes long value", + "gas_cost": "" + }, + "case_11": { + "description": "Change the value of three data keys already set of 20 bytes long value", + "gas_cost": "" + }, + "case_12": { + "description": "Remove the value of three data keys already set", + "gas_cost": "" + } + }, + "tokens": { + "case_1": { + "description": "Minting a LSP7Token to a UP (No Delegate) from an EOA", + "gas_cost": "" + }, + "case_2": { + "description": "Minting a LSP7Token to an EOA from an EOA", + "gas_cost": "" + }, + "case_3": { + "description": "Transferring an LSP7Token from a UP to another UP (No Delegate)", + "gas_cost": "" + }, + "case_4": { + "description": "Minting a LSP8Token to a UP (No Delegate) from an EOA ", + "gas_cost": "" + }, + "case_5": { + "description": "Minting a LSP8Token to an EOA from an EOA ", + "gas_cost": "" + }, + "case_6": { + "description": "Transferring an LSP8Token from a UP to another UP (No Delegate)", + "gas_cost": "" + } + } + }, + "KeyManager_owner": { + "execute": { + "case_1": { + "description": "LYX transfer --> to an EOA", + "main_controller": "", + "restricted_controller": "" + }, + "case_2": { + "description": "LYX transfer --> to a UP", + "main_controller": "", + "restricted_controller": "" + }, + "case_3": { + "description": "LSP7 token transfer --> to an EOA", + "main_controller": "", + "restricted_controller": "" + }, + "case_4": { + "description": "LSP7 token transfer --> to a UP", + "main_controller": "", + "restricted_controller": "" + }, + "case_5": { + "description": "LSP8 NFT transfer --> to an EOA", + "main_controller": "", + "restricted_controller": "" + }, + "case_6": { + "description": "LSP8 NFT transfer --> to a UP", + "main_controller": "", + "restricted_controller": "" + } + }, + "setData": { + "case_1": { + "description": "Update Profile details (LSP3Profile Metadata)", + "main_controller": "", + "restricted_controller": "" + }, + "case_2": { + "description": "Add a new controller with permission to `SET_DATA` + 3x allowed data keys:
`AddressPermissions[]`
+ `AddressPermissions[index]`
+ `AddressPermissions:Permissions:`
+ `AddressPermissions:AllowedERC725YDataKeys: 1. decrease `AddressPermissions[]` Array length
2. remove the controller address at `AddressPermissions[index]`
3. set \"0x\" for the controller permissions under AddressPermissions:Permissions:", + "main_controller": "", + "restricted_controller": "" + }, + "case_5": { + "description": "Write 5x new LSP12 Issued Assets", + "main_controller": "", + "restricted_controller": "" + }, + "case_6": { + "description": "Update 3x data keys (first 3)", + "main_controller": "", + "restricted_controller": "" + }, + "case_7": { + "description": "Update 3x data keys (middle 3)", + "main_controller": "", + "restricted_controller": "" + }, + "case_8": { + "description": "Update 3x data keys (last 3)", + "main_controller": "", + "restricted_controller": "" + }, + "case_9": { + "description": "Set 2 x new data keys + add 3x new controllers", + "main_controller": "", + "restricted_controller": "" + } + } + } + } +} diff --git a/tests/Benchmark.test.ts b/tests/Benchmark.test.ts index 1d4cdc8a9..aff0d2a1b 100644 --- a/tests/Benchmark.test.ts +++ b/tests/Benchmark.test.ts @@ -2,9 +2,10 @@ import fs from 'fs'; import { ethers } from 'hardhat'; import { expect } from 'chai'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; -import { Align, getMarkdownTable, Row } from 'markdown-table-ts'; import { + LSP1UniversalReceiverDelegateUP, + LSP1UniversalReceiverDelegateUP__factory, LSP6KeyManager__factory, LSP7Mintable, LSP7Mintable__factory, @@ -15,16 +16,21 @@ import { } from '../types'; import { - ALL_PERMISSIONS, ERC725YDataKeys, INTERFACE_IDS, OPERATION_TYPES, PERMISSIONS, CALLTYPE, + LSP8_TOKEN_ID_TYPES, } from '../constants'; import { LSP6TestContext } from './utils/context'; import { setupKeyManager, setupProfileWithKeyManagerWithURD } from './utils/fixtures'; -import { combineAllowedCalls, combinePermissions, encodeCompactBytesArray } from './utils/helpers'; +import { + abiCoder, + combineAllowedCalls, + combinePermissions, + encodeCompactBytesArray, +} from './utils/helpers'; import { BigNumber } from 'ethers'; export type UniversalProfileContext = { @@ -63,22 +69,82 @@ const buildUniversalProfileContext = async ( return { accounts, owner, universalProfile }; }; -let UniversalProfileSetDataTable; -let UniversalProfileExecuteTable; -let UniversalProfileTokensTable; +describe('⛽📊 Gas Benchmark', () => { + let gasBenchmark; -let mainControllerExecuteTable; -let restrictedControllerExecuteTable; + before('setup benchmark file', async () => { + gasBenchmark = JSON.parse(fs.readFileSync('./scripts/ci/gas_benchmark_template.json', 'utf8')); + }); -let mainControllerSetDataTable; -let restrictedControllerSetDataTable; + after(async () => { + fs.writeFileSync('./gas_benchmark_result.json', JSON.stringify(gasBenchmark, null, 2)); + }); + + describe('Deployment costs', () => { + it('deploy contracts + save deployment costs', async () => { + const accounts = await ethers.getSigners(); + + // Universal Profile + const universalProfile = await new UniversalProfile__factory(accounts[0]).deploy( + accounts[0].address, + ); + + const universalProfileDeployTransaction = universalProfile.deployTransaction; + const universalProfileDeploymentReceipt = await universalProfileDeployTransaction.wait(); + + gasBenchmark['deployment_costs']['UniversalProfile'] = + universalProfileDeploymentReceipt.gasUsed.toNumber(); + + // Key Manager + const keyManager = await new LSP6KeyManager__factory(accounts[0]).deploy( + universalProfile.address, + ); + + const keyManagerDeployTransaction = keyManager.deployTransaction; + const keyManagerDeploymentReceipt = await keyManagerDeployTransaction?.wait(); + + gasBenchmark['deployment_costs']['KeyManager'] = + keyManagerDeploymentReceipt?.gasUsed.toNumber(); + + // LSP1 Delegate + const lsp1Delegate = await new LSP1UniversalReceiverDelegateUP__factory(accounts[0]).deploy(); + + const lsp1DelegateDeployTransaction = lsp1Delegate.deployTransaction; + const lsp1DelegateDeploymentReceipt = await lsp1DelegateDeployTransaction.wait(); + + gasBenchmark['deployment_costs']['LSP1DelegateUP'] = + lsp1DelegateDeploymentReceipt.gasUsed.toNumber(); + + // LSP7 Token (Mintable preset) + const lsp7Mintable = await new LSP7Mintable__factory(accounts[0]).deploy( + 'Token', + 'MTKN', + accounts[0].address, + false, + ); + + const lsp7DeployTransaction = lsp7Mintable.deployTransaction; + const lsp7DeploymentReceipt = await lsp7DeployTransaction.wait(); + + gasBenchmark['deployment_costs']['LSP7Mintable'] = lsp7DeploymentReceipt.gasUsed.toNumber(); + + // LSP8 NFT (Mintable preset) + const lsp8Mintable = await new LSP8Mintable__factory(accounts[0]).deploy( + 'My NFT', + 'MNFT', + accounts[0].address, + LSP8_TOKEN_ID_TYPES.NUMBER, + ); + + const lsp8DeployTransaction = lsp8Mintable.deployTransaction; + const lsp8DeploymentReceipt = await lsp8DeployTransaction.wait(); + + gasBenchmark['deployment_costs']['LSP8Mintable'] = lsp8DeploymentReceipt.gasUsed.toNumber(); + }); + }); -describe('⛽📊 Gas Benchmark', () => { describe('UniversalProfile', () => { let context: UniversalProfileContext; - const executeUP: Row[] = []; - const setDataUP: Row[] = []; - const tokensUP: Row[] = []; describe('execute', () => { describe('execute Single', () => { @@ -98,10 +164,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - executeUP.push([ - 'Transfer 1 LYX to an EOA without data', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['EOA_owner']['execute']['case_1']['gas_cost'] = + receipt.gasUsed.toNumber(); }); it('Transfer 1 LYX to a UP without data', async () => { @@ -116,10 +180,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - executeUP.push([ - 'Transfer 1 LYX to a UP without data', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['EOA_owner']['execute']['case_2']['gas_cost'] = + receipt.gasUsed.toNumber(); }); it('Transfer 1 LYX to an EOA with 256 bytes of data', async () => { @@ -134,10 +196,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - executeUP.push([ - 'Transfer 1 LYX to an EOA with 256 bytes of data', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['EOA_owner']['execute']['case_3']['gas_cost'] = + receipt.gasUsed.toNumber(); }); it('Transfer 1 LYX to a UP with 256 bytes of data', async () => { @@ -152,15 +212,13 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - executeUP.push([ - 'Transfer 1 LYX to a UP with 256 bytes of data', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['EOA_owner']['execute']['case_4']['gas_cost'] = + receipt.gasUsed.toNumber(); }); }); describe('execute Array', () => { - let universalProfile1, universalProfile2, universalProfile3; + let universalProfile1: UniversalProfile, universalProfile2, universalProfile3; before(async () => { context = await buildUniversalProfileContext(ethers.utils.parseEther('50')); @@ -198,10 +256,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - executeUP.push([ - 'Transfer 0.1 LYX to 3x EOA without data', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['EOA_owner']['execute']['case_5']['gas_cost'] = + receipt.gasUsed.toNumber(); }); it('Transfer 0.1 LYX to 3x UP without data', async () => { @@ -220,10 +276,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - executeUP.push([ - 'Transfer 0.1 LYX to 3x UP without data', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['EOA_owner']['execute']['case_6']['gas_cost'] = + receipt.gasUsed.toNumber(); }); it('Transfer 0.1 LYX to 3x EOA with 256 bytes of data', async () => { @@ -246,10 +300,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - executeUP.push([ - 'Transfer 0.1 LYX to 3x EOA with 256 bytes of data', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['EOA_owner']['execute']['case_7']['gas_cost'] = + receipt.gasUsed.toNumber(); }); it('Transfer 0.1 LYX to 3x UP with 256 bytes of data', async () => { @@ -273,20 +325,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - executeUP.push([ - 'Transfer 0.1 LYX to 3x EOA with 256 bytes of data', - receipt.gasUsed.toNumber().toString(), - ]); - }); - }); - - after(async () => { - UniversalProfileExecuteTable = getMarkdownTable({ - table: { - head: ['`execute` scenarios - 👑 UP Owner', '⛽ Gas Usage'], - body: executeUP, - }, - alignment: [Align.Left, Align.Center], + gasBenchmark['runtime_costs']['EOA_owner']['execute']['case_8']['gas_cost'] = + receipt.gasUsed.toNumber(); }); }); }); @@ -305,7 +345,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - setDataUP.push(['Set a 20 bytes long value', receipt.gasUsed.toNumber().toString()]); + gasBenchmark['runtime_costs']['EOA_owner']['setData']['case_1']['gas_cost'] = + receipt.gasUsed.toNumber(); }); it('Set a 60 bytes long value', async () => { @@ -316,7 +357,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - setDataUP.push(['Set a 60 bytes long value', receipt.gasUsed.toNumber().toString()]); + gasBenchmark['runtime_costs']['EOA_owner']['setData']['case_2']['gas_cost'] = + receipt.gasUsed.toNumber(); }); it('Set a 160 bytes long value', async () => { @@ -327,7 +369,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - setDataUP.push(['Set a 160 bytes long value', receipt.gasUsed.toNumber().toString()]); + gasBenchmark['runtime_costs']['EOA_owner']['setData']['case_3']['gas_cost'] = + receipt.gasUsed.toNumber(); }); it('Set a 300 bytes long value', async () => { @@ -338,7 +381,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - setDataUP.push(['Set a 300 bytes long value', receipt.gasUsed.toNumber().toString()]); + gasBenchmark['runtime_costs']['EOA_owner']['setData']['case_4']['gas_cost'] = + receipt.gasUsed.toNumber(); }); it('Set a 600 bytes long value', async () => { @@ -349,7 +393,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - setDataUP.push(['Set a 600 bytes long value', receipt.gasUsed.toNumber().toString()]); + gasBenchmark['runtime_costs']['EOA_owner']['setData']['case_5']['gas_cost'] = + receipt.gasUsed.toNumber(); }); it('Change the value of a data key already set', async () => { @@ -363,10 +408,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - setDataUP.push([ - 'Change the value of a data key already set', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['EOA_owner']['setData']['case_6']['gas_cost'] = + receipt.gasUsed.toNumber(); }); it('Remove the value of a data key already set', async () => { @@ -379,10 +422,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - setDataUP.push([ - 'Remove the value of a data key already set', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['EOA_owner']['setData']['case_7']['gas_cost'] = + receipt.gasUsed.toNumber(); }); }); @@ -402,10 +443,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - setDataUP.push([ - 'Set 2 data keys of 20 bytes long value', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['EOA_owner']['setData']['case_8']['gas_cost'] = + receipt.gasUsed.toNumber(); }); it('Set 2 data keys of 100 bytes long value', async () => { @@ -419,10 +458,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - setDataUP.push([ - 'Set 2 data keys of 100 bytes long value', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['EOA_owner']['setData']['case_9']['gas_cost'] = + receipt.gasUsed.toNumber(); }); it('Set 3 data keys of 20 bytes long value', async () => { @@ -442,10 +479,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - setDataUP.push([ - 'Set 3 data keys of 20 bytes long value', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['EOA_owner']['setData']['case_10']['gas_cost'] = + receipt.gasUsed.toNumber(); }); it('Change the value of three data keys already set of 20 bytes long value', async () => { @@ -467,10 +502,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - setDataUP.push([ - 'Change the value of three data keys already set of 20 bytes long value', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['EOA_owner']['setData']['case_11']['gas_cost'] = + receipt.gasUsed.toNumber(); }); it('Remove the value of three data keys already set', async () => { @@ -492,20 +525,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - setDataUP.push([ - 'Remove the value of three data keys already set', - receipt.gasUsed.toNumber().toString(), - ]); - }); - }); - - after(async () => { - UniversalProfileSetDataTable = getMarkdownTable({ - table: { - head: ['`setData` scenarios - 👑 UP Owner', '⛽ Gas Usage'], - body: setDataUP, - }, - alignment: [Align.Left, Align.Center], + gasBenchmark['runtime_costs']['EOA_owner']['setData']['case_12']['gas_cost'] = + receipt.gasUsed.toNumber(); }); }); }); @@ -525,11 +546,12 @@ describe('⛽📊 Gas Benchmark', () => { false, ); - // deploy a LSP7 token + // deploy a LSP8 NFT lsp8Token = await new LSP8Mintable__factory(context.owner).deploy( - 'Token', - 'MTKN', + 'My NFT', + 'MNFT', context.owner.address, + LSP8_TOKEN_ID_TYPES.NUMBER, ); universalProfile1 = await new UniversalProfile__factory(context.owner).deploy( @@ -543,10 +565,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - tokensUP.push([ - 'Minting a LSP7Token to a UP (No Delegate) from an EOA', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['EOA_owner']['tokens']['case_1']['gas_cost'] = + receipt.gasUsed.toNumber(); }); it('when minting LSP7Token to a EOA without data', async () => { @@ -554,10 +574,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - tokensUP.push([ - 'Minting a LSP7Token to an EOA from an EOA', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['EOA_owner']['tokens']['case_2']['gas_cost'] = + receipt.gasUsed.toNumber(); }); it('when transferring LSP7Token from a UP to a UP without data', async () => { @@ -575,10 +593,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - tokensUP.push([ - 'Transferring an LSP7Token from a UP to another UP (No Delegate)', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['EOA_owner']['tokens']['case_3']['gas_cost'] = + receipt.gasUsed.toNumber(); }); }); @@ -600,10 +616,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - tokensUP.push([ - 'Minting a LSP8Token to a UP (No Delegate) from an EOA', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['EOA_owner']['tokens']['case_4']['gas_cost'] = + receipt.gasUsed.toNumber(); }); it('when minting LSP8Token to a EOA without data', async () => { @@ -611,10 +625,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - tokensUP.push([ - 'Minting a LSP8Token to an EOA from an EOA', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['EOA_owner']['tokens']['case_5']['gas_cost'] = + receipt.gasUsed.toNumber(); }); it('when transferring LSP8Token from a UP to a UP without data', async () => { @@ -632,20 +644,8 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - tokensUP.push([ - 'Transferring an LSP8Token from a UP to another UP (No Delegate)', - receipt.gasUsed.toNumber().toString(), - ]); - }); - }); - - after(async () => { - UniversalProfileTokensTable = getMarkdownTable({ - table: { - head: ['`Tokens` scenarios - 👑 UP Owner', '⛽ Gas Usage'], - body: tokensUP, - }, - alignment: [Align.Left, Align.Center], + gasBenchmark['runtime_costs']['EOA_owner']['tokens']['case_6']['gas_cost'] = + receipt.gasUsed.toNumber(); }); }); }); @@ -679,9 +679,18 @@ describe('⛽📊 Gas Benchmark', () => { const deployedContracts = await setupProfileWithKeyManagerWithURD(context.accounts[2]); aliceUP = deployedContracts[0] as UniversalProfile; - // the function `setupKeyManager` gives ALL PERMISSIONS - // to the owner as the first data key - await setupKeyManager(context, [], []); + const lsp1Delegate: LSP1UniversalReceiverDelegateUP = + await new LSP1UniversalReceiverDelegateUP__factory(context.accounts[0]).deploy(); + + // the function `setupKeyManager` gives ALL PERMISSIONS to the owner as the first data key + // We also setup the following: + // - LSP1 Delegate (for registering LSP7 tokens + LSP8 NFTs) + // - LSP3Profile metadata (to test for updates) + await setupKeyManager( + context, + [ERC725YDataKeys.LSP1.LSP1UniversalReceiverDelegate], + [lsp1Delegate.address], + ); // deploy a LSP7 token lsp7MetaCoin = await new LSP7Mintable__factory(context.owner).deploy( @@ -696,6 +705,7 @@ describe('⛽📊 Gas Benchmark', () => { 'MetaNFT', 'MNF', context.owner.address, + LSP8_TOKEN_ID_TYPES.NUMBER, ); // mint some tokens to the UP @@ -718,6 +728,10 @@ describe('⛽📊 Gas Benchmark', () => { 'transfer LYX to an EOA', receipt.gasUsed.toNumber().toString(), ]); + + gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_1'][ + 'main_controller' + ] = receipt.gasUsed.toNumber(); }); it('transfers some LYXes to a UP', async () => { @@ -731,6 +745,10 @@ describe('⛽📊 Gas Benchmark', () => { 'transfer LYX to a UP', receipt.gasUsed.toNumber().toString(), ]); + + gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_2'][ + 'main_controller' + ] = receipt.gasUsed.toNumber(); }); it('transfers some tokens (LSP7) to an EOA (no data)', async () => { @@ -755,6 +773,10 @@ describe('⛽📊 Gas Benchmark', () => { 'transfer tokens (LSP7) to an EOA (no data)', receipt.gasUsed.toNumber().toString(), ]); + + gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_3'][ + 'main_controller' + ] = receipt.gasUsed.toNumber(); }); it('transfer some tokens (LSP7) to a UP (no data)', async () => { @@ -779,6 +801,10 @@ describe('⛽📊 Gas Benchmark', () => { 'transfer tokens (LSP7) to a UP (no data)', receipt.gasUsed.toNumber().toString(), ]); + + gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_4'][ + 'main_controller' + ] = receipt.gasUsed.toNumber(); }); it('transfer a NFT (LSP8) to a EOA (no data)', async () => { @@ -803,6 +829,10 @@ describe('⛽📊 Gas Benchmark', () => { 'transfer a NFT (LSP8) to a EOA (no data)', receipt.gasUsed.toNumber().toString(), ]); + + gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_5'][ + 'main_controller' + ] = receipt.gasUsed.toNumber(); }); it('transfer a NFT (LSP8) to a UP (no data)', async () => { @@ -827,16 +857,10 @@ describe('⛽📊 Gas Benchmark', () => { 'transfer a NFT (LSP8) to a UP (no data)', receipt.gasUsed.toNumber().toString(), ]); - }); - after(async () => { - mainControllerExecuteTable = getMarkdownTable({ - table: { - head: ['`execute` scenarios - 👑 main controller', '⛽ Gas Usage'], - body: casesExecuteMainController, - }, - alignment: [Align.Left, Align.Center], - }); + gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_6'][ + 'main_controller' + ] = receipt.gasUsed.toNumber(); }); }); @@ -876,6 +900,7 @@ describe('⛽📊 Gas Benchmark', () => { recipientEOA = context.accounts[1]; + // UP receiving LYX, Tokens and NFT transfers const deployedContracts = await setupProfileWithKeyManagerWithURD(context.accounts[2]); aliceUP = deployedContracts[0] as UniversalProfile; @@ -911,12 +936,14 @@ describe('⛽📊 Gas Benchmark', () => { 'MetaNFT', 'MNF', context.owner.address, + LSP8_TOKEN_ID_TYPES.NUMBER, ); lsp8LyxPunks = await new LSP8Mintable__factory(context.owner).deploy( 'LyxPunks', 'LPK', context.owner.address, + LSP8_TOKEN_ID_TYPES.UNIQUE_ID, ); [ @@ -929,10 +956,15 @@ describe('⛽📊 Gas Benchmark', () => { }); }); + const lsp1Delegate = await new LSP1UniversalReceiverDelegateUP__factory( + context.accounts[0], + ).deploy(); + // prettier-ignore await setupKeyManager( context, [ + ERC725YDataKeys.LSP1.LSP1UniversalReceiverDelegate, ERC725YDataKeys.LSP6["AddressPermissions:Permissions"] + canTransferValueToOneAddress.address.substring(2), ERC725YDataKeys.LSP6["AddressPermissions:Permissions"] + canTransferTwoTokens.address.substring(2), ERC725YDataKeys.LSP6["AddressPermissions:Permissions"] + canTransferTwoNFTs.address.substring(2), @@ -941,10 +973,11 @@ describe('⛽📊 Gas Benchmark', () => { ERC725YDataKeys.LSP6["AddressPermissions:AllowedCalls"] + canTransferTwoNFTs.address.substring(2), ], [ + lsp1Delegate.address, PERMISSIONS.TRANSFERVALUE, PERMISSIONS.CALL, PERMISSIONS.CALL, - combineAllowedCalls([CALLTYPE.VALUE], [allowedAddressToTransferValue], ["0xffffffff"], ["0xffffffff"]), + combineAllowedCalls([CALLTYPE.VALUE, CALLTYPE.VALUE], [allowedAddressToTransferValue, aliceUP.address], ["0xffffffff", "0xffffffff"], ["0xffffffff", "0xffffffff"]), combineAllowedCalls( [CALLTYPE.CALL, CALLTYPE.CALL], [lsp7MetaCoin.address, lsp7LyxDai.address], @@ -961,7 +994,7 @@ describe('⛽📊 Gas Benchmark', () => { ) }); - it('transfer some LYXes to an EOA - restricted to 1 x allowed address only (TRANSFERVALUE + 1x AllowedCalls)', async () => { + it('transfer some LYXes to an EOA - restricted to 2 x allowed address only (TRANSFERVALUE + 2x AllowedCalls)', async () => { const lyxAmount = 10; const tx = await context.universalProfile @@ -970,9 +1003,32 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); casesExecuteRestrictedController.push([ - 'transfer some LYXes to an EOA - restricted to 1 x allowed address only (TRANSFERVALUE + 1x AllowedCalls)', + 'transfer some LYXes to an EOA - restricted to 2 x allowed address only (an EOA + a UP) (TRANSFERVALUE + 2x AllowedCalls)', receipt.gasUsed.toNumber().toString(), ]); + + gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_1'][ + 'restricted_controller' + ] = receipt.gasUsed.toNumber(); + }); + + it('transfer some LYXes to a UP - restricted to 2 x allowed address only (an EOA + a UP) (TRANSFERVALUE + 2x AllowedCalls)', async () => { + // ... + const lyxAmount = 10; + + const tx = await context.universalProfile + .connect(canTransferValueToOneAddress) + .execute(OPERATION_TYPES.CALL, aliceUP.address, lyxAmount, '0x'); + const receipt = await tx.wait(); + + casesExecuteRestrictedController.push([ + 'transfer some LYXes to a UP - restricted to 2 x allowed address only (an EOA + a UP) (TRANSFERVALUE + 2x AllowedCalls)', + receipt.gasUsed.toNumber().toString(), + ]); + + gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_2'][ + 'restricted_controller' + ] = receipt.gasUsed.toNumber(); }); it('transfers some tokens (LSP7) to an EOA - restricted to LSP7 + 2x allowed contracts only (CALL + 2x AllowedCalls) (no data)', async () => { @@ -997,6 +1053,10 @@ describe('⛽📊 Gas Benchmark', () => { 'transfers some tokens (LSP7) to an EOA - restricted to LSP7 + 2x allowed contracts only (CALL + 2x AllowedCalls) (no data)', receipt.gasUsed.toNumber().toString(), ]); + + gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_3'][ + 'restricted_controller' + ] = receipt.gasUsed.toNumber(); }); it('transfers some tokens (LSP7) to an other UP - restricted to LSP7 + 2x allowed contracts only (CALL + 2x AllowedCalls) (no data)', async () => { @@ -1021,6 +1081,10 @@ describe('⛽📊 Gas Benchmark', () => { 'transfers some tokens (LSP7) to an other UP - restricted to LSP7 + 2x allowed contracts only (CALL + 2x AllowedCalls) (no data)', receipt.gasUsed.toNumber().toString(), ]); + + gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_4'][ + 'restricted_controller' + ] = receipt.gasUsed.toNumber(); }); it('transfers a NFT (LSP8) to an EOA - restricted to LSP8 + 2x allowed contracts only (CALL + 2x AllowedCalls) (no data)', async () => { @@ -1045,6 +1109,10 @@ describe('⛽📊 Gas Benchmark', () => { 'transfers a NFT (LSP8) to an EOA - restricted to LSP8 + 2x allowed contracts only (CALL + 2x AllowedCalls) (no data)', receipt.gasUsed.toNumber().toString(), ]); + + gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_5'][ + 'restricted_controller' + ] = receipt.gasUsed.toNumber(); }); it('transfers a NFT (LSP8) to an other UP - restricted to LSP8 + 2x allowed contracts only (CALL + 2x AllowedCalls) (no data)', async () => { @@ -1069,16 +1137,10 @@ describe('⛽📊 Gas Benchmark', () => { 'transfers a NFT (LSP8) to an other UP - restricted to LSP8 + 2x allowed contracts only (CALL + 2x AllowedCalls) (no data)', receipt.gasUsed.toNumber().toString(), ]); - }); - after(async () => { - restrictedControllerExecuteTable = getMarkdownTable({ - table: { - head: ['`execute` scenarios - 🛃 restricted controller', '⛽ Gas Usage'], - body: casesExecuteRestrictedController, - }, - alignment: [Align.Left, Align.Center], - }); + gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_6'][ + 'restricted_controller' + ] = receipt.gasUsed.toNumber(); }); }); }); @@ -1086,8 +1148,7 @@ describe('⛽📊 Gas Benchmark', () => { describe('`setData(...)` via Key Manager', () => { let context: LSP6TestContext; - let controllerCanSetData: SignerWithAddress, - controllerCanSetDataAndAddController: SignerWithAddress; + let controllerToAddEditAndRemove: SignerWithAddress; const allowedERC725YDataKeys = [ ethers.utils.keccak256(ethers.utils.toUtf8Bytes('key1')), @@ -1102,45 +1163,38 @@ describe('⛽📊 Gas Benchmark', () => { ethers.utils.keccak256(ethers.utils.toUtf8Bytes('key10')), ]; + // Fictional scenario of a NFT Marketplace dApp + const nftMarketplaceDataKeys = [ + ethers.utils.keccak256(ethers.utils.toUtf8Bytes('NFT Marketplace dApp - settings')), + ethers.utils.keccak256(ethers.utils.toUtf8Bytes('NFT Marketplace dApp - followers')), + ethers.utils.keccak256(ethers.utils.toUtf8Bytes('NFT Marketplace dApp - rewards')), + ]; + before(async () => { context = await buildLSP6TestContext(); - controllerCanSetData = context.accounts[1]; - controllerCanSetDataAndAddController = context.accounts[2]; + controllerToAddEditAndRemove = context.accounts[1]; // prettier-ignore const permissionKeys = [ - ERC725YDataKeys.LSP6["AddressPermissions:Permissions"] + context.owner.address.substring(2), - ERC725YDataKeys.LSP6["AddressPermissions:Permissions"] + controllerCanSetData.address.substring(2), - ERC725YDataKeys.LSP6["AddressPermissions:AllowedERC725YDataKeys"] + controllerCanSetData.address.substring(2), - ERC725YDataKeys.LSP6["AddressPermissions:Permissions"] + controllerCanSetDataAndAddController.address.substring(2), - ERC725YDataKeys.LSP6["AddressPermissions:AllowedERC725YDataKeys"] + controllerCanSetDataAndAddController.address.substring(2), + ERC725YDataKeys.LSP3.LSP3Profile, ERC725YDataKeys.LSP6["AddressPermissions[]"].length, ERC725YDataKeys.LSP6["AddressPermissions[]"].index + "00000000000000000000000000000000", - ERC725YDataKeys.LSP6["AddressPermissions[]"].index + "00000000000000000000000000000001", - ERC725YDataKeys.LSP6["AddressPermissions[]"].index + "00000000000000000000000000000002", ]; - // // prettier-ignore const permissionValues = [ - ALL_PERMISSIONS, - PERMISSIONS.SETDATA, - encodeCompactBytesArray(allowedERC725YDataKeys), - combinePermissions(PERMISSIONS.SETDATA, PERMISSIONS.ADDCONTROLLER), - encodeCompactBytesArray(allowedERC725YDataKeys), + // Set some JSONURL for LSP3Profile metadata to test gas cost of updating your profile details + '0x6f357c6a70546a2accab18748420b63c63b5af4cf710848ae83afc0c51dd8ad17fb5e8b3697066733a2f2f516d65637247656a555156587057347a53393438704e76636e51724a314b69416f4d36626466725663575a736e35', ethers.utils.hexZeroPad(ethers.BigNumber.from(3).toHexString(), 16), context.owner.address, - controllerCanSetData.address, - controllerCanSetDataAndAddController.address, ]; + // The `context.owner` is given `ALL_PERMISSIONS` as the first data key through `setupKeyManager` method. await setupKeyManager(context, permissionKeys, permissionValues); }); describe('main controller (this browser extension) has SUPER_SETDATA ', () => { - const benchmarkCasesSetDataMainController: Row[] = []; - - it('updates profile details (LSP3Profile metadata)', async () => { + it('Update profile details (LSP3Profile metadata)', async () => { const dataKey = ERC725YDataKeys.LSP3['LSP3Profile']; const dataValue = '0x6f357c6a820464ddfac1bec070cc14a8daf04129871d458f2ca94368aae8391311af6361696670733a2f2f516d597231564a4c776572673670456f73636468564775676f3339706136727963455a4c6a7452504466573834554178'; @@ -1148,20 +1202,21 @@ describe('⛽📊 Gas Benchmark', () => { const tx = await context.universalProfile .connect(context.owner) .setData(dataKey, dataValue); + const receipt = await tx.wait(); - benchmarkCasesSetDataMainController.push([ - 'updates profile details (LSP3Profile metadata)', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['KeyManager_owner']['setData']['case_1'][ + 'main_controller' + ] = receipt.gasUsed.toNumber(); }); - it(`give permissions to a controller - 1. increase AddressPermissions[] array length - 2. put the controller address at AddressPermissions[index] - 3. give the controller the permission SETDATA under AddressPermissions:Permissions: + it(`Give permissions to a controller + 1. increase \`AddressPermissions[]\` array length + 2. put the controller address at \`AddressPermissions[index]\` + 3. give the controller the permission \`SETDATA\` under \`AddressPermissions:Permissions:\` + 4. allow the controller to set 3x specific ERC725Y data keys under \`AddressPermissions:AllowedERC725YDataKeys:\` `, async () => { - const newController = context.accounts[3]; + const newController = controllerToAddEditAndRemove; const AddressPermissionsArrayLength = await context.universalProfile['getData(bytes32)']( ERC725YDataKeys.LSP6['AddressPermissions[]'].length, @@ -1172,6 +1227,7 @@ describe('⛽📊 Gas Benchmark', () => { ERC725YDataKeys.LSP6["AddressPermissions[]"].length, ERC725YDataKeys.LSP6["AddressPermissions[]"].index + ethers.utils.hexZeroPad(ethers.utils.hexStripZeros(AddressPermissionsArrayLength), 16).substring(2), ERC725YDataKeys.LSP6["AddressPermissions:Permissions"] + newController.address.substring(2), + ERC725YDataKeys.LSP6["AddressPermissions:AllowedERC725YDataKeys"] + newController.address.substring(2), ]; // prettier-ignore @@ -1179,6 +1235,11 @@ describe('⛽📊 Gas Benchmark', () => { ethers.utils.hexZeroPad(ethers.BigNumber.from(AddressPermissionsArrayLength).add(1).toHexString(), 16), newController.address, combinePermissions(PERMISSIONS.SETDATA), + encodeCompactBytesArray([ + ERC725YDataKeys.LSP3.LSP3Profile, + ERC725YDataKeys.LSP12['LSP12IssuedAssets[]'].index, + ERC725YDataKeys.LSP12['LSP12IssuedAssetsMap'], + ]) ]; const tx = await context.universalProfile @@ -1189,60 +1250,19 @@ describe('⛽📊 Gas Benchmark', () => { expect(await context.universalProfile.getDataBatch(dataKeys)).to.deep.equal(dataValues); - benchmarkCasesSetDataMainController.push([ - 'give permissions to a controller (AddressPermissions[] + AddressPermissions[index] + AddressPermissions:Permissions:)', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['KeyManager_owner']['setData']['case_2'][ + 'main_controller' + ] = receipt.gasUsed.toNumber(); }); - it('restrict a controller to some specific ERC725Y Data Keys', async () => { - const controllerToEdit = context.accounts[3]; - - const allowedDataKeys = [ - ethers.utils.hexlify(ethers.utils.toUtf8Bytes('Allowed ERC725Y Data Key 1')), - ethers.utils.hexlify(ethers.utils.toUtf8Bytes('Allowed ERC725Y Data Key 2')), - ethers.utils.hexlify(ethers.utils.toUtf8Bytes('Allowed ERC725Y Data Key 3')), - ]; + it('Update permissions of previous controller. Allow it now to `SUPER_SETDATA`', async () => { + const controllerToEdit = controllerToAddEditAndRemove; - // prettier-ignore const dataKey = - ERC725YDataKeys.LSP6["AddressPermissions:AllowedERC725YDataKeys"] + controllerToEdit.address.substring(2) - - // prettier-ignore - const dataValue = encodeCompactBytesArray([allowedDataKeys[0], allowedDataKeys[1], allowedDataKeys[2]]) - - const tx = await context.universalProfile - .connect(context.owner) - .setData(dataKey, dataValue); - - const receipt = await tx.wait(); - - expect(await context.universalProfile.getData(dataKey)).to.equal(dataValue); - - benchmarkCasesSetDataMainController.push([ - 'restrict a controller to some specific ERC725Y Data Keys', - receipt.gasUsed.toNumber().toString(), - ]); - }); - - it('restrict a controller to interact only with 3x specific addresses', async () => { - const controllerToEdit = context.accounts[3]; - - const allowedAddresses = [ - context.accounts[4].address, - context.accounts[5].address, - context.accounts[6].address, - ]; - - // prettier-ignore - const dataKey = ERC725YDataKeys.LSP6["AddressPermissions:AllowedCalls"] + controllerToEdit.address.substring(2) + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + controllerToEdit.address.substring(2); - const dataValue = combineAllowedCalls( - [CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL], - [allowedAddresses[0], allowedAddresses[1], allowedAddresses[2]], - ['0xffffffff', '0xffffffff', '0xffffffff'], - ['0xffffffff', '0xffffffff', '0xffffffff'], - ); + const dataValue = combinePermissions(PERMISSIONS.SETDATA, PERMISSIONS.SUPER_SETDATA); const tx = await context.universalProfile .connect(context.owner) @@ -1252,18 +1272,18 @@ describe('⛽📊 Gas Benchmark', () => { expect(await context.universalProfile.getData(dataKey)).to.equal(dataValue); - benchmarkCasesSetDataMainController.push([ - 'restrict a controller to interact only with 3x specific addresses', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['KeyManager_owner']['setData']['case_3'][ + 'main_controller' + ] = receipt.gasUsed.toNumber(); }); - it(`remove a controller (its permissions + its address from the AddressPermissions[] array) - 1. decrease AddressPermissions[] array length - 2. remove the controller address at AddressPermissions[index] - 3. set "0x" for the controller permissions under AddressPermissions:Permissions: + it(`Remove a controller + 1. decrease \`AddressPermissions[]\` array length + 2. remove the controller address at \`AddressPermissions[index]\` + 3. set \`0x\` for the controller permissions under \`AddressPermissions:Permissions:\` + 4. remove the Allowed ERC725Y Data Keys previously set for the controller under \`AddressPermissions:AllowedERC725YDataKeys:\` `, async () => { - const newController = context.accounts[3]; + const newController = controllerToAddEditAndRemove; const AddressPermissionsArrayLength = await context.universalProfile['getData(bytes32)']( ERC725YDataKeys.LSP6['AddressPermissions[]'].length, @@ -1274,6 +1294,7 @@ describe('⛽📊 Gas Benchmark', () => { ERC725YDataKeys.LSP6["AddressPermissions[]"].length, ERC725YDataKeys.LSP6["AddressPermissions[]"].index + ethers.utils.hexZeroPad(ethers.utils.hexStripZeros(AddressPermissionsArrayLength), 16).substring(2), ERC725YDataKeys.LSP6["AddressPermissions:Permissions"] + newController.address.substring(2), + ERC725YDataKeys.LSP6["AddressPermissions:AllowedERC725YDataKeys"] + newController.address.substring(2), ]; // prettier-ignore @@ -1281,6 +1302,7 @@ describe('⛽📊 Gas Benchmark', () => { ethers.utils.hexZeroPad(ethers.BigNumber.from(AddressPermissionsArrayLength).sub(1).toHexString(), 16), "0x", "0x", + "0x", ]; const tx = await context.universalProfile @@ -1289,13 +1311,12 @@ describe('⛽📊 Gas Benchmark', () => { const receipt = await tx.wait(); - benchmarkCasesSetDataMainController.push([ - 'remove a controller (its permissions + its address from the AddressPermissions[] array)', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['KeyManager_owner']['setData']['case_4'][ + 'main_controller' + ] = receipt.gasUsed.toNumber(); }); - it('write 5x LSP12 Issued Assets', async () => { + it('Write 5x new LSP12 Issued Assets', async () => { // prettier-ignore const issuedAssetsDataKeys = [ ERC725YDataKeys.LSP12["LSP12IssuedAssets[]"].length, @@ -1327,196 +1348,492 @@ describe('⛽📊 Gas Benchmark', () => { issuedAssetsDataValues, ); - benchmarkCasesSetDataMainController.push([ - 'write 5x LSP12 Issued Assets', - receipt.gasUsed.toNumber().toString(), - ]); - }); - - after(async () => { - mainControllerSetDataTable = getMarkdownTable({ - table: { - head: ['`setData` scenarios - 👑 main controller', '⛽ Gas Usage'], - body: benchmarkCasesSetDataMainController, - }, - alignment: [Align.Left, Align.Center], - }); + gasBenchmark['runtime_costs']['KeyManager_owner']['setData']['case_5'][ + 'main_controller' + ] = receipt.gasUsed.toNumber(); }); - }); - describe('a controller (EOA) can SETDATA, ADDCONTROLLER and on 10x AllowedERC725YKeys', () => { - const benchmarkCasesSetDataRestrictedController: Row[] = []; - - it('`setData(bytes32,bytes)` -> updates 1x data key', async () => { + it('Updates 1x data key', async () => { const dataKey = allowedERC725YDataKeys[5]; const dataValue = '0xaabbccdd'; const tx = await context.universalProfile - .connect(controllerCanSetData) + .connect(context.owner) .setData(dataKey, dataValue); + const receipt = await tx.wait(); - benchmarkCasesSetDataRestrictedController.push([ - '`setData(bytes32,bytes)` -> updates 1x data key', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['KeyManager_owner']['setData']['case_5'][ + 'main_controller' + ] = receipt.gasUsed.toNumber(); }); - it('`setData(bytes32[],bytes[])` -> updates 3x data keys (first x3)', async () => { + it('Updates 3x data keys (first x3)', async () => { const dataKeys = allowedERC725YDataKeys.slice(0, 3); const dataValues = ['0xaabbccdd', '0xaabbccdd', '0xaabbccdd']; const tx = await context.universalProfile - .connect(controllerCanSetData) + .connect(context.owner) .setDataBatch(dataKeys, dataValues); + const receipt = await tx.wait(); - benchmarkCasesSetDataRestrictedController.push([ - '`setData(bytes32[],bytes[])` -> updates 3x data keys (first x3)', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['KeyManager_owner']['setData']['case_6'][ + 'main_controller' + ] = receipt.gasUsed.toNumber(); }); - it('`setData(bytes32[],bytes[])` -> updates 3x data keys (middle x3)', async () => { + it('Update 3x data keys (middle x3)', async () => { const dataKeys = allowedERC725YDataKeys.slice(3, 6); const dataValues = ['0xaabbccdd', '0xaabbccdd', '0xaabbccdd']; const tx = await context.universalProfile - .connect(controllerCanSetData) + .connect(context.owner) .setDataBatch(dataKeys, dataValues); + const receipt = await tx.wait(); - benchmarkCasesSetDataRestrictedController.push([ - '`setData(bytes32[],bytes[])` -> updates 3x data keys (middle x3)', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['KeyManager_owner']['setData']['case_7'][ + 'main_controller' + ] = receipt.gasUsed.toNumber(); }); - it('`setData(bytes32[],bytes[])` -> updates 3x data keys (last x3)', async () => { + it('Update 3x data keys (last x3)', async () => { const dataKeys = allowedERC725YDataKeys.slice(7, 10); const dataValues = ['0xaabbccdd', '0xaabbccdd', '0xaabbccdd']; const tx = await context.universalProfile - .connect(controllerCanSetData) + .connect(context.owner) .setDataBatch(dataKeys, dataValues); + const receipt = await tx.wait(); - benchmarkCasesSetDataRestrictedController.push([ - '`setData(bytes32[],bytes[])` -> updates 3x data keys (last x3)', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['KeyManager_owner']['setData']['case_8'][ + 'main_controller' + ] = receipt.gasUsed.toNumber(); }); - it('`setData(bytes32[],bytes[])` -> updates 2x data keys + add 3x new controllers (including setting the array length + indexes under AddressPermissions[index])', async () => { + it('Set 2x data keys + add 3x new controllers (including setting the array length + indexes under AddressPermissions[index]) - 12 data keys in total', async () => { + const addressPermissionsArrayLength = ethers.BigNumber.from( + await context.universalProfile.getData( + ERC725YDataKeys.LSP6['AddressPermissions[]'].length, + ), + ).toNumber(); + + const newArrayLengthUint128Hex = ethers.utils.hexZeroPad( + ethers.BigNumber.from(addressPermissionsArrayLength).add(3).toHexString(), + 16, + ); + + // example of a dApp that set some logic + const compactBytesArrayAllowedERC725YDataKeys = encodeCompactBytesArray([ + ...nftMarketplaceDataKeys, + ERC725YDataKeys.LSP12['LSP12IssuedAssets[]'].index, + ERC725YDataKeys.LSP12['LSP12IssuedAssetsMap'], + ]); + const dataKeys = [ - allowedERC725YDataKeys[0], - allowedERC725YDataKeys[1], + nftMarketplaceDataKeys[0], // set the settings and followers to 0 to start (rewards are set later) + nftMarketplaceDataKeys[1], + ERC725YDataKeys.LSP6['AddressPermissions[]'].length, + ERC725YDataKeys.LSP6['AddressPermissions[]'].index + + `0000000000000000000000000000000${addressPermissionsArrayLength}`, + ERC725YDataKeys.LSP6['AddressPermissions[]'].index + + `0000000000000000000000000000000${addressPermissionsArrayLength + 1}`, + ERC725YDataKeys.LSP6['AddressPermissions[]'].index + + `0000000000000000000000000000000${addressPermissionsArrayLength + 2}`, ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.accounts[3].address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.accounts[4].address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.accounts[5].address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + context.accounts[3].address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + context.accounts[4].address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + context.accounts[5].address.substring(2), ]; const dataValues = [ - '0xaabbccdd', - '0xaabbccdd', + // user settings + ethers.utils.hexlify(ethers.utils.toUtf8Bytes('Some default user settings to start')), + // followers count starts at 0 + abiCoder.encode(['uint256'], [0]), + newArrayLengthUint128Hex, + context.accounts[3].address, + context.accounts[4].address, + context.accounts[5].address, PERMISSIONS.SETDATA, PERMISSIONS.SETDATA, PERMISSIONS.SETDATA, + compactBytesArrayAllowedERC725YDataKeys, + compactBytesArrayAllowedERC725YDataKeys, + compactBytesArrayAllowedERC725YDataKeys, ]; const tx = await context.universalProfile - .connect(controllerCanSetDataAndAddController) + .connect(context.owner) .setDataBatch(dataKeys, dataValues); + const receipt = await tx.wait(); - benchmarkCasesSetDataRestrictedController.push([ - '`setData(bytes32[],bytes[])` -> updates 2x data keys + add 3x new controllers (including setting the array length + indexes under AddressPermissions[index])', - receipt.gasUsed.toNumber().toString(), - ]); + gasBenchmark['runtime_costs']['KeyManager_owner']['setData']['case_9'][ + 'main_controller' + ] = receipt.gasUsed.toNumber(); }); + }); - after(async () => { - restrictedControllerSetDataTable = getMarkdownTable({ - table: { - head: ['`setData` scenarios - 🛃 restricted controller', '⛽ Gas Usage'], - body: benchmarkCasesSetDataRestrictedController, - }, - alignment: [Align.Left, Align.Center], - }); + describe('restricted controllers', () => { + let controllercanSetTwoDataKeys: SignerWithAddress, + controllerCanAddControllers: SignerWithAddress, + controllerCanEditPermissions: SignerWithAddress, + controllerCanSetTenDataKeys: SignerWithAddress, + controllerCanSetDataAndAddControllers: SignerWithAddress; + + before(async () => { + context = await buildLSP6TestContext(); + + controllercanSetTwoDataKeys = context.accounts[1]; + controllerCanAddControllers = context.accounts[2]; + controllerCanEditPermissions = context.accounts[3]; + controllerCanSetTenDataKeys = context.accounts[4]; + controllerCanSetDataAndAddControllers = context.accounts[5]; + + controllerToAddEditAndRemove = context.accounts[6]; + + // prettier-ignore + const permissionKeys = [ + ERC725YDataKeys.LSP3.LSP3Profile, + ERC725YDataKeys.LSP6["AddressPermissions[]"].length, + ERC725YDataKeys.LSP6["AddressPermissions[]"].index + "00000000000000000000000000000000", + ERC725YDataKeys.LSP6["AddressPermissions:Permissions"] + controllercanSetTwoDataKeys.address.substring(2), + ERC725YDataKeys.LSP6["AddressPermissions:AllowedERC725YDataKeys"] + controllercanSetTwoDataKeys.address.substring(2), + ERC725YDataKeys.LSP6["AddressPermissions:Permissions"] + controllerCanAddControllers.address.substring(2), + ERC725YDataKeys.LSP6["AddressPermissions:Permissions"] + controllerCanEditPermissions.address.substring(2), + ERC725YDataKeys.LSP6["AddressPermissions:Permissions"] + controllerCanSetTenDataKeys.address.substring(2), + ERC725YDataKeys.LSP6["AddressPermissions:AllowedERC725YDataKeys"] + controllerCanSetTenDataKeys.address.substring(2), + ERC725YDataKeys.LSP6["AddressPermissions:Permissions"] + controllerCanSetDataAndAddControllers.address.substring(2), + ERC725YDataKeys.LSP6["AddressPermissions:AllowedERC725YDataKeys"] + controllerCanSetDataAndAddControllers.address.substring(2), + ]; + + const permissionValues = [ + // Set some JSONURL for LSP3Profile metadata to test gas cost of updating your profile details + '0x6f357c6a70546a2accab18748420b63c63b5af4cf710848ae83afc0c51dd8ad17fb5e8b3697066733a2f2f516d65637247656a555156587057347a53393438704e76636e51724a314b69416f4d36626466725663575a736e35', + ethers.utils.hexZeroPad(ethers.BigNumber.from(6).toHexString(), 16), + context.owner.address, + PERMISSIONS.SETDATA, + encodeCompactBytesArray([ + ERC725YDataKeys.LSP3.LSP3Profile, + ERC725YDataKeys.LSP12['LSP12IssuedAssets[]'].index, + ]), + PERMISSIONS.ADDCONTROLLER, + PERMISSIONS.EDITPERMISSIONS, + PERMISSIONS.SETDATA, + encodeCompactBytesArray(allowedERC725YDataKeys), + combinePermissions(PERMISSIONS.SETDATA, PERMISSIONS.ADDCONTROLLER), + encodeCompactBytesArray([ + ...nftMarketplaceDataKeys, + ERC725YDataKeys.LSP3.LSP3Profile, + ERC725YDataKeys.LSP12['LSP12IssuedAssets[]'].index, + ]), + ]; + + // The `context.owner` is given `ALL_PERMISSIONS` as the first data key through `setupKeyManager` method. + await setupKeyManager(context, permissionKeys, permissionValues); }); - }); - }); - }); - after(async () => { - const markdown = ` -👋 Hello -⛽ I am the Gas Bot Reporter. I keep track of the gas costs of common interactions using Universal Profiles 🆙 ! -📊 Here is a summary of the gas cost with the code introduced by this PR. + it('Update profile details (LSP3Profile metadata)', async () => { + const dataKey = ERC725YDataKeys.LSP3['LSP3Profile']; + const dataValue = + '0x6f357c6a820464ddfac1bec070cc14a8daf04129871d458f2ca94368aae8391311af6361696670733a2f2f516d597231564a4c776572673670456f73636468564775676f3339706136727963455a4c6a7452504466573834554178'; + + const tx = await context.universalProfile + .connect(controllercanSetTwoDataKeys) + .setData(dataKey, dataValue); + + const receipt = await tx.wait(); + + gasBenchmark['runtime_costs']['KeyManager_owner']['setData']['case_1'][ + 'restricted_controller' + ] = receipt.gasUsed.toNumber(); + }); + + it(`Give permissions to a controller + 1. increase \`AddressPermissions[]\` array length + 2. put the controller address at \`AddressPermissions[index]\` + 3. give the controller the permission \`SETDATA\` under \`AddressPermissions:Permissions:\` + 4. allow the controller to set 3x specific ERC725Y data keys under \`AddressPermissions:AllowedERC725YDataKeys:\` + `, async () => { + const newController = controllerToAddEditAndRemove; + + const AddressPermissionsArrayLength = await context.universalProfile['getData(bytes32)']( + ERC725YDataKeys.LSP6['AddressPermissions[]'].length, + ); + + // prettier-ignore + const dataKeys = [ + ERC725YDataKeys.LSP6["AddressPermissions[]"].length, + ERC725YDataKeys.LSP6["AddressPermissions[]"].index + ethers.utils.hexZeroPad(ethers.utils.hexStripZeros(AddressPermissionsArrayLength), 16).substring(2), + ERC725YDataKeys.LSP6["AddressPermissions:Permissions"] + newController.address.substring(2), + ERC725YDataKeys.LSP6["AddressPermissions:AllowedERC725YDataKeys"] + newController.address.substring(2), + ]; + + // prettier-ignore + const dataValues = [ + ethers.utils.hexZeroPad(ethers.BigNumber.from(AddressPermissionsArrayLength).add(1).toHexString(), 16), + newController.address, + combinePermissions(PERMISSIONS.SETDATA), + encodeCompactBytesArray([ + ERC725YDataKeys.LSP3.LSP3Profile, + ERC725YDataKeys.LSP12['LSP12IssuedAssets[]'].index, + ERC725YDataKeys.LSP12['LSP12IssuedAssetsMap'], + ]) + ]; + + const tx = await context.universalProfile + .connect(controllerCanAddControllers) + .setDataBatch(dataKeys, dataValues); + + const receipt = await tx.wait(); + + expect(await context.universalProfile.getDataBatch(dataKeys)).to.deep.equal(dataValues); + + gasBenchmark['runtime_costs']['KeyManager_owner']['setData']['case_2'][ + 'restricted_controller' + ] = receipt.gasUsed.toNumber(); + }); + + it('Update permissions of previous controller. Allow it now to `SUPER_SETDATA`', async () => { + const controllerToEdit = controllerToAddEditAndRemove; + + const dataKey = + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + controllerToEdit.address.substring(2); + + const dataValue = combinePermissions(PERMISSIONS.SETDATA, PERMISSIONS.SUPER_SETDATA); + + const tx = await context.universalProfile + .connect(controllerCanEditPermissions) + .setData(dataKey, dataValue); + + const receipt = await tx.wait(); + + expect(await context.universalProfile.getData(dataKey)).to.equal(dataValue); + + gasBenchmark['runtime_costs']['KeyManager_owner']['setData']['case_3'][ + 'restricted_controller' + ] = receipt.gasUsed.toNumber(); + }); + + it(`Remove a controller + 1. decrease \`AddressPermissions[]\` array length + 2. remove the controller address at \`AddressPermissions[index]\` + 3. set \`0x\` for the controller permissions under \`AddressPermissions:Permissions:\` + 4. remove the Allowed ERC725Y Data Keys previously set for the controller under \`AddressPermissions:AllowedERC725YDataKeys:\` + `, async () => { + const newController = controllerToAddEditAndRemove; -
-⛽📊 See Gas Benchmark report of Using UniversalProfile owned by an EOA + const AddressPermissionsArrayLength = await context.universalProfile['getData(bytes32)']( + ERC725YDataKeys.LSP6['AddressPermissions[]'].length, + ); -### 🔀 \`execute\` scenarios + // prettier-ignore + const dataKeys = [ + ERC725YDataKeys.LSP6["AddressPermissions[]"].length, + ERC725YDataKeys.LSP6["AddressPermissions[]"].index + ethers.utils.hexZeroPad(ethers.BigNumber.from(AddressPermissionsArrayLength).sub(1), 16).substring(2), + ERC725YDataKeys.LSP6["AddressPermissions:Permissions"] + newController.address.substring(2), + ERC725YDataKeys.LSP6["AddressPermissions:AllowedERC725YDataKeys"] + newController.address.substring(2), + ]; -${UniversalProfileExecuteTable} + // prettier-ignore + const dataValues = [ + ethers.utils.hexZeroPad(ethers.BigNumber.from(AddressPermissionsArrayLength).sub(1).toHexString(), 16), + "0x", + "0x", + "0x", + ]; -### 🗄️ \`setData\` scenarios + const tx = await context.universalProfile + .connect(controllerCanEditPermissions) + .setDataBatch(dataKeys, dataValues); -${UniversalProfileSetDataTable} + const receipt = await tx.wait(); -### 🗄️ \`Tokens\` scenarios + gasBenchmark['runtime_costs']['KeyManager_owner']['setData']['case_4'][ + 'restricted_controller' + ] = receipt.gasUsed.toNumber(); + }); -${UniversalProfileTokensTable} + it('Write 5x new LSP12 Issued Assets', async () => { + // prettier-ignore + const issuedAssetsDataKeys = [ + ERC725YDataKeys.LSP12["LSP12IssuedAssets[]"].length, + ERC725YDataKeys.LSP12["LSP12IssuedAssets[]"].index + "00000000000000000000000000000000", + ERC725YDataKeys.LSP12["LSP12IssuedAssets[]"].index + "00000000000000000000000000000001", + ERC725YDataKeys.LSP12["LSP12IssuedAssets[]"].index + "00000000000000000000000000000002", + ERC725YDataKeys.LSP12["LSP12IssuedAssets[]"].index + "00000000000000000000000000000003", + ERC725YDataKeys.LSP12["LSP12IssuedAssets[]"].index + "00000000000000000000000000000004", + ]; + // these are just random placeholder values + // they should be replaced with actual token contract address + const issuedAssetsDataValues = [ + '0x0000000000000000000000000000000000000000000000000000000000000005', + context.accounts[5].address, + context.accounts[6].address, + context.accounts[7].address, + context.accounts[8].address, + context.accounts[9].address, + ]; + const tx = await context.universalProfile + .connect(controllercanSetTwoDataKeys) + .setDataBatch(issuedAssetsDataKeys, issuedAssetsDataValues); -## 📝 Notes + const receipt = await tx.wait(); -- The \`execute\` and \`setData\` scenarios are executed on a fresh UniversalProfile smart contract, deployed as standard contracts (not as proxy behind a base contract implementation). + expect(await context.universalProfile.getDataBatch(issuedAssetsDataKeys)).to.deep.equal( + issuedAssetsDataValues, + ); + gasBenchmark['runtime_costs']['KeyManager_owner']['setData']['case_5'][ + 'restricted_controller' + ] = receipt.gasUsed.toNumber(); + }); -
+ it('Updates 1x data key', async () => { + const dataKey = allowedERC725YDataKeys[5]; + const dataValue = '0xaabbccdd'; + const tx = await context.universalProfile + .connect(controllerCanSetTenDataKeys) + .setData(dataKey, dataValue); -
-⛽📊 See Gas Benchmark report of Using UniversalProfile owned by an LSP6KeyManager + const receipt = await tx.wait(); -This document contains the gas usage for common interactions and scenarios when using UniversalProfile smart contracts. + gasBenchmark['runtime_costs']['KeyManager_owner']['setData']['case_5'][ + 'restricted_controller' + ] = receipt.gasUsed.toNumber(); + }); -### 🔀 \`execute\` scenarios + it('Updates 3x data keys (first x3)', async () => { + const dataKeys = allowedERC725YDataKeys.slice(0, 3); + const dataValues = ['0xaabbccdd', '0xaabbccdd', '0xaabbccdd']; -#### 👑 unrestricted controller + const tx = await context.universalProfile + .connect(controllerCanSetTenDataKeys) + .setDataBatch(dataKeys, dataValues); -${mainControllerExecuteTable} + const receipt = await tx.wait(); -#### 🛃 restricted controller + gasBenchmark['runtime_costs']['KeyManager_owner']['setData']['case_6'][ + 'restricted_controller' + ] = receipt.gasUsed.toNumber(); + }); -${restrictedControllerExecuteTable} + it('Update 3x data keys (middle x3)', async () => { + const dataKeys = allowedERC725YDataKeys.slice(3, 6); + const dataValues = ['0xaabbccdd', '0xaabbccdd', '0xaabbccdd']; -### 🗄️ \`setData\` scenarios + const tx = await context.universalProfile + .connect(controllerCanSetTenDataKeys) + .setDataBatch(dataKeys, dataValues); -#### 👑 unrestricted controller + const receipt = await tx.wait(); -${mainControllerSetDataTable} + gasBenchmark['runtime_costs']['KeyManager_owner']['setData']['case_7'][ + 'restricted_controller' + ] = receipt.gasUsed.toNumber(); + }); -#### 🛃 restricted controller + it('Update 3x data keys (last x3)', async () => { + const dataKeys = allowedERC725YDataKeys.slice(7, 10); + const dataValues = ['0xaabbccdd', '0xaabbccdd', '0xaabbccdd']; -${restrictedControllerSetDataTable} + const tx = await context.universalProfile + .connect(controllerCanSetTenDataKeys) + .setDataBatch(dataKeys, dataValues); + const receipt = await tx.wait(); -## 📝 Notes + gasBenchmark['runtime_costs']['KeyManager_owner']['setData']['case_8'][ + 'restricted_controller' + ] = receipt.gasUsed.toNumber(); + }); -- The \`execute\` and \`setData\` scenarios are executed on a fresh UniversalProfile and LSP6KeyManager smart contracts, deployed as standard contracts (not as proxy behind a base contract implementation). + it('Set 2x data keys + add 3x new controllers (including setting the array length + indexes under AddressPermissions[index]) - 12 data keys in total', async () => { + const addressPermissionsArrayLength = ethers.BigNumber.from( + await context.universalProfile.getData( + ERC725YDataKeys.LSP6['AddressPermissions[]'].length, + ), + ).toNumber(); + const newArrayLengthUint128Hex = ethers.utils.hexZeroPad( + ethers.BigNumber.from(addressPermissionsArrayLength).add(3).toHexString(), + 16, + ); -
-`; - const file = 'benchmark.md'; + // example of a dApp that set some logic + const compactBytesArrayAllowedERC725YDataKeys = encodeCompactBytesArray([ + ...nftMarketplaceDataKeys, + ERC725YDataKeys.LSP12['LSP12IssuedAssets[]'].index, + ERC725YDataKeys.LSP12['LSP12IssuedAssetsMap'], + ]); - fs.writeFileSync(file, markdown); + const dataKeys = [ + nftMarketplaceDataKeys[0], // set the settings and followers to 0 to start (rewards are set later) + nftMarketplaceDataKeys[1], + ERC725YDataKeys.LSP6['AddressPermissions[]'].length, + ERC725YDataKeys.LSP6['AddressPermissions[]'].index + + `0000000000000000000000000000000${addressPermissionsArrayLength}`, + ERC725YDataKeys.LSP6['AddressPermissions[]'].index + + `0000000000000000000000000000000${addressPermissionsArrayLength + 1}`, + ERC725YDataKeys.LSP6['AddressPermissions[]'].index + + `0000000000000000000000000000000${addressPermissionsArrayLength + 2}`, + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.accounts[7].address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.accounts[8].address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.accounts[9].address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + context.accounts[7].address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + context.accounts[8].address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + context.accounts[9].address.substring(2), + ]; + + const dataValues = [ + // user settings + ethers.utils.hexlify(ethers.utils.toUtf8Bytes('Some default user settings to start')), + // followers count starts at 0 + abiCoder.encode(['uint256'], [0]), + newArrayLengthUint128Hex, + context.accounts[7].address, + context.accounts[8].address, + context.accounts[9].address, + PERMISSIONS.SETDATA, + PERMISSIONS.SETDATA, + PERMISSIONS.SETDATA, + compactBytesArrayAllowedERC725YDataKeys, + compactBytesArrayAllowedERC725YDataKeys, + compactBytesArrayAllowedERC725YDataKeys, + ]; + + const tx = await context.universalProfile + .connect(controllerCanSetDataAndAddControllers) + .setDataBatch(dataKeys, dataValues); + + const receipt = await tx.wait(); + + gasBenchmark['runtime_costs']['KeyManager_owner']['setData']['case_9'][ + 'restricted_controller' + ] = receipt.gasUsed.toNumber(); + }); + }); + }); }); }); From a977312f99a3f957e581f5b502ef818f033f3846 Mon Sep 17 00:00:00 2001 From: Johann BICH <2253470+kalote@users.noreply.github.com> Date: Mon, 2 Oct 2023 11:24:19 +0200 Subject: [PATCH 33/55] fix: ts configs and tests (#733) * fix ts config and types on tests * lint * test: fix Typescript errors in `Benchmark.test.ts` * docs: update auto-generated docs --------- Co-authored-by: CJ42 --- tests/Benchmark.test.ts | 73 ++----------------- .../LSP14Ownable2Step.behaviour.ts | 8 ++ ...P1UniversalReceiverDelegateUP.behaviour.ts | 4 +- .../LSP20WithLSP14.behaviour.ts | 8 ++ .../LSP6/Interactions/Security.test.ts | 2 + .../LSP23LinkedContractsDeployment.test.ts | 49 +++++++------ .../LSP23LinkedContractsDeployment/helpers.ts | 17 +++-- .../PermissionTransferValue.test.ts | 30 +++++--- .../PermissionChangeAddController.test.ts | 16 ++-- .../LSP8CompatibleERC721.behaviour.ts | 1 + .../LSP8IdentifiableDigitalAsset.behaviour.ts | 2 +- tests/Reentrancy/LSP6/LSP6Reentrancy.test.ts | 20 +++-- ...gleExecuteRelayCallToSingleExecute.test.ts | 45 ++---------- ...eRelayCallToSingleExecuteRelayCall.test.ts | 43 ++--------- tests/Reentrancy/LSP6/reentrancyHelpers.ts | 14 ++-- tsconfig.json | 10 +-- tsconfig.module.json | 1 - 17 files changed, 126 insertions(+), 217 deletions(-) diff --git a/tests/Benchmark.test.ts b/tests/Benchmark.test.ts index aff0d2a1b..03ad2700f 100644 --- a/tests/Benchmark.test.ts +++ b/tests/Benchmark.test.ts @@ -546,12 +546,12 @@ describe('⛽📊 Gas Benchmark', () => { false, ); - // deploy a LSP8 NFT + // deploy a LSP8 token lsp8Token = await new LSP8Mintable__factory(context.owner).deploy( 'My NFT', 'MNFT', context.owner.address, - LSP8_TOKEN_ID_TYPES.NUMBER, + LSP8_TOKEN_ID_TYPES.UNIQUE_ID, ); universalProfile1 = await new UniversalProfile__factory(context.owner).deploy( @@ -654,8 +654,6 @@ describe('⛽📊 Gas Benchmark', () => { describe('KeyManager', () => { describe('`execute(...)` via Key Manager', () => { describe('main controller (this browser extension)', () => { - const casesExecuteMainController: Row[] = []; - let context: LSP6TestContext; let recipientEOA: SignerWithAddress; @@ -705,7 +703,7 @@ describe('⛽📊 Gas Benchmark', () => { 'MetaNFT', 'MNF', context.owner.address, - LSP8_TOKEN_ID_TYPES.NUMBER, + LSP8_TOKEN_ID_TYPES.UNIQUE_ID, ); // mint some tokens to the UP @@ -724,11 +722,6 @@ describe('⛽📊 Gas Benchmark', () => { const tx = await context.universalProfile.connect(context.owner).execute(OPERATION_TYPES.CALL, recipientEOA.address, lyxAmount, "0x"); const receipt = await tx.wait(); - casesExecuteMainController.push([ - 'transfer LYX to an EOA', - receipt.gasUsed.toNumber().toString(), - ]); - gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_1'][ 'main_controller' ] = receipt.gasUsed.toNumber(); @@ -741,11 +734,6 @@ describe('⛽📊 Gas Benchmark', () => { const tx = await context.universalProfile.connect(context.owner).execute(OPERATION_TYPES.CALL, aliceUP.address, lyxAmount, "0x"); const receipt = await tx.wait(); - casesExecuteMainController.push([ - 'transfer LYX to a UP', - receipt.gasUsed.toNumber().toString(), - ]); - gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_2'][ 'main_controller' ] = receipt.gasUsed.toNumber(); @@ -769,11 +757,6 @@ describe('⛽📊 Gas Benchmark', () => { ); const receipt = await tx.wait(); - casesExecuteMainController.push([ - 'transfer tokens (LSP7) to an EOA (no data)', - receipt.gasUsed.toNumber().toString(), - ]); - gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_3'][ 'main_controller' ] = receipt.gasUsed.toNumber(); @@ -797,11 +780,6 @@ describe('⛽📊 Gas Benchmark', () => { ); const receipt = await tx.wait(); - casesExecuteMainController.push([ - 'transfer tokens (LSP7) to a UP (no data)', - receipt.gasUsed.toNumber().toString(), - ]); - gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_4'][ 'main_controller' ] = receipt.gasUsed.toNumber(); @@ -825,11 +803,6 @@ describe('⛽📊 Gas Benchmark', () => { ); const receipt = await tx.wait(); - casesExecuteMainController.push([ - 'transfer a NFT (LSP8) to a EOA (no data)', - receipt.gasUsed.toNumber().toString(), - ]); - gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_5'][ 'main_controller' ] = receipt.gasUsed.toNumber(); @@ -853,11 +826,6 @@ describe('⛽📊 Gas Benchmark', () => { ); const receipt = await tx.wait(); - casesExecuteMainController.push([ - 'transfer a NFT (LSP8) to a UP (no data)', - receipt.gasUsed.toNumber().toString(), - ]); - gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_6'][ 'main_controller' ] = receipt.gasUsed.toNumber(); @@ -865,7 +833,6 @@ describe('⛽📊 Gas Benchmark', () => { }); describe('controllers with some restrictions', () => { - const casesExecuteRestrictedController: Row[] = []; let context: LSP6TestContext; let recipientEOA: SignerWithAddress; @@ -936,7 +903,7 @@ describe('⛽📊 Gas Benchmark', () => { 'MetaNFT', 'MNF', context.owner.address, - LSP8_TOKEN_ID_TYPES.NUMBER, + LSP8_TOKEN_ID_TYPES.UNIQUE_ID, ); lsp8LyxPunks = await new LSP8Mintable__factory(context.owner).deploy( @@ -1002,11 +969,6 @@ describe('⛽📊 Gas Benchmark', () => { .execute(OPERATION_TYPES.CALL, allowedAddressToTransferValue, lyxAmount, '0x'); const receipt = await tx.wait(); - casesExecuteRestrictedController.push([ - 'transfer some LYXes to an EOA - restricted to 2 x allowed address only (an EOA + a UP) (TRANSFERVALUE + 2x AllowedCalls)', - receipt.gasUsed.toNumber().toString(), - ]); - gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_1'][ 'restricted_controller' ] = receipt.gasUsed.toNumber(); @@ -1021,11 +983,6 @@ describe('⛽📊 Gas Benchmark', () => { .execute(OPERATION_TYPES.CALL, aliceUP.address, lyxAmount, '0x'); const receipt = await tx.wait(); - casesExecuteRestrictedController.push([ - 'transfer some LYXes to a UP - restricted to 2 x allowed address only (an EOA + a UP) (TRANSFERVALUE + 2x AllowedCalls)', - receipt.gasUsed.toNumber().toString(), - ]); - gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_2'][ 'restricted_controller' ] = receipt.gasUsed.toNumber(); @@ -1049,11 +1006,6 @@ describe('⛽📊 Gas Benchmark', () => { ); const receipt = await tx.wait(); - casesExecuteRestrictedController.push([ - 'transfers some tokens (LSP7) to an EOA - restricted to LSP7 + 2x allowed contracts only (CALL + 2x AllowedCalls) (no data)', - receipt.gasUsed.toNumber().toString(), - ]); - gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_3'][ 'restricted_controller' ] = receipt.gasUsed.toNumber(); @@ -1077,11 +1029,6 @@ describe('⛽📊 Gas Benchmark', () => { ); const receipt = await tx.wait(); - casesExecuteRestrictedController.push([ - 'transfers some tokens (LSP7) to an other UP - restricted to LSP7 + 2x allowed contracts only (CALL + 2x AllowedCalls) (no data)', - receipt.gasUsed.toNumber().toString(), - ]); - gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_4'][ 'restricted_controller' ] = receipt.gasUsed.toNumber(); @@ -1105,11 +1052,6 @@ describe('⛽📊 Gas Benchmark', () => { ); const receipt = await tx.wait(); - casesExecuteRestrictedController.push([ - 'transfers a NFT (LSP8) to an EOA - restricted to LSP8 + 2x allowed contracts only (CALL + 2x AllowedCalls) (no data)', - receipt.gasUsed.toNumber().toString(), - ]); - gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_5'][ 'restricted_controller' ] = receipt.gasUsed.toNumber(); @@ -1133,11 +1075,6 @@ describe('⛽📊 Gas Benchmark', () => { ); const receipt = await tx.wait(); - casesExecuteRestrictedController.push([ - 'transfers a NFT (LSP8) to an other UP - restricted to LSP8 + 2x allowed contracts only (CALL + 2x AllowedCalls) (no data)', - receipt.gasUsed.toNumber().toString(), - ]); - gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_6'][ 'restricted_controller' ] = receipt.gasUsed.toNumber(); @@ -1642,7 +1579,7 @@ describe('⛽📊 Gas Benchmark', () => { // prettier-ignore const dataKeys = [ ERC725YDataKeys.LSP6["AddressPermissions[]"].length, - ERC725YDataKeys.LSP6["AddressPermissions[]"].index + ethers.utils.hexZeroPad(ethers.BigNumber.from(AddressPermissionsArrayLength).sub(1), 16).substring(2), + ERC725YDataKeys.LSP6["AddressPermissions[]"].index + ethers.utils.hexZeroPad(ethers.BigNumber.from(AddressPermissionsArrayLength).sub(1).toHexString(), 16).substring(2), ERC725YDataKeys.LSP6["AddressPermissions:Permissions"] + newController.address.substring(2), ERC725YDataKeys.LSP6["AddressPermissions:AllowedERC725YDataKeys"] + newController.address.substring(2), ]; diff --git a/tests/LSP14Ownable2Step/LSP14Ownable2Step.behaviour.ts b/tests/LSP14Ownable2Step/LSP14Ownable2Step.behaviour.ts index c3e55b646..c962c6914 100644 --- a/tests/LSP14Ownable2Step/LSP14Ownable2Step.behaviour.ts +++ b/tests/LSP14Ownable2Step/LSP14Ownable2Step.behaviour.ts @@ -288,6 +288,8 @@ export const shouldBehaveLikeLSP14 = ( await artifacts.getBuildInfo('contracts/LSP9Vault/LSP9Vault.sol:LSP9Vault') )?.output.contracts[ 'contracts/LSP9Vault/LSP9Vault.sol' + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore ].LSP9Vault.storageLayout.storage.filter((elem) => { if (elem.label === '_renounceOwnershipStartedAt') return elem; })[0].slot, @@ -375,6 +377,8 @@ export const shouldBehaveLikeLSP14 = ( await artifacts.getBuildInfo('contracts/LSP9Vault/LSP9Vault.sol:LSP9Vault') )?.output.contracts[ 'contracts/LSP9Vault/LSP9Vault.sol' + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore ].LSP9Vault.storageLayout.storage.filter((elem) => { if (elem.label === '_renounceOwnershipStartedAt') return elem; })[0].slot, @@ -440,6 +444,8 @@ export const shouldBehaveLikeLSP14 = ( await artifacts.getBuildInfo('contracts/LSP9Vault/LSP9Vault.sol:LSP9Vault') )?.output.contracts[ 'contracts/LSP9Vault/LSP9Vault.sol' + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore ].LSP9Vault.storageLayout.storage.filter((elem) => { if (elem.label === '_renounceOwnershipStartedAt') return elem; })[0].slot, @@ -527,6 +533,8 @@ export const shouldBehaveLikeLSP14 = ( await artifacts.getBuildInfo('contracts/LSP9Vault/LSP9Vault.sol:LSP9Vault') )?.output.contracts[ 'contracts/LSP9Vault/LSP9Vault.sol' + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore ].LSP9Vault.storageLayout.storage.filter((elem) => { if (elem.label === '_renounceOwnershipStartedAt') return elem; })[0].slot, diff --git a/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP.behaviour.ts b/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP.behaviour.ts index e38f35450..49c0a6d01 100644 --- a/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP.behaviour.ts +++ b/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP.behaviour.ts @@ -1126,7 +1126,7 @@ export const shouldBehaveLikeLSP1Delegate = ( before(async () => { const setDataPayload = context.universalProfile1.interface.encodeFunctionData('setData', [ lsp5ArrayLengthDataKey, - lsp5ArrayLengthDataValue, + lsp5ArrayLengthDataValue.toHexString(), ]); await context.lsp6KeyManager1.connect(context.accounts.owner1).execute(setDataPayload); @@ -1173,7 +1173,7 @@ export const shouldBehaveLikeLSP1Delegate = ( before(async () => { const setDataPayload = context.universalProfile1.interface.encodeFunctionData('setData', [ lsp5ArrayLengthDataKey, - lsp5ArrayLengthDataValue, + lsp5ArrayLengthDataValue.toHexString(), ]); await context.lsp6KeyManager1.connect(context.accounts.owner1).execute(setDataPayload); diff --git a/tests/LSP20CallVerification/LSP20WithLSP14.behaviour.ts b/tests/LSP20CallVerification/LSP20WithLSP14.behaviour.ts index 8a767e99e..de7debaff 100644 --- a/tests/LSP20CallVerification/LSP20WithLSP14.behaviour.ts +++ b/tests/LSP20CallVerification/LSP20WithLSP14.behaviour.ts @@ -294,6 +294,8 @@ export const shouldBehaveLikeLSP14WithLSP20 = ( ) )?.output.contracts[ 'contracts/LSP0ERC725Account/LSP0ERC725Account.sol' + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore ].LSP0ERC725Account.storageLayout.storage.filter((elem) => { if (elem.label === '_renounceOwnershipStartedAt') return elem; })[0].slot, @@ -383,6 +385,8 @@ export const shouldBehaveLikeLSP14WithLSP20 = ( ) )?.output.contracts[ 'contracts/LSP0ERC725Account/LSP0ERC725Account.sol' + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore ].LSP0ERC725Account.storageLayout.storage.filter((elem) => { if (elem.label === '_renounceOwnershipStartedAt') return elem; })[0].slot, @@ -449,6 +453,8 @@ export const shouldBehaveLikeLSP14WithLSP20 = ( ) )?.output.contracts[ 'contracts/LSP0ERC725Account/LSP0ERC725Account.sol' + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore ].LSP0ERC725Account.storageLayout.storage.filter((elem) => { if (elem.label === '_renounceOwnershipStartedAt') return elem; })[0].slot, @@ -540,6 +546,8 @@ export const shouldBehaveLikeLSP14WithLSP20 = ( ) )?.output.contracts[ 'contracts/LSP0ERC725Account/LSP0ERC725Account.sol' + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore ].LSP0ERC725Account.storageLayout.storage.filter((elem) => { if (elem.label === '_renounceOwnershipStartedAt') return elem; })[0].slot, diff --git a/tests/LSP20CallVerification/LSP6/Interactions/Security.test.ts b/tests/LSP20CallVerification/LSP6/Interactions/Security.test.ts index ede08ed98..1c38af65f 100644 --- a/tests/LSP20CallVerification/LSP6/Interactions/Security.test.ts +++ b/tests/LSP20CallVerification/LSP6/Interactions/Security.test.ts @@ -304,6 +304,8 @@ export const testSecurityScenarios = (buildContext: () => Promise { if (elem.label === '_reentrancyStatus') return elem; })[0].slot, diff --git a/tests/LSP23LinkedContractsDeployment/LSP23LinkedContractsDeployment.test.ts b/tests/LSP23LinkedContractsDeployment/LSP23LinkedContractsDeployment.test.ts index d0b2884a5..b94465f54 100644 --- a/tests/LSP23LinkedContractsDeployment/LSP23LinkedContractsDeployment.test.ts +++ b/tests/LSP23LinkedContractsDeployment/LSP23LinkedContractsDeployment.test.ts @@ -2,10 +2,11 @@ import { ethers } from 'hardhat'; import { expect } from 'chai'; import { - LSP23LinkedContractsFactory, + ILSP23LinkedContractsFactory, + KeyManagerWithExtraParams, LSP6KeyManager, UniversalProfile, -} from '../../typechain-types'; +} from '../../types'; import { ERC725YDataKeys } from '../../constants'; import { calculateProxiesAddresses, @@ -35,16 +36,16 @@ describe('UniversalProfileDeployer', function () { const salt = ethers.utils.randomBytes(32); - const primaryContractDeployment: LSP23LinkedContractsFactory.PrimaryContractDeploymentStruct = + const primaryContractDeployment: ILSP23LinkedContractsFactory.PrimaryContractDeploymentStruct = { salt, fundingAmount: 0, creationBytecode: universalProfileCreationCode, }; - const secondaryContractDeployment: LSP23LinkedContractsFactory.SecondaryContractDeploymentInitStruct = + const secondaryContractDeployment: ILSP23LinkedContractsFactory.SecondaryContractDeploymentStruct = { - fundingAmount: 0, + fundingAmount: ethers.BigNumber.from(0), creationBytecode: keyManagerBytecode, addPrimaryContractAddress: true, extraConstructorParams: '0x', @@ -125,8 +126,10 @@ describe('UniversalProfileDeployer', function () { expect(upContract).to.equal(expectedUpAddress); expect(keyManagerContract).to.equal(expectedKeyManagerAddress); - const keyManagerInstance: LSP6KeyManager = KeyManagerFactory.attach(keyManagerContract); - const universalProfileInstance: UniversalProfile = UniversalProfileFactory.attach(upContract); + const keyManagerInstance = KeyManagerFactory.attach(keyManagerContract) as LSP6KeyManager; + const universalProfileInstance = UniversalProfileFactory.attach( + upContract, + ) as UniversalProfile; // CHECK that the UP is owned by the KeyManager contract expect(await universalProfileInstance.owner()).to.equal(keyManagerContract); @@ -154,14 +157,14 @@ describe('UniversalProfileDeployer', function () { const salt = ethers.utils.randomBytes(32); - const primaryContractDeployment: LSP23LinkedContractsFactory.PrimaryContractDeploymentStruct = + const primaryContractDeployment: ILSP23LinkedContractsFactory.PrimaryContractDeploymentStruct = { salt, fundingAmount: universalProfileFundAmount, creationBytecode: universalProfileCreationCode, }; - const secondaryContractDeployment: LSP23LinkedContractsFactory.SecondaryContractDeploymentInitStruct = + const secondaryContractDeployment: ILSP23LinkedContractsFactory.SecondaryContractDeploymentStruct = { fundingAmount: 0, creationBytecode: keyManagerBytecode, @@ -253,14 +256,14 @@ describe('UniversalProfileDeployer', function () { const salt = ethers.utils.randomBytes(32); - const primaryContractDeployment: LSP23LinkedContractsFactory.PrimaryContractDeploymentStruct = + const primaryContractDeployment: ILSP23LinkedContractsFactory.PrimaryContractDeploymentStruct = { salt, fundingAmount: universalProfileFundAmount, creationBytecode: universalProfileCreationCode, }; - const secondaryContractDeployment: LSP23LinkedContractsFactory.SecondaryContractDeploymentInitStruct = + const secondaryContractDeployment: ILSP23LinkedContractsFactory.SecondaryContractDeploymentStruct = { fundingAmount: 0, creationBytecode: keyManagerBytecode, @@ -341,7 +344,7 @@ describe('UniversalProfileDeployer', function () { const salt = ethers.utils.randomBytes(32); - const primaryContractDeployment: LSP23LinkedContractsFactory.PrimaryContractDeploymentStruct = + const primaryContractDeployment: ILSP23LinkedContractsFactory.PrimaryContractDeploymentStruct = { salt, fundingAmount: 0, @@ -364,7 +367,7 @@ describe('UniversalProfileDeployer', function () { keyManagerBytecode = keyManagerBytecode + secondaryContractFirstParam.slice(2); - const secondaryContractDeployment: LSP23LinkedContractsFactory.SecondaryContractDeploymentInitStruct = + const secondaryContractDeployment: ILSP23LinkedContractsFactory.SecondaryContractDeploymentStruct = { fundingAmount: 0, creationBytecode: keyManagerBytecode, @@ -447,8 +450,12 @@ describe('UniversalProfileDeployer', function () { expect(upContract).to.equal(expectedUpAddress); expect(keyManagerContract).to.equal(expectedKeyManagerAddress); - const keyManagerInstance: LSP6KeyManager = KeyManagerFactory.attach(keyManagerContract); - const universalProfileInstance: UniversalProfile = UniversalProfileFactory.attach(upContract); + const keyManagerInstance = KeyManagerFactory.attach( + keyManagerContract, + ) as KeyManagerWithExtraParams; + const universalProfileInstance = UniversalProfileFactory.attach( + upContract, + ) as UniversalProfile; // CHECK that the UP is owned by the KeyManager contract expect(await universalProfileInstance.owner()).to.equal(keyManagerContract); @@ -475,7 +482,7 @@ describe('UniversalProfileDeployer', function () { const salt = ethers.utils.randomBytes(32); - const primaryContractDeploymentInit: LSP23LinkedContractsFactory.PrimaryContractDeploymentInitStruct = + const primaryContractDeploymentInit: ILSP23LinkedContractsFactory.PrimaryContractDeploymentInitStruct = { salt, fundingAmount: 0, @@ -485,7 +492,7 @@ describe('UniversalProfileDeployer', function () { ]), }; - const secondaryContractDeploymentInit: LSP23LinkedContractsFactory.SecondaryContractDeploymentInitStruct = + const secondaryContractDeploymentInit: ILSP23LinkedContractsFactory.SecondaryContractDeploymentInitStruct = { fundingAmount: 0, implementationContract: keyManagerInit.address, @@ -605,7 +612,7 @@ describe('UniversalProfileDeployer', function () { const salt = ethers.utils.randomBytes(32); - const primaryContractDeploymentInit: LSP23LinkedContractsFactory.PrimaryContractDeploymentInitStruct = + const primaryContractDeploymentInit: ILSP23LinkedContractsFactory.PrimaryContractDeploymentInitStruct = { salt, fundingAmount: primaryFundingAmount, @@ -615,7 +622,7 @@ describe('UniversalProfileDeployer', function () { ]), }; - const secondaryContractDeploymentInit: LSP23LinkedContractsFactory.SecondaryContractDeploymentInitStruct = + const secondaryContractDeploymentInit: ILSP23LinkedContractsFactory.SecondaryContractDeploymentInitStruct = { fundingAmount: secondaryFundingAmount, implementationContract: keyManagerInit.address, @@ -672,7 +679,7 @@ describe('UniversalProfileDeployer', function () { const primaryFundingAmount = ethers.utils.parseEther('1'); const secondaryFundingAmount = ethers.utils.parseEther('0'); // key manager does not accept funds - const primaryContractDeploymentInit: LSP23LinkedContractsFactory.PrimaryContractDeploymentInitStruct = + const primaryContractDeploymentInit: ILSP23LinkedContractsFactory.PrimaryContractDeploymentInitStruct = { salt, fundingAmount: primaryFundingAmount, @@ -682,7 +689,7 @@ describe('UniversalProfileDeployer', function () { ]), }; - const secondaryContractDeploymentInit: LSP23LinkedContractsFactory.SecondaryContractDeploymentInitStruct = + const secondaryContractDeploymentInit: ILSP23LinkedContractsFactory.SecondaryContractDeploymentInitStruct = { fundingAmount: secondaryFundingAmount, implementationContract: keyManagerInit.address, diff --git a/tests/LSP23LinkedContractsDeployment/helpers.ts b/tests/LSP23LinkedContractsDeployment/helpers.ts index 1c48b9e09..2622b5ab3 100644 --- a/tests/LSP23LinkedContractsDeployment/helpers.ts +++ b/tests/LSP23LinkedContractsDeployment/helpers.ts @@ -1,13 +1,14 @@ import { ethers } from 'hardhat'; import { BytesLike } from 'ethers'; +import { PromiseOrValue } from '../../types/common'; export async function calculateProxiesAddresses( - salt: BytesLike, - primaryImplementationContractAddress: string, - secondaryImplementationContractAddress: string, - secondaryContractInitializationCalldata: BytesLike, - secondaryContractAddControlledContractAddress: boolean, - secondaryContractExtraInitializationParams: BytesLike, + salt: PromiseOrValue, + primaryImplementationContractAddress: PromiseOrValue, + secondaryImplementationContractAddress: PromiseOrValue, + secondaryContractInitializationCalldata: PromiseOrValue, + secondaryContractAddControlledContractAddress: PromiseOrValue, + secondaryContractExtraInitializationParams: PromiseOrValue, upPostDeploymentModuleAddress: string, postDeploymentCalldata: BytesLike, linkedContractsFactoryAddress: string, @@ -32,7 +33,7 @@ export async function calculateProxiesAddresses( generatedSalt, ethers.utils.keccak256( '0x3d602d80600a3d3981f3363d3d373d3d3d363d73' + - primaryImplementationContractAddress.slice(2) + + (primaryImplementationContractAddress as string).slice(2) + '5af43d82803e903d91602b57fd5bf3', ), ); @@ -42,7 +43,7 @@ export async function calculateProxiesAddresses( ethers.utils.keccak256(expectedPrimaryContractAddress), ethers.utils.keccak256( '0x3d602d80600a3d3981f3363d3d373d3d3d363d73' + - secondaryImplementationContractAddress.slice(2) + + (secondaryImplementationContractAddress as string).slice(2) + '5af43d82803e903d91602b57fd5bf3', ), ); diff --git a/tests/LSP6KeyManager/Interactions/PermissionTransferValue.test.ts b/tests/LSP6KeyManager/Interactions/PermissionTransferValue.test.ts index 2b8db6f30..1fb62b25f 100644 --- a/tests/LSP6KeyManager/Interactions/PermissionTransferValue.test.ts +++ b/tests/LSP6KeyManager/Interactions/PermissionTransferValue.test.ts @@ -312,10 +312,12 @@ export const shouldBehaveLikePermissionTransferValue = ( const initialBalanceUP = await provider.getBalance(context.universalProfile.address); const initialBalanceRecipient = await provider.getBalance(recipient.address); - const transferPayload = universalProfileInterface.encodeFunctionData( - 'execute(uint256,address,uint256,bytes)', - [OPERATION_TYPES.CALL, recipient.address, ethers.utils.parseEther('3'), data], - ); + const transferPayload = universalProfileInterface.encodeFunctionData('execute', [ + OPERATION_TYPES.CALL, + recipient.address, + ethers.utils.parseEther('3'), + data, + ]); await expect( context.keyManager.connect(canTransferValue)['execute(bytes)'](transferPayload), @@ -334,10 +336,12 @@ export const shouldBehaveLikePermissionTransferValue = ( it('should pass when caller has permission TRANSFERVALUE + CALL', async () => { const amount = ethers.utils.parseEther('3'); - const transferPayload = universalProfileInterface.encodeFunctionData( - 'execute(uint256,address,uint256,bytes)', - [OPERATION_TYPES.CALL, recipient.address, amount, data], - ); + const transferPayload = universalProfileInterface.encodeFunctionData('execute', [ + OPERATION_TYPES.CALL, + recipient.address, + amount, + data, + ]); await expect(() => context.keyManager @@ -450,10 +454,12 @@ export const shouldBehaveLikePermissionTransferValue = ( const initialBalanceUP = await provider.getBalance(context.universalProfile.address); const initialBalanceRecipient = await provider.getBalance(recipientUP.address); - const transferPayload = universalProfileInterface.encodeFunctionData( - 'execute(uint256,address,uint256,bytes)', - [OPERATION_TYPES.CALL, recipientUP.address, ethers.utils.parseEther('3'), data], - ); + const transferPayload = universalProfileInterface.encodeFunctionData('execute', [ + OPERATION_TYPES.CALL, + recipientUP.address, + ethers.utils.parseEther('3'), + data, + ]); await expect( context.keyManager.connect(canTransferValue)['execute(bytes)'](transferPayload), diff --git a/tests/LSP6KeyManager/SetPermissions/PermissionChangeAddController.test.ts b/tests/LSP6KeyManager/SetPermissions/PermissionChangeAddController.test.ts index 01ffa480b..da93c8b64 100644 --- a/tests/LSP6KeyManager/SetPermissions/PermissionChangeAddController.test.ts +++ b/tests/LSP6KeyManager/SetPermissions/PermissionChangeAddController.test.ts @@ -74,28 +74,28 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( context = await buildContext(); callerHasAllPermissionsTestCase.addressWith16BytesHexPermissionsLength = - new ethers.Wallet.createRandom().address.toLowerCase(); + ethers.Wallet.createRandom().address.toLowerCase(); callerHasAllPermissionsTestCase.addressWith40BytesHexPermsissionsLength = - new ethers.Wallet.createRandom().address.toLowerCase(); + ethers.Wallet.createRandom().address.toLowerCase(); callerHasAddControllerTestCase.addressWith16BytesHexPermissionsLength = - new ethers.Wallet.createRandom().address.toLowerCase(); + ethers.Wallet.createRandom().address.toLowerCase(); callerHasAddControllerTestCase.addressWith40BytesHexPermsissionsLength = - new ethers.Wallet.createRandom().address.toLowerCase(); + ethers.Wallet.createRandom().address.toLowerCase(); callerHasEditPermissionsTestCase.addressWith16BytesHexPermissionsLength = - new ethers.Wallet.createRandom().address.toLowerCase(); + ethers.Wallet.createRandom().address.toLowerCase(); callerHasEditPermissionsTestCase.addressWith40BytesHexPermsissionsLength = - new ethers.Wallet.createRandom().address.toLowerCase(); + ethers.Wallet.createRandom().address.toLowerCase(); callerHasSetDataTestCase.addressWith16BytesHexPermissionsLength = - new ethers.Wallet.createRandom().address.toLowerCase(); + ethers.Wallet.createRandom().address.toLowerCase(); callerHasSetDataTestCase.addressWith40BytesHexPermsissionsLength = - new ethers.Wallet.createRandom().address.toLowerCase(); + ethers.Wallet.createRandom().address.toLowerCase(); const firstSetupPermissionsKeys = [ ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + diff --git a/tests/LSP8IdentifiableDigitalAsset/LSP8CompatibleERC721.behaviour.ts b/tests/LSP8IdentifiableDigitalAsset/LSP8CompatibleERC721.behaviour.ts index 95076e985..44eaf4d7d 100644 --- a/tests/LSP8IdentifiableDigitalAsset/LSP8CompatibleERC721.behaviour.ts +++ b/tests/LSP8IdentifiableDigitalAsset/LSP8CompatibleERC721.behaviour.ts @@ -49,6 +49,7 @@ type LSP8CompatibleERC721DeployParams = { symbol: string; newOwner: string; lsp4MetadataValue: string; + tokenIdType: number; }; export type LSP8CompatibleERC721TestContext = { diff --git a/tests/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.behaviour.ts b/tests/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.behaviour.ts index 7c726b6c5..0e9cf9021 100644 --- a/tests/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.behaviour.ts +++ b/tests/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.behaviour.ts @@ -1824,7 +1824,7 @@ export const shouldInitializeLikeLSP8 = ( let context: LSP8InitializeTestContext; before(async () => { - context = await buildContext(0); + context = await buildContext(); }); describe('when the contract was initialized', () => { diff --git a/tests/Reentrancy/LSP6/LSP6Reentrancy.test.ts b/tests/Reentrancy/LSP6/LSP6Reentrancy.test.ts index 0ec0943fe..363d5c3c4 100644 --- a/tests/Reentrancy/LSP6/LSP6Reentrancy.test.ts +++ b/tests/Reentrancy/LSP6/LSP6Reentrancy.test.ts @@ -355,10 +355,12 @@ export const shouldBehaveLikeLSP6ReentrancyScenarios = ( const firstTargetSelector = firstReentrant.interface.encodeFunctionData('firstTarget'); - const payload = context.universalProfile.interface.encodeFunctionData( - 'execute(uint256,address,uint256,bytes)', - [OPERATION_TYPES.CALL, firstReentrant.address, 0, firstTargetSelector], - ); + const payload = context.universalProfile.interface.encodeFunctionData('execute', [ + OPERATION_TYPES.CALL, + firstReentrant.address, + 0, + firstTargetSelector, + ]); await expect(context.keyManager.connect(context.owner).execute(payload)) .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') @@ -384,10 +386,12 @@ export const shouldBehaveLikeLSP6ReentrancyScenarios = ( const firstTargetSelector = firstReentrant.interface.encodeFunctionData('firstTarget'); - const payload = context.universalProfile.interface.encodeFunctionData( - 'execute(uint256,address,uint256,bytes)', - [OPERATION_TYPES.CALL, firstReentrant.address, 0, firstTargetSelector], - ); + const payload = context.universalProfile.interface.encodeFunctionData('execute', [ + OPERATION_TYPES.CALL, + firstReentrant.address, + 0, + firstTargetSelector, + ]); await context.keyManager.connect(context.owner).execute(payload); diff --git a/tests/Reentrancy/LSP6/SingleExecuteRelayCallToSingleExecute.test.ts b/tests/Reentrancy/LSP6/SingleExecuteRelayCallToSingleExecute.test.ts index 70728e772..848bcd970 100644 --- a/tests/Reentrancy/LSP6/SingleExecuteRelayCallToSingleExecute.test.ts +++ b/tests/Reentrancy/LSP6/SingleExecuteRelayCallToSingleExecute.test.ts @@ -2,7 +2,7 @@ import { expect } from 'chai'; import { ethers } from 'hardhat'; //types -import { BigNumber, BytesLike } from 'ethers'; +import { BigNumber } from 'ethers'; // constants import { ERC725YDataKeys } from '../../../constants'; @@ -25,6 +25,7 @@ import { generateRelayCall, generateExecutePayload, loadTestCase, + RelayCallParams, } from './reentrancyHelpers'; export const testSingleExecuteRelayCallToSingleExecute = ( @@ -40,12 +41,7 @@ export const testSingleExecuteRelayCallToSingleExecute = ( }); describe('when reentering and transferring value', () => { - let relayCallParams: { - signature: BytesLike; - nonce: BigNumber; - validityTimestamps: BytesLike; - payload: BytesLike; - }; + let relayCallParams: RelayCallParams; before(async () => { const executePayload = generateExecutePayload( context.keyManager.address, @@ -145,12 +141,7 @@ export const testSingleExecuteRelayCallToSingleExecute = ( }); describe('when reentering and setting data', () => { - let relayCallParams: { - signature: BytesLike; - nonce: BigNumber; - validityTimestamps: BytesLike; - payload: BytesLike; - }; + let relayCallParams: RelayCallParams; before(async () => { const executePayload = generateExecutePayload( context.keyManager.address, @@ -241,12 +232,7 @@ export const testSingleExecuteRelayCallToSingleExecute = ( }); describe('when reentering and adding permissions', () => { - let relayCallParams: { - signature: BytesLike; - nonce: BigNumber; - validityTimestamps: BytesLike; - payload: BytesLike; - }; + let relayCallParams: RelayCallParams; before(async () => { const executePayload = generateExecutePayload( context.keyManager.address, @@ -317,12 +303,7 @@ export const testSingleExecuteRelayCallToSingleExecute = ( }); describe('when reentering and changing permissions', () => { - let relayCallParams: { - signature: BytesLike; - nonce: BigNumber; - validityTimestamps: BytesLike; - payload: BytesLike; - }; + let relayCallParams: RelayCallParams; before(async () => { const executePayload = generateExecutePayload( context.keyManager.address, @@ -392,12 +373,7 @@ export const testSingleExecuteRelayCallToSingleExecute = ( }); describe('when reentering and adding URD', () => { - let relayCallParams: { - signature: BytesLike; - nonce: BigNumber; - validityTimestamps: BytesLike; - payload: BytesLike; - }; + let relayCallParams: RelayCallParams; before(async () => { const executePayload = generateExecutePayload( context.keyManager.address, @@ -468,12 +444,7 @@ export const testSingleExecuteRelayCallToSingleExecute = ( }); describe('when reentering and changing URD', () => { - let relayCallParams: { - signature: BytesLike; - nonce: BigNumber; - validityTimestamps: BytesLike; - payload: BytesLike; - }; + let relayCallParams: RelayCallParams; before(async () => { const executePayload = generateExecutePayload( context.keyManager.address, diff --git a/tests/Reentrancy/LSP6/SingleExecuteRelayCallToSingleExecuteRelayCall.test.ts b/tests/Reentrancy/LSP6/SingleExecuteRelayCallToSingleExecuteRelayCall.test.ts index 50d3b66b6..35d4b41ed 100644 --- a/tests/Reentrancy/LSP6/SingleExecuteRelayCallToSingleExecuteRelayCall.test.ts +++ b/tests/Reentrancy/LSP6/SingleExecuteRelayCallToSingleExecuteRelayCall.test.ts @@ -26,6 +26,7 @@ import { generateRelayCall, generateSingleRelayPayload, loadTestCase, + RelayCallParams, } from './reentrancyHelpers'; export const testSingleExecuteRelayCallToSingleExecuteRelayCall = ( @@ -53,12 +54,7 @@ export const testSingleExecuteRelayCallToSingleExecuteRelayCall = ( }); describe('when reentering and transferring value', () => { - let relayCallParams: { - signature: BytesLike; - nonce: BigNumber; - validityTimestamps: BytesLike; - payload: BytesLike; - }; + let relayCallParams: RelayCallParams; before(async () => { relayCallParams = await generateRelayCall( context.keyManager, @@ -162,12 +158,7 @@ export const testSingleExecuteRelayCallToSingleExecuteRelayCall = ( }); describe('when reentering and setting data', () => { - let relayCallParams: { - signature: BytesLike; - nonce: BigNumber; - validityTimestamps: BytesLike; - payload: BytesLike; - }; + let relayCallParams: RelayCallParams; before(async () => { relayCallParams = await generateRelayCall( context.keyManager, @@ -262,12 +253,7 @@ export const testSingleExecuteRelayCallToSingleExecuteRelayCall = ( }); describe('when reentering and adding permissions', () => { - let relayCallParams: { - signature: BytesLike; - nonce: BigNumber; - validityTimestamps: BytesLike; - payload: BytesLike; - }; + let relayCallParams: RelayCallParams; before(async () => { relayCallParams = await generateRelayCall( context.keyManager, @@ -342,12 +328,7 @@ export const testSingleExecuteRelayCallToSingleExecuteRelayCall = ( }); describe('when reentering and changing permissions', () => { - let relayCallParams: { - signature: BytesLike; - nonce: BigNumber; - validityTimestamps: BytesLike; - payload: BytesLike; - }; + let relayCallParams: RelayCallParams; before(async () => { relayCallParams = await generateRelayCall( context.keyManager, @@ -421,12 +402,7 @@ export const testSingleExecuteRelayCallToSingleExecuteRelayCall = ( }); describe('when reentering and adding URD', () => { - let relayCallParams: { - signature: BytesLike; - nonce: BigNumber; - validityTimestamps: BytesLike; - payload: BytesLike; - }; + let relayCallParams: RelayCallParams; before(async () => { relayCallParams = await generateRelayCall( context.keyManager, @@ -501,12 +477,7 @@ export const testSingleExecuteRelayCallToSingleExecuteRelayCall = ( }); describe('when reentering and changing URD', () => { - let relayCallParams: { - signature: BytesLike; - nonce: BigNumber; - validityTimestamps: BytesLike; - payload: BytesLike; - }; + let relayCallParams: RelayCallParams; before(async () => { relayCallParams = await generateRelayCall( context.keyManager, diff --git a/tests/Reentrancy/LSP6/reentrancyHelpers.ts b/tests/Reentrancy/LSP6/reentrancyHelpers.ts index 7f6fa70e5..9c0cafa6d 100644 --- a/tests/Reentrancy/LSP6/reentrancyHelpers.ts +++ b/tests/Reentrancy/LSP6/reentrancyHelpers.ts @@ -67,6 +67,13 @@ export type ReentrancyContext = { randomLSP1TypeId: string; }; +export type RelayCallParams = { + signature: BytesLike; + nonce: BigNumber; + validityTimestamps: number | BytesLike; + payload: BytesLike; +}; + export const transferValueTestCases = { NotAuthorised: [ { @@ -382,12 +389,7 @@ export const generateRelayCall = async ( payload.toString(), ); - const relayCallContext: { - signature: BytesLike; - nonce: BigNumber; - validityTimestamps: BytesLike | number; - payload: BytesLike; - } = { + const relayCallContext: RelayCallParams = { signature, nonce, validityTimestamps, diff --git a/tsconfig.json b/tsconfig.json index a38d1f94b..9364e1eff 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,14 +10,6 @@ "skipLibCheck": true, "lib": ["ES2019", "es2019.array"] }, - "include": ["./src", "./test", "hardhat"], - "exclude": [ - "node_modules", - "dist", - "build", - "coverage", - "artifacts", - "cache" - ], + "include": ["./tests", "./deploy", "hardhat"], "files": ["./hardhat.config.ts"] } diff --git a/tsconfig.module.json b/tsconfig.module.json index 83997ab57..db1b7f1fd 100644 --- a/tsconfig.module.json +++ b/tsconfig.module.json @@ -3,7 +3,6 @@ "compilerOptions": { "module": "esNext", "target": "esNext", - "outDir": "module", "declaration": true, "skipLibCheck": false }, From 0ae4c83d80227e53c614d46dce96f8b727822839 Mon Sep 17 00:00:00 2001 From: Skima Harvey <64636974+skimaharvey@users.noreply.github.com> Date: Mon, 2 Oct 2023 16:33:43 +0100 Subject: [PATCH 34/55] feat!: add callee params to lsp20 & EXECUTE_RELAY_CALL permission & mapping reentrancyStatus (#729) * feat!: add callee params to lsp20 * chore: update lsp6 to with new lsp20 interface * test: update tests to work with new lsp20 interface * refactor: update constants.ts file * test: fix failing tests * test: fix foundry tests * docs: generate lsp6 new abi docs * docs: update lsp6 interfaceID * feat!: add EXECUTE_RELAY_CALL permission * refactor: move `EXECUTE_RELAY_CALL` permission as last bit in permissions range Co-authored-by: Skima Harvey * test: fix lsp6 tests * feat!: add LSP6ExecuteRelayCallModule to LSP6 * test: add EXECUTE_RELAY_CALL test * test: modify reentrancy tests with EXECUTE_RELAY_CALL permission * refactor: use uint8 for reentrancyStatus * docs: build lsp6 docs * test: fix reentrancy test * refactor: use mapping for reentrancyStatus * refactor: rename callee to targetContract * docs: update docs with targetContract * refactor: use uint256 for `reentrancyStatus` * refactor: use bool for reentrancyStatus * reactor: remove cast to bytes1 in _verifyCall --------- Co-authored-by: CJ42 Co-authored-by: Skima Harvey --- constants.ts | 59 ++++++------ .../ILSP20CallVerifier.sol | 2 + .../LSP20CallVerification.sol | 12 ++- .../LSP20CallVerification/LSP20Constants.sol | 8 +- contracts/LSP6KeyManager/LSP6Constants.sol | 5 +- contracts/LSP6KeyManager/LSP6KeyManager.sol | 1 - .../LSP6KeyManager/LSP6KeyManagerCore.sol | 86 +++++++++-------- .../LSP6KeyManagerInitAbstract.sol | 1 - .../LSP6ExecuteRelayCallModule.sol | 27 ++++++ .../KeyManager/KeyManagerInternalsTester.sol | 2 +- .../FirstCallReturnExpandedInvalidValue.sol | 3 +- .../FirstCallReturnInvalidMagicValue.sol | 1 + docs/_interface_ids_table.mdx | 4 +- .../LSP6KeyManager/LSP6KeyManager.md | 49 +++++----- .../LSP6/Interactions/PermissionCall.test.ts | 18 ++-- .../LSP6/Interactions/Security.test.ts | 3 +- .../Interactions/AllowedFunctions.test.ts | 10 +- .../Interactions/PermissionCall.test.ts | 40 ++++---- .../Interactions/PermissionDeploy.test.ts | 16 +++- .../Relay/ExecuteRelayCall.test.ts | 86 ++++++++++++++++- .../Relay/MultiChannelNonce.test.ts | 4 +- tests/Reentrancy/LSP20/reentrancyHelpers.ts | 88 ++++++++++++------ tests/Reentrancy/LSP6/LSP6Reentrancy.test.ts | 6 +- tests/Reentrancy/LSP6/reentrancyHelpers.ts | 92 +++++++++++++------ .../LSP6KeyManager/LSP6SetDataTest.t.sol | 14 ++- 25 files changed, 429 insertions(+), 208 deletions(-) create mode 100644 contracts/LSP6KeyManager/LSP6Modules/LSP6ExecuteRelayCallModule.sol diff --git a/constants.ts b/constants.ts index 2b7ff0a76..613937e7b 100644 --- a/constants.ts +++ b/constants.ts @@ -26,7 +26,7 @@ export const INTERFACE_IDS = { ERC725Y: '0x629aa694', LSP0ERC725Account: '0x24871b3d', LSP1UniversalReceiver: '0x6bb56a14', - LSP6KeyManager: '0x66918867', + LSP6KeyManager: '0xe7424397', LSP7DigitalAsset: '0x05519512', LSP8IdentifiableDigitalAsset: '0x1ae9ba1f', LSP9Vault: '0x28af17e6', @@ -35,7 +35,7 @@ export const INTERFACE_IDS = { LSP17Extendable: '0xa918fa6b', LSP17Extension: '0xcee78b40', LSP20CallVerification: '0x1a0eb6a5', - LSP20CallVerifier: '0x480c0ec2', + LSP20CallVerifier: '0xc9dfc532', LSP25ExecuteRelayCall: '0x5ac79908', }; @@ -60,10 +60,10 @@ export const ERC1271_VALUES = { */ export const LSP20_MAGIC_VALUES = { VERIFY_CALL: { - // bytes3(keccak256("lsp20VerifyCall(address,uint256,bytes)")) + "0x01" - WITH_POST_VERIFICATION: '0x9bf04b01', - // bytes3(keccak256("lsp20VerifyCall(address,uint256,bytes)")) + "0x00" - NO_POST_VERIFICATION: '0x9bf04b00', + // bytes3(keccak256("lsp20VerifyCall(address,address,uint256,bytes)")) + "0x00" + NO_POST_VERIFICATION: '0x1a238000', + // bytes3(keccak256("lsp20VerifyCall(address,address,uint256,bytes)")) + "0x01" + WITH_POST_VERIFICATION: '0x1a238001', }, // bytes4(keccak256("lsp20VerifyCallResult(bytes32,bytes)")) VERIFY_CALL_RESULT: '0xd3fc45d3', @@ -274,7 +274,7 @@ export const CALLTYPE = { /** * @dev `bytes32` hex value for all the LSP6 permissions excluding REENTRANCY, DELEGATECALL and SUPER_DELEGATECALL for security (these should be set manually) */ -export const ALL_PERMISSIONS = '0x00000000000000000000000000000000000000000000000000000000003f3f7f'; +export const ALL_PERMISSIONS = '0x00000000000000000000000000000000000000000000000000000000007f3f7f'; export type LSP6PermissionName = keyof typeof PERMISSIONS; @@ -283,28 +283,29 @@ export type LSP6PermissionName = keyof typeof PERMISSIONS; */ // prettier-ignore export const PERMISSIONS = { - CHANGEOWNER: "0x0000000000000000000000000000000000000000000000000000000000000001", - ADDCONTROLLER: "0x0000000000000000000000000000000000000000000000000000000000000002", - EDITPERMISSIONS: "0x0000000000000000000000000000000000000000000000000000000000000004", - ADDEXTENSIONS: "0x0000000000000000000000000000000000000000000000000000000000000008", - CHANGEEXTENSIONS: "0x0000000000000000000000000000000000000000000000000000000000000010", - ADDUNIVERSALRECEIVERDELEGATE: "0x0000000000000000000000000000000000000000000000000000000000000020", - CHANGEUNIVERSALRECEIVERDELEGATE: "0x0000000000000000000000000000000000000000000000000000000000000040", - REENTRANCY: "0x0000000000000000000000000000000000000000000000000000000000000080", - SUPER_TRANSFERVALUE: "0x0000000000000000000000000000000000000000000000000000000000000100", - TRANSFERVALUE: "0x0000000000000000000000000000000000000000000000000000000000000200", - SUPER_CALL: "0x0000000000000000000000000000000000000000000000000000000000000400", - CALL: "0x0000000000000000000000000000000000000000000000000000000000000800", - SUPER_STATICCALL: "0x0000000000000000000000000000000000000000000000000000000000001000", - STATICCALL: "0x0000000000000000000000000000000000000000000000000000000000002000", - SUPER_DELEGATECALL: "0x0000000000000000000000000000000000000000000000000000000000004000", - DELEGATECALL: "0x0000000000000000000000000000000000000000000000000000000000008000", - DEPLOY: "0x0000000000000000000000000000000000000000000000000000000000010000", - SUPER_SETDATA: "0x0000000000000000000000000000000000000000000000000000000000020000", - SETDATA: "0x0000000000000000000000000000000000000000000000000000000000040000", - ENCRYPT: "0x0000000000000000000000000000000000000000000000000000000000080000", - DECRYPT: "0x0000000000000000000000000000000000000000000000000000000000100000", - SIGN: "0x0000000000000000000000000000000000000000000000000000000000200000", + CHANGEOWNER: '0x0000000000000000000000000000000000000000000000000000000000000001', // .... .... .... .... .... 0001 + ADDCONTROLLER: '0x0000000000000000000000000000000000000000000000000000000000000002', // .... .... .... .... .... 0010 + EDITPERMISSIONS: '0x0000000000000000000000000000000000000000000000000000000000000004', // .... .... .... .... .... 0100 + ADDEXTENSIONS: '0x0000000000000000000000000000000000000000000000000000000000000008', // .... .... .... .... .... 1000 + CHANGEEXTENSIONS: '0x0000000000000000000000000000000000000000000000000000000000000010', // .... .... .... .... 0001 0000 + ADDUNIVERSALRECEIVERDELEGATE: '0x0000000000000000000000000000000000000000000000000000000000000020', // .... .... .... .... 0010 0000 + CHANGEUNIVERSALRECEIVERDELEGATE: '0x0000000000000000000000000000000000000000000000000000000000000040', // .... .... .... .... 0100 0000 + REENTRANCY: '0x0000000000000000000000000000000000000000000000000000000000000080', // .... .... .... .... 1000 0000 + SUPER_TRANSFERVALUE: '0x0000000000000000000000000000000000000000000000000000000000000100', // .... .... .... 0001 0000 0000 + TRANSFERVALUE: '0x0000000000000000000000000000000000000000000000000000000000000200', // .... .... .... 0010 0000 0000 + SUPER_CALL: '0x0000000000000000000000000000000000000000000000000000000000000400', // .... .... .... 0100 0000 0000 + CALL: '0x0000000000000000000000000000000000000000000000000000000000000800', // .... .... .... 1000 0000 0000 + SUPER_STATICCALL: '0x0000000000000000000000000000000000000000000000000000000000001000', // .... .... 0001 0000 0000 0000 + STATICCALL: '0x0000000000000000000000000000000000000000000000000000000000002000', // .... .... 0010 0000 0000 0000 + SUPER_DELEGATECALL: '0x0000000000000000000000000000000000000000000000000000000000004000', // .... .... 0100 0000 0000 0000 + DELEGATECALL: '0x0000000000000000000000000000000000000000000000000000000000008000', // .... .... 1000 0000 0000 0000 + DEPLOY: '0x0000000000000000000000000000000000000000000000000000000000010000', // .... 0001 0000 0000 0000 0000 + SUPER_SETDATA: '0x0000000000000000000000000000000000000000000000000000000000020000', // .... 0010 0000 0000 0000 0000 + SETDATA: '0x0000000000000000000000000000000000000000000000000000000000040000', // .... 0100 0000 0000 0000 0000 + ENCRYPT: '0x0000000000000000000000000000000000000000000000000000000000080000', // .... 1000 0000 0000 0000 0000 + DECRYPT: '0x0000000000000000000000000000000000000000000000000000000000100000', // 0001 0000 0000 0000 0000 0000 + SIGN: '0x0000000000000000000000000000000000000000000000000000000000200000', // 0010 0000 0000 0000 0000 0000 + EXECUTE_RELAY_CALL: '0x0000000000000000000000000000000000000000000000000000000000400000', // 0100 0000 0000 0000 0000 0000 } /** diff --git a/contracts/LSP20CallVerification/ILSP20CallVerifier.sol b/contracts/LSP20CallVerification/ILSP20CallVerifier.sol index 2f31efe1e..e550a8fa9 100644 --- a/contracts/LSP20CallVerification/ILSP20CallVerifier.sol +++ b/contracts/LSP20CallVerification/ILSP20CallVerifier.sol @@ -12,11 +12,13 @@ interface ILSP20CallVerifier { * the function is allowed, concatened with a byte that determines if the lsp20VerifyCallResult function should * be called after the original function call. The byte that invoke the lsp20VerifyCallResult function is strictly `0x01`. * + * @param callee The address of the contract that implements the `LSP20CallVerification` interface * @param caller The address who called the function on the msg.sender * @param value The value sent by the caller to the function called on the msg.sender * @param receivedCalldata The receivedCalldata sent by the caller to the msg.sender */ function lsp20VerifyCall( + address callee, address caller, uint256 value, bytes memory receivedCalldata diff --git a/contracts/LSP20CallVerification/LSP20CallVerification.sol b/contracts/LSP20CallVerification/LSP20CallVerification.sol index 9f3780ca5..1a864c28e 100644 --- a/contracts/LSP20CallVerification/LSP20CallVerification.sol +++ b/contracts/LSP20CallVerification/LSP20CallVerification.sol @@ -33,6 +33,7 @@ abstract contract LSP20CallVerification { (bool success, bytes memory returnedData) = logicVerifier.call( abi.encodeWithSelector( ILSP20.lsp20VerifyCall.selector, + address(this), msg.sender, msg.value, msg.data @@ -46,7 +47,7 @@ abstract contract LSP20CallVerification { if (bytes3(magicValue) != bytes3(ILSP20.lsp20VerifyCall.selector)) revert LSP20InvalidMagicValue(false, returnedData); - return bytes1(magicValue[3]) == 0x01; + return magicValue[3] == 0x01; } /** @@ -60,7 +61,14 @@ abstract contract LSP20CallVerification { (bool success, bytes memory returnedData) = logicVerifier.call( abi.encodeWithSelector( ILSP20.lsp20VerifyCallResult.selector, - keccak256(abi.encodePacked(msg.sender, msg.value, msg.data)), + keccak256( + abi.encodePacked( + address(this), + msg.sender, + msg.value, + msg.data + ) + ), callResult ) ); diff --git a/contracts/LSP20CallVerification/LSP20Constants.sol b/contracts/LSP20CallVerification/LSP20Constants.sol index 65dff7f87..4134c6a89 100644 --- a/contracts/LSP20CallVerification/LSP20Constants.sol +++ b/contracts/LSP20CallVerification/LSP20Constants.sol @@ -4,14 +4,14 @@ pragma solidity ^0.8.4; // bytes4(keccak256("LSP20CallVerification")) bytes4 constant _INTERFACEID_LSP20_CALL_VERIFICATION = 0x1a0eb6a5; -// `lsp20VerifyCall(address,uint256,bytes)` selector XOR `lsp20VerifyCallResult(bytes32,bytes)` selector -bytes4 constant _INTERFACEID_LSP20_CALL_VERIFIER = 0x480c0ec2; +// `lsp20VerifyCall(address,address,uint256,bytes)` selector XOR `lsp20VerifyCallResult(bytes32,bytes)` selector +bytes4 constant _INTERFACEID_LSP20_CALL_VERIFIER = 0xc9dfc532; // bytes4(bytes.concat(bytes3(ILSP20.lsp20VerifyCall.selector), hex"01")) -bytes4 constant _LSP20_VERIFY_CALL_MAGIC_VALUE_WITH_POST_VERIFICATION = 0x9bf04b01; +bytes4 constant _LSP20_VERIFY_CALL_MAGIC_VALUE_WITH_POST_VERIFICATION = 0x1a238001; // bytes4(bytes.concat(bytes3(ILSP20.lsp20VerifyCall.selector), hex"00")) -bytes4 constant _LSP20_VERIFY_CALL_MAGIC_VALUE_WITHOUT_POST_VERIFICATION = 0x9bf04b00; +bytes4 constant _LSP20_VERIFY_CALL_MAGIC_VALUE_WITHOUT_POST_VERIFICATION = 0x1a238000; // bytes4(ILSP20.lsp20VerifyCallResult.selector) bytes4 constant _LSP20_VERIFY_CALL_RESULT_MAGIC_VALUE = 0xd3fc45d3; diff --git a/contracts/LSP6KeyManager/LSP6Constants.sol b/contracts/LSP6KeyManager/LSP6Constants.sol index 8d4fba6a0..a7d26ede9 100644 --- a/contracts/LSP6KeyManager/LSP6Constants.sol +++ b/contracts/LSP6KeyManager/LSP6Constants.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.4; // --- ERC165 interface ids -bytes4 constant _INTERFACEID_LSP6 = 0x66918867; +bytes4 constant _INTERFACEID_LSP6 = 0xe7424397; // --- ERC725Y Data Keys @@ -52,9 +52,10 @@ bytes32 constant _PERMISSION_SETDATA = 0x000000000000000 bytes32 constant _PERMISSION_ENCRYPT = 0x0000000000000000000000000000000000000000000000000000000000080000; bytes32 constant _PERMISSION_DECRYPT = 0x0000000000000000000000000000000000000000000000000000000000100000; bytes32 constant _PERMISSION_SIGN = 0x0000000000000000000000000000000000000000000000000000000000200000; +bytes32 constant _PERMISSION_EXECUTE_RELAY_CALL = 0x0000000000000000000000000000000000000000000000000000000000400000; // All Permissions currently exclude REENTRANCY, DELEGATECALL and SUPER_DELEGATECALL for security -bytes32 constant ALL_REGULAR_PERMISSIONS = 0x00000000000000000000000000000000000000000000000000000000003f3f7f; +bytes32 constant ALL_REGULAR_PERMISSIONS = 0x00000000000000000000000000000000000000000000000000000000007f3f7f; // AllowedCalls types bytes4 constant _ALLOWEDCALLS_TRANSFERVALUE = 0x00000001; // 0000 0001 diff --git a/contracts/LSP6KeyManager/LSP6KeyManager.sol b/contracts/LSP6KeyManager/LSP6KeyManager.sol index d6c6d75d5..6e9e9cc32 100644 --- a/contracts/LSP6KeyManager/LSP6KeyManager.sol +++ b/contracts/LSP6KeyManager/LSP6KeyManager.sol @@ -21,6 +21,5 @@ contract LSP6KeyManager is LSP6KeyManagerCore { constructor(address target_) { if (target_ == address(0)) revert InvalidLSP6Target(); _target = target_; - _setupLSP6ReentrancyGuard(); } } diff --git a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol index 9f805a396..a1ddadb37 100644 --- a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol +++ b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol @@ -23,6 +23,9 @@ import {ERC725Y} from "@erc725/smart-contracts/contracts/ERC725Y.sol"; import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; import {LSP6SetDataModule} from "./LSP6Modules/LSP6SetDataModule.sol"; import {LSP6ExecuteModule} from "./LSP6Modules/LSP6ExecuteModule.sol"; +import { + LSP6ExecuteRelayCallModule +} from "./LSP6Modules/LSP6ExecuteRelayCallModule.sol"; import {LSP6OwnershipModule} from "./LSP6Modules/LSP6OwnershipModule.sol"; import { LSP25MultiChannelNonce @@ -83,6 +86,7 @@ abstract contract LSP6KeyManagerCore is ILSP25, LSP6SetDataModule, LSP6ExecuteModule, + LSP6ExecuteRelayCallModule, LSP6OwnershipModule, LSP25MultiChannelNonce { @@ -92,11 +96,7 @@ abstract contract LSP6KeyManagerCore is address internal _target; - // Variables, methods and modifier used for ReentrancyGuard are taken from the link below and modified accordingly. - // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.8/contracts/security/ReentrancyGuard.sol - uint8 internal _reentrancyStatus; - uint8 internal constant _NOT_ENTERED = 1; - uint8 internal constant _ENTERED = 2; + mapping(address => bool) internal _reentrancyStatus; /** * @inheritdoc ILSP6 @@ -315,10 +315,11 @@ abstract contract LSP6KeyManagerCore is * on the {`target`} contract (while sending `msgValue` alongside the call). * * If the permissions have been verified successfully and `caller` is authorized, one of the following two LSP20 magic value will be returned: - * - `0x9bf04b00`: LSP20 magic value **without** post verification (last byte is `0x00`). - * - `0x9bf04b01`: LSP20 magic value **with** post-verification (last byte is `0x01`). + * - `0x1a238000`: LSP20 magic value **without** post verification (last byte is `0x00`). + * - `0x1a238001`: LSP20 magic value **with** post-verification (last byte is `0x01`). */ function lsp20VerifyCall( + address targetContract, address caller, uint256 msgValue, bytes calldata data @@ -326,31 +327,29 @@ abstract contract LSP6KeyManagerCore is bool isSetData = bytes4(data) == IERC725Y.setData.selector || bytes4(data) == IERC725Y.setDataBatch.selector; - address targetContract = _target; - // If target is invoking the verification, emit the event and change the reentrancy guard if (msg.sender == targetContract) { - uint8 reentrancyStatus = _nonReentrantBefore( + bool reentrancyStatus = _nonReentrantBefore( targetContract, isSetData, caller ); - _verifyPermissions(targetContract, caller, msgValue, data); + _verifyPermissions(targetContract, caller, msgValue, false, data); emit PermissionsVerified(caller, msgValue, bytes4(data)); // if it's a setData call, do not invoke the `lsp20VerifyCallResult(..)` function return - isSetData || (reentrancyStatus == _ENTERED) + isSetData || reentrancyStatus ? _LSP20_VERIFY_CALL_MAGIC_VALUE_WITHOUT_POST_VERIFICATION : _LSP20_VERIFY_CALL_MAGIC_VALUE_WITH_POST_VERIFICATION; } /// @dev If a different address is invoking the verification, /// do not change the state or emit the event to allow read-only verification else { - uint8 reentrancyStatus = _reentrancyStatus; + bool reentrancyStatus = _reentrancyStatus[targetContract]; - if (reentrancyStatus == _ENTERED) { + if (reentrancyStatus) { _requirePermissions( caller, ERC725Y(targetContract).getPermissionsFor(caller), @@ -358,11 +357,11 @@ abstract contract LSP6KeyManagerCore is ); } - _verifyPermissions(targetContract, caller, msgValue, data); + _verifyPermissions(targetContract, caller, msgValue, false, data); // if it's a setData call, do not invoke the `lsp20VerifyCallResult(..)` function return - isSetData || (reentrancyStatus == _ENTERED) + isSetData || reentrancyStatus ? _LSP20_VERIFY_CALL_MAGIC_VALUE_WITHOUT_POST_VERIFICATION : _LSP20_VERIFY_CALL_MAGIC_VALUE_WITH_POST_VERIFICATION; } @@ -378,7 +377,7 @@ abstract contract LSP6KeyManagerCore is // If it's the target calling, set back the reentrancy guard // to false, if not return the magic value if (msg.sender == _target) { - _nonReentrantAfter(); + _nonReentrantAfter(msg.sender); } return _LSP20_VERIFY_CALL_RESULT_MAGIC_VALUE; } @@ -396,13 +395,20 @@ abstract contract LSP6KeyManagerCore is address targetContract = _target; - uint8 reentrancyStatus = _nonReentrantBefore( + bool reentrancyStatus = _nonReentrantBefore( targetContract, isSetData, msg.sender ); - _verifyPermissions(targetContract, msg.sender, msgValue, payload); + _verifyPermissions( + targetContract, + msg.sender, + msgValue, + false, + payload + ); + emit PermissionsVerified(msg.sender, msgValue, bytes4(payload)); bytes memory result = _executePayload( @@ -411,8 +417,8 @@ abstract contract LSP6KeyManagerCore is payload ); - if (reentrancyStatus == _NOT_ENTERED && !isSetData) { - _nonReentrantAfter(); + if (!reentrancyStatus && !isSetData) { + _nonReentrantAfter(targetContract); } return result; @@ -466,13 +472,13 @@ abstract contract LSP6KeyManagerCore is bool isSetData = bytes4(payload) == IERC725Y.setData.selector || bytes4(payload) == IERC725Y.setDataBatch.selector; - uint8 reentrancyStatus = _nonReentrantBefore( + bool reentrancyStatus = _nonReentrantBefore( targetContract, isSetData, signer ); - _verifyPermissions(targetContract, signer, msgValue, payload); + _verifyPermissions(targetContract, signer, msgValue, true, payload); emit PermissionsVerified(signer, msgValue, bytes4(payload)); bytes memory result = _executePayload( @@ -481,8 +487,8 @@ abstract contract LSP6KeyManagerCore is payload ); - if (reentrancyStatus == _NOT_ENTERED && !isSetData) { - _nonReentrantAfter(); + if (!reentrancyStatus && !isSetData) { + _nonReentrantAfter(targetContract); } return result; @@ -520,11 +526,19 @@ abstract contract LSP6KeyManagerCore is address targetContract, address from, uint256 msgValue, + bool isRelayedCall, bytes calldata payload ) internal view virtual { bytes32 permissions = ERC725Y(targetContract).getPermissionsFor(from); if (permissions == bytes32(0)) revert NoPermissionsSet(from); + if (isRelayedCall) { + LSP6ExecuteRelayCallModule._verifyExecuteRelayCallPermission( + from, + permissions + ); + } + bytes4 erc725Function = bytes4(payload); // ERC725Y.setData(bytes32,bytes) @@ -586,13 +600,6 @@ abstract contract LSP6KeyManagerCore is } } - /** - * @dev Initialise _reentrancyStatus to _NOT_ENTERED. - */ - function _setupLSP6ReentrancyGuard() internal virtual { - _reentrancyStatus = 1; - } - /** * @dev Update the status from `_NON_ENTERED` to `_ENTERED` and checks if * the status is `_ENTERED` in order to revert the call unless the caller has the REENTRANCY permission @@ -602,9 +609,10 @@ abstract contract LSP6KeyManagerCore is address targetContract, bool isSetData, address from - ) internal virtual returns (uint8 reentrancyStatus) { - reentrancyStatus = _reentrancyStatus; - if (reentrancyStatus == _ENTERED) { + ) internal virtual returns (bool reentrancyStatus) { + reentrancyStatus = _reentrancyStatus[targetContract]; + + if (reentrancyStatus) { // CHECK the caller has REENTRANCY permission _requirePermissions( from, @@ -613,19 +621,19 @@ abstract contract LSP6KeyManagerCore is ); } else { if (!isSetData) { - _reentrancyStatus = _ENTERED; + _reentrancyStatus[targetContract] = true; } } } /** - * @dev Resets the status to `_NOT_ENTERED` + * @dev Resets the status to `false` * Used in the end of the `nonReentrant` modifier after the method execution is terminated */ - function _nonReentrantAfter() internal virtual { + function _nonReentrantAfter(address targetContract) internal virtual { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) - _reentrancyStatus = _NOT_ENTERED; + _reentrancyStatus[targetContract] = false; } /** diff --git a/contracts/LSP6KeyManager/LSP6KeyManagerInitAbstract.sol b/contracts/LSP6KeyManager/LSP6KeyManagerInitAbstract.sol index 87f44138d..7d29da922 100644 --- a/contracts/LSP6KeyManager/LSP6KeyManagerInitAbstract.sol +++ b/contracts/LSP6KeyManager/LSP6KeyManagerInitAbstract.sol @@ -20,6 +20,5 @@ abstract contract LSP6KeyManagerInitAbstract is function _initialize(address target_) internal virtual onlyInitializing { if (target_ == address(0)) revert InvalidLSP6Target(); _target = target_; - _setupLSP6ReentrancyGuard(); } } diff --git a/contracts/LSP6KeyManager/LSP6Modules/LSP6ExecuteRelayCallModule.sol b/contracts/LSP6KeyManager/LSP6Modules/LSP6ExecuteRelayCallModule.sol new file mode 100644 index 000000000..4e0fd9447 --- /dev/null +++ b/contracts/LSP6KeyManager/LSP6Modules/LSP6ExecuteRelayCallModule.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.5; + +// libraries +import {LSP6Utils} from "../LSP6Utils.sol"; + +// constants +import {_PERMISSION_EXECUTE_RELAY_CALL} from "../LSP6Constants.sol"; + +// errors +import {NotAuthorised} from "../LSP6Errors.sol"; + +abstract contract LSP6ExecuteRelayCallModule { + function _verifyExecuteRelayCallPermission( + address controllerAddress, + bytes32 controllerPermissions + ) internal pure { + if ( + !LSP6Utils.hasPermission( + controllerPermissions, + _PERMISSION_EXECUTE_RELAY_CALL + ) + ) { + revert NotAuthorised(controllerAddress, "EXECUTE_RELAY_CALL"); + } + } +} diff --git a/contracts/Mocks/KeyManager/KeyManagerInternalsTester.sol b/contracts/Mocks/KeyManager/KeyManagerInternalsTester.sol index 007a58dfb..d3125f966 100644 --- a/contracts/Mocks/KeyManager/KeyManagerInternalsTester.sol +++ b/contracts/Mocks/KeyManager/KeyManagerInternalsTester.sol @@ -118,7 +118,7 @@ contract KeyManagerInternalTester is LSP6KeyManager { uint256 msgValue, bytes calldata payload ) public { - super._verifyPermissions(target(), from, msgValue, payload); + super._verifyPermissions(_target, from, msgValue, false, payload); // This event is emitted just for a sake of not marking this function as `view`, // as Hardhat has a bug that does not catch error that occured from failed `abi.decode` diff --git a/contracts/Mocks/LSP20Owners/FirstCallReturnExpandedInvalidValue.sol b/contracts/Mocks/LSP20Owners/FirstCallReturnExpandedInvalidValue.sol index cc5f69c7e..59ea77849 100644 --- a/contracts/Mocks/LSP20Owners/FirstCallReturnExpandedInvalidValue.sol +++ b/contracts/Mocks/LSP20Owners/FirstCallReturnExpandedInvalidValue.sol @@ -14,13 +14,14 @@ contract FirstCallReturnExpandedInvalidValue { address public target; function lsp20VerifyCall( + address callee, address caller, uint256 value, bytes memory data ) external returns (bytes32) { emit CallVerified(); - return keccak256(abi.encode(caller, value, data)); + return keccak256(abi.encode(callee, caller, value, data)); } function acceptOwnership(address newTarget) external { diff --git a/contracts/Mocks/LSP20Owners/FirstCallReturnInvalidMagicValue.sol b/contracts/Mocks/LSP20Owners/FirstCallReturnInvalidMagicValue.sol index 1a7d361c7..d2aaddff7 100644 --- a/contracts/Mocks/LSP20Owners/FirstCallReturnInvalidMagicValue.sol +++ b/contracts/Mocks/LSP20Owners/FirstCallReturnInvalidMagicValue.sol @@ -13,6 +13,7 @@ contract FirstCallReturnInvalidMagicValue { address public target; function lsp20VerifyCall( + address, address, uint256, bytes memory diff --git a/docs/_interface_ids_table.mdx b/docs/_interface_ids_table.mdx index dce5ae1a4..674870dac 100644 --- a/docs/_interface_ids_table.mdx +++ b/docs/_interface_ids_table.mdx @@ -6,7 +6,7 @@ | **ERC725Y** | `0x629aa694` | General Data key-value store. | | **LSP0ERC725Account** | `0x24871b3d` | Interface of the [LSP-0-ERC725Account] standard, an account based smart contract that represents an identity on-chain. | | **LSP1UniversalReceiver** | `0x6bb56a14` | Interface of the LSP1 - Universal Receiver standard, an entry function for a contract to receive arbitrary information. | -| **LSP6KeyManager** | `0x66918867` | Interface of the LSP6 - Key Manager standard, a contract acting as a controller of an ERC725 Account using predfined permissions. | +| **LSP6KeyManager** | `0xe7424397` | Interface of the LSP6 - Key Manager standard, a contract acting as a controller of an ERC725 Account using predfined permissions. | | **LSP7DigitalAsset** | `0x05519512` | Interface of the LSP7 - Digital Asset standard, a fungible digital asset. | | **LSP8IdentifiableDigitalAsset** | `0x1ae9ba1f` | Interface of the LSP8 - Identifiable Digital Asset standard, a non-fungible digital asset. | | **LSP9Vault** | `0x28af17e6` | Interface of LSP9 - Vault standard, a blockchain vault that can hold assets and interact with other smart contracts. | @@ -15,5 +15,5 @@ | **LSP17Extendable** | `0xa918fa6b` | Module to add more functionalities to a contract using extensions. | | **LSP17Extension** | `0xcee78b40` | Module to create a contract that can act as an extension. | | **LSP20CallVerification** | `0x1a0eb6a5` | Implementation of a contract calling the verification functions according to LSP20 - Call Verification standard. | -| **LSP20CallVerifier** | `0x480c0ec2` | Interface for the LSP20 Call Verification standard, a set of functions intended to perform verifications on behalf of another contract. | +| **LSP20CallVerifier** | `0xc9dfc532` | Interface for the LSP20 Call Verification standard, a set of functions intended to perform verifications on behalf of another contract. | | **LSP25ExecuteRelayCall** | `0x5ac79908` | | diff --git a/docs/contracts/LSP6KeyManager/LSP6KeyManager.md b/docs/contracts/LSP6KeyManager/LSP6KeyManager.md index 024890611..90eef8aea 100644 --- a/docs/contracts/LSP6KeyManager/LSP6KeyManager.md +++ b/docs/contracts/LSP6KeyManager/LSP6KeyManager.md @@ -332,8 +332,8 @@ Checks if a signature was signed by a controller that has the permission `SIGN`. - Specification details: [**LSP-6-KeyManager**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-6-KeyManager.md#lsp20verifycall) - Solidity implementation: [`LSP6KeyManager.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP6KeyManager/LSP6KeyManager.sol) -- Function signature: `lsp20VerifyCall(address,uint256,bytes)` -- Function selector: `0x9bf04b11` +- Function signature: `lsp20VerifyCall(address,address,uint256,bytes)` +- Function selector: `0x1a2380e1` ::: @@ -341,13 +341,14 @@ Checks if a signature was signed by a controller that has the permission `SIGN`. This function can call by any other address than the {`target`}. This allows to verify permissions in a _"read-only"_ manner. Anyone can call this function to verify if the `caller` has the right permissions to perform the abi-encoded function call `data` on the {`target`} contract (while sending `msgValue` alongside the call). If the permissions have been verified successfully and `caller` is authorized, one of the following two LSP20 magic value will be returned: -- `0x9bf04b00`: LSP20 magic value **without** post verification (last byte is `0x00`). -- `0x9bf04b01`: LSP20 magic value **with** post-verification (last byte is `0x01`). +- `0x1a238000`: LSP20 magic value **without** post verification (last byte is `0x00`). +- `0x1a238001`: LSP20 magic value **with** post-verification (last byte is `0x01`). ::: ```solidity function lsp20VerifyCall( + address targetContract, address caller, uint256 msgValue, bytes data @@ -356,11 +357,12 @@ function lsp20VerifyCall( #### Parameters -| Name | Type | Description | -| ---------- | :-------: | ----------------------------------------------------- | -| `caller` | `address` | The address who called the function on the msg.sender | -| `msgValue` | `uint256` | - | -| `data` | `bytes` | - | +| Name | Type | Description | +| ---------------- | :-------: | ----------------------------------------------------- | +| `targetContract` | `address` | - | +| `caller` | `address` | The address who called the function on the msg.sender | +| `msgValue` | `uint256` | - | +| `data` | `bytes` | - | #### Returns @@ -941,6 +943,17 @@ function _isAllowedCallType(
+### \_verifyExecuteRelayCallPermission + +```solidity +function _verifyExecuteRelayCallPermission( + address controllerAddress, + bytes32 controllerPermissions +) internal pure; +``` + +
+ ### \_verifyOwnershipPermissions ```solidity @@ -1155,6 +1168,7 @@ function _verifyPermissions( address targetContract, address from, uint256 msgValue, + bool isRelayedCall, bytes payload ) internal view; ``` @@ -1168,20 +1182,11 @@ Verify if the `from` address is allowed to execute the `payload` on the [`target | `targetContract` | `address` | - | | `from` | `address` | Either the caller of {execute} or the signer of {executeRelayCall}. | | `msgValue` | `uint256` | - | +| `isRelayedCall` | `bool` | - | | `payload` | `bytes` | The abi-encoded function call to execute on the {target} contract. |
-### \_setupLSP6ReentrancyGuard - -```solidity -function _setupLSP6ReentrancyGuard() internal nonpayable; -``` - -Initialise \_reentrancyStatus to \_NOT_ENTERED. - -
- ### \_nonReentrantBefore ```solidity @@ -1189,7 +1194,7 @@ function _nonReentrantBefore( address targetContract, bool isSetData, address from -) internal nonpayable returns (uint8 reentrancyStatus); +) internal nonpayable returns (bool reentrancyStatus); ``` Update the status from `_NON_ENTERED` to `_ENTERED` and checks if @@ -1201,10 +1206,10 @@ Used in the beginning of the `nonReentrant` modifier, before the method executio ### \_nonReentrantAfter ```solidity -function _nonReentrantAfter() internal nonpayable; +function _nonReentrantAfter(address targetContract) internal nonpayable; ``` -Resets the status to `_NOT_ENTERED` +Resets the status to `false` Used in the end of the `nonReentrant` modifier after the method execution is terminated
diff --git a/tests/LSP20CallVerification/LSP6/Interactions/PermissionCall.test.ts b/tests/LSP20CallVerification/LSP6/Interactions/PermissionCall.test.ts index 1287fc62a..4346ff2b6 100644 --- a/tests/LSP20CallVerification/LSP6/Interactions/PermissionCall.test.ts +++ b/tests/LSP20CallVerification/LSP6/Interactions/PermissionCall.test.ts @@ -99,11 +99,11 @@ export const shouldBehaveLikePermissionCall = ( ); const permissionsValues = [ - PERMISSIONS.SIGN, - PERMISSIONS.SIGN, - PERMISSIONS.CALL, - PERMISSIONS.CALL, - PERMISSIONS.SUPER_CALL, + combinePermissions(PERMISSIONS.SIGN, PERMISSIONS.EXECUTE_RELAY_CALL), + combinePermissions(PERMISSIONS.SIGN, PERMISSIONS.EXECUTE_RELAY_CALL), + combinePermissions(PERMISSIONS.CALL, PERMISSIONS.EXECUTE_RELAY_CALL), + combinePermissions(PERMISSIONS.CALL, PERMISSIONS.EXECUTE_RELAY_CALL), + combinePermissions(PERMISSIONS.SUPER_CALL, PERMISSIONS.EXECUTE_RELAY_CALL), allowedCallsValues, allowedCallsValues, ]; @@ -343,9 +343,9 @@ export const shouldBehaveLikePermissionCall = ( const permissionsValues = [ ALL_PERMISSIONS, - PERMISSIONS.CALL, - PERMISSIONS.CALL, - PERMISSIONS.SETDATA, + combinePermissions(PERMISSIONS.CALL, PERMISSIONS.EXECUTE_RELAY_CALL), + combinePermissions(PERMISSIONS.CALL, PERMISSIONS.EXECUTE_RELAY_CALL), + combinePermissions(PERMISSIONS.SETDATA, PERMISSIONS.EXECUTE_RELAY_CALL), combineAllowedCalls( [CALLTYPE.CALL], [targetContract.address], @@ -497,7 +497,7 @@ export const shouldBehaveLikePermissionCall = ( it('Should revert when caller calls the KeyManager through execute', async () => { const lsp20VerifyCallPayload = context.keyManager.interface.encodeFunctionData( 'lsp20VerifyCall', - [context.accounts[2].address, 0, '0xaabbccdd'], // random arguments + [context.keyManager.address, context.accounts[2].address, 0, '0xaabbccdd'], // random arguments ); await expect( diff --git a/tests/LSP20CallVerification/LSP6/Interactions/Security.test.ts b/tests/LSP20CallVerification/LSP6/Interactions/Security.test.ts index 1c38af65f..8df443a2f 100644 --- a/tests/LSP20CallVerification/LSP6/Interactions/Security.test.ts +++ b/tests/LSP20CallVerification/LSP6/Interactions/Security.test.ts @@ -106,7 +106,7 @@ export const testSecurityScenarios = (buildContext: () => Promise { const lsp20VerifyCallPayload = context.keyManager.interface.encodeFunctionData( 'lsp20VerifyCall', - [context.accounts[2].address, 0, '0xaabbccdd'], // random arguments + [context.keyManager.address, context.accounts[2].address, 0, '0xaabbccdd'], // random arguments ); await expect( @@ -290,6 +290,7 @@ export const testSecurityScenarios = (buildContext: () => Promise Promise) => { let context: LSP6TestContext; @@ -56,8 +56,8 @@ export const shouldBehaveLikeAllowedFunctions = (buildContext: () => Promise Promise Promise { const lsp20VerifyCallPayload = context.keyManager.interface.encodeFunctionData( 'lsp20VerifyCall', - [context.accounts[2].address, 0, '0xaabbccdd'], // random arguments + [context.keyManager.address, context.accounts[2].address, 0, '0xaabbccdd'], // random arguments ); const executePayload = context.universalProfile.interface.encodeFunctionData('execute', [ @@ -1102,12 +1102,16 @@ export const shouldBehaveLikePermissionCall = ( const permissionValues = [ // permissions - PERMISSIONS.TRANSFERVALUE, - combinePermissions(PERMISSIONS.TRANSFERVALUE, PERMISSIONS.CALL), - PERMISSIONS.CALL, - PERMISSIONS.SIGN, - PERMISSIONS.SUPER_CALL, - PERMISSIONS.SUPER_TRANSFERVALUE, + combinePermissions(PERMISSIONS.TRANSFERVALUE, PERMISSIONS.EXECUTE_RELAY_CALL), + combinePermissions( + PERMISSIONS.TRANSFERVALUE, + PERMISSIONS.CALL, + PERMISSIONS.EXECUTE_RELAY_CALL, + ), + combinePermissions(PERMISSIONS.EXECUTE_RELAY_CALL, PERMISSIONS.CALL), + combinePermissions(PERMISSIONS.SIGN, PERMISSIONS.EXECUTE_RELAY_CALL), + combinePermissions(PERMISSIONS.SUPER_CALL, PERMISSIONS.EXECUTE_RELAY_CALL), + combinePermissions(PERMISSIONS.SUPER_TRANSFERVALUE, PERMISSIONS.EXECUTE_RELAY_CALL), // allowed calls, allowedCall, allowedCall, @@ -1267,9 +1271,9 @@ export const shouldBehaveLikePermissionCall = ( const permissionValues = [ // permissions - PERMISSIONS.CALL, - PERMISSIONS.SUPER_CALL, - PERMISSIONS.SIGN, + combinePermissions(PERMISSIONS.CALL, PERMISSIONS.EXECUTE_RELAY_CALL), + combinePermissions(PERMISSIONS.SUPER_CALL, PERMISSIONS.EXECUTE_RELAY_CALL), + combinePermissions(PERMISSIONS.SIGN, PERMISSIONS.EXECUTE_RELAY_CALL), // allowed calls, allowedCall, ]; diff --git a/tests/LSP6KeyManager/Interactions/PermissionDeploy.test.ts b/tests/LSP6KeyManager/Interactions/PermissionDeploy.test.ts index b83f8f804..8f19f3edf 100644 --- a/tests/LSP6KeyManager/Interactions/PermissionDeploy.test.ts +++ b/tests/LSP6KeyManager/Interactions/PermissionDeploy.test.ts @@ -54,10 +54,18 @@ export const shouldBehaveLikePermissionDeploy = ( const permissionsValues = [ ALL_PERMISSIONS, - PERMISSIONS.DEPLOY, - combinePermissions(PERMISSIONS.DEPLOY, PERMISSIONS.TRANSFERVALUE), - combinePermissions(PERMISSIONS.DEPLOY, PERMISSIONS.SUPER_TRANSFERVALUE), - PERMISSIONS.CALL, + combinePermissions(PERMISSIONS.DEPLOY, PERMISSIONS.EXECUTE_RELAY_CALL), + combinePermissions( + PERMISSIONS.DEPLOY, + PERMISSIONS.TRANSFERVALUE, + PERMISSIONS.EXECUTE_RELAY_CALL, + ), + combinePermissions( + PERMISSIONS.DEPLOY, + PERMISSIONS.SUPER_TRANSFERVALUE, + PERMISSIONS.EXECUTE_RELAY_CALL, + ), + combinePermissions(PERMISSIONS.CALL, PERMISSIONS.EXECUTE_RELAY_CALL), ]; await setupKeyManager(context, permissionKeys, permissionsValues); diff --git a/tests/LSP6KeyManager/Relay/ExecuteRelayCall.test.ts b/tests/LSP6KeyManager/Relay/ExecuteRelayCall.test.ts index ab6c0165e..29a71b9cc 100644 --- a/tests/LSP6KeyManager/Relay/ExecuteRelayCall.test.ts +++ b/tests/LSP6KeyManager/Relay/ExecuteRelayCall.test.ts @@ -45,7 +45,9 @@ export const shouldBehaveLikeExecuteRelayCall = ( let signer: SignerWithAddress, relayer: SignerWithAddress, random: SignerWithAddress, - signerNoAllowedCalls: SignerWithAddress; + signerNoAllowedCalls: SignerWithAddress, + signerWithoutExecuteRelayCall: SignerWithAddress; + const signerPrivateKey = LOCAL_PRIVATE_KEYS.ACCOUNT1; let targetContract: TargetContract; @@ -57,6 +59,7 @@ export const shouldBehaveLikeExecuteRelayCall = ( relayer = context.accounts[2]; signerNoAllowedCalls = context.accounts[3]; random = context.accounts[4]; + signerWithoutExecuteRelayCall = context.accounts[5]; targetContract = await new TargetContract__factory(context.accounts[0]).deploy(); @@ -66,11 +69,24 @@ export const shouldBehaveLikeExecuteRelayCall = ( ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + signer.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + signerNoAllowedCalls.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + signerWithoutExecuteRelayCall.address.substring(2), ]; + const allPermissionsWithoutExecuteRelayCall = ethers.utils.hexZeroPad( + BigNumber.from(ALL_PERMISSIONS) + .sub(BigNumber.from(PERMISSIONS.EXECUTE_RELAY_CALL)) + .toHexString(), + 32, + ); + const permissionsValues = [ ALL_PERMISSIONS, - combinePermissions(PERMISSIONS.CALL, PERMISSIONS.TRANSFERVALUE), + combinePermissions( + PERMISSIONS.CALL, + PERMISSIONS.TRANSFERVALUE, + PERMISSIONS.EXECUTE_RELAY_CALL, + ), combineAllowedCalls( [ combineCallTypes(CALLTYPE.VALUE, CALLTYPE.CALL), @@ -80,12 +96,74 @@ export const shouldBehaveLikeExecuteRelayCall = ( ['0xffffffff', '0xffffffff'], ['0xffffffff', '0xffffffff'], ), - combinePermissions(PERMISSIONS.CALL, PERMISSIONS.TRANSFERVALUE), + combinePermissions( + PERMISSIONS.CALL, + PERMISSIONS.TRANSFERVALUE, + PERMISSIONS.EXECUTE_RELAY_CALL, + ), + allPermissionsWithoutExecuteRelayCall, ]; await setupKeyManager(context, permissionKeys, permissionsValues); }); + describe('When signer does not have EXECUTE_RELAY_CALL permission', () => { + it('should revert', async () => { + const executeRelayCallPayload = context.universalProfile.interface.encodeFunctionData( + 'execute', + [OPERATION_TYPES.CALL, random.address, 0, '0x'], + ); + + const latestNonce = await context.keyManager.callStatic.getNonce( + signerWithoutExecuteRelayCall.address, + 0, + ); + + const validityTimestamps = 0; + const signedMessageParams = { + lsp25Version: LSP25_VERSION, + chainId: 31337, // HARDHAT_CHAINID + nonce: latestNonce, + validityTimestamps, + msgValue: 0, + payload: executeRelayCallPayload, + }; + + const encodedMessage = ethers.utils.solidityPack( + ['uint256', 'uint256', 'uint256', 'uint256', 'uint256', 'bytes'], + [ + signedMessageParams.lsp25Version, + signedMessageParams.chainId, + signedMessageParams.nonce, + signedMessageParams.validityTimestamps, + signedMessageParams.msgValue, + signedMessageParams.payload, + ], + ); + + const eip191Signer = new EIP191Signer(); + + const { signature } = await eip191Signer.signDataWithIntendedValidator( + context.keyManager.address, + encodedMessage, + LOCAL_PRIVATE_KEYS.ACCOUNT5, + ); + + await expect( + context.keyManager + .connect(relayer) + .executeRelayCall( + signature, + signedMessageParams.nonce, + signedMessageParams.validityTimestamps, + signedMessageParams.payload, + { value: 0 }, + ), + ) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(signerWithoutExecuteRelayCall.address, 'EXECUTE_RELAY_CALL'); + }); + }); describe('When testing signed message', () => { describe('When testing msg.value', () => { describe('When sending more than the signed msg.value', () => { @@ -1241,7 +1319,7 @@ export const shouldBehaveLikeExecuteRelayCall = ( ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + minter.address.substring(2), ], [ - PERMISSIONS.CALL, + combinePermissions(PERMISSIONS.CALL, PERMISSIONS.EXECUTE_RELAY_CALL), combineAllowedCalls( [CALLTYPE.CALL], [tokenContract.address], diff --git a/tests/LSP6KeyManager/Relay/MultiChannelNonce.test.ts b/tests/LSP6KeyManager/Relay/MultiChannelNonce.test.ts index 228cc35bf..6c8ab53b0 100644 --- a/tests/LSP6KeyManager/Relay/MultiChannelNonce.test.ts +++ b/tests/LSP6KeyManager/Relay/MultiChannelNonce.test.ts @@ -18,7 +18,7 @@ import { // setup import { LSP6TestContext } from '../../utils/context'; import { setupKeyManager } from '../../utils/fixtures'; -import { LOCAL_PRIVATE_KEYS, combineAllowedCalls } from '../../utils/helpers'; +import { LOCAL_PRIVATE_KEYS, combineAllowedCalls, combinePermissions } from '../../utils/helpers'; export const shouldBehaveLikeMultiChannelNonce = (buildContext: () => Promise) => { let context: LSP6TestContext; @@ -42,7 +42,7 @@ export const shouldBehaveLikeMultiChannelNonce = (buildContext: () => Promise { const permissionValues = [ ALL_PERMISSIONS, - PERMISSIONS.CALL, + combinePermissions(PERMISSIONS.EXECUTE_RELAY_CALL, PERMISSIONS.CALL), combineAllowedCalls( // allow controller to call the 3 x addresses listed below [CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL], @@ -342,7 +374,7 @@ export const buildReentrancyContext = async (context: LSP6TestContext) => { ['0xffffffff', '0xffffffff', '0xffffffff'], ['0xffffffff', '0xffffffff', '0xffffffff'], ), - PERMISSIONS.CALL, + combinePermissions(PERMISSIONS.EXECUTE_RELAY_CALL, PERMISSIONS.CALL), combineAllowedCalls( // allow controller to call the 3 x addresses listed below [CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL], diff --git a/tests/foundry/LSP6KeyManager/LSP6SetDataTest.t.sol b/tests/foundry/LSP6KeyManager/LSP6SetDataTest.t.sol index f8e4901f8..0f8ef3959 100644 --- a/tests/foundry/LSP6KeyManager/LSP6SetDataTest.t.sol +++ b/tests/foundry/LSP6KeyManager/LSP6SetDataTest.t.sol @@ -102,7 +102,12 @@ contract LSP6SetDataTest is Test { keyManager.execute(callData); // CHECK the LSP20 verification function reverts as well - keyManager.lsp20VerifyCall(malicious, 0, functionArgs); + keyManager.lsp20VerifyCall( + address(universalProfile), + malicious, + 0, + functionArgs + ); // CHECK it reverts when calling directly the Universal Profile universalProfile.setData(dataKey, dataValue); @@ -222,7 +227,12 @@ contract LSP6SetDataTest is Test { keyManager.execute(callData); // CHECK the LSP20 verification function reverts as well - keyManager.lsp20VerifyCall(malicious, 0, functionArgs); + keyManager.lsp20VerifyCall( + address(universalProfile), + malicious, + 0, + functionArgs + ); // CHECK it reverts when calling directly the Universal Profile universalProfile.setData(dataKey, dataValue); From ba501e25a7eb8db70c4d7e8926bfa41570ad4a14 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Wed, 27 Sep 2023 18:48:15 +0100 Subject: [PATCH 35/55] tests: change name from `owner` to `mainController` in LSP6 tests --- tests/Benchmark.test.ts | 136 +++++++++--------- ...P1UniversalReceiverDelegateUP.behaviour.ts | 8 +- .../PermissionChangeAddExtensions.test.ts | 27 ++-- .../LSP6/Admin/PermissionChangeAddURD.test.ts | 27 ++-- .../LSP6/Admin/PermissionChangeOwner.test.ts | 44 +++--- .../Interactions/AllowedAddresses.test.ts | 7 +- .../Interactions/AllowedStandards.test.ts | 13 +- .../LSP6/Interactions/OtherScenarios.test.ts | 5 +- .../LSP6/Interactions/PermissionCall.test.ts | 12 +- .../PermissionDelegateCall.test.ts | 11 +- .../Interactions/PermissionDeploy.test.ts | 7 +- .../Interactions/PermissionStaticCall.test.ts | 5 +- .../PermissionTransferValue.test.ts | 10 +- .../LSP6/Interactions/Security.test.ts | 24 ++-- .../LSP6/LSP20WithLSP6.test.ts | 17 ++- .../LSP6/LSP20WithLSP6Init.test.ts | 14 +- .../SetData/AllowedERC725YDataKeys.test.ts | 24 ++-- .../LSP6/SetData/PermissionSetData.test.ts | 16 ++- .../PermissionChangeAddController.test.ts | 53 ++++--- .../PermissionChangeAddExtensions.test.ts | 33 ++--- .../Admin/PermissionChangeAddURD.test.ts | 27 ++-- .../Admin/PermissionChangeOwner.test.ts | 63 ++++---- .../Admin/PermissionSign.test.ts | 3 +- .../Interactions/AllowedAddresses.test.ts | 7 +- .../Interactions/AllowedStandards.test.ts | 15 +- .../Interactions/BatchExecute.test.ts | 39 ++--- .../InvalidExecutePayloads.test.ts | 5 +- .../Interactions/PermissionCall.test.ts | 20 +-- .../PermissionDelegateCall.test.ts | 11 +- .../Interactions/PermissionDeploy.test.ts | 31 ++-- .../Interactions/PermissionStaticCall.test.ts | 20 ++- .../PermissionTransferValue.test.ts | 14 +- .../LSP6ControlledToken.test.ts | 75 +++++----- tests/LSP6KeyManager/LSP6KeyManager.test.ts | 29 ++-- .../LSP6KeyManager/LSP6KeyManagerInit.test.ts | 14 +- .../Relay/ExecuteRelayCall.test.ts | 36 ++--- .../Relay/MultiChannelNonce.test.ts | 3 +- .../SetData/AllowedERC725YDataKeys.test.ts | 27 ++-- .../SetData/PermissionSetData.test.ts | 18 +-- .../PermissionChangeAddController.test.ts | 43 +++--- .../internals/AllowedCalls.internal.ts | 24 ++-- .../internals/Execute.internal.ts | 11 +- .../internals/ReadPermissions.internal.ts | 13 +- .../internals/SetData.internal.ts | 9 +- tests/Mocks/KeyManagerExecutionCosts.test.ts | 20 ++- tests/Reentrancy/LSP20/reentrancyHelpers.ts | 2 +- tests/Reentrancy/LSP6/LSP6Reentrancy.test.ts | 27 ++-- tests/Reentrancy/LSP6/reentrancyHelpers.ts | 2 +- tests/Reentrancy/Reentrancy.test.ts | 17 ++- tests/Reentrancy/ReentrancyInit.test.ts | 14 +- tests/utils/context.ts | 4 +- tests/utils/fixtures.ts | 21 +-- 52 files changed, 640 insertions(+), 517 deletions(-) diff --git a/tests/Benchmark.test.ts b/tests/Benchmark.test.ts index 03ad2700f..302f0a722 100644 --- a/tests/Benchmark.test.ts +++ b/tests/Benchmark.test.ts @@ -35,7 +35,7 @@ import { BigNumber } from 'ethers'; export type UniversalProfileContext = { accounts: SignerWithAddress[]; - owner: SignerWithAddress; + mainController: SignerWithAddress; universalProfile: UniversalProfile; initialFunding?: BigNumber; }; @@ -46,27 +46,35 @@ function generateRandomData(length) { const buildLSP6TestContext = async (initialFunding?: BigNumber): Promise => { const accounts = await ethers.getSigners(); - const owner = accounts[0]; - - const universalProfile = await new UniversalProfile__factory(owner).deploy(owner.address, { - value: initialFunding, - }); - const keyManager = await new LSP6KeyManager__factory(owner).deploy(universalProfile.address); - - return { accounts, owner, universalProfile, keyManager }; + const mainController = accounts[0]; + + const universalProfile = await new UniversalProfile__factory(mainController).deploy( + mainController.address, + { + value: initialFunding, + }, + ); + const keyManager = await new LSP6KeyManager__factory(mainController).deploy( + universalProfile.address, + ); + + return { accounts, mainController, universalProfile, keyManager }; }; const buildUniversalProfileContext = async ( initialFunding?: BigNumber, ): Promise => { const accounts = await ethers.getSigners(); - const owner = accounts[0]; + const mainController = accounts[0]; - const universalProfile = await new UniversalProfile__factory(owner).deploy(owner.address, { - value: initialFunding, - }); + const universalProfile = await new UniversalProfile__factory(mainController).deploy( + mainController.address, + { + value: initialFunding, + }, + ); - return { accounts, owner, universalProfile }; + return { accounts, mainController, universalProfile }; }; describe('⛽📊 Gas Benchmark', () => { @@ -154,7 +162,7 @@ describe('⛽📊 Gas Benchmark', () => { it('Transfer 1 LYX to an EOA without data', async () => { const tx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .execute( OPERATION_TYPES.CALL, context.accounts[1].address, @@ -170,7 +178,7 @@ describe('⛽📊 Gas Benchmark', () => { it('Transfer 1 LYX to a UP without data', async () => { const tx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .execute( OPERATION_TYPES.CALL, context.universalProfile.address, @@ -186,7 +194,7 @@ describe('⛽📊 Gas Benchmark', () => { it('Transfer 1 LYX to an EOA with 256 bytes of data', async () => { const tx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .execute( OPERATION_TYPES.CALL, context.accounts[1].address, @@ -202,7 +210,7 @@ describe('⛽📊 Gas Benchmark', () => { it('Transfer 1 LYX to a UP with 256 bytes of data', async () => { const tx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .execute( OPERATION_TYPES.CALL, context.universalProfile.address, @@ -223,22 +231,22 @@ describe('⛽📊 Gas Benchmark', () => { before(async () => { context = await buildUniversalProfileContext(ethers.utils.parseEther('50')); - universalProfile1 = await new UniversalProfile__factory(context.owner).deploy( + universalProfile1 = await new UniversalProfile__factory(context.mainController).deploy( context.accounts[2].address, ); - universalProfile2 = await new UniversalProfile__factory(context.owner).deploy( + universalProfile2 = await new UniversalProfile__factory(context.mainController).deploy( context.accounts[3].address, ); - universalProfile3 = await new UniversalProfile__factory(context.owner).deploy( + universalProfile3 = await new UniversalProfile__factory(context.mainController).deploy( context.accounts[4].address, ); }); it('Transfer 0.1 LYX to 3x EOA without data', async () => { const tx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .executeBatch( [OPERATION_TYPES.CALL, OPERATION_TYPES.CALL, OPERATION_TYPES.CALL], [ @@ -262,7 +270,7 @@ describe('⛽📊 Gas Benchmark', () => { it('Transfer 0.1 LYX to 3x UP without data', async () => { const tx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .executeBatch( [OPERATION_TYPES.CALL, OPERATION_TYPES.CALL, OPERATION_TYPES.CALL], [universalProfile1.address, universalProfile2.address, universalProfile3.address], @@ -282,7 +290,7 @@ describe('⛽📊 Gas Benchmark', () => { it('Transfer 0.1 LYX to 3x EOA with 256 bytes of data', async () => { const tx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .executeBatch( [OPERATION_TYPES.CALL, OPERATION_TYPES.CALL, OPERATION_TYPES.CALL], [ @@ -311,7 +319,7 @@ describe('⛽📊 Gas Benchmark', () => { ]); const tx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .executeBatch( [OPERATION_TYPES.CALL, OPERATION_TYPES.CALL, OPERATION_TYPES.CALL], [universalProfile1.address, universalProfile2.address, universalProfile3.address], @@ -539,22 +547,22 @@ describe('⛽📊 Gas Benchmark', () => { before(async () => { context = await buildUniversalProfileContext(ethers.utils.parseEther('50')); // deploy a LSP7 token - lsp7Token = await new LSP7Mintable__factory(context.owner).deploy( + lsp7Token = await new LSP7Mintable__factory(context.mainController).deploy( 'Token', 'MTKN', - context.owner.address, + context.mainController.address, false, ); // deploy a LSP8 token - lsp8Token = await new LSP8Mintable__factory(context.owner).deploy( + lsp8Token = await new LSP8Mintable__factory(context.mainController).deploy( 'My NFT', 'MNFT', - context.owner.address, + context.mainController.address, LSP8_TOKEN_ID_TYPES.UNIQUE_ID, ); - universalProfile1 = await new UniversalProfile__factory(context.owner).deploy( + universalProfile1 = await new UniversalProfile__factory(context.mainController).deploy( context.accounts[2].address, ); }); @@ -588,7 +596,7 @@ describe('⛽📊 Gas Benchmark', () => { ]); const tx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .execute(OPERATION_TYPES.CALL, lsp7Token.address, 0, lsp7TransferPayload); const receipt = await tx.wait(); @@ -639,7 +647,7 @@ describe('⛽📊 Gas Benchmark', () => { ]); const tx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .execute(OPERATION_TYPES.CALL, lsp8Token.address, 0, lsp8TransferPayload); const receipt = await tx.wait(); @@ -691,18 +699,18 @@ describe('⛽📊 Gas Benchmark', () => { ); // deploy a LSP7 token - lsp7MetaCoin = await new LSP7Mintable__factory(context.owner).deploy( + lsp7MetaCoin = await new LSP7Mintable__factory(context.mainController).deploy( 'MetaCoin', 'MTC', - context.owner.address, + context.mainController.address, false, ); // deploy a LSP8 NFT - lsp8MetaNFT = await new LSP8Mintable__factory(context.owner).deploy( + lsp8MetaNFT = await new LSP8Mintable__factory(context.mainController).deploy( 'MetaNFT', 'MNF', - context.owner.address, + context.mainController.address, LSP8_TOKEN_ID_TYPES.UNIQUE_ID, ); @@ -719,7 +727,7 @@ describe('⛽📊 Gas Benchmark', () => { const lyxAmount = ethers.utils.parseEther('3'); // prettier-ignore - const tx = await context.universalProfile.connect(context.owner).execute(OPERATION_TYPES.CALL, recipientEOA.address, lyxAmount, "0x"); + const tx = await context.universalProfile.connect(context.mainController).execute(OPERATION_TYPES.CALL, recipientEOA.address, lyxAmount, "0x"); const receipt = await tx.wait(); gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_1'][ @@ -731,7 +739,7 @@ describe('⛽📊 Gas Benchmark', () => { const lyxAmount = ethers.utils.parseEther('3'); // prettier-ignore - const tx = await context.universalProfile.connect(context.owner).execute(OPERATION_TYPES.CALL, aliceUP.address, lyxAmount, "0x"); + const tx = await context.universalProfile.connect(context.mainController).execute(OPERATION_TYPES.CALL, aliceUP.address, lyxAmount, "0x"); const receipt = await tx.wait(); gasBenchmark['runtime_costs']['KeyManager_owner']['execute']['case_2'][ @@ -743,7 +751,7 @@ describe('⛽📊 Gas Benchmark', () => { const tokenAmount = 100; // prettier-ignore - const tx = await context.universalProfile.connect(context.owner).execute( + const tx = await context.universalProfile.connect(context.mainController).execute( OPERATION_TYPES.CALL, lsp7MetaCoin.address, 0, @@ -766,7 +774,7 @@ describe('⛽📊 Gas Benchmark', () => { const tokenAmount = 100; // prettier-ignore - const tx = await context.universalProfile.connect(context.owner).execute( + const tx = await context.universalProfile.connect(context.mainController).execute( OPERATION_TYPES.CALL, lsp7MetaCoin.address, 0, @@ -789,7 +797,7 @@ describe('⛽📊 Gas Benchmark', () => { const nftId = nftList[0]; // prettier-ignore - const tx = await context.universalProfile.connect(context.owner).execute( + const tx = await context.universalProfile.connect(context.mainController).execute( OPERATION_TYPES.CALL, lsp8MetaNFT.address, 0, @@ -812,7 +820,7 @@ describe('⛽📊 Gas Benchmark', () => { const nftId = nftList[1]; // prettier-ignore - const tx = await context.universalProfile.connect(context.owner).execute( + const tx = await context.universalProfile.connect(context.mainController).execute( OPERATION_TYPES.CALL, lsp8MetaNFT.address, 0, @@ -878,17 +886,17 @@ describe('⛽📊 Gas Benchmark', () => { // LSP7 token transfer scenarios canTransferTwoTokens = context.accounts[3]; - lsp7MetaCoin = await new LSP7Mintable__factory(context.owner).deploy( + lsp7MetaCoin = await new LSP7Mintable__factory(context.mainController).deploy( 'MetaCoin', 'MTC', - context.owner.address, + context.mainController.address, false, ); - lsp7LyxDai = await new LSP7Mintable__factory(context.owner).deploy( + lsp7LyxDai = await new LSP7Mintable__factory(context.mainController).deploy( 'LyxDai', 'LDAI', - context.owner.address, + context.mainController.address, false, ); @@ -899,17 +907,17 @@ describe('⛽📊 Gas Benchmark', () => { // LSP8 NFT transfer scenarios canTransferTwoNFTs = context.accounts[4]; - lsp8MetaNFT = await new LSP8Mintable__factory(context.owner).deploy( + lsp8MetaNFT = await new LSP8Mintable__factory(context.mainController).deploy( 'MetaNFT', 'MNF', - context.owner.address, + context.mainController.address, LSP8_TOKEN_ID_TYPES.UNIQUE_ID, ); - lsp8LyxPunks = await new LSP8Mintable__factory(context.owner).deploy( + lsp8LyxPunks = await new LSP8Mintable__factory(context.mainController).deploy( 'LyxPunks', 'LPK', - context.owner.address, + context.mainController.address, LSP8_TOKEN_ID_TYPES.UNIQUE_ID, ); @@ -1123,10 +1131,10 @@ describe('⛽📊 Gas Benchmark', () => { // Set some JSONURL for LSP3Profile metadata to test gas cost of updating your profile details '0x6f357c6a70546a2accab18748420b63c63b5af4cf710848ae83afc0c51dd8ad17fb5e8b3697066733a2f2f516d65637247656a555156587057347a53393438704e76636e51724a314b69416f4d36626466725663575a736e35', ethers.utils.hexZeroPad(ethers.BigNumber.from(3).toHexString(), 16), - context.owner.address, + context.mainController.address, ]; - // The `context.owner` is given `ALL_PERMISSIONS` as the first data key through `setupKeyManager` method. + // The `context.mainController` is given `ALL_PERMISSIONS` as the first data key through `setupKeyManager` method. await setupKeyManager(context, permissionKeys, permissionValues); }); @@ -1137,7 +1145,7 @@ describe('⛽📊 Gas Benchmark', () => { '0x6f357c6a820464ddfac1bec070cc14a8daf04129871d458f2ca94368aae8391311af6361696670733a2f2f516d597231564a4c776572673670456f73636468564775676f3339706136727963455a4c6a7452504466573834554178'; const tx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setData(dataKey, dataValue); const receipt = await tx.wait(); @@ -1180,7 +1188,7 @@ describe('⛽📊 Gas Benchmark', () => { ]; const tx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setDataBatch(dataKeys, dataValues); const receipt = await tx.wait(); @@ -1202,7 +1210,7 @@ describe('⛽📊 Gas Benchmark', () => { const dataValue = combinePermissions(PERMISSIONS.SETDATA, PERMISSIONS.SUPER_SETDATA); const tx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setData(dataKey, dataValue); const receipt = await tx.wait(); @@ -1243,7 +1251,7 @@ describe('⛽📊 Gas Benchmark', () => { ]; const tx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setDataBatch(dataKeys, dataValues); const receipt = await tx.wait(); @@ -1276,7 +1284,7 @@ describe('⛽📊 Gas Benchmark', () => { ]; const tx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setDataBatch(issuedAssetsDataKeys, issuedAssetsDataValues); const receipt = await tx.wait(); @@ -1295,7 +1303,7 @@ describe('⛽📊 Gas Benchmark', () => { const dataValue = '0xaabbccdd'; const tx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setData(dataKey, dataValue); const receipt = await tx.wait(); @@ -1310,7 +1318,7 @@ describe('⛽📊 Gas Benchmark', () => { const dataValues = ['0xaabbccdd', '0xaabbccdd', '0xaabbccdd']; const tx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setDataBatch(dataKeys, dataValues); const receipt = await tx.wait(); @@ -1325,7 +1333,7 @@ describe('⛽📊 Gas Benchmark', () => { const dataValues = ['0xaabbccdd', '0xaabbccdd', '0xaabbccdd']; const tx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setDataBatch(dataKeys, dataValues); const receipt = await tx.wait(); @@ -1340,7 +1348,7 @@ describe('⛽📊 Gas Benchmark', () => { const dataValues = ['0xaabbccdd', '0xaabbccdd', '0xaabbccdd']; const tx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setDataBatch(dataKeys, dataValues); const receipt = await tx.wait(); @@ -1411,7 +1419,7 @@ describe('⛽📊 Gas Benchmark', () => { ]; const tx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setDataBatch(dataKeys, dataValues); const receipt = await tx.wait(); @@ -1459,7 +1467,7 @@ describe('⛽📊 Gas Benchmark', () => { // Set some JSONURL for LSP3Profile metadata to test gas cost of updating your profile details '0x6f357c6a70546a2accab18748420b63c63b5af4cf710848ae83afc0c51dd8ad17fb5e8b3697066733a2f2f516d65637247656a555156587057347a53393438704e76636e51724a314b69416f4d36626466725663575a736e35', ethers.utils.hexZeroPad(ethers.BigNumber.from(6).toHexString(), 16), - context.owner.address, + context.mainController.address, PERMISSIONS.SETDATA, encodeCompactBytesArray([ ERC725YDataKeys.LSP3.LSP3Profile, @@ -1477,7 +1485,7 @@ describe('⛽📊 Gas Benchmark', () => { ]), ]; - // The `context.owner` is given `ALL_PERMISSIONS` as the first data key through `setupKeyManager` method. + // The `context.mainController` is given `ALL_PERMISSIONS` as the first data key through `setupKeyManager` method. await setupKeyManager(context, permissionKeys, permissionValues); }); diff --git a/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP.behaviour.ts b/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP.behaviour.ts index 49c0a6d01..31ca3a20f 100644 --- a/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP.behaviour.ts +++ b/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP.behaviour.ts @@ -2785,7 +2785,7 @@ export const shouldBehaveLikeLSP1Delegate = ( testContext = { accounts: signerAddresses, - owner: profileOwner, + mainController: profileOwner, universalProfile: deployedUniversalProfile, keyManager: deployedKeyManager, }; @@ -2803,7 +2803,9 @@ export const shouldBehaveLikeLSP1Delegate = ( [ERC725YDataKeys.LSP1.LSP1UniversalReceiverDelegate, lsp1Delegate.address], ); - await testContext.keyManager.connect(testContext.owner).execute(setLSP1DelegatePayload); + await testContext.keyManager + .connect(testContext.mainController) + .execute(setLSP1DelegatePayload); }); it('check that the LSP9Vault address is not set under LSP10', async () => { @@ -2848,7 +2850,7 @@ export const shouldBehaveLikeLSP1Delegate = ( [OPERATION_TYPES.CALL, vault.address, 0, transferOwnershipPayload], ); - await testContext.keyManager.connect(testContext.owner).execute(executePayload); + await testContext.keyManager.connect(testContext.mainController).execute(executePayload); // check that the new vault owner is the pending owner expect(await vault.pendingOwner()).to.equal(newVaultOwner.address); diff --git a/tests/LSP20CallVerification/LSP6/Admin/PermissionChangeAddExtensions.test.ts b/tests/LSP20CallVerification/LSP6/Admin/PermissionChangeAddExtensions.test.ts index 75363c66e..7b96c5875 100644 --- a/tests/LSP20CallVerification/LSP6/Admin/PermissionChangeAddExtensions.test.ts +++ b/tests/LSP20CallVerification/LSP6/Admin/PermissionChangeAddExtensions.test.ts @@ -80,7 +80,8 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( canOnlyCall = context.accounts[6]; let permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + canAddAndChangeExtensions.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + @@ -126,7 +127,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( permissionArrayValues = [ ethers.utils.hexZeroPad(ethers.utils.hexlify(7), 16), - context.owner.address, + context.mainController.address, canAddAndChangeExtensions.address, canOnlyAddExtensions.address, canOnlyChangeExtensions.address, @@ -150,7 +151,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setData(payloadParam.dataKey, payloadParam.dataValue); const result = await context.universalProfile.getData(payloadParam.dataKey); @@ -164,7 +165,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setData(payloadParam.dataKey, payloadParam.dataValue); const result = await context.universalProfile.getData(payloadParam.dataKey); @@ -178,7 +179,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setData(payloadParam.dataKey, payloadParam.dataValue); const result = await context.universalProfile.getData(payloadParam.dataKey); @@ -348,7 +349,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setData(payloadParam.dataKey, payloadParam.dataValue); }); it('should NOT be allowed to ADD another ExtensionHandler key', async () => { @@ -407,7 +408,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setData(payloadParam.dataKey, payloadParam.dataValue); }); @@ -467,7 +468,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setData(payloadParam.dataKey, payloadParam.dataValue); }); @@ -535,7 +536,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setDataBatch(payloadParam.dataKeys, payloadParam.dataValues); const result = await context.universalProfile.getDataBatch(payloadParam.dataKeys); @@ -558,7 +559,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setDataBatch(payloadParam.dataKeys, payloadParam.dataValues); const result = await context.universalProfile.getDataBatch(payloadParam.dataKeys); @@ -577,7 +578,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setDataBatch(payloadParam.dataKeys, payloadParam.dataValues); const result = await context.universalProfile.getDataBatch(payloadParam.dataKeys); @@ -661,7 +662,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setDataBatch(payloadParam.dataKeys, payloadParam.dataValues); }); describe('when adding multiple ExtensionHandler keys', () => { @@ -936,7 +937,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setDataBatch(payloadParam.dataKeys, payloadParam.dataValues); }); describe('When adding ExtensionHandler key and one of his allowedERC725Y Data Key', () => { diff --git a/tests/LSP20CallVerification/LSP6/Admin/PermissionChangeAddURD.test.ts b/tests/LSP20CallVerification/LSP6/Admin/PermissionChangeAddURD.test.ts index 367d81cfb..d0dde441b 100644 --- a/tests/LSP20CallVerification/LSP6/Admin/PermissionChangeAddURD.test.ts +++ b/tests/LSP20CallVerification/LSP6/Admin/PermissionChangeAddURD.test.ts @@ -78,7 +78,8 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( canOnlyCall = context.accounts[6]; let permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + canAddAndChangeUniversalReceiverDelegate.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + @@ -128,7 +129,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( permissionArrayValues = [ ethers.utils.hexZeroPad(ethers.utils.hexlify(7), 16), - context.owner.address, + context.mainController.address, canAddAndChangeUniversalReceiverDelegate.address, canOnlyAddUniversalReceiverDelegate.address, canOnlyChangeUniversalReceiverDelegate.address, @@ -152,7 +153,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setData(payloadParam.dataKey, payloadParam.dataValue); const result = await context.universalProfile.getData(payloadParam.dataKey); @@ -166,7 +167,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setData(payloadParam.dataKey, payloadParam.dataValue); const result = await context.universalProfile.getData(payloadParam.dataKey); @@ -180,7 +181,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setData(payloadParam.dataKey, payloadParam.dataValue); const result = await context.universalProfile.getData(payloadParam.dataKey); @@ -362,7 +363,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setData(payloadParam.dataKey, payloadParam.dataValue); }); it('should NOT be allowed to ADD another UniversalReceiverDelegate key', async () => { @@ -421,7 +422,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setData(payloadParam.dataKey, payloadParam.dataValue); }); @@ -481,7 +482,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setData(payloadParam.dataKey, payloadParam.dataValue); }); @@ -549,7 +550,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setDataBatch(payloadParam.dataKeys, payloadParam.dataValues); const result = await context.universalProfile.getDataBatch(payloadParam.dataKeys); @@ -572,7 +573,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setDataBatch(payloadParam.dataKeys, payloadParam.dataValues); const result = await context.universalProfile.getDataBatch(payloadParam.dataKeys); @@ -591,7 +592,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setDataBatch(payloadParam.dataKeys, payloadParam.dataValues); const result = await context.universalProfile.getDataBatch(payloadParam.dataKeys); @@ -678,7 +679,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setDataBatch(payloadParam.dataKeys, payloadParam.dataValues); }); describe('when adding multiple UniversalReceiverDelegate keys', () => { @@ -981,7 +982,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( }; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setDataBatch(payloadParam.dataKeys, payloadParam.dataValues); }); describe('When adding UniversalReceiverDelegate key and one of his allowedERC725Y Data Key', () => { diff --git a/tests/LSP20CallVerification/LSP6/Admin/PermissionChangeOwner.test.ts b/tests/LSP20CallVerification/LSP6/Admin/PermissionChangeOwner.test.ts index 9fb87df9a..c89b0cc22 100644 --- a/tests/LSP20CallVerification/LSP6/Admin/PermissionChangeOwner.test.ts +++ b/tests/LSP20CallVerification/LSP6/Admin/PermissionChangeOwner.test.ts @@ -33,7 +33,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( canChangeOwner = context.accounts[1]; cannotChangeOwner = context.accounts[2]; - newKeyManager = await new LSP6KeyManager__factory(context.owner).deploy( + newKeyManager = await new LSP6KeyManager__factory(context.mainController).deploy( context.universalProfile.address, ); @@ -74,13 +74,13 @@ export const shouldBehaveLikePermissionChangeOwner = ( describe('when caller has ALL PERMISSIONS', () => { before('`transferOwnership(...)` to new Key Manager', async () => { await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .transferOwnership(newKeyManager.address); }); after('reset ownership', async () => { await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .transferOwnership(ethers.constants.AddressZero); }); @@ -93,7 +93,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( const ownerBefore = await context.universalProfile.owner(); await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .transferOwnership(newKeyManager.address); const ownerAfter = await context.universalProfile.owner(); @@ -107,7 +107,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( const key = '0xcafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe'; const value = '0xabcd'; - await context.universalProfile.connect(context.owner).setData(key, value); + await context.universalProfile.connect(context.mainController).setData(key, value); const result = await context.universalProfile.getData(key); expect(result).to.equal(value); @@ -121,7 +121,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( const accountBalanceBefore = await provider.getBalance(context.universalProfile.address); await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .execute(OPERATION_TYPES.CALL, recipient.address, amount, '0x'); const recipientBalanceAfter = await provider.getBalance(recipient.address); @@ -139,7 +139,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( const overridenPendingOwner = ethers.Wallet.createRandom().address; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .transferOwnership(overridenPendingOwner); const pendingOwner = await context.universalProfile.pendingOwner(); @@ -156,7 +156,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( after('reset ownership', async () => { await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .transferOwnership(ethers.constants.AddressZero); }); @@ -179,9 +179,9 @@ export const shouldBehaveLikePermissionChangeOwner = ( }); it('should override the pendingOwner when transferOwnership(...) is called twice', async () => { - const overridenPendingOwner = await new LSP6KeyManager__factory(context.owner).deploy( - context.universalProfile.address, - ); + const overridenPendingOwner = await new LSP6KeyManager__factory( + context.mainController, + ).deploy(context.universalProfile.address); await context.universalProfile .connect(canChangeOwner) @@ -201,9 +201,9 @@ export const shouldBehaveLikePermissionChangeOwner = ( const payload = context.universalProfile.interface.getSighash('acceptOwnership'); - await expect(notPendingKeyManager.connect(context.owner).execute(payload)).to.be.revertedWith( - 'LSP14: caller is not the pendingOwner', - ); + await expect( + notPendingKeyManager.connect(context.mainController).execute(payload), + ).to.be.revertedWith('LSP14: caller is not the pendingOwner'); }); }); @@ -212,7 +212,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( before(async () => { await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .transferOwnership(newKeyManager.address); pendingOwner = await context.universalProfile.pendingOwner(); @@ -220,7 +220,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( const acceptOwnershipPayload = context.universalProfile.interface.getSighash('acceptOwnership'); - await newKeyManager.connect(context.owner).execute(acceptOwnershipPayload); + await newKeyManager.connect(context.mainController).execute(acceptOwnershipPayload); }); it("should have change the account's owner to the pendingOwner (= pending KeyManager)", async () => { @@ -251,7 +251,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( value, ]); - await expect(oldKeyManager.connect(context.owner).execute(payload)) + await expect(oldKeyManager.connect(context.mainController).execute(payload)) .to.be.revertedWithCustomError(newKeyManager, 'NoPermissionsSet') .withArgs(oldKeyManager.address); }); @@ -267,7 +267,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( '0x', ]); - await expect(oldKeyManager.connect(context.owner).execute(payload)) + await expect(oldKeyManager.connect(context.mainController).execute(payload)) .to.be.revertedWithCustomError(newKeyManager, 'NoPermissionsSet') .withArgs(oldKeyManager.address); }); @@ -283,7 +283,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( value, ]); - await newKeyManager.connect(context.owner).execute(payload); + await newKeyManager.connect(context.mainController).execute(payload); const result = await context.universalProfile.getData(key); expect(result).to.equal(value); @@ -303,7 +303,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( '0x', ]); - await newKeyManager.connect(context.owner).execute(payload); + await newKeyManager.connect(context.mainController).execute(payload); const recipientBalanceAfter = await provider.getBalance(recipient.address); const accountBalanceAfter = await provider.getBalance(context.universalProfile.address); @@ -325,7 +325,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( before(async () => { // 1st call renounceOwnershipFirstTx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .renounceOwnership(); // mine 200 blocks @@ -333,7 +333,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( // 2nd call renounceOwnershipSecondTx = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .renounceOwnership(); }); diff --git a/tests/LSP20CallVerification/LSP6/Interactions/AllowedAddresses.test.ts b/tests/LSP20CallVerification/LSP6/Interactions/AllowedAddresses.test.ts index 09c059816..fb76b459d 100644 --- a/tests/LSP20CallVerification/LSP6/Interactions/AllowedAddresses.test.ts +++ b/tests/LSP20CallVerification/LSP6/Interactions/AllowedAddresses.test.ts @@ -52,7 +52,8 @@ export const shouldBehaveLikeAllowedAddresses = (buildContext: () => Promise Promise Promise Promise Promise Promise Promise { it('ERC1271', async () => { const sampleHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes('Sample Message')); - const sampleSignature = await context.owner.signMessage('Sample Message'); + const sampleSignature = await context.mainController.signMessage('Sample Message'); const payload = signatureValidatorContract.interface.encodeFunctionData( 'isValidSignature', @@ -125,7 +126,7 @@ export const shouldBehaveLikeAllowedStandards = (buildContext: () => Promise Promise Promise) targetContract = await new TargetContract__factory(context.accounts[0]).deploy(); const permissionsKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + addressCanMakeCall.address.substring(2), ]; @@ -42,7 +43,7 @@ export const otherTestScenarios = (buildContext: () => Promise) await expect( context.universalProfile - .connect(context.owner) + .connect(context.mainController) .execute(INVALID_OPERATION_TYPE, targetContract.address, 0, targetPayload), ).to.be.revertedWithCustomError(context.universalProfile, 'ERC725X_UnknownOperationType'); }); diff --git a/tests/LSP20CallVerification/LSP6/Interactions/PermissionCall.test.ts b/tests/LSP20CallVerification/LSP6/Interactions/PermissionCall.test.ts index 4346ff2b6..ec906ccb9 100644 --- a/tests/LSP20CallVerification/LSP6/Interactions/PermissionCall.test.ts +++ b/tests/LSP20CallVerification/LSP6/Interactions/PermissionCall.test.ts @@ -330,7 +330,8 @@ export const shouldBehaveLikePermissionCall = ( targetContract = await new TargetContract__factory(context.accounts[0]).deploy(); const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + addressCanMakeCallNoAllowedCalls.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + @@ -365,7 +366,7 @@ export const shouldBehaveLikePermissionCall = ( const targetPayload = targetContract.interface.encodeFunctionData('setName', [argument]); await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .execute(OPERATION_TYPES.CALL, targetContract.address, 0, targetPayload); const result = await targetContract.callStatic.getName(); @@ -379,7 +380,7 @@ export const shouldBehaveLikePermissionCall = ( const targetContractPayload = targetContract.interface.encodeFunctionData('getName'); const result = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .callStatic.execute( OPERATION_TYPES.CALL, targetContract.address, @@ -397,7 +398,7 @@ export const shouldBehaveLikePermissionCall = ( const targetContractPayload = targetContract.interface.encodeFunctionData('getNumber'); const result = await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .callStatic.execute( OPERATION_TYPES.CALL, targetContract.address, @@ -486,7 +487,8 @@ export const shouldBehaveLikePermissionCall = ( context = await buildContext(); const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ]; const permissionValues = [ALL_PERMISSIONS]; diff --git a/tests/LSP20CallVerification/LSP6/Interactions/PermissionDelegateCall.test.ts b/tests/LSP20CallVerification/LSP6/Interactions/PermissionDelegateCall.test.ts index a67fd8d97..c4b5f09ec 100644 --- a/tests/LSP20CallVerification/LSP6/Interactions/PermissionDelegateCall.test.ts +++ b/tests/LSP20CallVerification/LSP6/Interactions/PermissionDelegateCall.test.ts @@ -35,12 +35,13 @@ export const shouldBehaveLikePermissionDelegateCall = ( addressCanDelegateCall = context.accounts[1]; addressCannotDelegateCall = context.accounts[2]; - erc725YDelegateCallContract = await new ERC725YDelegateCall__factory(context.owner).deploy( - context.universalProfile.address, - ); + erc725YDelegateCallContract = await new ERC725YDelegateCall__factory( + context.mainController, + ).deploy(context.universalProfile.address); const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + addressCanDelegateCall.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + @@ -70,7 +71,7 @@ export const shouldBehaveLikePermissionDelegateCall = ( await expect( context.universalProfile - .connect(context.owner) + .connect(context.mainController) .execute( OPERATION_TYPES.DELEGATECALL, erc725YDelegateCallContract.address, diff --git a/tests/LSP20CallVerification/LSP6/Interactions/PermissionDeploy.test.ts b/tests/LSP20CallVerification/LSP6/Interactions/PermissionDeploy.test.ts index 6d03d4306..f7232c6d3 100644 --- a/tests/LSP20CallVerification/LSP6/Interactions/PermissionDeploy.test.ts +++ b/tests/LSP20CallVerification/LSP6/Interactions/PermissionDeploy.test.ts @@ -29,7 +29,8 @@ export const shouldBehaveLikePermissionDeploy = (buildContext: () => Promise Promise Promise context.universalProfile - .connect(context.owner) + .connect(context.mainController) .execute(OPERATION_TYPES.CALL, recipient.address, amount, data), ).to.changeEtherBalances( [context.universalProfile.address, recipient.address], @@ -207,7 +208,7 @@ export const shouldBehaveLikePermissionTransferValue = ( const initialBalanceRecipient = await provider.getBalance(recipient.address); await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .execute(OPERATION_TYPES.CALL, recipient.address, ethers.utils.parseEther('3'), data); const newBalanceUP = await provider.getBalance(context.universalProfile.address); @@ -396,7 +397,8 @@ export const shouldBehaveLikePermissionTransferValue = ( ); const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + contractCanTransferValue.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + diff --git a/tests/LSP20CallVerification/LSP6/Interactions/Security.test.ts b/tests/LSP20CallVerification/LSP6/Interactions/Security.test.ts index 8df443a2f..61880dc6f 100644 --- a/tests/LSP20CallVerification/LSP6/Interactions/Security.test.ts +++ b/tests/LSP20CallVerification/LSP6/Interactions/Security.test.ts @@ -60,7 +60,8 @@ export const testSecurityScenarios = (buildContext: () => Promise Promise Promise Promise Promise { it('should allow the URD to use `setData(..)` through the LSP6', async () => { const universalReceiverDelegateDataUpdater = - await new UniversalReceiverDelegateDataUpdater__factory(context.owner).deploy(); + await new UniversalReceiverDelegateDataUpdater__factory(context.mainController).deploy(); const randomHardcodedKey = ethers.utils.keccak256( ethers.utils.toUtf8Bytes('some random data key'), @@ -180,7 +181,7 @@ export const testSecurityScenarios = (buildContext: () => Promise Promise Promise Promise Promise Promise { const buildTestContext = async (initialFunding?: BigNumber): Promise => { const accounts = await ethers.getSigners(); - const owner = accounts[0]; + const mainController = accounts[0]; - const universalProfile = await new UniversalProfile__factory(owner).deploy(owner.address, { - value: initialFunding, - }); + const universalProfile = await new UniversalProfile__factory(mainController).deploy( + mainController.address, + { + value: initialFunding, + }, + ); - const keyManager = await new LSP6KeyManager__factory(owner).deploy(universalProfile.address); + const keyManager = await new LSP6KeyManager__factory(mainController).deploy( + universalProfile.address, + ); - return { accounts, owner, universalProfile, keyManager, initialFunding }; + return { accounts, mainController, universalProfile, keyManager, initialFunding }; }; describe('when testing deployed contract', () => { diff --git a/tests/LSP20CallVerification/LSP6/LSP20WithLSP6Init.test.ts b/tests/LSP20CallVerification/LSP6/LSP20WithLSP6Init.test.ts index 4db9f0ddc..5d9729e17 100644 --- a/tests/LSP20CallVerification/LSP6/LSP20WithLSP6Init.test.ts +++ b/tests/LSP20CallVerification/LSP6/LSP20WithLSP6Init.test.ts @@ -12,21 +12,21 @@ import { shouldBehaveLikeLSP6 } from './LSP20WithLSP6.behaviour'; describe('LSP20 Init + LSP6 Init with proxy', () => { const buildProxyTestContext = async (initialFunding?: BigNumber): Promise => { const accounts = await ethers.getSigners(); - const owner = accounts[0]; + const mainController = accounts[0]; - const baseUP = await new UniversalProfileInit__factory(owner).deploy(); - const upProxy = await deployProxy(baseUP.address, owner); + const baseUP = await new UniversalProfileInit__factory(mainController).deploy(); + const upProxy = await deployProxy(baseUP.address, mainController); const universalProfile = await baseUP.attach(upProxy); - const baseKM = await new LSP6KeyManagerInit__factory(owner).deploy(); - const kmProxy = await deployProxy(baseKM.address, owner); + const baseKM = await new LSP6KeyManagerInit__factory(mainController).deploy(); + const kmProxy = await deployProxy(baseKM.address, mainController); const keyManager = await baseKM.attach(kmProxy); - return { accounts, owner, universalProfile, keyManager, initialFunding }; + return { accounts, mainController, universalProfile, keyManager, initialFunding }; }; const initializeProxy = async (context: LSP6TestContext) => { - await context.universalProfile['initialize(address)'](context.owner.address, { + await context.universalProfile['initialize(address)'](context.mainController.address, { value: context.initialFunding, }); diff --git a/tests/LSP20CallVerification/LSP6/SetData/AllowedERC725YDataKeys.test.ts b/tests/LSP20CallVerification/LSP6/SetData/AllowedERC725YDataKeys.test.ts index 5a70b2299..96b4735ce 100644 --- a/tests/LSP20CallVerification/LSP6/SetData/AllowedERC725YDataKeys.test.ts +++ b/tests/LSP20CallVerification/LSP6/SetData/AllowedERC725YDataKeys.test.ts @@ -38,7 +38,8 @@ export const shouldBehaveLikeAllowedERC725YDataKeys = ( controllerCanSetManyKeys = context.accounts[2]; const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + controllerCanSetOneKey.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + @@ -653,7 +654,7 @@ export const shouldBehaveLikeAllowedERC725YDataKeys = ( const key = ethers.utils.hexlify(ethers.utils.randomBytes(32)); const value = ethers.utils.hexlify(ethers.utils.toUtf8Bytes('Some data')); - await context.universalProfile.connect(context.owner).setData(key, value); + await context.universalProfile.connect(context.mainController).setData(key, value); const result = await context.universalProfile.getData(key); expect(result).to.equal(value); @@ -673,7 +674,7 @@ export const shouldBehaveLikeAllowedERC725YDataKeys = ( ethers.utils.hexlify(ethers.utils.toUtf8Bytes('Some data 3')), ]; - await context.universalProfile.connect(context.owner).setDataBatch(keys, values); + await context.universalProfile.connect(context.mainController).setDataBatch(keys, values); const result = await context.universalProfile.getDataBatch(keys); @@ -704,7 +705,8 @@ export const shouldBehaveLikeAllowedERC725YDataKeys = ( controllerCanSetMappingKeys = context.accounts[1]; const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + controllerCanSetMappingKeys.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + @@ -897,7 +899,7 @@ export const shouldBehaveLikeAllowedERC725YDataKeys = ( ); await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setData(randomMappingKey, randomMappingValue); const result = await context.universalProfile.getData(randomMappingKey); @@ -919,7 +921,7 @@ export const shouldBehaveLikeAllowedERC725YDataKeys = ( ]; await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setDataBatch(randomMappingKeys, randomMappingValues); const result = await context.universalProfile.getDataBatch(randomMappingKeys); @@ -952,7 +954,8 @@ export const shouldBehaveLikeAllowedERC725YDataKeys = ( controllerCanSetArrayKeys = context.accounts[1]; const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + controllerCanSetArrayKeys.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + @@ -1101,7 +1104,7 @@ export const shouldBehaveLikeAllowedERC725YDataKeys = ( const permissionKeys = [ ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - context.owner.address.substring(2), + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + controllerCanSetSomeKeys.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + @@ -1228,7 +1231,7 @@ export const shouldBehaveLikeAllowedERC725YDataKeys = ( const permissionKeys = [ ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - context.owner.address.substring(2), + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + controllerCanSetSomeKeys.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + @@ -1373,7 +1376,8 @@ export const shouldBehaveLikeAllowedERC725YDataKeys = ( controllerCanSetSomeKeys = context.accounts[1]; const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + controllerCanSetSomeKeys.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + diff --git a/tests/LSP20CallVerification/LSP6/SetData/PermissionSetData.test.ts b/tests/LSP20CallVerification/LSP6/SetData/PermissionSetData.test.ts index c9eb4d23e..d1ea42ea4 100644 --- a/tests/LSP20CallVerification/LSP6/SetData/PermissionSetData.test.ts +++ b/tests/LSP20CallVerification/LSP6/SetData/PermissionSetData.test.ts @@ -64,7 +64,8 @@ export const shouldBehaveLikePermissionSetData = (buildContext: () => Promise Promise Promise Promise Promise Promise { context = await buildContext(); - contractCanSetData = await new ExecutorLSP20__factory(context.owner).deploy( + contractCanSetData = await new ExecutorLSP20__factory(context.mainController).deploy( context.universalProfile.address, ); const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + contractCanSetData.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + diff --git a/tests/LSP20CallVerification/LSP6/SetPermissions/PermissionChangeAddController.test.ts b/tests/LSP20CallVerification/LSP6/SetPermissions/PermissionChangeAddController.test.ts index 73c05fbe6..2f0eb16b0 100644 --- a/tests/LSP20CallVerification/LSP6/SetPermissions/PermissionChangeAddController.test.ts +++ b/tests/LSP20CallVerification/LSP6/SetPermissions/PermissionChangeAddController.test.ts @@ -18,7 +18,7 @@ async function setupPermissions( permissionValues: string[], ) { await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setDataBatch(permissionsKeys, permissionValues); } @@ -27,7 +27,7 @@ async function setupPermissions( */ async function resetPermissions(context: LSP6TestContext, permissionsKeys: string[]) { await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .setDataBatch(permissionsKeys, Array(permissionsKeys.length).fill('0x')); } @@ -47,7 +47,10 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( await setupKeyManager( context, - [ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2)], + [ + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), + ], [ALL_PERMISSIONS], ); }); @@ -106,7 +109,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( permissionArrayValues = [ ethers.utils.hexZeroPad(ethers.utils.hexlify(6), 16), - context.owner.address, + context.mainController.address, canOnlyAddController.address, canOnlyEditPermissions.address, canOnlySetData.address, @@ -143,7 +146,9 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + newController.address.substr(2); - await context.universalProfile.connect(context.owner).setData(key, PERMISSIONS.SETDATA); + await context.universalProfile + .connect(context.mainController) + .setData(key, PERMISSIONS.SETDATA); // prettier-ignore const result = await context.universalProfile.getData(key); @@ -157,7 +162,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( const value = PERMISSIONS.SETDATA; - await context.universalProfile.connect(context.owner).setData(key, value); + await context.universalProfile.connect(context.mainController).setData(key, value); // prettier-ignore const result = await context.universalProfile.getData(key); @@ -174,7 +179,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( const value = ethers.utils.hexZeroPad(ethers.utils.hexlify(newLength), 16); - await context.universalProfile.connect(context.owner).setData(key, value); + await context.universalProfile.connect(context.mainController).setData(key, value); // prettier-ignore const result = await context.universalProfile.getData(key); @@ -190,7 +195,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( const value = ethers.utils.hexZeroPad(ethers.utils.hexlify(newLength), 16); - await context.universalProfile.connect(context.owner).setData(key, value); + await context.universalProfile.connect(context.mainController).setData(key, value); // prettier-ignore const result = await context.universalProfile.getData(key); @@ -205,7 +210,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( '00000000000000000000000000000006'; const value = ethers.Wallet.createRandom().address.toLowerCase(); - await context.universalProfile.connect(context.owner).setData(key, value); + await context.universalProfile.connect(context.mainController).setData(key, value); const result = await context.universalProfile.getData(key); expect(result).to.equal(value); @@ -219,7 +224,9 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( // set some random bytes under AddressPermissions[7] - await expect(context.universalProfile.connect(context.owner).setData(key, randomValue)) + await expect( + context.universalProfile.connect(context.mainController).setData(key, randomValue), + ) .to.be.revertedWithCustomError(context.keyManager, 'InvalidDataValuesForDataKeys') .withArgs(key, randomValue); }); @@ -232,7 +239,9 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( // set some random bytes under AddressPermissions[7] - await expect(context.universalProfile.connect(context.owner).setData(key, randomValue)) + await expect( + context.universalProfile.connect(context.mainController).setData(key, randomValue), + ) .to.be.revertedWithCustomError(context.keyManager, 'InvalidDataValuesForDataKeys') .withArgs(key, randomValue); }); @@ -248,7 +257,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( const value = randomWallet.address; - await context.universalProfile.connect(context.owner).setData(key, value); + await context.universalProfile.connect(context.mainController).setData(key, value); // prettier-ignore const result = await context.universalProfile.getData(key); @@ -263,7 +272,9 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( // set some random bytes under AddressPermissions[7] - await expect(context.universalProfile.connect(context.owner).setData(key, randomValue)) + await expect( + context.universalProfile.connect(context.mainController).setData(key, randomValue), + ) .to.be.revertedWithCustomError(context.keyManager, 'InvalidDataValuesForDataKeys') .withArgs(key, randomValue); }); @@ -276,7 +287,9 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( // set some random bytes under AddressPermissions[7] - await expect(context.universalProfile.connect(context.owner).setData(key, randomValue)) + await expect( + context.universalProfile.connect(context.mainController).setData(key, randomValue), + ) .to.be.revertedWithCustomError(context.keyManager, 'InvalidDataValuesForDataKeys') .withArgs(key, randomValue); }); @@ -290,7 +303,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( const value = '0x'; - await context.universalProfile.connect(context.owner).setData(key, value); + await context.universalProfile.connect(context.mainController).setData(key, value); // prettier-ignore const result = await context.universalProfile.getData(key); @@ -309,7 +322,9 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( // the value does not matter in the case of the test here const value = '0x0000000000000000000000000000000000000000000000000000000000000008'; - await expect(context.universalProfile.connect(context.owner).setData(key, value)) + await expect( + context.universalProfile.connect(context.mainController).setData(key, value), + ) .to.be.revertedWithCustomError(context.keyManager, 'NotRecognisedPermissionKey') .withArgs(key.toLowerCase()); }); @@ -906,7 +921,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( PERMISSIONS.SETDATA, ]; - await context.universalProfile.connect(context.owner).setDataBatch(keys, values); + await context.universalProfile.connect(context.mainController).setDataBatch(keys, values); // prettier-ignore const fetchedResult = await context.universalProfile.getDataBatch(keys); @@ -930,7 +945,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( combinePermissions(PERMISSIONS.SETDATA, PERMISSIONS.TRANSFERVALUE), ]; - await context.universalProfile.connect(context.owner).setDataBatch(keys, values); + await context.universalProfile.connect(context.mainController).setDataBatch(keys, values); // prettier-ignore const fetchedResult = await context.universalProfile.getDataBatch(keys); @@ -956,7 +971,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( combinePermissions(PERMISSIONS.SETDATA, PERMISSIONS.TRANSFERVALUE), ]; - await context.universalProfile.connect(context.owner).setDataBatch(keys, values); + await context.universalProfile.connect(context.mainController).setDataBatch(keys, values); // prettier-ignore const fetchedResult = await context.universalProfile.getDataBatch(keys); diff --git a/tests/LSP6KeyManager/Admin/PermissionChangeAddExtensions.test.ts b/tests/LSP6KeyManager/Admin/PermissionChangeAddExtensions.test.ts index dad51e43a..5cb9a7ab2 100644 --- a/tests/LSP6KeyManager/Admin/PermissionChangeAddExtensions.test.ts +++ b/tests/LSP6KeyManager/Admin/PermissionChangeAddExtensions.test.ts @@ -80,7 +80,8 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( canOnlyCall = context.accounts[6]; let permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + canAddAndChangeExtensions.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + @@ -126,7 +127,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( permissionArrayValues = [ ethers.utils.hexZeroPad(ethers.utils.hexlify(7), 16), - context.owner.address, + context.mainController.address, canAddAndChangeExtensions.address, canOnlyAddExtensions.address, canOnlyChangeExtensions.address, @@ -154,7 +155,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( payloadParam.dataValue, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); const result = await context.universalProfile.getData(payloadParam.dataKey); expect(result).to.equal(payloadParam.dataValue); @@ -171,7 +172,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( payloadParam.dataValue, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); const result = await context.universalProfile.getData(payloadParam.dataKey); expect(result).to.equal(payloadParam.dataValue); @@ -188,7 +189,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( payloadParam.dataValue, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); const result = await context.universalProfile.getData(payloadParam.dataKey); expect(result).to.equal(payloadParam.dataValue); @@ -212,7 +213,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( ]); await expect( - context.keyManager.connect(context.owner).execute(payload), + context.keyManager.connect(context.mainController).execute(payload), ).to.be.revertedWithCustomError( context.keyManager, 'KeyManagerCannotBeSetAsExtensionForLSP20Functions', @@ -237,7 +238,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( ]); await expect( - context.keyManager.connect(context.owner).execute(payload), + context.keyManager.connect(context.mainController).execute(payload), ).to.be.revertedWithCustomError( context.keyManager, 'KeyManagerCannotBeSetAsExtensionForLSP20Functions', @@ -268,7 +269,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( payloadParam.dataValues, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); const result = await context.universalProfile.getDataBatch(payloadParam.dataKeys); expect(result).to.deep.equal(payloadParam.dataValues); @@ -463,7 +464,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( payloadParam.dataValue, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); }); it('should NOT be allowed to ADD another ExtensionHandler key', async () => { const payloadParam = { @@ -528,7 +529,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( payloadParam.dataValue, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); }); it('should NOT be allowed to ADD another ExtensionHandler key even when ExtensionHandler key is allowed in AllowedERC725YDataKey', async () => { @@ -594,7 +595,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( payloadParam.dataValue, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); }); it('should NOT be allowed to ADD another ExtensionHandler key', async () => { @@ -668,7 +669,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( payloadParam.dataValues, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); const result = await context.universalProfile.getDataBatch(payloadParam.dataKeys); @@ -694,7 +695,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( payloadParam.dataValues, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); const result = await context.universalProfile.getDataBatch(payloadParam.dataKeys); @@ -716,7 +717,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( payloadParam.dataValues, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); const result = await context.universalProfile.getDataBatch(payloadParam.dataKeys); @@ -808,7 +809,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( payloadParam.dataValues, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); }); describe('when adding multiple ExtensionHandler keys', () => { it('should pass', async () => { @@ -1105,7 +1106,7 @@ export const shouldBehaveLikePermissionChangeOrAddExtensions = ( payloadParam.dataValues, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); }); describe('When adding ExtensionHandler key and one of his allowedERC725Y Data Key', () => { it('should pass', async () => { diff --git a/tests/LSP6KeyManager/Admin/PermissionChangeAddURD.test.ts b/tests/LSP6KeyManager/Admin/PermissionChangeAddURD.test.ts index d2ebf63da..8474edacf 100644 --- a/tests/LSP6KeyManager/Admin/PermissionChangeAddURD.test.ts +++ b/tests/LSP6KeyManager/Admin/PermissionChangeAddURD.test.ts @@ -78,7 +78,8 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( canOnlyCall = context.accounts[6]; let permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + canAddAndChangeUniversalReceiverDelegate.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + @@ -128,7 +129,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( permissionArrayValues = [ ethers.utils.hexZeroPad(ethers.utils.hexlify(7), 16), - context.owner.address, + context.mainController.address, canAddAndChangeUniversalReceiverDelegate.address, canOnlyAddUniversalReceiverDelegate.address, canOnlyChangeUniversalReceiverDelegate.address, @@ -156,7 +157,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( payloadParam.dataValue, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); const result = await context.universalProfile.getData(payloadParam.dataKey); expect(result).to.equal(payloadParam.dataValue); @@ -173,7 +174,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( payloadParam.dataValue, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); const result = await context.universalProfile.getData(payloadParam.dataKey); expect(result).to.equal(payloadParam.dataValue); @@ -190,7 +191,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( payloadParam.dataValue, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); const result = await context.universalProfile.getData(payloadParam.dataKey); expect(result).to.equal(payloadParam.dataValue); @@ -411,7 +412,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( payloadParam.dataValue, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); }); it('should NOT be allowed to ADD another UniversalReceiverDelegate key', async () => { const payloadParam = { @@ -476,7 +477,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( payloadParam.dataValue, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); }); it('should NOT be allowed to ADD another UniversalReceiverDelegate key even when UniversalReceiverDelegate key is allowed in AllowedERC725YDataKey', async () => { @@ -542,7 +543,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( payloadParam.dataValue, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); }); it('should NOT be allowed to ADD another UniversalReceiverDelegate key', async () => { @@ -616,7 +617,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( payloadParam.dataValues, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); const result = await context.universalProfile.getDataBatch(payloadParam.dataKeys); @@ -642,7 +643,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( payloadParam.dataValues, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); const result = await context.universalProfile.getDataBatch(payloadParam.dataKeys); @@ -664,7 +665,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( payloadParam.dataValues, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); const result = await context.universalProfile.getDataBatch(payloadParam.dataKeys); @@ -765,7 +766,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( payloadParam.dataValues, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); }); describe('when adding multiple UniversalReceiverDelegate keys', () => { it('should pass', async () => { @@ -1106,7 +1107,7 @@ export const shouldBehaveLikePermissionChangeOrAddURD = ( payloadParam.dataValues, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); }); describe('When adding UniversalReceiverDelegate key and one of his allowedERC725Y Data Key', () => { it('should pass', async () => { diff --git a/tests/LSP6KeyManager/Admin/PermissionChangeOwner.test.ts b/tests/LSP6KeyManager/Admin/PermissionChangeOwner.test.ts index a21d617a2..44aa2c626 100644 --- a/tests/LSP6KeyManager/Admin/PermissionChangeOwner.test.ts +++ b/tests/LSP6KeyManager/Admin/PermissionChangeOwner.test.ts @@ -35,7 +35,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( canChangeOwner = context.accounts[1]; cannotChangeOwner = context.accounts[2]; - newKeyManager = await new LSP6KeyManager__factory(context.owner).deploy( + newKeyManager = await new LSP6KeyManager__factory(context.mainController).deploy( context.universalProfile.address, ); @@ -86,11 +86,11 @@ export const shouldBehaveLikePermissionChangeOwner = ( describe('when caller has ALL PERMISSIONS', () => { before('`transferOwnership(...)` to new Key Manager', async () => { - await context.keyManager.connect(context.owner).execute(transferOwnershipPayload); + await context.keyManager.connect(context.mainController).execute(transferOwnershipPayload); }); after('reset ownership', async () => { - await context.keyManager.connect(context.owner).execute(resetOwnershipPayload); + await context.keyManager.connect(context.mainController).execute(resetOwnershipPayload); }); it('should have set newKeyManager as pendingOwner', async () => { @@ -106,7 +106,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( [newKeyManager.address], ); - await context.keyManager.connect(context.owner).execute(transferOwnershipPayload); + await context.keyManager.connect(context.mainController).execute(transferOwnershipPayload); const ownerAfter = await context.universalProfile.owner(); @@ -124,7 +124,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( value, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); const result = await context.universalProfile.getData(key); expect(result).to.equal(value); @@ -142,7 +142,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( ]); await expect( - context.keyManager.connect(context.owner).execute(payload), + context.keyManager.connect(context.mainController).execute(payload), ).to.changeEtherBalances([context.universalProfile, recipient], [`-${amount}`, amount]); }); }); @@ -151,7 +151,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( const overridenPendingOwner = ethers.Wallet.createRandom().address; await context.keyManager - .connect(context.owner) + .connect(context.mainController) .execute( context.universalProfile.interface.encodeFunctionData('transferOwnership', [ overridenPendingOwner, @@ -170,7 +170,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( }); after('reset ownership', async () => { - await context.keyManager.connect(context.owner).execute(resetOwnershipPayload); + await context.keyManager.connect(context.mainController).execute(resetOwnershipPayload); }); it('should have set newKeyManager as pendingOwner', async () => { @@ -195,9 +195,9 @@ export const shouldBehaveLikePermissionChangeOwner = ( }); it('should override the pendingOwner when transferOwnership(...) is called twice', async () => { - const overridenPendingOwner = await new LSP6KeyManager__factory(context.owner).deploy( - context.universalProfile.address, - ); + const overridenPendingOwner = await new LSP6KeyManager__factory( + context.mainController, + ).deploy(context.universalProfile.address); await context.keyManager .connect(canChangeOwner) @@ -215,7 +215,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( describe('when calling acceptOwnership(...) from a KeyManager that is not the pendingOwner', () => { before('`transferOwnership(...)` to new Key Manager', async () => { - await context.keyManager.connect(context.owner).execute(transferOwnershipPayload); + await context.keyManager.connect(context.mainController).execute(transferOwnershipPayload); }); it('should revert', async () => { @@ -225,9 +225,9 @@ export const shouldBehaveLikePermissionChangeOwner = ( const payload = context.universalProfile.interface.getSighash('acceptOwnership'); - await expect(notPendingKeyManager.connect(context.owner).execute(payload)).to.be.revertedWith( - 'LSP14: caller is not the pendingOwner', - ); + await expect( + notPendingKeyManager.connect(context.mainController).execute(payload), + ).to.be.revertedWith('LSP14: caller is not the pendingOwner'); }); }); @@ -236,7 +236,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( before('`transferOwnership(...)` to new Key Manager', async () => { await context.universalProfile - .connect(context.owner) + .connect(context.mainController) .transferOwnership(newKeyManager.address); pendingOwner = await context.universalProfile.pendingOwner(); @@ -244,7 +244,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( const acceptOwnershipPayload = context.universalProfile.interface.getSighash('acceptOwnership'); - await newKeyManager.connect(context.owner).execute(acceptOwnershipPayload); + await newKeyManager.connect(context.mainController).execute(acceptOwnershipPayload); }); it("should have change the account's owner to the pendingOwner (= pending KeyManager)", async () => { @@ -276,7 +276,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( value, ]); - await expect(oldKeyManager.connect(context.owner).execute(payload)) + await expect(oldKeyManager.connect(context.mainController).execute(payload)) .to.be.revertedWithCustomError(newKeyManager, 'NoPermissionsSet') .withArgs(oldKeyManager.address); }); @@ -292,7 +292,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( '0x', ]); - await expect(oldKeyManager.connect(context.owner).execute(payload)) + await expect(oldKeyManager.connect(context.mainController).execute(payload)) .to.be.revertedWithCustomError(newKeyManager, 'NoPermissionsSet') .withArgs(oldKeyManager.address); }); @@ -308,7 +308,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( value, ]); - await newKeyManager.connect(context.owner).execute(payload); + await newKeyManager.connect(context.mainController).execute(payload); const result = await context.universalProfile.getData(key); expect(result).to.equal(value); @@ -325,10 +325,9 @@ export const shouldBehaveLikePermissionChangeOwner = ( '0x', ]); - await expect(newKeyManager.connect(context.owner).execute(payload)).to.changeEtherBalances( - [recipient, context.universalProfile], - [amount, `-${amount}`], - ); + await expect( + newKeyManager.connect(context.mainController).execute(payload), + ).to.changeEtherBalances([recipient, context.universalProfile], [amount, `-${amount}`]); }); }); }); @@ -343,13 +342,17 @@ export const shouldBehaveLikePermissionChangeOwner = ( const payload = context.universalProfile.interface.getSighash('renounceOwnership'); // 1st call - renounceOwnershipFirstTx = await newKeyManager.connect(context.owner).execute(payload); + renounceOwnershipFirstTx = await newKeyManager + .connect(context.mainController) + .execute(payload); // mine 200 blocks await network.provider.send('hardhat_mine', [ethers.utils.hexValue(200)]); // 2nd call - renounceOwnershipSecondTx = await newKeyManager.connect(context.owner).execute(payload); + renounceOwnershipSecondTx = await newKeyManager + .connect(context.mainController) + .execute(payload); }); it('should emit `RenounceOwnershipStarted` on first call', async () => { @@ -397,7 +400,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( // ---------------------------------------------- // ------ 1st call ------ - const firstNonce = await context.keyManager.getNonce(context.owner.address, 0); + const firstNonce = await context.keyManager.getNonce(context.mainController.address, 0); const firstEncodedMessage = ethers.utils.solidityPack( ['uint256', 'uint256', 'uint256', 'uint256', 'uint256', 'bytes'], @@ -411,7 +414,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( ).signature; renounceOwnershipFirstTx = await context.keyManager - .connect(context.owner) + .connect(context.mainController) .executeRelayCall(firstSignature, firstNonce, validityTimestamps, payload, { value: valueToSend, }); @@ -421,7 +424,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( await network.provider.send('hardhat_mine', [ethers.utils.hexValue(200)]); // ------ 2nd call ------ - const secondNonce = await context.keyManager.getNonce(context.owner.address, 0); + const secondNonce = await context.keyManager.getNonce(context.mainController.address, 0); const secondEncodedMessage = ethers.utils.solidityPack( ['uint256', 'uint256', 'uint256', 'uint256', 'uint256', 'bytes'], @@ -435,7 +438,7 @@ export const shouldBehaveLikePermissionChangeOwner = ( ).signature; renounceOwnershipSecondTx = await context.keyManager - .connect(context.owner) + .connect(context.mainController) .executeRelayCall(secondSignature, secondNonce, validityTimestamps, payload, { value: valueToSend, }); diff --git a/tests/LSP6KeyManager/Admin/PermissionSign.test.ts b/tests/LSP6KeyManager/Admin/PermissionSign.test.ts index 202197a16..f6a02ea7b 100644 --- a/tests/LSP6KeyManager/Admin/PermissionSign.test.ts +++ b/tests/LSP6KeyManager/Admin/PermissionSign.test.ts @@ -26,7 +26,8 @@ export const shouldBehaveLikePermissionSign = (buildContext: () => Promise Promise Promise Promise Promise Promise Promise Promise { it('ERC1271', async () => { const sampleHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes('Sample Message')); - const sampleSignature = await context.owner.signMessage('Sample Message'); + const sampleSignature = await context.mainController.signMessage('Sample Message'); const payload = signatureValidatorContract.interface.encodeFunctionData( 'isValidSignature', @@ -136,7 +137,9 @@ export const shouldBehaveLikeAllowedStandards = (buildContext: () => Promise Promise Promise Promise { // deploy a UP from another UP and check that the new UP is funded + its owner was set - const initialUpOwner = context.owner.address; + const initialUpOwner = context.mainController.address; // generate the init code that contains the constructor args with the initial UP owner const upDeploymentTx = new UniversalProfile__factory( @@ -120,10 +121,10 @@ export const shouldBehaveLikePermissionDeploy = ( // do first a callstatic to retrieve the address of the contract expected to be deployed // so we can check it against the address emitted in the ContractCreated event const expectedContractAddress = await context.keyManager - .connect(context.owner) + .connect(context.mainController) .callStatic.execute(payload); - await expect(context.keyManager.connect(context.owner).execute(payload)) + await expect(context.keyManager.connect(context.mainController).execute(payload)) .to.emit(context.universalProfile, 'ContractCreated') .withArgs( OPERATION_TYPES.CREATE, @@ -159,14 +160,14 @@ export const shouldBehaveLikePermissionDeploy = ( contractBytecodeToDeploy, ).toLowerCase(); - await expect(context.keyManager.connect(context.owner).execute(payload)) + await expect(context.keyManager.connect(context.mainController).execute(payload)) .to.emit(context.universalProfile, 'ContractCreated') .withArgs(OPERATION_TYPES.CREATE2, ethers.utils.getAddress(preComputedAddress), 0, salt); }); it('should be allowed to deploy + fund a contract with CREATE2', async () => { // deploy a UP from another UP and check that the new UP is funded + its owner was set - const initialUpOwner = context.owner.address; + const initialUpOwner = context.mainController.address; // generate the init code that contains the constructor args with the initial UP owner const upDeploymentTx = new UniversalProfile__factory( @@ -191,7 +192,7 @@ export const shouldBehaveLikePermissionDeploy = ( contractBytecodeToDeploy, ).toLowerCase(); - await expect(context.keyManager.connect(context.owner).execute(payload)) + await expect(context.keyManager.connect(context.mainController).execute(payload)) .to.emit(context.universalProfile, 'ContractCreated') .withArgs( OPERATION_TYPES.CREATE2, @@ -237,7 +238,7 @@ export const shouldBehaveLikePermissionDeploy = ( it('should revert with error `NotAuthorised(SUPER_TRANSFERVALUE)` when trying to deploy + fund a contract with CREATE', async () => { // deploy a UP from another UP and check that the new UP is funded + its owner was set - const initialUpOwner = context.owner.address; + const initialUpOwner = context.mainController.address; // generate the init code that contains the constructor args with the initial UP owner const upDeploymentTx = new UniversalProfile__factory( @@ -283,7 +284,7 @@ export const shouldBehaveLikePermissionDeploy = ( it('should revert with error `NotAuthorised(SUPER_TRANSFERVALUE)` when trying to deploy + fund a contract with CREATE2', async () => { // deploy a UP from another UP and check that the new UP is funded + its owner was set - const initialUpOwner = context.owner.address; + const initialUpOwner = context.mainController.address; // generate the init code that contains the constructor args with the initial UP owner const upDeploymentTx = new UniversalProfile__factory( @@ -337,7 +338,7 @@ export const shouldBehaveLikePermissionDeploy = ( it('should revert with error `NotAuthorised(SUPER_TRANSFERVALUE)` when trying to deploy + fund a contract with CREATE', async () => { // deploy a UP from another UP and check that the new UP is funded + its owner was set - const initialUpOwner = context.owner.address; + const initialUpOwner = context.mainController.address; // generate the init code that contains the constructor args with the initial UP owner const upDeploymentTx = new UniversalProfile__factory( @@ -383,7 +384,7 @@ export const shouldBehaveLikePermissionDeploy = ( it('should revert with error `NotAuthorised(SUPER_TRANSFERVALUE)` when trying to deploy + fund a contract with CREATE2', async () => { // deploy a UP from another UP and check that the new UP is funded + its owner was set - const initialUpOwner = context.owner.address; + const initialUpOwner = context.mainController.address; // generate the init code that contains the constructor args with the initial UP owner const upDeploymentTx = new UniversalProfile__factory( @@ -439,7 +440,7 @@ export const shouldBehaveLikePermissionDeploy = ( it('should be allowed to deploy + fund a contract with CREATE', async () => { // deploy a UP from another UP and check that the new UP is funded + its owner was set - const initialUpOwner = context.owner.address; + const initialUpOwner = context.mainController.address; // generate the init code that contains the constructor args with the initial UP owner const upDeploymentTx = new UniversalProfile__factory( @@ -509,7 +510,7 @@ export const shouldBehaveLikePermissionDeploy = ( it('should be allowed to deploy + fund a contract with CREATE2', async () => { // deploy a UP from another UP and check that the new UP is funded + its owner was set - const initialUpOwner = context.owner.address; + const initialUpOwner = context.mainController.address; // generate the init code that contains the constructor args with the initial UP owner const upDeploymentTx = new UniversalProfile__factory( diff --git a/tests/LSP6KeyManager/Interactions/PermissionStaticCall.test.ts b/tests/LSP6KeyManager/Interactions/PermissionStaticCall.test.ts index eab6894a9..28a4dd437 100644 --- a/tests/LSP6KeyManager/Interactions/PermissionStaticCall.test.ts +++ b/tests/LSP6KeyManager/Interactions/PermissionStaticCall.test.ts @@ -62,7 +62,8 @@ export const shouldBehaveLikePermissionStaticCall = ( ).deploy(); const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + addressCanMakeStaticCall.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + @@ -107,7 +108,7 @@ export const shouldBehaveLikePermissionStaticCall = ( ]); const result = await context.keyManager - .connect(context.owner) + .connect(context.mainController) .callStatic.execute(executePayload); const [decodedResult] = abiCoder.decode(['string'], result); @@ -162,7 +163,7 @@ export const shouldBehaveLikePermissionStaticCall = ( describe('when calling `isValidSignature(bytes32,bytes)` on a contract', () => { it('should pass and return data when `value` param is 0', async () => { const message = 'some message to sign'; - const signature = await context.owner.signMessage(message); + const signature = await context.mainController.signMessage(message); const messageHash = ethers.utils.hashMessage(message); const erc1271ContractPayload = signatureValidator.interface.encodeFunctionData( @@ -189,7 +190,7 @@ export const shouldBehaveLikePermissionStaticCall = ( const lyxAmount = ethers.utils.parseEther('3'); const message = 'some message to sign'; - const signature = await context.owner.signMessage(message); + const signature = await context.mainController.signMessage(message); const messageHash = ethers.utils.hashMessage(message); const erc1271ContractPayload = signatureValidator.interface.encodeFunctionData( @@ -219,8 +220,8 @@ export const shouldBehaveLikePermissionStaticCall = ( const onERC721Payload = onERC721ReceivedContract.interface.encodeFunctionData( 'onERC721Received', [ - context.owner.address, - context.owner.address, + context.mainController.address, + context.mainController.address, 1, ethers.utils.toUtf8Bytes('some data'), ], @@ -251,7 +252,12 @@ export const shouldBehaveLikePermissionStaticCall = ( // the params are not relevant for this test and just used as placeholders. const onERC721Payload = onERC721ReceivedContract.interface.encodeFunctionData( 'onERC721Received', - [context.owner.address, context.owner.address, 1, ethers.utils.toUtf8Bytes('some data')], + [ + context.mainController.address, + context.mainController.address, + 1, + ethers.utils.toUtf8Bytes('some data'), + ], ); const executePayload = context.universalProfile.interface.encodeFunctionData('execute', [ diff --git a/tests/LSP6KeyManager/Interactions/PermissionTransferValue.test.ts b/tests/LSP6KeyManager/Interactions/PermissionTransferValue.test.ts index 1fb62b25f..c59d65538 100644 --- a/tests/LSP6KeyManager/Interactions/PermissionTransferValue.test.ts +++ b/tests/LSP6KeyManager/Interactions/PermissionTransferValue.test.ts @@ -91,7 +91,8 @@ export const shouldBehaveLikePermissionTransferValue = ( ).to.equal(graffitiExtension.address); const permissionsKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + canTransferValue.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + @@ -149,7 +150,7 @@ export const shouldBehaveLikePermissionTransferValue = ( * @see https://hardhat.org/hardhat-chai-matchers/docs/reference#.changeetherbalances */ await expect( - context.keyManager.connect(context.owner).execute(transferPayload), + context.keyManager.connect(context.mainController).execute(transferPayload), ).to.changeEtherBalances( [context.universalProfile.address, recipient.address], [`-${amount}`, amount], @@ -231,7 +232,7 @@ export const shouldBehaveLikePermissionTransferValue = ( data, ]); - await context.keyManager.connect(context.owner).execute(transferPayload); + await context.keyManager.connect(context.mainController).execute(transferPayload); const newBalanceUP = await provider.getBalance(context.universalProfile.address); expect(newBalanceUP).to.be.lt(initialBalanceUP); @@ -384,7 +385,7 @@ export const shouldBehaveLikePermissionTransferValue = ( ); // ethereum signed message prefix - const signature = await context.owner.signMessage(encodedMessage); + const signature = await context.mainController.signMessage(encodedMessage); await expect( context.keyManager.executeRelayCall( @@ -434,7 +435,7 @@ export const shouldBehaveLikePermissionTransferValue = ( await expect( context.keyManager - .connect(context.owner) + .connect(context.mainController) .executeRelayCall(signature, 0, validityTimestamps, executeRelayCallPayload, { value: valueToSend, }), @@ -525,7 +526,8 @@ export const shouldBehaveLikePermissionTransferValue = ( ); const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + contractCanTransferValue.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + diff --git a/tests/LSP6KeyManager/LSP6ControlledToken.test.ts b/tests/LSP6KeyManager/LSP6ControlledToken.test.ts index c0a3e1fae..3254e30f2 100644 --- a/tests/LSP6KeyManager/LSP6ControlledToken.test.ts +++ b/tests/LSP6KeyManager/LSP6ControlledToken.test.ts @@ -20,7 +20,7 @@ export type LSP6ControlledToken = { accounts: SignerWithAddress[]; token: LSP7Mintable | LSP8Mintable; keyManager: LSP6KeyManager; - owner: SignerWithAddress; + mainController: SignerWithAddress; }; const buildContext = async () => { @@ -50,7 +50,7 @@ const buildContext = async () => { accounts, token: lsp7, keyManager, - owner: accounts[0], + mainController: accounts[0], }; }; @@ -71,7 +71,7 @@ const addControllerWithPermission = async ( const payload = context.token.interface.encodeFunctionData('setDataBatch', [keys, values]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); }; describe('When deploying LSP7 with LSP6 as owner', () => { @@ -107,10 +107,11 @@ describe('When deploying LSP7 with LSP6 as owner', () => { const keys = [ ERC725YDataKeys.LSP6['AddressPermissions[]'].length, ERC725YDataKeys.LSP6['AddressPermissions[]'].index + '0'.repeat(31) + '0', - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ]; - const values = [ARRAY_LENGTH.ONE, context.owner.address, ALL_PERMISSIONS]; + const values = [ARRAY_LENGTH.ONE, context.mainController.address, ALL_PERMISSIONS]; expect(await context.token.getDataBatch(keys)).to.deep.equal(values); }); @@ -119,13 +120,13 @@ describe('When deploying LSP7 with LSP6 as owner', () => { it('should revert because function does not exist on LSP6', async () => { const LSP7 = context.token as LSP7Mintable; const mintPayload = LSP7.interface.encodeFunctionData('mint', [ - context.owner.address, + context.mainController.address, 1, true, '0x', ]); - await expect(context.keyManager.connect(context.owner).execute(mintPayload)) + await expect(context.keyManager.connect(context.mainController).execute(mintPayload)) .to.be.revertedWithCustomError(context.keyManager, 'InvalidERC725Function') .withArgs(mintPayload.substring(0, 10)); }); @@ -136,7 +137,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { const renounceOwnershipPayload = context.token.interface.encodeFunctionData('renounceOwnership'); - await context.keyManager.connect(context.owner).execute(renounceOwnershipPayload); + await context.keyManager.connect(context.mainController).execute(renounceOwnershipPayload); expect(await context.token.owner()).to.equal(ethers.constants.AddressZero); }); @@ -153,7 +154,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { newOwner.address, ]); - await context.keyManager.connect(context.owner).execute(transferOwnershipPayload); + await context.keyManager.connect(context.mainController).execute(transferOwnershipPayload); expect(await context.token.owner()).to.equal(newOwner.address); }); @@ -163,9 +164,9 @@ describe('When deploying LSP7 with LSP6 as owner', () => { const value = ethers.utils.keccak256(ethers.utils.toUtf8Bytes('SecondRandomString')); const payload = context.token.interface.encodeFunctionData('setData', [key, value]); - await expect(context.keyManager.connect(context.owner).execute(payload)).to.be.revertedWith( - 'Ownable: caller is not the owner', - ); + await expect( + context.keyManager.connect(context.mainController).execute(payload), + ).to.be.revertedWith('Ownable: caller is not the owner'); }); it('should allow the new owner to call setData(..)', async () => { @@ -180,13 +181,13 @@ describe('When deploying LSP7 with LSP6 as owner', () => { it("`mint(..)` -> should revert with 'InvalidERC725Function' error.", async () => { const LSP7 = context.token as LSP7Mintable; const mintPayload = LSP7.interface.encodeFunctionData('mint', [ - context.owner.address, + context.mainController.address, 1, true, '0x', ]); - await expect(context.keyManager.connect(context.owner).execute(mintPayload)) + await expect(context.keyManager.connect(context.mainController).execute(mintPayload)) .to.be.revertedWithCustomError(context.keyManager, 'InvalidERC725Function') .withArgs(mintPayload.substring(0, 10)); }); @@ -194,9 +195,9 @@ describe('When deploying LSP7 with LSP6 as owner', () => { it('should allow the new owner to call mint(..)', async () => { const LSP7 = context.token as LSP7Mintable; - await LSP7.connect(newOwner).mint(context.owner.address, 1, true, '0x'); + await LSP7.connect(newOwner).mint(context.mainController.address, 1, true, '0x'); - expect(await LSP7.balanceOf(context.owner.address)).to.equal(1); + expect(await LSP7.balanceOf(context.mainController.address)).to.equal(1); }); it("`transferOwnership(..)` -> should revert with 'caller is not the owner' error.", async () => { @@ -206,7 +207,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { ); await expect( - context.keyManager.connect(context.owner).execute(transferOwnershipPayload), + context.keyManager.connect(context.mainController).execute(transferOwnershipPayload), ).to.be.revertedWith('Ownable: caller is not the owner'); }); @@ -221,7 +222,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { context.token.interface.encodeFunctionData('renounceOwnership'); await expect( - context.keyManager.connect(context.owner).execute(renounceOwnershipPayload), + context.keyManager.connect(context.mainController).execute(renounceOwnershipPayload), ).to.be.revertedWith('Ownable: caller is not the owner'); }); @@ -255,13 +256,13 @@ describe('When deploying LSP7 with LSP6 as owner', () => { ERC725YDataKeys.LSP6['AddressPermissions[]'].index + '0'.repeat(31) + '0', ERC725YDataKeys.LSP6['AddressPermissions[]'].index + '0'.repeat(31) + '1', ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - context.owner.address.substring(2), + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + addressCanChangeOwner.address.substring(2), ]; const values = [ ARRAY_LENGTH.TWO, - context.owner.address, + context.mainController.address, addressCanChangeOwner.address, ALL_PERMISSIONS, PERMISSIONS.CHANGEOWNER, @@ -320,7 +321,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { ERC725YDataKeys.LSP6['AddressPermissions[]'].index + '0'.repeat(31) + '1', ERC725YDataKeys.LSP6['AddressPermissions[]'].index + '0'.repeat(31) + '2', ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - context.owner.address.substring(2), + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + addressCanChangeOwner.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + @@ -328,7 +329,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { ]; const values = [ ARRAY_LENGTH.THREE, - context.owner.address, + context.mainController.address, addressCanChangeOwner.address, addressCanEditPermissions.address, ALL_PERMISSIONS, @@ -342,7 +343,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { it("should revert if caller doesn't have EDITPERMISSIONS permission", async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - context.owner.address.substring(2); + context.mainController.address.substring(2); const value = PERMISSIONS.CALL; const payload = context.token.interface.encodeFunctionData('setData', [key, value]); @@ -354,7 +355,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { it('should change ALL_PERMISSIONS to CALL permission of the address', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - context.owner.address.substring(2); + context.mainController.address.substring(2); const value = PERMISSIONS.CALL; const payload = context.token.interface.encodeFunctionData('setData', [key, value]); @@ -366,7 +367,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { it('should add back ALL_PERMISSIONS of the address', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - context.owner.address.substring(2); + context.mainController.address.substring(2); const value = ALL_PERMISSIONS; const payload = context.token.interface.encodeFunctionData('setData', [key, value]); @@ -396,7 +397,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { ERC725YDataKeys.LSP6['AddressPermissions[]'].index + '0'.repeat(31) + '2', ERC725YDataKeys.LSP6['AddressPermissions[]'].index + '0'.repeat(31) + '3', ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - context.owner.address.substring(2), + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + addressCanChangeOwner.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + @@ -406,7 +407,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { ]; const values = [ ARRAY_LENGTH.FOUR, - context.owner.address, + context.mainController.address, addressCanChangeOwner.address, addressCanEditPermissions.address, addressCanAddController.address, @@ -450,7 +451,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { const value = '0x'; const payload = context.token.interface.encodeFunctionData('setData', [key, value]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); }); }); @@ -485,7 +486,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { ERC725YDataKeys.LSP6['AddressPermissions[]'].index + '0'.repeat(31) + '3', ERC725YDataKeys.LSP6['AddressPermissions[]'].index + '0'.repeat(31) + '4', ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - context.owner.address.substring(2), + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + addressCanChangeOwner.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + @@ -497,7 +498,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { ]; const values = [ ARRAY_LENGTH.FIVE, - context.owner.address, + context.mainController.address, addressCanChangeOwner.address, addressCanEditPermissions.address, addressCanAddController.address, @@ -529,7 +530,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { const value = encodeCompactBytesArray([firstRandomSringKey.substring(0, 34)]); const payload = context.token.interface.encodeFunctionData('setData', [key, value]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); expect(await context.token.getData(key)).to.equal(value); }); @@ -592,14 +593,14 @@ describe('When deploying LSP7 with LSP6 as owner', () => { describe('when trying to call execute(..) function on LSP7 through LSP6', () => { it('should revert because function does not exist on LSP7', async () => { // deploying a dummy token contract with public mint function - const newTokenContract = await new LSP7Tester__factory(context.owner).deploy( + const newTokenContract = await new LSP7Tester__factory(context.mainController).deploy( 'NewTokenName', 'NewTokenSymbol', - context.owner.address, + context.mainController.address, ); // creating a payload to mint tokens in the new contract const mintPayload = newTokenContract.interface.encodeFunctionData('mint', [ - context.owner.address, + context.mainController.address, 1000, true, '0x', @@ -613,7 +614,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { ]); await expect( - context.keyManager.connect(context.owner).execute(payload), + context.keyManager.connect(context.mainController).execute(payload), ).to.be.revertedWithCustomError(newTokenContract, 'NoExtensionFoundForFunctionSelector'); }); }); @@ -640,7 +641,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { ERC725YDataKeys.LSP6['AddressPermissions[]'].index + '0'.repeat(31) + '4', ERC725YDataKeys.LSP6['AddressPermissions[]'].index + '0'.repeat(31) + '5', ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - context.owner.address.substring(2), + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + addressCanChangeOwner.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + @@ -654,7 +655,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { ]; const values = [ ARRAY_LENGTH.SIX, - context.owner.address, + context.mainController.address, addressCanChangeOwner.address, addressCanEditPermissions.address, addressCanAddController.address, diff --git a/tests/LSP6KeyManager/LSP6KeyManager.test.ts b/tests/LSP6KeyManager/LSP6KeyManager.test.ts index f2adeee39..d01ea7192 100644 --- a/tests/LSP6KeyManager/LSP6KeyManager.test.ts +++ b/tests/LSP6KeyManager/LSP6KeyManager.test.ts @@ -18,15 +18,20 @@ import { describe('LSP6KeyManager with constructor', () => { const buildTestContext = async (initialFunding?: BigNumber): Promise => { const accounts = await ethers.getSigners(); - const owner = accounts[0]; + const mainController = accounts[0]; - const universalProfile = await new UniversalProfile__factory(owner).deploy(owner.address, { - value: initialFunding, - }); + const universalProfile = await new UniversalProfile__factory(mainController).deploy( + mainController.address, + { + value: initialFunding, + }, + ); - const keyManager = await new LSP6KeyManager__factory(owner).deploy(universalProfile.address); + const keyManager = await new LSP6KeyManager__factory(mainController).deploy( + universalProfile.address, + ); - return { accounts, owner, universalProfile, keyManager, initialFunding }; + return { accounts, mainController, universalProfile, keyManager, initialFunding }; }; describe('when deploying the contract', () => { @@ -42,14 +47,16 @@ describe('LSP6KeyManager with constructor', () => { describe('testing internal functions', () => { testLSP6InternalFunctions(async () => { const accounts = await ethers.getSigners(); - const owner = accounts[0]; + const mainController = accounts[0]; - const universalProfile = await new UniversalProfile__factory(owner).deploy(owner.address); - const keyManagerInternalTester = await new KeyManagerInternalTester__factory(owner).deploy( - universalProfile.address, + const universalProfile = await new UniversalProfile__factory(mainController).deploy( + mainController.address, ); + const keyManagerInternalTester = await new KeyManagerInternalTester__factory( + mainController, + ).deploy(universalProfile.address); - return { owner, accounts, universalProfile, keyManagerInternalTester }; + return { mainController, accounts, universalProfile, keyManagerInternalTester }; }); }); }); diff --git a/tests/LSP6KeyManager/LSP6KeyManagerInit.test.ts b/tests/LSP6KeyManager/LSP6KeyManagerInit.test.ts index e2b46c20f..5d1869cb9 100644 --- a/tests/LSP6KeyManager/LSP6KeyManagerInit.test.ts +++ b/tests/LSP6KeyManager/LSP6KeyManagerInit.test.ts @@ -11,21 +11,21 @@ describe('LSP6KeyManager with proxy', () => { const buildProxyTestContext = async (initialFunding?: BigNumber): Promise => { const accounts = await ethers.getSigners(); - const owner = accounts[0]; + const mainController = accounts[0]; - const baseUP = await new UniversalProfileInit__factory(owner).deploy(); - const upProxy = await deployProxy(baseUP.address, owner); + const baseUP = await new UniversalProfileInit__factory(mainController).deploy(); + const upProxy = await deployProxy(baseUP.address, mainController); const universalProfile = await baseUP.attach(upProxy); - const baseKM = await new LSP6KeyManagerInit__factory(owner).deploy(); - const kmProxy = await deployProxy(baseKM.address, owner); + const baseKM = await new LSP6KeyManagerInit__factory(mainController).deploy(); + const kmProxy = await deployProxy(baseKM.address, mainController); const keyManager = await baseKM.attach(kmProxy); - return { accounts, owner, universalProfile, keyManager, initialFunding }; + return { accounts, mainController, universalProfile, keyManager, initialFunding }; }; const initializeProxies = async (context: LSP6TestContext) => { - await context.universalProfile['initialize(address)'](context.owner.address, { + await context.universalProfile['initialize(address)'](context.mainController.address, { value: context.initialFunding, }); diff --git a/tests/LSP6KeyManager/Relay/ExecuteRelayCall.test.ts b/tests/LSP6KeyManager/Relay/ExecuteRelayCall.test.ts index 29a71b9cc..a3c49da70 100644 --- a/tests/LSP6KeyManager/Relay/ExecuteRelayCall.test.ts +++ b/tests/LSP6KeyManager/Relay/ExecuteRelayCall.test.ts @@ -64,7 +64,8 @@ export const shouldBehaveLikeExecuteRelayCall = ( targetContract = await new TargetContract__factory(context.accounts[0]).deploy(); const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + signer.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + signer.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + @@ -1204,7 +1205,8 @@ export const shouldBehaveLikeExecuteRelayCall = ( ); const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ]; const permissionsValues = [ALL_PERMISSIONS]; @@ -1222,7 +1224,7 @@ export const shouldBehaveLikeExecuteRelayCall = ( await expect( context.keyManager - .connect(context.owner) + .connect(context.mainController) .executeRelayCallBatch(signatures, nonces, validityTimestamps, values, payloads), ).to.be.revertedWithCustomError( context.keyManager, @@ -1241,7 +1243,7 @@ export const shouldBehaveLikeExecuteRelayCall = ( '0x', ]); - const ownerNonce = await context.keyManager.getNonce(context.owner.address, 0); + const ownerNonce = await context.keyManager.getNonce(context.mainController.address, 0); const validityTimestamps = 0; @@ -1292,7 +1294,7 @@ export const shouldBehaveLikeExecuteRelayCall = ( // the incorrectly recovered address (as explained above) await expect( context.keyManager - .connect(context.owner) + .connect(context.mainController) .executeRelayCallBatch( [transferLyxSignature, transferLyxSignature], [ownerNonce, ownerNonce.add(1)], @@ -1330,7 +1332,7 @@ export const shouldBehaveLikeExecuteRelayCall = ( ], ); - const ownerNonce = await context.keyManager.getNonce(context.owner.address, 0); + const ownerNonce = await context.keyManager.getNonce(context.mainController.address, 0); const ownerGivePermissionsSignature = await signLSP6ExecuteRelayCall( context.keyManager, @@ -1389,7 +1391,7 @@ export const shouldBehaveLikeExecuteRelayCall = ( ); await context.keyManager - .connect(context.owner) + .connect(context.mainController) .executeRelayCallBatch( [ownerGivePermissionsSignature, minterMintSignature, ownerRemovePermissionsSignature], [ownerNonce, minterNonce, newOwnerNonce], @@ -1456,7 +1458,7 @@ export const shouldBehaveLikeExecuteRelayCall = ( [OPERATION_TYPES.CALL, thirdRecipient, transferAmounts[2], '0x'], ); - const ownerNonce = await context.keyManager.getNonce(context.owner.address, 0); + const ownerNonce = await context.keyManager.getNonce(context.mainController.address, 0); const validityTimestamps = 0; @@ -1487,7 +1489,7 @@ export const shouldBehaveLikeExecuteRelayCall = ( await expect( context.keyManager - .connect(context.owner) + .connect(context.mainController) .executeRelayCallBatch( [firstTransferLyxSignature, secondTransferLyxSignature, thirdTransferLyxSignature], [ownerNonce, ownerNonce.add(1), ownerNonce.add(2)], @@ -1542,7 +1544,7 @@ export const shouldBehaveLikeExecuteRelayCall = ( [OPERATION_TYPES.CALL, thirdRecipient, transferAmounts[2], '0x'], ); - const ownerNonce = await context.keyManager.getNonce(context.owner.address, 0); + const ownerNonce = await context.keyManager.getNonce(context.mainController.address, 0); const validityTimestamps = 0; @@ -1573,7 +1575,7 @@ export const shouldBehaveLikeExecuteRelayCall = ( await expect( context.keyManager - .connect(context.owner) + .connect(context.mainController) .executeRelayCallBatch( [firstTransferLyxSignature, secondTransferLyxSignature, thirdTransferLyxSignature], [ownerNonce, ownerNonce.add(1), ownerNonce.add(2)], @@ -1625,7 +1627,7 @@ export const shouldBehaveLikeExecuteRelayCall = ( [OPERATION_TYPES.CALL, thirdRecipient, transferAmounts[2], '0x'], ); - const ownerNonce = await context.keyManager.getNonce(context.owner.address, 0); + const ownerNonce = await context.keyManager.getNonce(context.mainController.address, 0); const validityTimestamps = 0; @@ -1655,7 +1657,7 @@ export const shouldBehaveLikeExecuteRelayCall = ( ); const tx = await context.keyManager - .connect(context.owner) + .connect(context.mainController) .executeRelayCallBatch( [firstTransferLyxSignature, secondTransferLyxSignature, thirdTransferLyxSignature], [ownerNonce, ownerNonce.add(1), ownerNonce.add(2)], @@ -1700,7 +1702,7 @@ export const shouldBehaveLikeExecuteRelayCall = ( [OPERATION_TYPES.CALL, randomRecipient, validAmount, '0x'], ); - const ownerNonce = await context.keyManager.getNonce(context.owner.address, 0); + const ownerNonce = await context.keyManager.getNonce(context.mainController.address, 0); const nonces = [ownerNonce, ownerNonce.add(1), ownerNonce.add(2)]; @@ -1738,7 +1740,7 @@ export const shouldBehaveLikeExecuteRelayCall = ( await expect( context.keyManager - .connect(context.owner) + .connect(context.mainController) .executeRelayCallBatch( signatures, nonces, @@ -1775,7 +1777,7 @@ export const shouldBehaveLikeExecuteRelayCall = ( [OPERATION_TYPES.CALL, randomRecipient, validAmount, '0x'], ); - const ownerNonce = await context.keyManager.getNonce(context.owner.address, 0); + const ownerNonce = await context.keyManager.getNonce(context.mainController.address, 0); const nonces = [ownerNonce, ownerNonce.add(1), ownerNonce.add(2)]; const values = [0, 0, 0]; @@ -1814,7 +1816,7 @@ export const shouldBehaveLikeExecuteRelayCall = ( await expect( context.keyManager - .connect(context.owner) + .connect(context.mainController) .executeRelayCallBatch( signatures, nonces, diff --git a/tests/LSP6KeyManager/Relay/MultiChannelNonce.test.ts b/tests/LSP6KeyManager/Relay/MultiChannelNonce.test.ts index 6c8ab53b0..cc4cf1050 100644 --- a/tests/LSP6KeyManager/Relay/MultiChannelNonce.test.ts +++ b/tests/LSP6KeyManager/Relay/MultiChannelNonce.test.ts @@ -35,7 +35,8 @@ export const shouldBehaveLikeMultiChannelNonce = (buildContext: () => Promise Promise Promise Promise Promise Promise Promise Promise { context = await buildContext(); - contractCanSetData = await new Executor__factory(context.owner).deploy( + contractCanSetData = await new Executor__factory(context.mainController).deploy( context.universalProfile.address, context.keyManager.address, ); const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + contractCanSetData.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + diff --git a/tests/LSP6KeyManager/SetPermissions/PermissionChangeAddController.test.ts b/tests/LSP6KeyManager/SetPermissions/PermissionChangeAddController.test.ts index da93c8b64..4551588f7 100644 --- a/tests/LSP6KeyManager/SetPermissions/PermissionChangeAddController.test.ts +++ b/tests/LSP6KeyManager/SetPermissions/PermissionChangeAddController.test.ts @@ -22,7 +22,7 @@ async function setupPermissions( permissionValues, ]); - await context.keyManager.connect(context.owner).execute(setupPayload); + await context.keyManager.connect(context.mainController).execute(setupPayload); } /** @@ -34,7 +34,7 @@ async function resetPermissions(context: LSP6TestContext, permissionsKeys: strin Array(permissionsKeys.length).fill('0x'), ]); - await context.keyManager.connect(context.owner).execute(teardownPayload); + await context.keyManager.connect(context.mainController).execute(teardownPayload); } export const shouldBehaveLikePermissionChangeOrAddController = ( @@ -135,7 +135,8 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( await setupKeyManager( context, [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ...firstSetupPermissionsKeys, ], [ALL_PERMISSIONS, ...firstSetupPermissionsValues], @@ -200,7 +201,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( permissionArrayValues = [ ethers.utils.hexZeroPad(ethers.utils.hexlify(6), 16), - context.owner.address, + context.mainController.address, canOnlyAddController.address, canOnlyEditPermissions.address, canOnlySetData.address, @@ -243,7 +244,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( PERMISSIONS.SETDATA, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); // prettier-ignore const result = await context.universalProfile.getData(key); @@ -262,7 +263,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( value, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); // prettier-ignore const result = await context.universalProfile.getData(key); @@ -280,7 +281,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( value, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); expect(await context.universalProfile.getData(key)).to.equal(value); }); @@ -295,7 +296,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( value, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); expect(await context.universalProfile.getData(key)).to.equal(value); }); @@ -314,7 +315,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( value, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); // prettier-ignore const result = await context.universalProfile.getData(key); @@ -335,7 +336,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( value, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); // prettier-ignore const result = await context.universalProfile.getData(key); @@ -353,7 +354,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( value, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); const result = await context.universalProfile.getData(key); expect(result).to.equal(value); @@ -369,7 +370,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( randomValue, ]); - await expect(context.keyManager.connect(context.owner).execute(setupPayload)) + await expect(context.keyManager.connect(context.mainController).execute(setupPayload)) .to.be.revertedWithCustomError(context.keyManager, 'InvalidDataValuesForDataKeys') .withArgs(key, randomValue); }); @@ -384,7 +385,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( randomValue, ]); - await expect(context.keyManager.connect(context.owner).execute(setupPayload)) + await expect(context.keyManager.connect(context.mainController).execute(setupPayload)) .to.be.revertedWithCustomError(context.keyManager, 'InvalidDataValuesForDataKeys') .withArgs(key, randomValue); }); @@ -403,7 +404,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( value, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); // prettier-ignore const result = await context.universalProfile.getData(key); @@ -420,7 +421,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( randomValue, ]); - await expect(context.keyManager.connect(context.owner).execute(setupPayload)) + await expect(context.keyManager.connect(context.mainController).execute(setupPayload)) .to.be.revertedWithCustomError(context.keyManager, 'InvalidDataValuesForDataKeys') .withArgs(key, randomValue); }); @@ -435,7 +436,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( randomValue, ]); - await expect(context.keyManager.connect(context.owner).execute(setupPayload)) + await expect(context.keyManager.connect(context.mainController).execute(setupPayload)) .to.be.revertedWithCustomError(context.keyManager, 'InvalidDataValuesForDataKeys') .withArgs(key, randomValue); }); @@ -452,7 +453,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( value, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); // prettier-ignore const result = await context.universalProfile.getData(key); @@ -476,7 +477,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( value, ]); - await expect(context.keyManager.connect(context.owner).execute(payload)) + await expect(context.keyManager.connect(context.mainController).execute(payload)) .to.be.revertedWithCustomError(context.keyManager, 'NotRecognisedPermissionKey') .withArgs(key.toLowerCase()); }); @@ -1285,7 +1286,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( values, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); // prettier-ignore const fetchedResult = await context.universalProfile.getDataBatch(keys); @@ -1314,7 +1315,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( values, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); // prettier-ignore const fetchedResult = await context.universalProfile.getDataBatch(keys); @@ -1345,7 +1346,7 @@ export const shouldBehaveLikePermissionChangeOrAddController = ( values, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); // prettier-ignore const fetchedResult = await context.universalProfile.getDataBatch(keys); diff --git a/tests/LSP6KeyManager/internals/AllowedCalls.internal.ts b/tests/LSP6KeyManager/internals/AllowedCalls.internal.ts index 26b6f5017..de2e1b21c 100644 --- a/tests/LSP6KeyManager/internals/AllowedCalls.internal.ts +++ b/tests/LSP6KeyManager/internals/AllowedCalls.internal.ts @@ -29,7 +29,7 @@ async function teardownKeyManagerHelper( Array(permissionsKeys.length).fill('0x'), ]); - await context.keyManagerInternalTester.connect(context.owner).execute(teardownPayload); + await context.keyManagerInternalTester.connect(context.mainController).execute(teardownPayload); } export const testAllowedCallsInternals = ( @@ -157,7 +157,8 @@ export const testAllowedCallsInternals = ( ); const permissionsKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + canCallOnlyTwoAddresses.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + @@ -184,13 +185,13 @@ export const testAllowedCallsInternals = ( it('should return no bytes when no allowed calls were set', async () => { const bytesResult = await context.keyManagerInternalTester.getAllowedCallsFor( - context.owner.address, + context.mainController.address, ); expect(bytesResult).to.equal('0x'); const resultFromAccount = await context.universalProfile['getData(bytes32)']( ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - context.owner.address.substring(2), + context.mainController.address.substring(2), ); expect(resultFromAccount).to.equal('0x'); }); @@ -333,7 +334,7 @@ export const testAllowedCallsInternals = ( permissionValues, ]); - await context.keyManagerInternalTester.connect(context.owner).execute(setup); + await context.keyManagerInternalTester.connect(context.mainController).execute(setup); }); after('reset permissions', async () => { @@ -444,7 +445,7 @@ export const testAllowedCallsInternals = ( permissionValues, ]); - await context.keyManagerInternalTester.connect(context.owner).execute(setup); + await context.keyManagerInternalTester.connect(context.mainController).execute(setup); }); after('reset permissions', async () => { @@ -555,7 +556,7 @@ export const testAllowedCallsInternals = ( permissionValues, ]); - await context.keyManagerInternalTester.connect(context.owner).execute(setup); + await context.keyManagerInternalTester.connect(context.mainController).execute(setup); }); after('reset permissions', async () => { @@ -674,7 +675,8 @@ export const testAllowedCallsInternals = ( ]; const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ...Object.values(controllers).map( (controller) => ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + @@ -775,7 +777,8 @@ export const testAllowedCallsInternals = ( context = await buildContext(); const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.accounts[1].address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + @@ -837,7 +840,8 @@ export const testAllowedCallsInternals = ( anyAllowedCalls = context.accounts[1]; const permissionsKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + anyAllowedCalls.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + diff --git a/tests/LSP6KeyManager/internals/Execute.internal.ts b/tests/LSP6KeyManager/internals/Execute.internal.ts index 9541523d6..e908e4d19 100644 --- a/tests/LSP6KeyManager/internals/Execute.internal.ts +++ b/tests/LSP6KeyManager/internals/Execute.internal.ts @@ -14,7 +14,8 @@ export const testExecuteInternals = (buildContext: () => Promise Promise Promise { expect( - await context.keyManagerInternalTester.getPermissionsFor(context.owner.address), + await context.keyManagerInternalTester.getPermissionsFor(context.mainController.address), ).to.equal(ALL_PERMISSIONS); // ALL_PERMISSIONS = "0xffff..." }); @@ -125,7 +126,8 @@ export const testReadingPermissionsInternals = ( addressCanSetData = context.accounts[1]; const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + addressCanSetData.address.substring(2), ]; @@ -164,7 +166,8 @@ export const testReadingPermissionsInternals = ( fourthBeneficiary = context.accounts[4]; let permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + firstBeneficiary.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + @@ -196,7 +199,7 @@ export const testReadingPermissionsInternals = ( // set AddressPermissions array values permissionArrayValues = [ '0x05', - context.owner.address, + context.mainController.address, firstBeneficiary.address, secondBeneficiary.address, thirdBeneficiary.address, diff --git a/tests/LSP6KeyManager/internals/SetData.internal.ts b/tests/LSP6KeyManager/internals/SetData.internal.ts index 4d56d2f13..b252504bf 100644 --- a/tests/LSP6KeyManager/internals/SetData.internal.ts +++ b/tests/LSP6KeyManager/internals/SetData.internal.ts @@ -13,7 +13,8 @@ export const testSetDataInternals = (buildContext: () => Promise Promise Promise Promise { describe('when using LSP6KeyManager with constructor', () => { const buildLSP6TestContext = async (): Promise => { const accounts = await ethers.getSigners(); - const owner = accounts[0]; + const mainController = accounts[0]; - const universalProfile = await new UniversalProfile__factory(owner).deploy(owner.address); - const keyManager = await new LSP6KeyManager__factory(owner).deploy(universalProfile.address); + const universalProfile = await new UniversalProfile__factory(mainController).deploy( + mainController.address, + ); + const keyManager = await new LSP6KeyManager__factory(mainController).deploy( + universalProfile.address, + ); - return { accounts, owner, universalProfile, keyManager }; + return { accounts, mainController, universalProfile, keyManager }; }; describe('after deploying the contract', () => { @@ -54,7 +58,7 @@ describe('Key Manager gas cost interactions', () => { const permissionKeys = [ ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - context.owner.address.substring(2), + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + restrictedToOneAddress.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + @@ -85,7 +89,7 @@ describe('Key Manager gas cost interactions', () => { await setupKeyManager(context, permissionKeys, permissionValues); - await context.owner.sendTransaction({ + await context.mainController.sendTransaction({ to: context.universalProfile.address, value: ethers.utils.parseEther('10'), }); @@ -107,7 +111,9 @@ describe('Key Manager gas cost interactions', () => { ], ); - const tx = await context.keyManager.connect(context.owner).execute(transferLyxPayload); + const tx = await context.keyManager + .connect(context.mainController) + .execute(transferLyxPayload); const receipt = await tx.wait(); diff --git a/tests/Reentrancy/LSP20/reentrancyHelpers.ts b/tests/Reentrancy/LSP20/reentrancyHelpers.ts index bdef32d0c..13495a86a 100644 --- a/tests/Reentrancy/LSP20/reentrancyHelpers.ts +++ b/tests/Reentrancy/LSP20/reentrancyHelpers.ts @@ -662,5 +662,5 @@ export const loadTestCase = async ( 'setDataBatch', [permissionKeys, permissionValues], ); - await context.keyManager.connect(context.owner).execute(permissionsPayload); + await context.keyManager.connect(context.mainController).execute(permissionsPayload); }; diff --git a/tests/Reentrancy/LSP6/LSP6Reentrancy.test.ts b/tests/Reentrancy/LSP6/LSP6Reentrancy.test.ts index d0d46c2f0..71cc74b75 100644 --- a/tests/Reentrancy/LSP6/LSP6Reentrancy.test.ts +++ b/tests/Reentrancy/LSP6/LSP6Reentrancy.test.ts @@ -68,7 +68,8 @@ export const shouldBehaveLikeLSP6ReentrancyScenarios = ( ); const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + signer.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + signer.address.substring(2), ]; @@ -95,7 +96,7 @@ export const shouldBehaveLikeLSP6ReentrancyScenarios = ( await setupKeyManager(context, permissionKeys, permissionValues); // Fund Universal Profile with some LYXe - await context.owner.sendTransaction({ + await context.mainController.sendTransaction({ to: context.universalProfile.address, value: ethers.utils.parseEther('10'), }); @@ -126,7 +127,7 @@ export const shouldBehaveLikeLSP6ReentrancyScenarios = ( // send LYX to malicious contract // at this point, the malicious contract receive function try to drain funds by re-entering the KeyManager // this should not be possible since it does not have the permission `REENTRANCY` - await expect(context.keyManager.connect(context.owner).execute(transferPayload)) + await expect(context.keyManager.connect(context.mainController).execute(transferPayload)) .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') .withArgs(maliciousContract.address, 'REENTRANCY'); @@ -207,13 +208,13 @@ export const shouldBehaveLikeLSP6ReentrancyScenarios = ( await maliciousContract.loadPayload(executePayload); - await expect(context.keyManager.connect(context.owner).execute(transferPayload)) + await expect(context.keyManager.connect(context.mainController).execute(transferPayload)) .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') .withArgs(maliciousContract.address, 'REENTRANCY'); }); it('should pass when reentered by URD and the URD has REENTRANCY permission', async () => { - const URDDummy = await new Reentrancy__factory(context.owner).deploy( + const URDDummy = await new Reentrancy__factory(context.mainController).deploy( context.keyManager.address, ); @@ -240,7 +241,7 @@ export const shouldBehaveLikeLSP6ReentrancyScenarios = ( ], ); - await context.keyManager.connect(context.owner).execute(setDataPayload); + await context.keyManager.connect(context.mainController).execute(setDataPayload); const transferPayload = context.universalProfile.interface.encodeFunctionData('execute', [ OPERATION_TYPES.CALL, @@ -258,7 +259,7 @@ export const shouldBehaveLikeLSP6ReentrancyScenarios = ( const initialAccountBalance = await provider.getBalance(context.universalProfile.address); const initialAttackerContractBalance = await provider.getBalance(maliciousContract.address); - await context.keyManager.connect(context.owner).execute(transferPayload); + await context.keyManager.connect(context.mainController).execute(transferPayload); const newAccountBalance = await provider.getBalance(context.universalProfile.address); const newAttackerContractBalance = await provider.getBalance(URDDummy.address); @@ -271,7 +272,7 @@ export const shouldBehaveLikeLSP6ReentrancyScenarios = ( it('should allow the URD to use `setData(..)` through the LSP6', async () => { const universalReceiverDelegateDataUpdater = - await new UniversalReceiverDelegateDataUpdater__factory(context.owner).deploy(); + await new UniversalReceiverDelegateDataUpdater__factory(context.mainController).deploy(); const randomHardcodedKey = ethers.utils.keccak256( ethers.utils.toUtf8Bytes('some random data key'), @@ -298,7 +299,7 @@ export const shouldBehaveLikeLSP6ReentrancyScenarios = ( ], ); - await context.keyManager.connect(context.owner).execute(setDataPayload); + await context.keyManager.connect(context.mainController).execute(setDataPayload); const universalReceiverDelegatePayload = universalReceiverDelegateDataUpdater.interface.encodeFunctionData('universalReceiver', [ @@ -313,7 +314,7 @@ export const shouldBehaveLikeLSP6ReentrancyScenarios = ( universalReceiverDelegatePayload, ]); - await context.keyManager.connect(context.owner).execute(executePayload); + await context.keyManager.connect(context.mainController).execute(executePayload); expect(await context.universalProfile.getData(randomHardcodedKey)).to.equal( randomHardcodedValue, @@ -336,7 +337,7 @@ export const shouldBehaveLikeLSP6ReentrancyScenarios = ( const permissionKeys = [ ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - context.owner.address.substring(2), + context.mainController.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + firstReentrant.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + @@ -366,7 +367,7 @@ export const shouldBehaveLikeLSP6ReentrancyScenarios = ( firstTargetSelector, ]); - await expect(context.keyManager.connect(context.owner).execute(payload)) + await expect(context.keyManager.connect(context.mainController).execute(payload)) .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') .withArgs(secondReentrant.address, 'REENTRANCY'); }); @@ -397,7 +398,7 @@ export const shouldBehaveLikeLSP6ReentrancyScenarios = ( firstTargetSelector, ]); - await context.keyManager.connect(context.owner).execute(payload); + await context.keyManager.connect(context.mainController).execute(payload); const result = await context.universalProfile['getData(bytes32)']( ethers.constants.HashZero, diff --git a/tests/Reentrancy/LSP6/reentrancyHelpers.ts b/tests/Reentrancy/LSP6/reentrancyHelpers.ts index cb4292540..b32efb594 100644 --- a/tests/Reentrancy/LSP6/reentrancyHelpers.ts +++ b/tests/Reentrancy/LSP6/reentrancyHelpers.ts @@ -664,5 +664,5 @@ export const loadTestCase = async ( 'setDataBatch', [permissionKeys, permissionValues], ); - await context.keyManager.connect(context.owner).execute(permissionsPayload); + await context.keyManager.connect(context.mainController).execute(permissionsPayload); }; diff --git a/tests/Reentrancy/Reentrancy.test.ts b/tests/Reentrancy/Reentrancy.test.ts index 70e6530ec..9ab0f7cb0 100644 --- a/tests/Reentrancy/Reentrancy.test.ts +++ b/tests/Reentrancy/Reentrancy.test.ts @@ -11,15 +11,20 @@ import { shouldBehaveLikeLSP20WithLSP6ReentrancyScenarios } from './LSP20/LSP20W describe('Reentrancy scenarios with constructor', () => { const buildTestContext = async (initialFunding?: BigNumber): Promise => { const accounts = await ethers.getSigners(); - const owner = accounts[0]; + const mainController = accounts[0]; - const universalProfile = await new UniversalProfile__factory(owner).deploy(owner.address, { - value: initialFunding, - }); + const universalProfile = await new UniversalProfile__factory(mainController).deploy( + mainController.address, + { + value: initialFunding, + }, + ); - const keyManager = await new LSP6KeyManager__factory(owner).deploy(universalProfile.address); + const keyManager = await new LSP6KeyManager__factory(mainController).deploy( + universalProfile.address, + ); - return { accounts, owner, universalProfile, keyManager, initialFunding }; + return { accounts, mainController, universalProfile, keyManager, initialFunding }; }; describe('when testing Reentrancy scenarios for LSP6', () => { diff --git a/tests/Reentrancy/ReentrancyInit.test.ts b/tests/Reentrancy/ReentrancyInit.test.ts index 0645d1819..2a3c0a33e 100644 --- a/tests/Reentrancy/ReentrancyInit.test.ts +++ b/tests/Reentrancy/ReentrancyInit.test.ts @@ -12,21 +12,21 @@ import { shouldBehaveLikeLSP20WithLSP6ReentrancyScenarios } from './LSP20/LSP20W describe('Reentrancy scenarios with proxy', () => { const buildProxyTestContext = async (initialFunding?: BigNumber): Promise => { const accounts = await ethers.getSigners(); - const owner = accounts[0]; + const mainController = accounts[0]; - const baseUP = await new UniversalProfileInit__factory(owner).deploy(); - const upProxy = await deployProxy(baseUP.address, owner); + const baseUP = await new UniversalProfileInit__factory(mainController).deploy(); + const upProxy = await deployProxy(baseUP.address, mainController); const universalProfile = await baseUP.attach(upProxy); - const baseKM = await new LSP6KeyManagerInit__factory(owner).deploy(); - const kmProxy = await deployProxy(baseKM.address, owner); + const baseKM = await new LSP6KeyManagerInit__factory(mainController).deploy(); + const kmProxy = await deployProxy(baseKM.address, mainController); const keyManager = await baseKM.attach(kmProxy); - return { accounts, owner, universalProfile, keyManager, initialFunding }; + return { accounts, mainController, universalProfile, keyManager, initialFunding }; }; const initializeProxies = async (context: LSP6TestContext) => { - await context.universalProfile['initialize(address)'](context.owner.address, { + await context.universalProfile['initialize(address)'](context.mainController.address, { value: context.initialFunding, }); diff --git a/tests/utils/context.ts b/tests/utils/context.ts index 266d1856c..7433a2ea6 100644 --- a/tests/utils/context.ts +++ b/tests/utils/context.ts @@ -4,7 +4,7 @@ import { KeyManagerInternalTester, LSP6KeyManager, UniversalProfile } from '../. export type LSP6TestContext = { accounts: SignerWithAddress[]; - owner: SignerWithAddress; + mainController: SignerWithAddress; universalProfile: UniversalProfile; keyManager: LSP6KeyManager; initialFunding?: BigNumber; @@ -12,7 +12,7 @@ export type LSP6TestContext = { export type LSP6InternalsTestContext = { accounts: SignerWithAddress[]; - owner: SignerWithAddress; + mainController: SignerWithAddress; universalProfile: UniversalProfile; keyManagerInternalTester: KeyManagerInternalTester; }; diff --git a/tests/utils/fixtures.ts b/tests/utils/fixtures.ts index 8b9934130..772b146d4 100644 --- a/tests/utils/fixtures.ts +++ b/tests/utils/fixtures.ts @@ -49,24 +49,25 @@ export async function setupKeyManager( _dataKeys: string[], _dataValues: string[], ) { - await _context.universalProfile.connect(_context.owner).setDataBatch( + await _context.universalProfile.connect(_context.mainController).setDataBatch( [ - // required to set owner permission so that it can acceptOwnership(...) via the KeyManager - // otherwise, the KeyManager will flag the calling owner as not having the permission CHANGEOWNER + // required to set main controller permission so that it can acceptOwnership(...) via the KeyManager + // otherwise, the KeyManager will flag the calling main controller as not having the permission CHANGEOWNER // when trying to setup the KeyManager - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + _context.owner.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + _context.mainController.address.substring(2), ..._dataKeys, ], [ALL_PERMISSIONS, ..._dataValues], ); await _context.universalProfile - .connect(_context.owner) + .connect(_context.mainController) .transferOwnership(_context.keyManager.address); const payload = _context.universalProfile.interface.getSighash('acceptOwnership'); - await _context.keyManager.connect(_context.owner).execute(payload); + await _context.keyManager.connect(_context.mainController).execute(payload); } export async function setupKeyManagerHelper( @@ -75,23 +76,23 @@ export async function setupKeyManagerHelper( _permissionsValues: string[], ) { await _context.universalProfile - .connect(_context.owner) + .connect(_context.mainController) .setDataBatch( [ ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - _context.owner.address.substring(2), + _context.mainController.address.substring(2), ..._permissionsKeys, ], [ALL_PERMISSIONS, ..._permissionsValues], ); await _context.universalProfile - .connect(_context.owner) + .connect(_context.mainController) .transferOwnership(_context.keyManagerInternalTester.address); const payload = _context.universalProfile.interface.getSighash('acceptOwnership'); - await _context.keyManagerInternalTester.connect(_context.owner).execute(payload); + await _context.keyManagerInternalTester.connect(_context.mainController).execute(payload); } /** From 0d43077a96b542f645d50cf9389f26c292c8b39e Mon Sep 17 00:00:00 2001 From: Jean Cvllr <31145285+CJ42@users.noreply.github.com> Date: Thu, 5 Oct 2023 14:57:40 +0100 Subject: [PATCH 36/55] fix: update logic to check against controller permissions when setting its Allowed Calls or ERC725Y Data Keys (#734) * fix: check against beneficiary permissions to set allowed calls and ERC725Y data keys * test: update tests to set Allowed Calls * test: update tests with new permission logic --- .../LSP6Modules/LSP6SetDataModule.sol | 46 +- .../LSP6KeyManager/LSP6KeyManager.md | 28 +- .../SetPermissions/SetAllowedCalls.test.ts | 767 ++++++----- .../SetAllowedERC725YDataKeys.test.ts | 385 +++--- .../SetPermissions/SetAllowedCalls.test.ts | 1116 +++++++++-------- .../SetAllowedERC725YDataKeys.test.ts | 494 ++++---- 6 files changed, 1538 insertions(+), 1298 deletions(-) diff --git a/contracts/LSP6KeyManager/LSP6Modules/LSP6SetDataModule.sol b/contracts/LSP6KeyManager/LSP6Modules/LSP6SetDataModule.sol index e89c1b382..ab623774e 100644 --- a/contracts/LSP6KeyManager/LSP6Modules/LSP6SetDataModule.sol +++ b/contracts/LSP6KeyManager/LSP6Modules/LSP6SetDataModule.sol @@ -446,11 +446,11 @@ abstract contract LSP6SetDataModule { } /** - * @dev retrieve the permission required to set some AllowedCalls for a controller. - * @param controlledContract the address of the ERC725Y contract where the data key is verified. - * @param dataKey `AddressPermissions:AllowedCalls:`. - * @param dataValue the updated value for the `dataKey`. MUST be a bytes28[CompactBytesArray] of Allowed Calls. - * @return either ADD or CHANGE PERMISSIONS. + * @dev Retrieve the permission required to set some AllowedCalls for a controller. + * @param controlledContract The address of the ERC725Y contract from which to fetch the value of `dataKey`. + * @param dataKey A data key ion the format `AddressPermissions:AllowedCalls:`. + * @param dataValue The updated value for the `dataKey`. MUST be a bytes32[CompactBytesArray] of Allowed Calls. + * @return Either ADD or EDIT PERMISSIONS. */ function _getPermissionToSetAllowedCalls( address controlledContract, @@ -466,23 +466,24 @@ abstract contract LSP6SetDataModule { // No permission required as CHECK is already done. We don't need to read `target` storage. if (hasBothAddControllerAndEditPermissions) return bytes32(0); - // if nothing is stored under the controller's Allowed Calls of the controller, - // we are trying to ADD a list of restricted calls (standards + address + function selector) - // - // if some data is already set under the Allowed Calls of the controller, - // we are trying to CHANGE (= edit) these restrictions. + // extract the address of the controller from the data key `AddressPermissions:AllowedCalls:` + address controller = address(bytes20(dataKey << 96)); + + // if the controller exists and has some permissions set, this is considered as EDIT a "sub-set" of its permissions. + // (even if the controller does not have any allowed calls set). return - ERC725Y(controlledContract).getData(dataKey).length == 0 + ERC725Y(controlledContract).getPermissionsFor(controller) == + bytes32(0) ? _PERMISSION_ADDCONTROLLER : _PERMISSION_EDITPERMISSIONS; } /** - * @dev retrieve the permission required to set some Allowed ERC725Y Data Keys for a controller. - * @param controlledContract the address of the ERC725Y contract where the data key is verified. - * @param dataKey or `AddressPermissions:AllowedERC725YDataKeys:`. - * @param dataValue the updated value for the `dataKey`. MUST be a bytes[CompactBytesArray] of Allowed ERC725Y Data Keys. - * @return either ADD or CHANGE PERMISSIONS. + * @dev Retrieve the permission required to set some Allowed ERC725Y Data Keys for a controller. + * @param controlledContract the address of the ERC725Y contract from which to fetch the value of `dataKey`. + * @param dataKey A data key in the format `AddressPermissions:AllowedERC725YDataKeys:`. + * @param dataValue The updated value for the `dataKey`. MUST be a bytes[CompactBytesArray] of Allowed ERC725Y Data Keys. + * @return Either ADD or EDIT PERMISSIONS. */ function _getPermissionToSetAllowedERC725YDataKeys( address controlledContract, @@ -501,13 +502,14 @@ abstract contract LSP6SetDataModule { // CHECK is already done. We don't need to read `target` storage. if (hasBothAddControllerAndEditPermissions) return bytes32(0); - // if there is nothing stored under the Allowed ERC725Y Data Keys of the controller, - // we are trying to ADD a list of restricted ERC725Y Data Keys. - // - // if there are already some data set under the Allowed ERC725Y Data Keys of the controller, - // we are trying to CHANGE (= edit) these restricted ERC725Y data keys. + // extract the address of the controller from the data key `AddressPermissions:AllowedERC725YDataKeys:` + address controller = address(bytes20(dataKey << 96)); + + // if the controller exists and has some permissions set, this is considered as EDIT a "sub-set" of its permissions. + // (even if the controller does not have any allowed ERC725Y data keys set). return - ERC725Y(controlledContract).getData(dataKey).length == 0 + ERC725Y(controlledContract).getPermissionsFor(controller) == + bytes32(0) ? _PERMISSION_ADDCONTROLLER : _PERMISSION_EDITPERMISSIONS; } diff --git a/docs/contracts/LSP6KeyManager/LSP6KeyManager.md b/docs/contracts/LSP6KeyManager/LSP6KeyManager.md index 90eef8aea..a316cd365 100644 --- a/docs/contracts/LSP6KeyManager/LSP6KeyManager.md +++ b/docs/contracts/LSP6KeyManager/LSP6KeyManager.md @@ -616,22 +616,22 @@ function _getPermissionToSetAllowedCalls( ) internal view returns (bytes32); ``` -retrieve the permission required to set some AllowedCalls for a controller. +Retrieve the permission required to set some AllowedCalls for a controller. #### Parameters | Name | Type | Description | | ---------------------------------------- | :-------: | ------------------------------------------------------------------------------------------- | -| `controlledContract` | `address` | the address of the ERC725Y contract where the data key is verified. | -| `dataKey` | `bytes32` | `AddressPermissions:AllowedCalls:`. | -| `dataValue` | `bytes` | the updated value for the `dataKey`. MUST be a bytes28[CompactBytesArray] of Allowed Calls. | +| `controlledContract` | `address` | The address of the ERC725Y contract from which to fetch the value of `dataKey`. | +| `dataKey` | `bytes32` | A data key ion the format `AddressPermissions:AllowedCalls:`. | +| `dataValue` | `bytes` | The updated value for the `dataKey`. MUST be a bytes32[CompactBytesArray] of Allowed Calls. | | `hasBothAddControllerAndEditPermissions` | `bool` | - | #### Returns -| Name | Type | Description | -| ---- | :-------: | --------------------------------- | -| `0` | `bytes32` | either ADD or CHANGE PERMISSIONS. | +| Name | Type | Description | +| ---- | :-------: | ------------------------------- | +| `0` | `bytes32` | Either ADD or EDIT PERMISSIONS. |
@@ -646,22 +646,22 @@ function _getPermissionToSetAllowedERC725YDataKeys( ) internal view returns (bytes32); ``` -retrieve the permission required to set some Allowed ERC725Y Data Keys for a controller. +Retrieve the permission required to set some Allowed ERC725Y Data Keys for a controller. #### Parameters | Name | Type | Description | | ---------------------------------------- | :-------: | ----------------------------------------------------------------------------------------------------- | -| `controlledContract` | `address` | the address of the ERC725Y contract where the data key is verified. | -| `dataKey` | `bytes32` | or `AddressPermissions:AllowedERC725YDataKeys:`. | -| `dataValue` | `bytes` | the updated value for the `dataKey`. MUST be a bytes[CompactBytesArray] of Allowed ERC725Y Data Keys. | +| `controlledContract` | `address` | the address of the ERC725Y contract from which to fetch the value of `dataKey`. | +| `dataKey` | `bytes32` | A data key in the format `AddressPermissions:AllowedERC725YDataKeys:`. | +| `dataValue` | `bytes` | The updated value for the `dataKey`. MUST be a bytes[CompactBytesArray] of Allowed ERC725Y Data Keys. | | `hasBothAddControllerAndEditPermissions` | `bool` | - | #### Returns -| Name | Type | Description | -| ---- | :-------: | --------------------------------- | -| `0` | `bytes32` | either ADD or CHANGE PERMISSIONS. | +| Name | Type | Description | +| ---- | :-------: | ------------------------------- | +| `0` | `bytes32` | Either ADD or EDIT PERMISSIONS. |
diff --git a/tests/LSP20CallVerification/LSP6/SetPermissions/SetAllowedCalls.test.ts b/tests/LSP20CallVerification/LSP6/SetPermissions/SetAllowedCalls.test.ts index 233cb7f17..7a77517f0 100644 --- a/tests/LSP20CallVerification/LSP6/SetPermissions/SetAllowedCalls.test.ts +++ b/tests/LSP20CallVerification/LSP6/SetPermissions/SetAllowedCalls.test.ts @@ -18,9 +18,10 @@ export const shouldBehaveLikeSetAllowedCalls = (buildContext: () => Promise { let canOnlyAddController: SignerWithAddress, canOnlyEditPermissions: SignerWithAddress; - let beneficiary: SignerWithAddress; - let invalidBytes: SignerWithAddress; - let noBytes: SignerWithAddress; + let beneficiaryWithPermissions: SignerWithAddress, + beneficiaryNoPermissions: SignerWithAddress, + invalidBytes: SignerWithAddress, + noBytes: SignerWithAddress; before(async () => { context = await buildContext(); @@ -28,18 +29,20 @@ export const shouldBehaveLikeSetAllowedCalls = (buildContext: () => Promise Promise Promise Promise { - it('should revert and not be allowed to clear the list of allowed calls for an address', async () => { - const dataKey = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - beneficiary.address.substring(2); - const dataValue = '0x'; + describe('when controller / beneficiary has some permissions', () => { + it('should revert and not be allowed to clear the list of allowed calls for an address', async () => { + const dataKey = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + beneficiaryWithPermissions.address.substring(2); + const dataValue = '0x'; - await expect( - context.universalProfile.connect(canOnlyAddController).setData(dataKey, dataValue), - ) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + await expect( + context.universalProfile.connect(canOnlyAddController).setData(dataKey, dataValue), + ) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + }); + }); + + describe('when controller / beneficiary has no permissions', () => { + it('should pass and set the list of allowed calls for an address', async () => { + const dataKey = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + beneficiaryNoPermissions.address.substring(2); + const dataValue = '0x'; + + await context.universalProfile.connect(canOnlyAddController).setData(dataKey, dataValue); + + expect(await context.universalProfile.getData(dataKey)).to.equal(dataValue); + }); }); }); - describe('when caller has CHANGE permission', () => { - it('should allow to clear the list of allowed calls for an address', async () => { - const dataKey = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - beneficiary.address.substring(2); - const dataValue = '0x'; + describe('when caller has EDIT permission', () => { + describe('when controller / beneficiary has some permissions', () => { + it('should allow to clear the list of allowed calls for an address', async () => { + const dataKey = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + beneficiaryWithPermissions.address.substring(2); + const dataValue = '0x'; + + await context.universalProfile + .connect(canOnlyEditPermissions) + .setData(dataKey, dataValue); - await context.universalProfile.connect(canOnlyEditPermissions).setData(dataKey, dataValue); + const result = await context.universalProfile.getData(dataKey); + expect(result).to.equal(dataValue); + }); + }); + + describe('when controller / beneficiary has no permissions', () => { + it("should revert with error `NotAuthorised('EDITPERMISSIONS')` when trying to clear the list of allowed calls for an address", async () => { + const dataKey = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + beneficiaryNoPermissions.address.substring(2); + const dataValue = '0x'; - const result = await context.universalProfile.getData(dataKey); - expect(result).to.equal(dataValue); + await expect( + context.universalProfile.connect(canOnlyEditPermissions).setData(dataKey, dataValue), + ) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyEditPermissions.address, 'ADDCONTROLLER'); + }); }); }); }); @@ -115,14 +167,16 @@ export const shouldBehaveLikeSetAllowedCalls = (buildContext: () => Promise Promise Promise Promise Promise Promise { - it('should fail when trying to edit existing allowed functions for an address', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - beneficiary.address.substring(2); - - const value = combineAllowedCalls( - // allow beneficiary to make a CALL to only function selectors 0xcafecafe and 0xf00df00d - [CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - ['0xffffffff', '0xffffffff'], - ['0xcafecafe', '0xf00df00d'], - ); - - await expect(context.universalProfile.connect(canOnlyAddController).setData(key, value)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); - }); - - it('should fail with NotAuthorised -> when beneficiary address had an invalid bytes28[CompactBytesArray] initially', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - invalidBeneficiary.address.substring(2); - - const value = combineAllowedCalls( - // allow beneficiary to make a CALL to only function selectors 0xcafecafe and 0xf00df00d - [CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - ['0xffffffff', '0xffffffff'], - ['0xcafecafe', '0xf00df00d'], - ); - - await expect(context.universalProfile.connect(canOnlyAddController).setData(key, value)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); - }); - - // Even if the controller had some 00 bytes set as allowed calls, it is not considered as it does not have any allowed calls set - // but rather that its allowed calls are "disabled" - describe('when beneficiary (= controller) had 00 bytes set initially as allowed calls (e.g: allowed calls disabled)', () => { - it('should fail with NotAuthorised -> when beneficiary had 32 x 0 bytes set initially as allowed calls', async () => { + describe('when controller to edit Allowed Calls for has some permissions set', () => { + it('should fail when trying to edit existing allowed functions for an address', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - zero32Bytes.address.substring(2); + beneficiary.address.substring(2); const value = combineAllowedCalls( - [CALLTYPE.VALUE, CALLTYPE.VALUE], - ['0xffffffff', '0xffffffff'], - ['0xcafecafe', '0xca11ca11'], + // allow beneficiary to make a CALL to only function selectors 0xcafecafe and 0xf00df00d + [CALLTYPE.CALL, CALLTYPE.CALL], [ '0xffffffffffffffffffffffffffffffffffffffff', '0xffffffffffffffffffffffffffffffffffffffff', ], + ['0xffffffff', '0xffffffff'], + ['0xcafecafe', '0xf00df00d'], ); await expect(context.universalProfile.connect(canOnlyAddController).setData(key, value)) @@ -556,49 +579,95 @@ export const shouldBehaveLikeSetAllowedCalls = (buildContext: () => Promise when beneficiary had 40 x 0 bytes set initially as allowed calls', async () => { + it('should fail with NotAuthorised -> when beneficiary address had an invalid bytes28[CompactBytesArray] initially', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - zero40Bytes.address.substring(2); + invalidBeneficiary.address.substring(2); const value = combineAllowedCalls( + // allow beneficiary to make a CALL to only function selectors 0xcafecafe and 0xf00df00d [CALLTYPE.CALL, CALLTYPE.CALL], [ '0xffffffffffffffffffffffffffffffffffffffff', '0xffffffffffffffffffffffffffffffffffffffff', ], ['0xffffffff', '0xffffffff'], - ['0xcafecafe', '0xca11ca11'], + ['0xcafecafe', '0xf00df00d'], ); await expect(context.universalProfile.connect(canOnlyAddController).setData(key, value)) .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); }); - }); - it('should pass when beneficiary had no values set under AddressPermissions:AllowedCalls:... + setting a valid bytes28[CompactBytesArray]', async () => { - const newController = ethers.Wallet.createRandom(); + // Even if the controller had some 00 bytes set as allowed calls, it is not considered as it does not have any allowed calls set + // but rather that its allowed calls are "disabled" + describe('when beneficiary (= controller) had 00 bytes set initially as allowed calls (e.g: allowed calls disabled)', () => { + it('should fail with NotAuthorised -> when beneficiary had 32 x 0 bytes set initially as allowed calls', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + zero32Bytes.address.substring(2); + + const value = combineAllowedCalls( + [CALLTYPE.VALUE, CALLTYPE.VALUE], + ['0xffffffff', '0xffffffff'], + ['0xcafecafe', '0xca11ca11'], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + ); + + await expect(context.universalProfile.connect(canOnlyAddController).setData(key, value)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + }); + + it('should fail with NotAuthorised -> when beneficiary had 40 x 0 bytes set initially as allowed calls', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + zero40Bytes.address.substring(2); + + const value = combineAllowedCalls( + [CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + ['0xffffffff', '0xffffffff'], + ['0xcafecafe', '0xca11ca11'], + ); + + await expect(context.universalProfile.connect(canOnlyAddController).setData(key, value)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + }); + }); - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + newController.address.substr(2); + it('should pass when beneficiary had no values set under AddressPermissions:AllowedCalls:... + setting a valid bytes28[CompactBytesArray]', async () => { + const newController = ethers.Wallet.createRandom(); - const value = combineAllowedCalls( - // allow beneficiary to CALL only function selectors 0xcafecafe and 0xf00df00d - [CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - ['0xffffffff', '0xffffffff'], - ['0xcafecafe', '0xf00df00d'], - ); + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + newController.address.substr(2); - await context.universalProfile.connect(canOnlyAddController).setData(key, value); + const value = combineAllowedCalls( + // allow beneficiary to CALL only function selectors 0xcafecafe and 0xf00df00d + [CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + ['0xffffffff', '0xffffffff'], + ['0xcafecafe', '0xf00df00d'], + ); - // prettier-ignore - const result = await context.universalProfile.getData(key); - expect(result).to.equal(value); + await context.universalProfile.connect(canOnlyAddController).setData(key, value); + + // prettier-ignore + const result = await context.universalProfile.getData(key); + expect(result).to.equal(value); + }); }); describe('when setting an invalid bytes28[CompactBytesArray] for a new beneficiary', () => { @@ -633,83 +702,37 @@ export const shouldBehaveLikeSetAllowedCalls = (buildContext: () => Promise { - it('should fail when beneficiary had no values set under AddressPermissions:AllowedCalls:...', async () => { - const newController = ethers.Wallet.createRandom(); - - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + newController.address.substr(2); - - const value = combineAllowedCalls( - // allow beneficiary to CALL only function selectors 0xcafecafe and 0xbeefbeef - [CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - ['0xffffffff', '0xffffffff'], - ['0xcafecafe', '0xbeefbeef'], - ); - - await expect(context.universalProfile.connect(canOnlyEditPermissions).setData(key, value)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyEditPermissions.address, 'ADDCONTROLLER'); - }); - - it('should pass when trying to edit existing allowed bytes4 selectors under ANY:ANY:', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - beneficiary.address.substring(2); - - const value = combineAllowedCalls( - // allow beneficiary to CALL only function selectors 0xcafecafe and 0xbeefbeef - [CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - ['0xffffffff', '0xffffffff'], - ['0xcafecafe', '0xbeefbeef'], - ); - - await context.universalProfile.connect(canOnlyEditPermissions).setData(key, value); - - // prettier-ignore - const result = await context.universalProfile.getData(key); - expect(result).to.equal(value); - }); - - it('should pass when address had an invalid bytes28[CompactBytesArray] initially', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - invalidBeneficiary.address.substring(2); + describe('when controller to edit Allowed Calls for has some permissions set', () => { + it('should fail when beneficiary had no values set under AddressPermissions:AllowedCalls:...', async () => { + const newController = ethers.Wallet.createRandom(); - const value = combineAllowedCalls( - // allow beneficiary to CALL only function selectors 0xcafecafe and 0xbeefbeef - [CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - ['0xffffffff', '0xffffffff'], - ['0xcafecafe', '0xbeefbeef'], - ); + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + newController.address.substr(2); - await context.universalProfile.connect(canOnlyEditPermissions).setData(key, value); + const value = combineAllowedCalls( + // allow beneficiary to CALL only function selectors 0xcafecafe and 0xbeefbeef + [CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + ['0xffffffff', '0xffffffff'], + ['0xcafecafe', '0xbeefbeef'], + ); - // prettier-ignore - const result = await context.universalProfile.getData(key); - expect(result).to.equal(value); - }); + await expect(context.universalProfile.connect(canOnlyEditPermissions).setData(key, value)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyEditPermissions.address, 'ADDCONTROLLER'); + }); - // Even if the controller had some 00 bytes set as allowed calls, it is not considered as it does not have any allowed calls set - // but rather that its allowed calls are "disabled" - describe('when beneficiary (= controller) had 00 bytes set initially as allowed calls (e.g: allowed calls disabled)', () => { - it('should pass when address had 32 x 0 bytes set initially as allowed calls', async () => { + it('should pass when trying to edit existing allowed bytes4 selectors under ANY:ANY:', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - zero32Bytes.address.substring(2); + beneficiary.address.substring(2); const value = combineAllowedCalls( + // allow beneficiary to CALL only function selectors 0xcafecafe and 0xbeefbeef [CALLTYPE.CALL, CALLTYPE.CALL], [ '0xffffffffffffffffffffffffffffffffffffffff', @@ -726,12 +749,13 @@ export const shouldBehaveLikeSetAllowedCalls = (buildContext: () => Promise { + it('should pass when address had an invalid bytes28[CompactBytesArray] initially', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - zero40Bytes.address.substring(2); + invalidBeneficiary.address.substring(2); const value = combineAllowedCalls( + // allow beneficiary to CALL only function selectors 0xcafecafe and 0xbeefbeef [CALLTYPE.CALL, CALLTYPE.CALL], [ '0xffffffffffffffffffffffffffffffffffffffff', @@ -747,6 +771,52 @@ export const shouldBehaveLikeSetAllowedCalls = (buildContext: () => Promise { + it('should pass when address had 32 x 0 bytes set initially as allowed calls', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + zero32Bytes.address.substring(2); + + const value = combineAllowedCalls( + [CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + ['0xffffffff', '0xffffffff'], + ['0xcafecafe', '0xbeefbeef'], + ); + + await context.universalProfile.connect(canOnlyEditPermissions).setData(key, value); + + // prettier-ignore + const result = await context.universalProfile.getData(key); + expect(result).to.equal(value); + }); + + it('should pass when address had 40 x 0 bytes set initially as allowed functions', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + zero40Bytes.address.substring(2); + + const value = combineAllowedCalls( + [CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + ['0xffffffff', '0xffffffff'], + ['0xcafecafe', '0xbeefbeef'], + ); + + await context.universalProfile.connect(canOnlyEditPermissions).setData(key, value); + + // prettier-ignore + const result = await context.universalProfile.getData(key); + expect(result).to.equal(value); + }); + }); }); describe('when changing the list of selectors in allowed calls from existing ANY:ANY: to an invalid value', () => { @@ -796,14 +866,16 @@ export const shouldBehaveLikeSetAllowedCalls = (buildContext: () => Promise Promise Promise { - it('should fail when trying to edit existing allowed standards for an address', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - beneficiary.address.substring(2); - - const value = combineAllowedCalls( - [CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - [ - INTERFACE_IDS.LSP7DigitalAsset, - INTERFACE_IDS.ERC20, - // add NFT standards (new LSP8 + old ERC721) - // in the list of allowed calls for the beneficiary controller - // (in addition to token contracts LSP7 + ERC20) - INTERFACE_IDS.LSP8IdentifiableDigitalAsset, - INTERFACE_IDS.ERC721, - ], - ['0xffffffff', '0xffffffff', '0xffffffff', '0xffffffff'], - ); - - await expect(context.universalProfile.connect(canOnlyAddController).setData(key, value)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); - }); - - it('should fail with NotAuthorised -> when beneficiary address had an invalid bytes28[CompactBytesArray] initially', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - invalidBeneficiary.address.substring(2); - - const value = combineAllowedCalls( - [CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - [ - INTERFACE_IDS.LSP7DigitalAsset, - INTERFACE_IDS.ERC20, - // add NFT standards (new LSP8 + old ERC721) - // in the list of allowed calls for the beneficiary controller - // (in addition to token standards LSP7 + ERC20) - INTERFACE_IDS.LSP8IdentifiableDigitalAsset, - INTERFACE_IDS.ERC721, - ], - ['0xffffffff', '0xffffffff', '0xffffffff', '0xffffffff'], - ); - - await expect(context.universalProfile.connect(canOnlyAddController).setData(key, value)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); - }); - - // Even if the controller had some 00 bytes set as allowed calls, it is not considered as it does not have any allowed calls set - // but rather that its allowed calls are "disabled" - describe('when beneficiary (= controller) had 00 bytes set initially as allowed calls (e.g: allowed calls disabled)', () => { - it('should fail with NotAuthorised -> when beneficiary had 32 x 0 bytes set initially as allowed calls', async () => { + describe('when controller / beneficiary has some allowed calls set', () => { + it('should fail when trying to edit existing allowed standards for an address', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - zero32Bytes.address.substring(2); + beneficiary.address.substring(2); const value = combineAllowedCalls( [CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL], @@ -910,6 +924,9 @@ export const shouldBehaveLikeSetAllowedCalls = (buildContext: () => Promise Promise when beneficiary had 40 x 0 bytes set initially as allowed calls', async () => { + it('should fail with NotAuthorised -> when beneficiary address had an invalid bytes28[CompactBytesArray] initially', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - zero40Bytes.address.substring(2); + invalidBeneficiary.address.substring(2); const value = combineAllowedCalls( [CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL], @@ -937,6 +954,9 @@ export const shouldBehaveLikeSetAllowedCalls = (buildContext: () => Promise Promise { + it('should fail with NotAuthorised -> when beneficiary had 32 x 0 bytes set initially as allowed calls', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + zero32Bytes.address.substring(2); + + const value = combineAllowedCalls( + [CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + [ + INTERFACE_IDS.LSP7DigitalAsset, + INTERFACE_IDS.ERC20, + INTERFACE_IDS.LSP8IdentifiableDigitalAsset, + INTERFACE_IDS.ERC721, + ], + ['0xffffffff', '0xffffffff', '0xffffffff', '0xffffffff'], + ); + + await expect(context.universalProfile.connect(canOnlyAddController).setData(key, value)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + }); + + it('should fail with NotAuthorised -> when beneficiary had 40 x 0 bytes set initially as allowed calls', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + zero40Bytes.address.substring(2); + + const value = combineAllowedCalls( + [CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + [ + INTERFACE_IDS.LSP7DigitalAsset, + INTERFACE_IDS.ERC20, + INTERFACE_IDS.LSP8IdentifiableDigitalAsset, + INTERFACE_IDS.ERC721, + ], + ['0xffffffff', '0xffffffff', '0xffffffff', '0xffffffff'], + ); + + await expect(context.universalProfile.connect(canOnlyAddController).setData(key, value)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + }); + }); }); it('should pass when beneficiary had no values set under AddressPermissions:AllowedCalls:... + setting a valid bytes28[CompactBytesArray]', async () => { @@ -1014,91 +1092,13 @@ export const shouldBehaveLikeSetAllowedCalls = (buildContext: () => Promise { - it('should fail when beneficiary had no values set under AddressPermissions:AllowedCalls:...', async () => { - const newController = ethers.Wallet.createRandom(); - - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + newController.address.substr(2); - - const value = combineAllowedCalls( - [CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - // try to add in the list of allowed calls for the beneficiary controller - // the rights to CALL any LSP7 or ERC20 token contract - // (NB: just the AllowedCalls, not the permission CALL) - [INTERFACE_IDS.LSP7DigitalAsset, INTERFACE_IDS.ERC20], - ['0xffffffff', '0xffffffff'], - ); - - await expect(context.universalProfile.connect(canOnlyEditPermissions).setData(key, value)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyEditPermissions.address, 'ADDCONTROLLER'); - }); - - it('should pass when trying to edit existing allowed standards for an address', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - beneficiary.address.substring(2); - - const value = combineAllowedCalls( - [CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - [ - INTERFACE_IDS.LSP7DigitalAsset, - INTERFACE_IDS.ERC20, - // add NFT standards (new LSP8 + old ERC721) - // in the list of allowed calls for the beneficiary controller - // (in addition to token standards LSP7 + ERC20) - INTERFACE_IDS.LSP8IdentifiableDigitalAsset, - INTERFACE_IDS.ERC721, - ], - ['0xffffffff', '0xffffffff', '0xffffffff', '0xffffffff'], - ); - - await context.universalProfile.connect(canOnlyEditPermissions).setData(key, value); - - // prettier-ignore - const result = await context.universalProfile.getData(key); - expect(result).to.equal(value); - }); - - it('should pass when address had an invalid bytes28[CompactBytesArray] initially', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - invalidBeneficiary.address.substring(2); - - const value = combineAllowedCalls( - [CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - [INTERFACE_IDS.LSP7DigitalAsset, INTERFACE_IDS.ERC20], - ['0xffffffff', '0xffffffff'], - ); - - await context.universalProfile.connect(canOnlyEditPermissions).setData(key, value); - - // prettier-ignore - const result = await context.universalProfile.getData(key); - expect(result).to.equal(value); - }); + describe('when controller / beneificary had some allowed calls set', () => { + it('should fail when beneficiary had no values set under AddressPermissions:AllowedCalls:...', async () => { + const newController = ethers.Wallet.createRandom(); - // Even if the controller had some 00 bytes set as allowed calls, it is not considered as it does not have any allowed calls set - // but rather that its allowed calls are "disabled" - describe('when beneficiary (= controller) had 00 bytes set initially as allowed calls (e.g: allowed calls disabled)', () => { - it('should pass when address had 32 x 0 bytes set initially as allowed calls', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - zero32Bytes.address.substring(2); + newController.address.substr(2); const value = combineAllowedCalls( [CALLTYPE.CALL, CALLTYPE.CALL], @@ -1106,10 +1106,43 @@ export const shouldBehaveLikeSetAllowedCalls = (buildContext: () => Promise { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + beneficiary.address.substring(2); + + const value = combineAllowedCalls( + [CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + [ + INTERFACE_IDS.LSP7DigitalAsset, + INTERFACE_IDS.ERC20, + // add NFT standards (new LSP8 + old ERC721) + // in the list of allowed calls for the beneficiary controller + // (in addition to token standards LSP7 + ERC20) + INTERFACE_IDS.LSP8IdentifiableDigitalAsset, + INTERFACE_IDS.ERC721, + ], + ['0xffffffff', '0xffffffff', '0xffffffff', '0xffffffff'], + ); + await context.universalProfile.connect(canOnlyEditPermissions).setData(key, value); // prettier-ignore @@ -1117,10 +1150,10 @@ export const shouldBehaveLikeSetAllowedCalls = (buildContext: () => Promise { + it('should pass when address had an invalid bytes28[CompactBytesArray] initially', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - zero40Bytes.address.substring(2); + invalidBeneficiary.address.substring(2); const value = combineAllowedCalls( [CALLTYPE.CALL, CALLTYPE.CALL], @@ -1138,6 +1171,52 @@ export const shouldBehaveLikeSetAllowedCalls = (buildContext: () => Promise { + it('should pass when address had 32 x 0 bytes set initially as allowed calls', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + zero32Bytes.address.substring(2); + + const value = combineAllowedCalls( + [CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + [INTERFACE_IDS.LSP7DigitalAsset, INTERFACE_IDS.ERC20], + ['0xffffffff', '0xffffffff'], + ); + + await context.universalProfile.connect(canOnlyEditPermissions).setData(key, value); + + // prettier-ignore + const result = await context.universalProfile.getData(key); + expect(result).to.equal(value); + }); + + it('should pass when address had 40 x 0 bytes set initially as allowed calls', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + zero40Bytes.address.substring(2); + + const value = combineAllowedCalls( + [CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + [INTERFACE_IDS.LSP7DigitalAsset, INTERFACE_IDS.ERC20], + ['0xffffffff', '0xffffffff'], + ); + + await context.universalProfile.connect(canOnlyEditPermissions).setData(key, value); + + // prettier-ignore + const result = await context.universalProfile.getData(key); + expect(result).to.equal(value); + }); + }); }); describe('when changing the list of interface IDs in allowed calls :ANY:ANY to an invalid value', () => { diff --git a/tests/LSP20CallVerification/LSP6/SetPermissions/SetAllowedERC725YDataKeys.test.ts b/tests/LSP20CallVerification/LSP6/SetPermissions/SetAllowedERC725YDataKeys.test.ts index 5bc43bc5b..cfbe6cc53 100644 --- a/tests/LSP20CallVerification/LSP6/SetPermissions/SetAllowedERC725YDataKeys.test.ts +++ b/tests/LSP20CallVerification/LSP6/SetPermissions/SetAllowedERC725YDataKeys.test.ts @@ -36,24 +36,27 @@ export const shouldBehaveLikeSetAllowedERC725YDataKeys = ( zero32Bytes = context.accounts[5]; zero40Bytes = context.accounts[6]; + // prettier-ignore const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - canOnlyAddController.address.substring(2), - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - canOnlyEditPermissions.address.substring(2), - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - beneficiary.address.substring(2), - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - invalidBeneficiary.address.substring(2), - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - zero32Bytes.address.substring(2), - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - zero40Bytes.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + canOnlyAddController.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + canOnlyEditPermissions.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + beneficiary.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + invalidBeneficiary.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + zero32Bytes.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + zero40Bytes.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + beneficiary.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + invalidBeneficiary.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + zero32Bytes.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + zero40Bytes.address.substring(2), ]; const permissionValues = [ PERMISSIONS.ADDCONTROLLER, PERMISSIONS.EDITPERMISSIONS, + PERMISSIONS.SETDATA, + PERMISSIONS.SETDATA, + PERMISSIONS.SETDATA, + PERMISSIONS.SETDATA, encodeCompactBytesArray([ ERC725YDataKeys.LSP3['LSP3Profile'], // prettier-ignore @@ -68,205 +71,211 @@ export const shouldBehaveLikeSetAllowedERC725YDataKeys = ( }); describe('when caller has ADDCONTROLLER', () => { - describe('when beneficiary had some ERC725Y data keys set under AddressPermissions:AllowedERC725YDataKeys:...', () => { - it('should fail when adding an extra allowed ERC725Y data key', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - beneficiary.address.substring(2); - - const value = encodeCompactBytesArray([ - ERC725YDataKeys.LSP3['LSP3Profile'], - // prettier-ignore - ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Some Custom Profile Data Key")), - // prettier-ignore - ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Another Custom Data Key")), - ]); - - await expect(context.universalProfile.connect(canOnlyAddController).setData(key, value)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); - }); - - it('should fail when removing an allowed ERC725Y data key', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - beneficiary.address.substring(2); - - const value = encodeCompactBytesArray([ERC725YDataKeys.LSP3['LSP3Profile']]); - - await expect(context.universalProfile.connect(canOnlyAddController).setData(key, value)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); - }); - - it('should fail when trying to clear the CompactedBytesArray completely', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - beneficiary.address.substring(2); - - const value = '0x'; - - await expect(context.universalProfile.connect(canOnlyAddController).setData(key, value)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + describe('when controller / beneficiary had some permissions set', () => { + describe('when beneficiary had some ERC725Y data keys set under AddressPermissions:AllowedERC725YDataKeys:...', () => { + it('should fail when adding an extra allowed ERC725Y data key', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + beneficiary.address.substring(2); + + const value = encodeCompactBytesArray([ + ERC725YDataKeys.LSP3['LSP3Profile'], + // prettier-ignore + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Some Custom Profile Data Key")), + // prettier-ignore + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Another Custom Data Key")), + ]); + + await expect(context.universalProfile.connect(canOnlyAddController).setData(key, value)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + }); + + it('should fail when removing an allowed ERC725Y data key', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + beneficiary.address.substring(2); + + const value = encodeCompactBytesArray([ERC725YDataKeys.LSP3['LSP3Profile']]); + + await expect(context.universalProfile.connect(canOnlyAddController).setData(key, value)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + }); + + it('should fail when trying to clear the CompactedBytesArray completely', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + beneficiary.address.substring(2); + + const value = '0x'; + + await expect(context.universalProfile.connect(canOnlyAddController).setData(key, value)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + }); + + it('should fail when setting an invalid CompactedBytesArray', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + beneficiary.address.substring(2); + + const value = '0xbadbadbadbad'; + + await expect( + context.universalProfile.connect(canOnlyAddController).setData(key, value), + ).to.be.revertedWithCustomError( + context.keyManager, + 'InvalidEncodedAllowedERC725YDataKeys', + ); + }); }); - it('should fail when setting an invalid CompactedBytesArray', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - beneficiary.address.substring(2); - - const value = '0xbadbadbadbad'; + describe('when beneficiary had no ERC725Y data keys set under AddressPermissions:AllowedERC725YDataKeys:...', () => { + it('should pass when setting a valid CompactedBytesArray', async () => { + const newController = ethers.Wallet.createRandom(); - await expect( - context.universalProfile.connect(canOnlyAddController).setData(key, value), - ).to.be.revertedWithCustomError( - context.keyManager, - 'InvalidEncodedAllowedERC725YDataKeys', - ); - }); - }); + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + newController.address.substr(2); - describe('when beneficiary had no ERC725Y data keys set under AddressPermissions:AllowedERC725YDataKeys:...', () => { - it('should pass when setting a valid CompactedBytesArray', async () => { - const newController = ethers.Wallet.createRandom(); + const value = encodeCompactBytesArray([ + // prettier-ignore + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("My Custom Profile Key 1")), + // prettier-ignore + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("My Custom Profile Key 2")), + ]); - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - newController.address.substr(2); + await context.universalProfile.connect(canOnlyAddController).setData(key, value); - const value = encodeCompactBytesArray([ - // prettier-ignore - ethers.utils.keccak256(ethers.utils.toUtf8Bytes("My Custom Profile Key 1")), // prettier-ignore - ethers.utils.keccak256(ethers.utils.toUtf8Bytes("My Custom Profile Key 2")), - ]); - - await context.universalProfile.connect(canOnlyAddController).setData(key, value); - - // prettier-ignore - const result = await context.universalProfile.getData(key); - expect(result).to.equal(value); - }); - - it('should fail when setting an invalid CompactedBytesArray (random bytes)', async () => { - const newController = ethers.Wallet.createRandom(); - - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - newController.address.substr(2); - - const value = '0xbadbadbadbad'; - - await expect( - context.universalProfile.connect(canOnlyAddController).setData(key, value), - ).to.be.revertedWithCustomError( - context.keyManager, - 'InvalidEncodedAllowedERC725YDataKeys', - ); + const result = await context.universalProfile.getData(key); + expect(result).to.equal(value); + }); + + it('should fail when setting an invalid CompactedBytesArray (random bytes)', async () => { + const newController = ethers.Wallet.createRandom(); + + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + newController.address.substr(2); + + const value = '0xbadbadbadbad'; + + await expect( + context.universalProfile.connect(canOnlyAddController).setData(key, value), + ).to.be.revertedWithCustomError( + context.keyManager, + 'InvalidEncodedAllowedERC725YDataKeys', + ); + }); }); }); }); describe('when caller has EDITPERMISSIONS', () => { - describe('when beneficiary had some ERC725Y data keys set under AddressPermissions:AllowedERC725YDataKeys:...', () => { - it('should pass when adding an extra allowed ERC725Y data key', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - beneficiary.address.substring(2); - - const value = encodeCompactBytesArray([ - ERC725YDataKeys.LSP3['LSP3Profile'], - // prettier-ignore - ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Some Custom Profile Data Key")), - // prettier-ignore - ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Another Custom Data Key")), - ]); - - await context.universalProfile.connect(canOnlyEditPermissions).setData(key, value); - - // prettier-ignore - const result = await context.universalProfile.getData(key); - expect(result).to.equal(value); - }); - - it('should pass when removing an allowed ERC725Y data key', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - beneficiary.address.substring(2); - - const value = encodeCompactBytesArray([ERC725YDataKeys.LSP3['LSP3Profile']]); - - await context.universalProfile.connect(canOnlyEditPermissions).setData(key, value); - - // prettier-ignore - const result = await context.universalProfile.getData(key); - expect(result).to.equal(value); - }); - - it('should pass when trying to clear the CompactedBytesArray completely', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - beneficiary.address.substring(2); + describe('when controller / beneficiary had some permissions set', () => { + describe('when beneficiary had some ERC725Y data keys set under AddressPermissions:AllowedERC725YDataKeys:...', () => { + it('should pass when adding an extra allowed ERC725Y data key', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + beneficiary.address.substring(2); + + const value = encodeCompactBytesArray([ + ERC725YDataKeys.LSP3['LSP3Profile'], + // prettier-ignore + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Some Custom Profile Data Key")), + // prettier-ignore + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Another Custom Data Key")), + ]); + + await context.universalProfile.connect(canOnlyEditPermissions).setData(key, value); - const value = '0x'; - - await context.universalProfile.connect(canOnlyEditPermissions).setData(key, value); + // prettier-ignore + const result = await context.universalProfile.getData(key); + expect(result).to.equal(value); + }); - // prettier-ignore - const result = await context.universalProfile.getData(key); - expect(result).to.equal(value); - }); + it('should pass when removing an allowed ERC725Y data key', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + beneficiary.address.substring(2); - it('should fail when setting an invalid CompactedBytesArray', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - beneficiary.address.substring(2); + const value = encodeCompactBytesArray([ERC725YDataKeys.LSP3['LSP3Profile']]); - const value = '0xbadbadbadbad'; + await context.universalProfile.connect(canOnlyEditPermissions).setData(key, value); - await expect( - context.universalProfile.connect(canOnlyEditPermissions).setData(key, value), - ).to.be.revertedWithCustomError( - context.keyManager, - 'InvalidEncodedAllowedERC725YDataKeys', - ); - }); - }); + // prettier-ignore + const result = await context.universalProfile.getData(key); + expect(result).to.equal(value); + }); - describe('when beneficiary had no ERC725Y data keys set under AddressPermissions:AllowedERC725YDataKeys:...', () => { - it('should fail and not authorize to add a list of allowed ERC725Y data keys (not authorised)', async () => { - const newController = ethers.Wallet.createRandom(); + it('should pass when trying to clear the CompactedBytesArray completely', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + beneficiary.address.substring(2); - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - newController.address.substr(2); + const value = '0x'; - const value = encodeCompactBytesArray([ - ethers.utils.keccak256(ethers.utils.toUtf8Bytes('My Custom Key 1')), - ethers.utils.keccak256(ethers.utils.toUtf8Bytes('My Custom Key 2')), - ]); + await context.universalProfile.connect(canOnlyEditPermissions).setData(key, value); - await expect(context.universalProfile.connect(canOnlyEditPermissions).setData(key, value)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyEditPermissions.address, 'ADDCONTROLLER'); + // prettier-ignore + const result = await context.universalProfile.getData(key); + expect(result).to.equal(value); + }); + + it('should fail when setting an invalid CompactedBytesArray', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + beneficiary.address.substring(2); + + const value = '0xbadbadbadbad'; + + await expect( + context.universalProfile.connect(canOnlyEditPermissions).setData(key, value), + ).to.be.revertedWithCustomError( + context.keyManager, + 'InvalidEncodedAllowedERC725YDataKeys', + ); + }); }); - it('should fail when setting an invalid CompactedBytesArray', async () => { - const newController = ethers.Wallet.createRandom(); - - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - newController.address.substr(2); - - const value = '0xbadbadbadbad'; - - await expect( - context.universalProfile.connect(canOnlyEditPermissions).setData(key, value), - ).to.be.revertedWithCustomError( - context.keyManager, - 'InvalidEncodedAllowedERC725YDataKeys', - ); + describe('when beneficiary had no ERC725Y data keys set under AddressPermissions:AllowedERC725YDataKeys:...', () => { + it('should fail and not authorize to add a list of allowed ERC725Y data keys (not authorised)', async () => { + const newController = ethers.Wallet.createRandom(); + + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + newController.address.substr(2); + + const value = encodeCompactBytesArray([ + ethers.utils.keccak256(ethers.utils.toUtf8Bytes('My Custom Key 1')), + ethers.utils.keccak256(ethers.utils.toUtf8Bytes('My Custom Key 2')), + ]); + + await expect( + context.universalProfile.connect(canOnlyEditPermissions).setData(key, value), + ) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyEditPermissions.address, 'ADDCONTROLLER'); + }); + + it('should fail when setting an invalid CompactedBytesArray', async () => { + const newController = ethers.Wallet.createRandom(); + + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + newController.address.substr(2); + + const value = '0xbadbadbadbad'; + + await expect( + context.universalProfile.connect(canOnlyEditPermissions).setData(key, value), + ).to.be.revertedWithCustomError( + context.keyManager, + 'InvalidEncodedAllowedERC725YDataKeys', + ); + }); }); }); }); diff --git a/tests/LSP6KeyManager/SetPermissions/SetAllowedCalls.test.ts b/tests/LSP6KeyManager/SetPermissions/SetAllowedCalls.test.ts index 160d31382..3ad8fbfa2 100644 --- a/tests/LSP6KeyManager/SetPermissions/SetAllowedCalls.test.ts +++ b/tests/LSP6KeyManager/SetPermissions/SetAllowedCalls.test.ts @@ -20,9 +20,10 @@ export const shouldBehaveLikeSettingAllowedCalls = ( describe('deleting AllowedCalls', () => { let canOnlyAddController: SignerWithAddress, canOnlyEditPermissions: SignerWithAddress; - let beneficiary: SignerWithAddress; - let invalidBytes: SignerWithAddress; - let noBytes: SignerWithAddress; + let beneficiaryWithPermissions: SignerWithAddress, + beneficiaryNoPermissions: SignerWithAddress, + invalidBytes: SignerWithAddress, + noBytes: SignerWithAddress; before(async () => { context = await buildContext(); @@ -30,18 +31,20 @@ export const shouldBehaveLikeSettingAllowedCalls = ( canOnlyAddController = context.accounts[1]; canOnlyEditPermissions = context.accounts[2]; - beneficiary = context.accounts[3]; - invalidBytes = context.accounts[4]; - noBytes = context.accounts[5]; + beneficiaryWithPermissions = context.accounts[3]; + beneficiaryNoPermissions = context.accounts[4]; + invalidBytes = context.accounts[5]; + noBytes = context.accounts[6]; + // prettier-ignore const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - canOnlyAddController.address.substring(2), - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - canOnlyEditPermissions.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + canOnlyAddController.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + canOnlyEditPermissions.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + beneficiaryWithPermissions.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + invalidBytes.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + noBytes.address.substring(2), - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + beneficiary.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + beneficiaryWithPermissions.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + beneficiaryNoPermissions.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + invalidBytes.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + noBytes.address.substring(2), ]; @@ -51,6 +54,19 @@ export const shouldBehaveLikeSettingAllowedCalls = ( PERMISSIONS.EDITPERMISSIONS, PERMISSIONS.CALL, PERMISSIONS.CALL, + PERMISSIONS.CALL, + // beneficiaryWithPermissions + combineAllowedCalls( + // allow the beneficiary to transfer value to addresses 0xcafe... and 0xbeef... + [CALLTYPE.VALUE, CALLTYPE.VALUE], + [ + '0xcafecafecafecafecafecafecafecafecafecafe', + '0xbeefbeefbeefbeefbeefbeefbeefbeefbeefbeef', + ], + ['0xffffffff', '0xffffffff'], + ['0xffffffff', '0xffffffff'], + ), + // beneficiaryNoPermissions combineAllowedCalls( // allow the beneficiary to transfer value to addresses 0xcafe... and 0xbeef... [CALLTYPE.VALUE, CALLTYPE.VALUE], @@ -61,47 +77,88 @@ export const shouldBehaveLikeSettingAllowedCalls = ( ['0xffffffff', '0xffffffff'], ['0xffffffff', '0xffffffff'], ), + // invalidBytes '0xbadbadbadbad', + // noBytes '0x', ]; await setupKeyManager(context, permissionKeys, permissionValues); }); - describe('when caller has ADD permission', () => { - it('should revert and not be allowed to clear the list of allowed calls for an address', async () => { - const dataKey = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - beneficiary.address.substring(2); - const dataValue = '0x'; + describe('when caller has permission ADD_CONTROLLER', () => { + describe('when controller in `AddressPermissions:AllowedCalls:` has some permissions', () => { + it('should revert and not be allowed to clear the list of allowed calls', async () => { + const dataKey = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + beneficiaryWithPermissions.address.substring(2); + const dataValue = '0x'; - const setDataPayload = context.universalProfile.interface.encodeFunctionData('setData', [ - dataKey, - dataValue, - ]); + const setDataPayload = context.universalProfile.interface.encodeFunctionData('setData', [ + dataKey, + dataValue, + ]); - await expect(context.keyManager.connect(canOnlyAddController).execute(setDataPayload)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + await expect(context.keyManager.connect(canOnlyAddController).execute(setDataPayload)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + }); + }); + + describe('when controller in `AddressPermissions:AllowedCalls:` has no permissions', () => { + it('should pass and clear the list of allowed calls', async () => { + const dataKey = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + beneficiaryNoPermissions.address.substring(2); + const dataValue = '0x'; + + const setDataPayload = context.universalProfile.interface.encodeFunctionData('setData', [ + dataKey, + dataValue, + ]); + + await context.keyManager.connect(canOnlyAddController).execute(setDataPayload); + + expect(await context.universalProfile.getData(dataKey)).to.equal(dataValue); + }); }); }); - describe('when caller has CHANGE permission', () => { - it('should allow to clear the list of allowed calls for an address', async () => { - const dataKey = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - beneficiary.address.substring(2); - const dataValue = '0x'; + describe('when caller has EDIT_PERMISSIONS', () => { + describe('when controller in `AddressPermissions:AllowedCalls:` has some permissions', () => { + it('should allow to clear the list of allowed calls', async () => { + const dataKey = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + beneficiaryWithPermissions.address.substring(2); + const dataValue = '0x'; - const setDataPayload = context.universalProfile.interface.encodeFunctionData('setData', [ - dataKey, - dataValue, - ]); + const setDataPayload = context.universalProfile.interface.encodeFunctionData('setData', [ + dataKey, + dataValue, + ]); + + await context.keyManager.connect(canOnlyEditPermissions).execute(setDataPayload); + + expect(await context.universalProfile.getData(dataKey)).to.equal(dataValue); + }); + }); + + describe('when controller in `AddressPermissions:AllowedCalls:` has no permissions', () => { + it('should revert and not allow to clear the list of allowed calls', async () => { + const dataKey = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + beneficiaryNoPermissions.address.substring(2); + const dataValue = '0x'; - await context.keyManager.connect(canOnlyEditPermissions).execute(setDataPayload); + const setDataPayload = context.universalProfile.interface.encodeFunctionData('setData', [ + dataKey, + dataValue, + ]); - const result = await context.universalProfile.getData(dataKey); - expect(result).to.equal(dataValue); + await expect(context.keyManager.connect(canOnlyEditPermissions).execute(setDataPayload)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyEditPermissions.address, 'ADDCONTROLLER'); + }); }); }); }); @@ -125,14 +182,16 @@ export const shouldBehaveLikeSettingAllowedCalls = ( zero32Bytes = context.accounts[5]; zero40Bytes = context.accounts[6]; + // prettier-ignore const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - canOnlyAddController.address.substring(2), - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - canOnlyEditPermissions.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + canOnlyAddController.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + canOnlyEditPermissions.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + beneficiary.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + invalidBeneficiary.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + zero32Bytes.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + zero40Bytes.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + beneficiary.address.substring(2), - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - invalidBeneficiary.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + invalidBeneficiary.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + zero32Bytes.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + zero40Bytes.address.substring(2), ]; @@ -140,6 +199,10 @@ export const shouldBehaveLikeSettingAllowedCalls = ( const permissionValues = [ PERMISSIONS.ADDCONTROLLER, PERMISSIONS.EDITPERMISSIONS, + PERMISSIONS.CALL, + PERMISSIONS.CALL, + PERMISSIONS.CALL, + PERMISSIONS.CALL, combineAllowedCalls( // allow the beneficiary to transfer value to addresses 0xcafe... and 0xbeef... [CALLTYPE.VALUE, CALLTYPE.VALUE], @@ -161,71 +224,17 @@ export const shouldBehaveLikeSettingAllowedCalls = ( }); describe('when caller has permission ADDCONTROLLER', () => { - it('should fail when trying to edit existing allowed addresses for an address', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - beneficiary.address.substring(2); - - const value = combineAllowedCalls( - [CALLTYPE.VALUE, CALLTYPE.VALUE], - [ - '0xcafecafecafecafecafecafecafecafecafecafe', - '0xca11ca11ca11ca11ca11ca11ca11ca11ca11ca11', - ], - ['0xffffffff', '0xffffffff'], - ['0xffffffff', '0xffffffff'], - ); - - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); - - await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); - }); - - it('should fail with NotAuthorised -> when beneficiary address had an invalid bytes28[CompatBytesArray]', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - invalidBeneficiary.address.substring(2); - - // try to set for the invalidBeneficiary some allowed calls - // that allow it to transfer value to addresses 0xcafe... and 0xbeef... - const value = combineAllowedCalls( - [CALLTYPE.VALUE, CALLTYPE.VALUE], - [ - '0xcafecafecafecafecafecafecafecafecafecafe', - '0xbeefbeefbeefbeefbeefbeefbeefbeefbeefbeef', - ], - ['0xffffffff', '0xffffffff'], - ['0xffffffff', '0xffffffff'], - ); - - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); - - await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); - }); - - // even if the controller had some 00 bytes set as allowed calls, it is not considered as it does not have any allowed calls set - // but rather that its allowed calls are "disabled" - describe('when beneficiary (= controller) had 00 bytes set initially as allowed calls (e.g: allowed calls disabled)', () => { - it('should fail with NotAuthorised -> when beneficiary had 32 x 0 bytes set initially as allowed calls', async () => { + describe('when the controller to edit the AllowedCalls for has some permissions', () => { + it('should fail when trying to edit existing allowed addresses for an address', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - zero32Bytes.address.substring(2); + beneficiary.address.substring(2); const value = combineAllowedCalls( [CALLTYPE.VALUE, CALLTYPE.VALUE], [ '0xcafecafecafecafecafecafecafecafecafecafe', - '0xbeefbeefbeefbeefbeefbeefbeefbeefbeefbeef', + '0xca11ca11ca11ca11ca11ca11ca11ca11ca11ca11', ], ['0xffffffff', '0xffffffff'], ['0xffffffff', '0xffffffff'], @@ -241,11 +250,13 @@ export const shouldBehaveLikeSettingAllowedCalls = ( .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); }); - it('should fail with NotAuthorised -> when beneficiary had 40 x 0 bytes set initially as allowed calls', async () => { + it('should fail with NotAuthorised -> when beneficiary address had an invalid bytes32[CompactBytesArray]', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - zero40Bytes.address.substring(2); + invalidBeneficiary.address.substring(2); + // try to set for the invalidBeneficiary some allowed calls + // that allow it to transfer value to addresses 0xcafe... and 0xbeef... const value = combineAllowedCalls( [CALLTYPE.VALUE, CALLTYPE.VALUE], [ @@ -265,36 +276,89 @@ export const shouldBehaveLikeSettingAllowedCalls = ( .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); }); - }); - it('should pass when beneficiary had no values set under AddressPermissions:AllowedCalls:... + setting a valid bytes28[CompactBytesArray]', async () => { - const newController = ethers.Wallet.createRandom(); + describe('when beneficiary (= controller) had 00 bytes set initially as allowed calls (e.g: allowed calls disabled)', () => { + it('should fail with NotAuthorised -> when beneficiary had 32 x 0 bytes set initially as allowed calls', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + zero32Bytes.address.substring(2); + + const value = combineAllowedCalls( + [CALLTYPE.VALUE, CALLTYPE.VALUE], + [ + '0xcafecafecafecafecafecafecafecafecafecafe', + '0xbeefbeefbeefbeefbeefbeefbeefbeefbeefbeef', + ], + ['0xffffffff', '0xffffffff'], + ['0xffffffff', '0xffffffff'], + ); + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + }); + + it('should fail with NotAuthorised -> when beneficiary had 40 x 0 bytes set initially as allowed calls', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + zero40Bytes.address.substring(2); + + const value = combineAllowedCalls( + [CALLTYPE.VALUE, CALLTYPE.VALUE], + [ + '0xcafecafecafecafecafecafecafecafecafecafe', + '0xbeefbeefbeefbeefbeefbeefbeefbeefbeefbeef', + ], + ['0xffffffff', '0xffffffff'], + ['0xffffffff', '0xffffffff'], + ); + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + }); + }); - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + newController.address.substr(2); + it('should pass when beneficiary had no values set under AddressPermissions:AllowedCalls:... + setting a valid bytes28[CompactBytesArray]', async () => { + const newController = ethers.Wallet.createRandom(); - // set for the newController some allowed calls - // that allow it to transfer value to addresses 0xcafe... and 0xbeef... - const value = combineAllowedCalls( - [CALLTYPE.VALUE, CALLTYPE.VALUE], - [ - '0xcafecafecafecafecafecafecafecafecafecafe', - '0xbeefbeefbeefbeefbeefbeefbeefbeefbeefbeef', - ], - ['0xffffffff', '0xffffffff'], - ['0xffffffff', '0xffffffff'], - ); + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + newController.address.substr(2); - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); + // set for the newController some allowed calls + // that allow it to transfer value to addresses 0xcafe... and 0xbeef... + const value = combineAllowedCalls( + [CALLTYPE.VALUE, CALLTYPE.VALUE], + [ + '0xcafecafecafecafecafecafecafecafecafecafe', + '0xbeefbeefbeefbeefbeefbeefbeefbeefbeefbeef', + ], + ['0xffffffff', '0xffffffff'], + ['0xffffffff', '0xffffffff'], + ); - await context.keyManager.connect(canOnlyAddController).execute(payload); + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); - // prettier-ignore - const result = await context.universalProfile.getData(key); - expect(result).to.equal(value); + await context.keyManager.connect(canOnlyAddController).execute(payload); + + // prettier-ignore + const result = await context.universalProfile.getData(key); + expect(result).to.equal(value); + }); }); describe('when setting an invalid bytes28[CompactBytesArray] for a new beneficiary', () => { @@ -540,14 +604,16 @@ export const shouldBehaveLikeSettingAllowedCalls = ( zero32Bytes = context.accounts[5]; zero40Bytes = context.accounts[6]; + // prettier-ignore const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - canOnlyAddController.address.substring(2), - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - canOnlyEditPermissions.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + canOnlyAddController.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + canOnlyEditPermissions.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + beneficiary.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + invalidBeneficiary.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + zero32Bytes.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + zero40Bytes.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + beneficiary.address.substring(2), - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - invalidBeneficiary.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + invalidBeneficiary.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + zero32Bytes.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + zero40Bytes.address.substring(2), ]; @@ -555,6 +621,10 @@ export const shouldBehaveLikeSettingAllowedCalls = ( const permissionValues = [ PERMISSIONS.ADDCONTROLLER, PERMISSIONS.EDITPERMISSIONS, + PERMISSIONS.CALL, + PERMISSIONS.CALL, + PERMISSIONS.CALL, + PERMISSIONS.CALL, combineAllowedCalls( [CALLTYPE.CALL, CALLTYPE.CALL], [ @@ -573,74 +643,21 @@ export const shouldBehaveLikeSettingAllowedCalls = ( }); describe('when caller has permission ADDCONTROLLER', () => { - it('should fail when trying to edit existing allowed functions for an address', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - beneficiary.address.substring(2); - - const value = combineAllowedCalls( - // allow beneficiary to make a CALL to only function selectors 0xcafecafe and 0xf00df00d - [CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - ['0xffffffff', '0xffffffff'], - ['0xcafecafe', '0xf00df00d'], - ); - - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); - - await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); - }); - - it('should fail with NotAuthorised -> when beneficiary address had an invalid bytes28[CompactBytesArray] initially', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - invalidBeneficiary.address.substring(2); - - const value = combineAllowedCalls( - // allow beneficiary to make a CALL to only function selectors 0xcafecafe and 0xf00df00d - [CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - ['0xffffffff', '0xffffffff'], - ['0xcafecafe', '0xf00df00d'], - ); - - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); - - await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); - }); - - // even if the controller had some 00 bytes set as allowed calls, it is not considered as it does not have any allowed calls set - // but rather that its allowed calls are "disabled" - describe('when beneficiary (= controller) had 00 bytes set initially as allowed calls (e.g: allowed calls disabled)', () => { - it('should fail with NotAuthorised -> when beneficiary had 32 x 0 bytes set initially as allowed calls', async () => { + describe('when controller to edit Allowed Calls for has some permissions set', () => { + it('should fail when trying to edit existing allowed functions for an address', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - zero32Bytes.address.substring(2); + beneficiary.address.substring(2); const value = combineAllowedCalls( + // allow beneficiary to make a CALL to only function selectors 0xcafecafe and 0xf00df00d [CALLTYPE.CALL, CALLTYPE.CALL], [ '0xffffffffffffffffffffffffffffffffffffffff', '0xffffffffffffffffffffffffffffffffffffffff', ], ['0xffffffff', '0xffffffff'], - ['0xcafecafe', '0xca11ca11'], + ['0xcafecafe', '0xf00df00d'], ); const payload = context.universalProfile.interface.encodeFunctionData('setData', [ @@ -653,19 +670,20 @@ export const shouldBehaveLikeSettingAllowedCalls = ( .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); }); - it('should fail with NotAuthorised -> when beneficiary had 40 x 0 bytes set initially as allowed calls', async () => { + it('should fail with NotAuthorised -> when beneficiary address had an invalid bytes28[CompactBytesArray] initially', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - zero40Bytes.address.substring(2); + invalidBeneficiary.address.substring(2); const value = combineAllowedCalls( + // allow beneficiary to make a CALL to only function selectors 0xcafecafe and 0xf00df00d [CALLTYPE.CALL, CALLTYPE.CALL], [ '0xffffffffffffffffffffffffffffffffffffffff', '0xffffffffffffffffffffffffffffffffffffffff', ], ['0xffffffff', '0xffffffff'], - ['0xcafecafe', '0xca11ca11'], + ['0xcafecafe', '0xf00df00d'], ); const payload = context.universalProfile.interface.encodeFunctionData('setData', [ @@ -677,35 +695,90 @@ export const shouldBehaveLikeSettingAllowedCalls = ( .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); }); - }); - it('should pass when beneficiary had no values set under AddressPermissions:AllowedCalls:... + setting a valid bytes28[CompactBytesArray]', async () => { - const newController = ethers.Wallet.createRandom(); + // even if the controller had some 00 bytes set as allowed calls, it is not considered as it does not have any allowed calls set + // but rather that its allowed calls are "disabled" + describe('when beneficiary (= controller) had 00 bytes set initially as allowed calls (e.g: allowed calls disabled)', () => { + it('should fail with NotAuthorised -> when beneficiary had 32 x 0 bytes set initially as allowed calls', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + zero32Bytes.address.substring(2); + + const value = combineAllowedCalls( + [CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + ['0xffffffff', '0xffffffff'], + ['0xcafecafe', '0xca11ca11'], + ); + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + }); + + it('should fail with NotAuthorised -> when beneficiary had 40 x 0 bytes set initially as allowed calls', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + zero40Bytes.address.substring(2); + + const value = combineAllowedCalls( + [CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + ['0xffffffff', '0xffffffff'], + ['0xcafecafe', '0xca11ca11'], + ); + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + }); + }); - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + newController.address.substr(2); + it('should pass when beneficiary had no values set under AddressPermissions:AllowedCalls:... + setting a valid bytes28[CompactBytesArray]', async () => { + const newController = ethers.Wallet.createRandom(); - const value = combineAllowedCalls( - // allow beneficiary to CALL only function selectors 0xcafecafe and 0xf00df00d - [CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - ['0xffffffff', '0xffffffff'], - ['0xcafecafe', '0xf00df00d'], - ); + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + newController.address.substr(2); - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); + const value = combineAllowedCalls( + // allow beneficiary to CALL only function selectors 0xcafecafe and 0xf00df00d + [CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + ['0xffffffff', '0xffffffff'], + ['0xcafecafe', '0xf00df00d'], + ); - await context.keyManager.connect(canOnlyAddController).execute(payload); + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); - // prettier-ignore - const result = await context.universalProfile.getData(key); - expect(result).to.equal(value); + await context.keyManager.connect(canOnlyAddController).execute(payload); + + // prettier-ignore + const result = await context.universalProfile.getData(key); + expect(result).to.equal(value); + }); }); describe('when setting an invalid bytes28[CompactBytesArray] for a new beneficiary', () => { @@ -750,97 +823,42 @@ export const shouldBehaveLikeSettingAllowedCalls = ( }); describe('when caller has EDITPERMISSIONS', () => { - it('should fail when beneficiary had no values set under AddressPermissions:AllowedCalls:...', async () => { - const newController = ethers.Wallet.createRandom(); - - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + newController.address.substr(2); + describe('when controller to edit Allowed Calls for has some permissions set', () => { + it('should fail when beneficiary had no values set under AddressPermissions:AllowedCalls:...', async () => { + const newController = ethers.Wallet.createRandom(); - const value = combineAllowedCalls( - // allow beneficiary to CALL only function selectors 0xcafecafe and 0xbeefbeef - [CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - ['0xffffffff', '0xffffffff'], - ['0xcafecafe', '0xbeefbeef'], - ); + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + newController.address.substr(2); - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); - - await expect(context.keyManager.connect(canOnlyEditPermissions).execute(payload)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyEditPermissions.address, 'ADDCONTROLLER'); - }); - - it('should pass when trying to edit existing allowed bytes4 selectors under ANY:ANY:', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - beneficiary.address.substring(2); - - const value = combineAllowedCalls( - // allow beneficiary to CALL only function selectors 0xcafecafe and 0xbeefbeef - [CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - ['0xffffffff', '0xffffffff'], - ['0xcafecafe', '0xbeefbeef'], - ); - - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); - - await context.keyManager.connect(canOnlyEditPermissions).execute(payload); - - // prettier-ignore - const result = await context.universalProfile.getData(key); - expect(result).to.equal(value); - }); - - it('should pass when address had an invalid bytes28[CompactBytesArray] initially', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - invalidBeneficiary.address.substring(2); - - const value = combineAllowedCalls( - // allow beneficiary to CALL only function selectors 0xcafecafe and 0xbeefbeef - [CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - ['0xffffffff', '0xffffffff'], - ['0xcafecafe', '0xbeefbeef'], - ); - - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); + const value = combineAllowedCalls( + // allow beneficiary to CALL only function selectors 0xcafecafe and 0xbeefbeef + [CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + ['0xffffffff', '0xffffffff'], + ['0xcafecafe', '0xbeefbeef'], + ); - await context.keyManager.connect(canOnlyEditPermissions).execute(payload); + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); - const result = await context.universalProfile.getData(key); - expect(result).to.equal(value); - }); + await expect(context.keyManager.connect(canOnlyEditPermissions).execute(payload)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyEditPermissions.address, 'ADDCONTROLLER'); + }); - // even if the controller had some 00 bytes set as allowed calls, it is not considered as it does not have any allowed calls set - // but rather that its allowed calls are "disabled" - describe('when beneficiary (= controller) had 00 bytes set initially as allowed calls (e.g: allowed calls disabled)', () => { - it('should pass when address had 32 x 0 bytes set initially as allowed calls', async () => { + it('should pass when trying to edit existing allowed bytes4 selectors under ANY:ANY:', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - zero32Bytes.address.substring(2); + beneficiary.address.substring(2); const value = combineAllowedCalls( + // allow beneficiary to CALL only function selectors 0xcafecafe and 0xbeefbeef [CALLTYPE.CALL, CALLTYPE.CALL], [ '0xffffffffffffffffffffffffffffffffffffffff', @@ -857,16 +875,18 @@ export const shouldBehaveLikeSettingAllowedCalls = ( await context.keyManager.connect(canOnlyEditPermissions).execute(payload); + // prettier-ignore const result = await context.universalProfile.getData(key); expect(result).to.equal(value); }); - it('should pass when address had 40 x 0 bytes set initially as allowed functions', async () => { + it('should pass when address had an invalid bytes28[CompactBytesArray] initially', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - zero40Bytes.address.substring(2); + invalidBeneficiary.address.substring(2); const value = combineAllowedCalls( + // allow beneficiary to CALL only function selectors 0xcafecafe and 0xbeefbeef [CALLTYPE.CALL, CALLTYPE.CALL], [ '0xffffffffffffffffffffffffffffffffffffffff', @@ -883,10 +903,64 @@ export const shouldBehaveLikeSettingAllowedCalls = ( await context.keyManager.connect(canOnlyEditPermissions).execute(payload); - // prettier-ignore const result = await context.universalProfile.getData(key); expect(result).to.equal(value); }); + + describe('when beneficiary (= controller) had 00 bytes set initially as allowed calls (e.g: allowed calls disabled)', () => { + it('should pass when address had 32 x 0 bytes set initially as allowed calls', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + zero32Bytes.address.substring(2); + + const value = combineAllowedCalls( + [CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + ['0xffffffff', '0xffffffff'], + ['0xcafecafe', '0xbeefbeef'], + ); + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await context.keyManager.connect(canOnlyEditPermissions).execute(payload); + + const result = await context.universalProfile.getData(key); + expect(result).to.equal(value); + }); + + it('should pass when address had 40 x 0 bytes set initially as allowed functions', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + zero40Bytes.address.substring(2); + + const value = combineAllowedCalls( + [CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + ['0xffffffff', '0xffffffff'], + ['0xcafecafe', '0xbeefbeef'], + ); + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await context.keyManager.connect(canOnlyEditPermissions).execute(payload); + + // prettier-ignore + const result = await context.universalProfile.getData(key); + expect(result).to.equal(value); + }); + }); }); describe('when changing the list of selectors in allowed calls from existing ANY:ANY: to an invalid value', () => { @@ -946,14 +1020,16 @@ export const shouldBehaveLikeSettingAllowedCalls = ( zero32Bytes = context.accounts[5]; zero40Bytes = context.accounts[6]; + // prettier-ignore const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - canOnlyAddController.address.substring(2), - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - canOnlyEditPermissions.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + canOnlyAddController.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + canOnlyEditPermissions.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + beneficiary.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + invalidBeneficiary.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + zero32Bytes.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + zero40Bytes.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + beneficiary.address.substring(2), - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - invalidBeneficiary.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + invalidBeneficiary.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + zero32Bytes.address.substring(2), ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + zero40Bytes.address.substring(2), ]; @@ -961,6 +1037,10 @@ export const shouldBehaveLikeSettingAllowedCalls = ( const permissionValues = [ PERMISSIONS.ADDCONTROLLER, PERMISSIONS.EDITPERMISSIONS, + PERMISSIONS.CALL, + PERMISSIONS.CALL, + PERMISSIONS.CALL, + PERMISSIONS.CALL, combineAllowedCalls( // allow beneficiary controller to CALL any functions // on any LSP7 or ERC20 contracts @@ -981,83 +1061,11 @@ export const shouldBehaveLikeSettingAllowedCalls = ( }); describe('when caller has ADDCONTROLLER', () => { - it('should fail when trying to edit existing allowed standards for an address', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - beneficiary.address.substring(2); - - const value = combineAllowedCalls( - [CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - [ - INTERFACE_IDS.LSP7DigitalAsset, - INTERFACE_IDS.ERC20, - // add NFT standards (new LSP8 + old ERC721) - // in the list of allowed calls for the beneficiary controller - // (in addition to token contracts LSP7 + ERC20) - INTERFACE_IDS.LSP8IdentifiableDigitalAsset, - INTERFACE_IDS.ERC721, - ], - ['0xffffffff', '0xffffffff', '0xffffffff', '0xffffffff'], - ); - - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); - - await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); - }); - - it('should fail with NotAuthorised -> when beneficiary address had an invalid bytes28[CompactBytesArray] initially', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - invalidBeneficiary.address.substring(2); - - const value = combineAllowedCalls( - [CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - [ - INTERFACE_IDS.LSP7DigitalAsset, - INTERFACE_IDS.ERC20, - // add NFT standards (new LSP8 + old ERC721) - // in the list of allowed calls for the beneficiary controller - // (in addition to token standards LSP7 + ERC20) - INTERFACE_IDS.LSP8IdentifiableDigitalAsset, - INTERFACE_IDS.ERC721, - ], - ['0xffffffff', '0xffffffff', '0xffffffff', '0xffffffff'], - ); - - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); - - await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); - }); - - // even if the controller had some 00 bytes set as allowed calls, it is not considered as it does not have any allowed calls set - // but rather that its allowed calls are "disabled" - describe('when beneficiary (= controller) had 00 bytes set initially as allowed calls (e.g: allowed calls disabled)', () => { - it('should fail with NotAuthorised -> when beneficiary had 32 x 0 bytes set initially as allowed calls', async () => { + describe('when controller to edit Allowed Calls for has some permissions', () => { + it('should fail when trying to edit existing allowed standards for an address', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - zero32Bytes.address.substring(2); + beneficiary.address.substring(2); const value = combineAllowedCalls( [CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL], @@ -1070,6 +1078,9 @@ export const shouldBehaveLikeSettingAllowedCalls = ( [ INTERFACE_IDS.LSP7DigitalAsset, INTERFACE_IDS.ERC20, + // add NFT standards (new LSP8 + old ERC721) + // in the list of allowed calls for the beneficiary controller + // (in addition to token contracts LSP7 + ERC20) INTERFACE_IDS.LSP8IdentifiableDigitalAsset, INTERFACE_IDS.ERC721, ], @@ -1086,10 +1097,10 @@ export const shouldBehaveLikeSettingAllowedCalls = ( .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); }); - it('should fail with NotAuthorised -> when beneficiary had 40 x 0 bytes set initially as allowed calls', async () => { + it('should fail with NotAuthorised -> when beneficiary address had an invalid bytes28[CompactBytesArray] initially', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - zero40Bytes.address.substring(2); + invalidBeneficiary.address.substring(2); const value = combineAllowedCalls( [CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL], @@ -1102,6 +1113,9 @@ export const shouldBehaveLikeSettingAllowedCalls = ( [ INTERFACE_IDS.LSP7DigitalAsset, INTERFACE_IDS.ERC20, + // add NFT standards (new LSP8 + old ERC721) + // in the list of allowed calls for the beneficiary controller + // (in addition to token standards LSP7 + ERC20) INTERFACE_IDS.LSP8IdentifiableDigitalAsset, INTERFACE_IDS.ERC721, ], @@ -1117,44 +1131,113 @@ export const shouldBehaveLikeSettingAllowedCalls = ( .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); }); - }); - it('should pass when beneficiary had no values set under AddressPermissions:AllowedCalls:... + setting a valid bytes28[CompactBytesArray]', async () => { - const newController = ethers.Wallet.createRandom(); + // even if the controller had some 00 bytes set as allowed calls, it is not considered as it does not have any allowed calls set + // but rather that its allowed calls are "disabled" + describe('when beneficiary (= controller) had 00 bytes set initially as allowed calls (e.g: allowed calls disabled)', () => { + it('should fail with NotAuthorised -> when beneficiary had 32 x 0 bytes set initially as allowed calls', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + zero32Bytes.address.substring(2); + + const value = combineAllowedCalls( + [CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + [ + INTERFACE_IDS.LSP7DigitalAsset, + INTERFACE_IDS.ERC20, + INTERFACE_IDS.LSP8IdentifiableDigitalAsset, + INTERFACE_IDS.ERC721, + ], + ['0xffffffff', '0xffffffff', '0xffffffff', '0xffffffff'], + ); + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + }); + + it('should fail with NotAuthorised -> when beneficiary had 40 x 0 bytes set initially as allowed calls', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + zero40Bytes.address.substring(2); + + const value = combineAllowedCalls( + [CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + [ + INTERFACE_IDS.LSP7DigitalAsset, + INTERFACE_IDS.ERC20, + INTERFACE_IDS.LSP8IdentifiableDigitalAsset, + INTERFACE_IDS.ERC721, + ], + ['0xffffffff', '0xffffffff', '0xffffffff', '0xffffffff'], + ); + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + }); + }); - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + newController.address.substr(2); + it('should pass when beneficiary had no values set under AddressPermissions:AllowedCalls:... + setting a valid bytes28[CompactBytesArray]', async () => { + const newController = ethers.Wallet.createRandom(); - const value = combineAllowedCalls( - [CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - [ - INTERFACE_IDS.LSP7DigitalAsset, - INTERFACE_IDS.ERC20, - // add NFT standards (new LSP8 + old ERC721) - // in the list of allowed calls for the beneficiary controller - // (in addition to token standards LSP7 + ERC20) - INTERFACE_IDS.LSP8IdentifiableDigitalAsset, - INTERFACE_IDS.ERC721, - ], - ['0xffffffff', '0xffffffff', '0xffffffff', '0xffffffff'], - ); + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + newController.address.substr(2); - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); + const value = combineAllowedCalls( + [CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + [ + INTERFACE_IDS.LSP7DigitalAsset, + INTERFACE_IDS.ERC20, + // add NFT standards (new LSP8 + old ERC721) + // in the list of allowed calls for the beneficiary controller + // (in addition to token standards LSP7 + ERC20) + INTERFACE_IDS.LSP8IdentifiableDigitalAsset, + INTERFACE_IDS.ERC721, + ], + ['0xffffffff', '0xffffffff', '0xffffffff', '0xffffffff'], + ); - await context.keyManager.connect(canOnlyAddController).execute(payload); + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); - // prettier-ignore - const result = await context.universalProfile.getData(key); - expect(result).to.equal(value); + await context.keyManager.connect(canOnlyAddController).execute(payload); + + // prettier-ignore + const result = await context.universalProfile.getData(key); + expect(result).to.equal(value); + }); }); describe('when setting an invalid bytes28[CompactBytesArray] of allowed calls for a new beneficiary', () => { @@ -1199,114 +1282,60 @@ export const shouldBehaveLikeSettingAllowedCalls = ( }); describe('when caller has EDITPERMISSIONS', () => { - it('should fail when beneficiary had no values set under AddressPermissions:AllowedCalls:...', async () => { - const newController = ethers.Wallet.createRandom(); - - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + newController.address.substr(2); - - const value = combineAllowedCalls( - [CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - // try to add in the list of allowed calls for the beneficiary controller - // the rights to CALL any LSP7 or ERC20 token contract - // (NB: just the AllowedCalls, not the permission CALL) - [INTERFACE_IDS.LSP7DigitalAsset, INTERFACE_IDS.ERC20], - ['0xffffffff', '0xffffffff'], - ); - - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); - - await expect(context.keyManager.connect(canOnlyEditPermissions).execute(payload)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyEditPermissions.address, 'ADDCONTROLLER'); - }); - - it('should pass when trying to edit existing allowed standards for an address', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - beneficiary.address.substring(2); - - const value = combineAllowedCalls( - [CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - [ - INTERFACE_IDS.LSP7DigitalAsset, - INTERFACE_IDS.ERC20, - // add NFT standards (new LSP8 + old ERC721) - // in the list of allowed calls for the beneficiary controller - // (in addition to token standards LSP7 + ERC20) - INTERFACE_IDS.LSP8IdentifiableDigitalAsset, - INTERFACE_IDS.ERC721, - ], - ['0xffffffff', '0xffffffff', '0xffffffff', '0xffffffff'], - ); - - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); - - await context.keyManager.connect(canOnlyEditPermissions).execute(payload); - - // prettier-ignore - const result = await context.universalProfile.getData(key); - expect(result).to.equal(value); - }); - - it('should pass when address had an invalid bytes28[CompactBytesArray] initially', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - invalidBeneficiary.address.substring(2); + describe('when controller to edit Allowed Calls for has some permissions', () => { + it('should fail when beneficiary had no values set under AddressPermissions:AllowedCalls:...', async () => { + const newController = ethers.Wallet.createRandom(); - const value = combineAllowedCalls( - [CALLTYPE.CALL, CALLTYPE.CALL], - [ - '0xffffffffffffffffffffffffffffffffffffffff', - '0xffffffffffffffffffffffffffffffffffffffff', - ], - [INTERFACE_IDS.LSP7DigitalAsset, INTERFACE_IDS.ERC20], - ['0xffffffff', '0xffffffff'], - ); + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + newController.address.substr(2); - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); + const value = combineAllowedCalls( + [CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + // try to add in the list of allowed calls for the beneficiary controller + // the rights to CALL any LSP7 or ERC20 token contract + // (NB: just the AllowedCalls, not the permission CALL) + [INTERFACE_IDS.LSP7DigitalAsset, INTERFACE_IDS.ERC20], + ['0xffffffff', '0xffffffff'], + ); - await context.keyManager.connect(canOnlyEditPermissions).execute(payload); + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); - const result = await context.universalProfile.getData(key); - expect(result).to.equal(value); - }); + await expect(context.keyManager.connect(canOnlyEditPermissions).execute(payload)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyEditPermissions.address, 'ADDCONTROLLER'); + }); - // even if the controller had some 00 bytes set as allowed calls, it is not considered as it does not have any allowed calls set - // but rather that its allowed calls are "disabled" - describe('when beneficiary (= controller) had 00 bytes set initially as allowed calls (e.g: allowed calls disabled)', () => { - it('should pass when address had 32 x 0 bytes set initially as allowed calls', async () => { + it('should pass when trying to edit existing allowed standards for an address', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - zero32Bytes.address.substring(2); + beneficiary.address.substring(2); const value = combineAllowedCalls( - [CALLTYPE.CALL, CALLTYPE.CALL], + [CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL, CALLTYPE.CALL], [ '0xffffffffffffffffffffffffffffffffffffffff', '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', ], - [INTERFACE_IDS.LSP7DigitalAsset, INTERFACE_IDS.ERC20], - ['0xffffffff', '0xffffffff'], + [ + INTERFACE_IDS.LSP7DigitalAsset, + INTERFACE_IDS.ERC20, + // add NFT standards (new LSP8 + old ERC721) + // in the list of allowed calls for the beneficiary controller + // (in addition to token standards LSP7 + ERC20) + INTERFACE_IDS.LSP8IdentifiableDigitalAsset, + INTERFACE_IDS.ERC721, + ], + ['0xffffffff', '0xffffffff', '0xffffffff', '0xffffffff'], ); const payload = context.universalProfile.interface.encodeFunctionData('setData', [ @@ -1316,14 +1345,15 @@ export const shouldBehaveLikeSettingAllowedCalls = ( await context.keyManager.connect(canOnlyEditPermissions).execute(payload); + // prettier-ignore const result = await context.universalProfile.getData(key); expect(result).to.equal(value); }); - it('should pass when address had 40 x 0 bytes set initially as allowed calls', async () => { + it('should pass when address had an invalid bytes28[CompactBytesArray] initially', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + - zero40Bytes.address.substring(2); + invalidBeneficiary.address.substring(2); const value = combineAllowedCalls( [CALLTYPE.CALL, CALLTYPE.CALL], @@ -1342,10 +1372,66 @@ export const shouldBehaveLikeSettingAllowedCalls = ( await context.keyManager.connect(canOnlyEditPermissions).execute(payload); - // prettier-ignore const result = await context.universalProfile.getData(key); expect(result).to.equal(value); }); + + // even if the controller had some 00 bytes set as allowed calls, it is not considered as it does not have any allowed calls set + // but rather that its allowed calls are "disabled" + describe('when beneficiary (= controller) had 00 bytes set initially as allowed calls (e.g: allowed calls disabled)', () => { + it('should pass when address had 32 x 0 bytes set initially as allowed calls', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + zero32Bytes.address.substring(2); + + const value = combineAllowedCalls( + [CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + [INTERFACE_IDS.LSP7DigitalAsset, INTERFACE_IDS.ERC20], + ['0xffffffff', '0xffffffff'], + ); + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await context.keyManager.connect(canOnlyEditPermissions).execute(payload); + + const result = await context.universalProfile.getData(key); + expect(result).to.equal(value); + }); + + it('should pass when address had 40 x 0 bytes set initially as allowed calls', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedCalls'] + + zero40Bytes.address.substring(2); + + const value = combineAllowedCalls( + [CALLTYPE.CALL, CALLTYPE.CALL], + [ + '0xffffffffffffffffffffffffffffffffffffffff', + '0xffffffffffffffffffffffffffffffffffffffff', + ], + [INTERFACE_IDS.LSP7DigitalAsset, INTERFACE_IDS.ERC20], + ['0xffffffff', '0xffffffff'], + ); + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await context.keyManager.connect(canOnlyEditPermissions).execute(payload); + + // prettier-ignore + const result = await context.universalProfile.getData(key); + expect(result).to.equal(value); + }); + }); }); describe('when changing the list of interface IDs in allowed calls :ANY:ANY to an invalid value', () => { diff --git a/tests/LSP6KeyManager/SetPermissions/SetAllowedERC725YDataKeys.test.ts b/tests/LSP6KeyManager/SetPermissions/SetAllowedERC725YDataKeys.test.ts index 848987cb8..f39dcccad 100644 --- a/tests/LSP6KeyManager/SetPermissions/SetAllowedERC725YDataKeys.test.ts +++ b/tests/LSP6KeyManager/SetPermissions/SetAllowedERC725YDataKeys.test.ts @@ -18,7 +18,8 @@ export const shouldBehaveLikeSetAllowedERC725YDataKeys = ( describe('setting Allowed ERC725YDataKeys', () => { let canOnlyAddController: SignerWithAddress, canOnlyEditPermissions: SignerWithAddress; - let beneficiary: SignerWithAddress, + let beneficiaryWithPermissions: SignerWithAddress, + beneficiaryNoPermissions: SignerWithAddress, invalidBeneficiary: SignerWithAddress, zero32Bytes: SignerWithAddress, zero40Bytes: SignerWithAddress; @@ -29,34 +30,43 @@ export const shouldBehaveLikeSetAllowedERC725YDataKeys = ( canOnlyAddController = context.accounts[1]; canOnlyEditPermissions = context.accounts[2]; - beneficiary = context.accounts[3]; - invalidBeneficiary = context.accounts[4]; - zero32Bytes = context.accounts[5]; - zero40Bytes = context.accounts[6]; + beneficiaryWithPermissions = context.accounts[3]; + beneficiaryNoPermissions = context.accounts[4]; + invalidBeneficiary = context.accounts[5]; + zero32Bytes = context.accounts[6]; + zero40Bytes = context.accounts[7]; + // prettier-ignore const permissionKeys = [ - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - canOnlyAddController.address.substring(2), - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - canOnlyEditPermissions.address.substring(2), - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - beneficiary.address.substring(2), - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - invalidBeneficiary.address.substring(2), - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - zero32Bytes.address.substring(2), - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - zero40Bytes.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + canOnlyAddController.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + canOnlyEditPermissions.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + beneficiaryWithPermissions.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + invalidBeneficiary.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + zero32Bytes.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + zero40Bytes.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + beneficiaryWithPermissions.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + beneficiaryNoPermissions.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + invalidBeneficiary.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + zero32Bytes.address.substring(2), + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + zero40Bytes.address.substring(2), ]; const permissionValues = [ PERMISSIONS.ADDCONTROLLER, PERMISSIONS.EDITPERMISSIONS, + PERMISSIONS.SETDATA, + PERMISSIONS.SETDATA, + PERMISSIONS.SETDATA, + PERMISSIONS.SETDATA, encodeCompactBytesArray([ ERC725YDataKeys.LSP3['LSP3Profile'], // prettier-ignore ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Some Custom Profile Data Key")), ]), + encodeCompactBytesArray([ + ethers.utils.hexlify(ethers.utils.randomBytes(32)), + ethers.utils.hexlify(ethers.utils.randomBytes(32)), + ]), '0x11223344', '0x0000000000000000000000000000000000000000000000000000000000000000', '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000', @@ -66,98 +76,149 @@ export const shouldBehaveLikeSetAllowedERC725YDataKeys = ( }); describe('when caller has ADDCONTROLLER', () => { - describe('when beneficiary had some ERC725Y data keys set under AddressPermissions:AllowedERC725YDataKeys:...', () => { - it('should fail when adding an extra allowed ERC725Y data key', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - beneficiary.address.substring(2); - - const value = encodeCompactBytesArray([ - ERC725YDataKeys.LSP3['LSP3Profile'], - // prettier-ignore - ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Some Custom Profile Data Key")), - // prettier-ignore - ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Another Custom Data Key")), - ]); - - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); - - await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); - }); - - it('should fail when removing an allowed ERC725Y data key', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - beneficiary.address.substring(2); - - const value = encodeCompactBytesArray([ERC725YDataKeys.LSP3['LSP3Profile']]); - - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); - - await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + describe('when controller / beneficiary had some permissions set', () => { + describe('when beneficiary had some ERC725Y data keys set under AddressPermissions:AllowedERC725YDataKeys:...', () => { + it('should fail when adding an extra allowed ERC725Y data key', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + beneficiaryWithPermissions.address.substring(2); + + const value = encodeCompactBytesArray([ + ERC725YDataKeys.LSP3['LSP3Profile'], + // prettier-ignore + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Some Custom Profile Data Key")), + // prettier-ignore + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Another Custom Data Key")), + ]); + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + }); + + it('should fail when removing an allowed ERC725Y data key', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + beneficiaryWithPermissions.address.substring(2); + + const value = encodeCompactBytesArray([ERC725YDataKeys.LSP3['LSP3Profile']]); + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + }); + + it('should fail when trying to clear the CompactedBytesArray completely', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + beneficiaryWithPermissions.address.substring(2); + + const value = '0x'; + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); + }); + + it('should fail when setting an invalid CompactedBytesArray', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + beneficiaryWithPermissions.address.substring(2); + + const value = '0xbadbadbadbad'; + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) + .to.be.revertedWithCustomError( + context.keyManager, + 'InvalidEncodedAllowedERC725YDataKeys', + ) + .withArgs(value, "couldn't VALIDATE the data value"); + }); }); - it('should fail when trying to clear the CompactedBytesArray completely', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - beneficiary.address.substring(2); - - const value = '0x'; - - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); + describe('when beneficiary had no ERC725Y data keys set under AddressPermissions:AllowedERC725YDataKeys:...', () => { + it('should pass when setting a valid CompactedBytesArray', async () => { + const newController = ethers.Wallet.createRandom(); - await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) - .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') - .withArgs(canOnlyAddController.address, 'EDITPERMISSIONS'); - }); + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + newController.address.substr(2); - it('should fail when setting an invalid CompactedBytesArray', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - beneficiary.address.substring(2); + const value = encodeCompactBytesArray([ + // prettier-ignore + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("My Custom Profile Key 1")), + // prettier-ignore + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("My Custom Profile Key 2")), + ]); - const value = '0xbadbadbadbad'; + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); + await context.keyManager.connect(canOnlyAddController).execute(payload); - await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) - .to.be.revertedWithCustomError( - context.keyManager, - 'InvalidEncodedAllowedERC725YDataKeys', - ) - .withArgs(value, "couldn't VALIDATE the data value"); + // prettier-ignore + const result = await context.universalProfile.getData(key); + expect(result).to.equal(value); + }); + + it('should fail when setting an invalid CompactedBytesArray (random bytes)', async () => { + const newController = ethers.Wallet.createRandom(); + + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + newController.address.substr(2); + + const value = '0xbadbadbadbad'; + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) + .to.be.revertedWithCustomError( + context.keyManager, + 'InvalidEncodedAllowedERC725YDataKeys', + ) + .withArgs(value, "couldn't VALIDATE the data value"); + }); }); }); - describe('when beneficiary had no ERC725Y data keys set under AddressPermissions:AllowedERC725YDataKeys:...', () => { - it('should pass when setting a valid CompactedBytesArray', async () => { - const newController = ethers.Wallet.createRandom(); - + describe('when controller / beneficiary had no permissions set', () => { + it('should pass and edit the list of Allowed ERC725Y Data Keys', async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - newController.address.substr(2); + beneficiaryNoPermissions.address.substring(2); const value = encodeCompactBytesArray([ + ERC725YDataKeys.LSP3['LSP3Profile'], // prettier-ignore - ethers.utils.keccak256(ethers.utils.toUtf8Bytes("My Custom Profile Key 1")), + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Some Custom Profile Data Key")), // prettier-ignore - ethers.utils.keccak256(ethers.utils.toUtf8Bytes("My Custom Profile Key 2")), + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Another Custom Data Key")), ]); const payload = context.universalProfile.interface.encodeFunctionData('setData', [ @@ -167,132 +228,157 @@ export const shouldBehaveLikeSetAllowedERC725YDataKeys = ( await context.keyManager.connect(canOnlyAddController).execute(payload); - // prettier-ignore - const result = await context.universalProfile.getData(key); - expect(result).to.equal(value); - }); - - it('should fail when setting an invalid CompactedBytesArray (random bytes)', async () => { - const newController = ethers.Wallet.createRandom(); - - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - newController.address.substr(2); - - const value = '0xbadbadbadbad'; - - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); - - await expect(context.keyManager.connect(canOnlyAddController).execute(payload)) - .to.be.revertedWithCustomError( - context.keyManager, - 'InvalidEncodedAllowedERC725YDataKeys', - ) - .withArgs(value, "couldn't VALIDATE the data value"); + expect(await context.universalProfile.getData(key)).to.equal(value); }); }); }); describe('when caller has EDITPERMISSIONS', () => { - describe('when beneficiary had some ERC725Y data keys set under AddressPermissions:AllowedERC725YDataKeys:...', () => { - it('should pass when adding an extra allowed ERC725Y data key', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - beneficiary.address.substring(2); + describe('when controller / beneficiary had some permissions set', () => { + describe('when beneficiary had some ERC725Y data keys set under AddressPermissions:AllowedERC725YDataKeys:...', () => { + it('should pass when adding an extra allowed ERC725Y data key', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + beneficiaryWithPermissions.address.substring(2); + + const value = encodeCompactBytesArray([ + ERC725YDataKeys.LSP3['LSP3Profile'], + // prettier-ignore + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Some Custom Profile Data Key")), + // prettier-ignore + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Another Custom Data Key")), + ]); + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await context.keyManager.connect(canOnlyEditPermissions).execute(payload); - const value = encodeCompactBytesArray([ - ERC725YDataKeys.LSP3['LSP3Profile'], - // prettier-ignore - ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Some Custom Profile Data Key")), // prettier-ignore - ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Another Custom Data Key")), - ]); - - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); - - await context.keyManager.connect(canOnlyEditPermissions).execute(payload); - - // prettier-ignore - const result = await context.universalProfile.getData(key); - expect(result).to.equal(value); - }); + const result = await context.universalProfile.getData(key); + expect(result).to.equal(value); + }); - it('should pass when removing an allowed ERC725Y data key', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - beneficiary.address.substring(2); + it('should pass when removing an allowed ERC725Y data key', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + beneficiaryWithPermissions.address.substring(2); - const value = encodeCompactBytesArray([ERC725YDataKeys.LSP3['LSP3Profile']]); + const value = encodeCompactBytesArray([ERC725YDataKeys.LSP3['LSP3Profile']]); - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); - await context.keyManager.connect(canOnlyEditPermissions).execute(payload); + await context.keyManager.connect(canOnlyEditPermissions).execute(payload); - // prettier-ignore - const result = await context.universalProfile.getData(key); - expect(result).to.equal(value); - }); + // prettier-ignore + const result = await context.universalProfile.getData(key); + expect(result).to.equal(value); + }); - it('should pass when trying to clear the CompactedBytesArray completely', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - beneficiary.address.substring(2); + it('should pass when trying to clear the CompactedBytesArray completely', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + beneficiaryWithPermissions.address.substring(2); - const value = '0x'; + const value = '0x'; - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); - await context.keyManager.connect(canOnlyEditPermissions).execute(payload); + await context.keyManager.connect(canOnlyEditPermissions).execute(payload); - // prettier-ignore - const result = await context.universalProfile.getData(key); - expect(result).to.equal(value); + // prettier-ignore + const result = await context.universalProfile.getData(key); + expect(result).to.equal(value); + }); + + it('should fail when setting an invalid CompactedBytesArray', async () => { + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + beneficiaryWithPermissions.address.substring(2); + + const value = '0xbadbadbadbad'; + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await expect(context.keyManager.connect(canOnlyEditPermissions).execute(payload)) + .to.be.revertedWithCustomError( + context.keyManager, + 'InvalidEncodedAllowedERC725YDataKeys', + ) + .withArgs(value, "couldn't VALIDATE the data value"); + }); }); - it('should fail when setting an invalid CompactedBytesArray', async () => { - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - beneficiary.address.substring(2); - - const value = '0xbadbadbadbad'; - - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); - - await expect(context.keyManager.connect(canOnlyEditPermissions).execute(payload)) - .to.be.revertedWithCustomError( - context.keyManager, - 'InvalidEncodedAllowedERC725YDataKeys', - ) - .withArgs(value, "couldn't VALIDATE the data value"); + describe('when beneficiary had no ERC725Y data keys set under AddressPermissions:AllowedERC725YDataKeys:...', () => { + it('should fail and not authorize to add a list of allowed ERC725Y data keys (not authorised)', async () => { + const newController = ethers.Wallet.createRandom(); + + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + newController.address.substr(2); + + const value = encodeCompactBytesArray([ + ethers.utils.keccak256(ethers.utils.toUtf8Bytes('My Custom Key 1')), + ethers.utils.keccak256(ethers.utils.toUtf8Bytes('My Custom Key 2')), + ]); + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await expect(context.keyManager.connect(canOnlyEditPermissions).execute(payload)) + .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') + .withArgs(canOnlyEditPermissions.address, 'ADDCONTROLLER'); + }); + + it('should fail when setting an invalid CompactedBytesArray', async () => { + const newController = ethers.Wallet.createRandom(); + + const key = + ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + + newController.address.substr(2); + + const value = '0xbadbadbadbad'; + + const payload = context.universalProfile.interface.encodeFunctionData('setData', [ + key, + value, + ]); + + await expect(context.keyManager.connect(canOnlyEditPermissions).execute(payload)) + .to.be.revertedWithCustomError( + context.keyManager, + 'InvalidEncodedAllowedERC725YDataKeys', + ) + .withArgs(value, "couldn't VALIDATE the data value"); + }); }); }); - describe('when beneficiary had no ERC725Y data keys set under AddressPermissions:AllowedERC725YDataKeys:...', () => { - it('should fail and not authorize to add a list of allowed ERC725Y data keys (not authorised)', async () => { - const newController = ethers.Wallet.createRandom(); - + describe('when controller / beneficiary had no permissions set', () => { + it("should revert with error `NotAuthorised('ADDCONTROLLER')` when trying to add a list of allowed ERC725Y data keys", async () => { const key = ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - newController.address.substr(2); + beneficiaryNoPermissions.address.substring(2); const value = encodeCompactBytesArray([ - ethers.utils.keccak256(ethers.utils.toUtf8Bytes('My Custom Key 1')), - ethers.utils.keccak256(ethers.utils.toUtf8Bytes('My Custom Key 2')), + ERC725YDataKeys.LSP3['LSP3Profile'], + // prettier-ignore + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Some Custom Profile Data Key")), + // prettier-ignore + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Another Custom Data Key")), ]); const payload = context.universalProfile.interface.encodeFunctionData('setData', [ @@ -304,28 +390,6 @@ export const shouldBehaveLikeSetAllowedERC725YDataKeys = ( .to.be.revertedWithCustomError(context.keyManager, 'NotAuthorised') .withArgs(canOnlyEditPermissions.address, 'ADDCONTROLLER'); }); - - it('should fail when setting an invalid CompactedBytesArray', async () => { - const newController = ethers.Wallet.createRandom(); - - const key = - ERC725YDataKeys.LSP6['AddressPermissions:AllowedERC725YDataKeys'] + - newController.address.substr(2); - - const value = '0xbadbadbadbad'; - - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - key, - value, - ]); - - await expect(context.keyManager.connect(canOnlyEditPermissions).execute(payload)) - .to.be.revertedWithCustomError( - context.keyManager, - 'InvalidEncodedAllowedERC725YDataKeys', - ) - .withArgs(value, "couldn't VALIDATE the data value"); - }); }); }); }); From d1df1d0c106f47bd24427f1c20c3423a00bb993c Mon Sep 17 00:00:00 2001 From: Skima Harvey <64636974+skimaharvey@users.noreply.github.com> Date: Mon, 9 Oct 2023 16:53:53 +0100 Subject: [PATCH 37/55] feat: create Extension4337 (#735) * chore: add @account-abstraction/contracts to package * feat: create Extension4337 * chore: add 4337 tests to package and ci * test: create test helpers 4337 * test: create tests for 4337 * fix: remove unused imports * fix: lint issues * refactor: apply recommendations * feat: move `OnERC721ReceivedExtension` from Mocks to LSP17 folder * docs: add auto-generated docs for LSP17 Extensions * fix: depositTo entrypoint * test: apply recommendations * fix: check for _LSP20_VERIFY_CALL_RESULT_MAGIC_VALUE * fix: signature verification in extension * refactor: remove autorefund logic from 4337 extension --------- Co-authored-by: CJ42 --- .github/workflows/build-lint-test.yml | 1 + contracts/LSP17Extensions/Extension4337.sol | 100 +++++++ .../OnERC721ReceivedExtension.sol | 15 ++ contracts/LSP2ERC725YJSONSchema/LSP2Utils.sol | 2 +- .../OnERC721ReceivedExtension.sol | 16 -- .../Mocks/Tokens/RequireCallbackToken.sol | 2 +- .../LSP17Extensions/Extension4337.md | 173 ++++++++++++ .../OnERC721ReceivedExtension.md | 61 +++++ dodoc/config.ts | 2 + package-lock.json | 11 + package.json | 2 + .../Extension4337/4337.test.ts | 219 +++++++++++++++ .../LSP17Extensions/helpers/Create2Factory.ts | 124 +++++++++ tests/LSP17Extensions/helpers/UserOp.ts | 251 ++++++++++++++++++ .../LSP17Extensions/helpers/solidityTypes.ts | 10 + tests/LSP17Extensions/helpers/utils.ts | 32 +++ 16 files changed, 1003 insertions(+), 18 deletions(-) create mode 100644 contracts/LSP17Extensions/Extension4337.sol create mode 100644 contracts/LSP17Extensions/OnERC721ReceivedExtension.sol delete mode 100644 contracts/Mocks/FallbackExtensions/OnERC721ReceivedExtension.sol create mode 100644 docs/contracts/LSP17Extensions/Extension4337.md create mode 100644 docs/contracts/LSP17Extensions/OnERC721ReceivedExtension.md create mode 100644 tests/LSP17Extensions/Extension4337/4337.test.ts create mode 100644 tests/LSP17Extensions/helpers/Create2Factory.ts create mode 100644 tests/LSP17Extensions/helpers/UserOp.ts create mode 100644 tests/LSP17Extensions/helpers/solidityTypes.ts create mode 100644 tests/LSP17Extensions/helpers/utils.ts diff --git a/.github/workflows/build-lint-test.yml b/.github/workflows/build-lint-test.yml index 887607dfc..99b5a8e54 100644 --- a/.github/workflows/build-lint-test.yml +++ b/.github/workflows/build-lint-test.yml @@ -76,6 +76,7 @@ jobs: "lsp11", "lsp11init", "lsp17", + "lsp17extensions", "lsp20", "lsp20init", "lsp23", diff --git a/contracts/LSP17Extensions/Extension4337.sol b/contracts/LSP17Extensions/Extension4337.sol new file mode 100644 index 000000000..81cf154d3 --- /dev/null +++ b/contracts/LSP17Extensions/Extension4337.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.9; + +// interfaces +import {IAccount} from "@account-abstraction/contracts/interfaces/IAccount.sol"; +import { + IERC725Y +} from "@erc725/smart-contracts/contracts/interfaces/IERC725Y.sol"; +import { + ILSP20CallVerifier +} from "../LSP20CallVerification/ILSP20CallVerifier.sol"; + +// modules +import {LSP14Ownable2Step} from "../LSP14Ownable2Step/LSP14Ownable2Step.sol"; +import {LSP17Extension} from "../LSP17ContractExtension/LSP17Extension.sol"; + +// librairies +import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; +import {LSP6Utils} from "../LSP6KeyManager/LSP6Utils.sol"; + +// constants +import { + UserOperation +} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; + +contract Extension4337 is LSP17Extension, IAccount { + using ECDSA for bytes32; + using LSP6Utils for *; + + address internal immutable _ENTRY_POINT; + + // permission needed to be able to use this extension + bytes32 internal constant _4337_PERMISSION = + 0x0000000000000000000000000000000000000000000000000000000000800000; + + // error code returned when signature or permission validation fails + uint256 internal constant _SIG_VALIDATION_FAILED = 1; + + constructor(address entryPoint_) { + _ENTRY_POINT = entryPoint_; + } + + /** + * @inheritdoc IAccount + */ + function validateUserOp( + UserOperation calldata userOp, + bytes32 userOpHash, + uint256 /* missingAccountFunds */ + ) external returns (uint256) { + require( + _extendableMsgSender() == _ENTRY_POINT, + "Only EntryPoint contract can call this" + ); + + // recover initiator of the tx from the signature + bytes32 hash = userOpHash.toEthSignedMessageHash(); + address recovered = hash.recover(userOp.signature); + + // verify that the recovered address has the _4337_PERMISSION + if ( + !LSP6Utils.hasPermission( + IERC725Y(msg.sender).getPermissionsFor(recovered), + _4337_PERMISSION + ) + ) { + return _SIG_VALIDATION_FAILED; + } + + // retrieve owner from caller + address owner = LSP14Ownable2Step(msg.sender).owner(); + + // verify that the recovered address can execute the userOp.callData + bytes4 magicValue = ILSP20CallVerifier(owner).lsp20VerifyCall({ + callee: msg.sender, + caller: recovered, + value: 0, + receivedCalldata: userOp.callData + }); + + // if the call verifier returns a different magic value, return signature validation failed + if ( + bytes3(magicValue) != + bytes3(ILSP20CallVerifier.lsp20VerifyCall.selector) + ) { + return _SIG_VALIDATION_FAILED; + } + + // if sig validation passed, return 0 + return 0; + } + + /** + * @dev Get the address of the Entry Point contract that will execute the user operation. + * @return The address of the EntryPoint contract + */ + function entryPoint() public view returns (address) { + return _ENTRY_POINT; + } +} diff --git a/contracts/LSP17Extensions/OnERC721ReceivedExtension.sol b/contracts/LSP17Extensions/OnERC721ReceivedExtension.sol new file mode 100644 index 000000000..47f6be65e --- /dev/null +++ b/contracts/LSP17Extensions/OnERC721ReceivedExtension.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.4; + +import { + ERC721Holder +} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; + +/** + * @dev LSP17 Extension that can be attached to a LSP17Extendable contract + * to allow it to receive ERC721 tokens via `safeTransferFrom`. + */ +// solhint-disable-next-line no-empty-blocks +contract OnERC721ReceivedExtension is ERC721Holder { + +} diff --git a/contracts/LSP2ERC725YJSONSchema/LSP2Utils.sol b/contracts/LSP2ERC725YJSONSchema/LSP2Utils.sol index 06fd72f1d..1c1319b00 100644 --- a/contracts/LSP2ERC725YJSONSchema/LSP2Utils.sol +++ b/contracts/LSP2ERC725YJSONSchema/LSP2Utils.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0 +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; // interfaces diff --git a/contracts/Mocks/FallbackExtensions/OnERC721ReceivedExtension.sol b/contracts/Mocks/FallbackExtensions/OnERC721ReceivedExtension.sol deleted file mode 100644 index 6dfa3f4a9..000000000 --- a/contracts/Mocks/FallbackExtensions/OnERC721ReceivedExtension.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.4; - -/** - * @dev This contract is used only for testing purposes - */ -contract OnERC721ReceivedExtension { - function onERC721Received( - address /* operator */, - address /* from */, - uint256 /* tokenId */, - bytes calldata /* data */ - ) external pure returns (bytes4) { - return 0x150b7a02; - } -} diff --git a/contracts/Mocks/Tokens/RequireCallbackToken.sol b/contracts/Mocks/Tokens/RequireCallbackToken.sol index e7bacc99b..e2d7dfaaa 100644 --- a/contracts/Mocks/Tokens/RequireCallbackToken.sol +++ b/contracts/Mocks/Tokens/RequireCallbackToken.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.4; import { OnERC721ReceivedExtension -} from "../FallbackExtensions/OnERC721ReceivedExtension.sol"; +} from "../../LSP17Extensions/OnERC721ReceivedExtension.sol"; /** * @dev This contract is used only for testing purposes diff --git a/docs/contracts/LSP17Extensions/Extension4337.md b/docs/contracts/LSP17Extensions/Extension4337.md new file mode 100644 index 000000000..9c8b510c2 --- /dev/null +++ b/docs/contracts/LSP17Extensions/Extension4337.md @@ -0,0 +1,173 @@ + + + +# Extension4337 + +:::info Standard Specifications + +[`LSP-17-Extensions`](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-17-Extensions.md) + +::: +:::info Solidity implementation + +[`Extension4337.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP17Extensions/Extension4337.sol) + +::: + +## Public Methods + +Public methods are accessible externally from users, allowing interaction with this function from dApps or other smart contracts. +When marked as 'public', a method can be called both externally and internally, on the other hand, when marked as 'external', a method can only be called externally. + +### constructor + +:::note References + +- Specification details: [**LSP-17-Extensions**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-17-Extensions.md#constructor) +- Solidity implementation: [`Extension4337.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP17Extensions/Extension4337.sol) + +::: + +```solidity +constructor(address entryPoint_); +``` + +#### Parameters + +| Name | Type | Description | +| ------------- | :-------: | ----------- | +| `entryPoint_` | `address` | - | + +
+ +### entryPoint + +:::note References + +- Specification details: [**LSP-17-Extensions**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-17-Extensions.md#entrypoint) +- Solidity implementation: [`Extension4337.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP17Extensions/Extension4337.sol) +- Function signature: `entryPoint()` +- Function selector: `0xb0d691fe` + +::: + +```solidity +function entryPoint() external view returns (address); +``` + +Get the address of the Entry Point contract that will execute the user operation. + +#### Returns + +| Name | Type | Description | +| ---- | :-------: | -------------------------------------- | +| `0` | `address` | The address of the EntryPoint contract | + +
+ +### supportsInterface + +:::note References + +- Specification details: [**LSP-17-Extensions**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-17-Extensions.md#supportsinterface) +- Solidity implementation: [`Extension4337.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP17Extensions/Extension4337.sol) +- Function signature: `supportsInterface(bytes4)` +- Function selector: `0x01ffc9a7` + +::: + +```solidity +function supportsInterface(bytes4 interfaceId) external view returns (bool); +``` + +See [`IERC165-supportsInterface`](#ierc165-supportsinterface). + +#### Parameters + +| Name | Type | Description | +| ------------- | :------: | ----------- | +| `interfaceId` | `bytes4` | - | + +#### Returns + +| Name | Type | Description | +| ---- | :----: | ----------- | +| `0` | `bool` | - | + +
+ +### validateUserOp + +:::note References + +- Specification details: [**LSP-17-Extensions**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-17-Extensions.md#validateuserop) +- Solidity implementation: [`Extension4337.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP17Extensions/Extension4337.sol) +- Function signature: `validateUserOp(UserOperation,bytes32,)` +- Function selector: `0x68159319` + +::: + +```solidity +function validateUserOp( + UserOperation userOp, + bytes32 userOpHash, + uint256 +) external nonpayable returns (uint256); +``` + +_Validate user's signature and nonce the entryPoint will make the call to the recipient only if this validation call returns successfully. signature failure should be reported by returning SIG_VALIDATION_FAILED (1). This allows making a "simulation call" without a valid signature Other failures (e.g. nonce mismatch, or invalid signature format) should still revert to signal failure._ + +Must validate caller is the entryPoint. Must validate the signature and nonce + +#### Parameters + +| Name | Type | Description | +| ------------ | :-------------: | ------------------------------------------------------------------------ | +| `userOp` | `UserOperation` | the operation that is about to be executed. | +| `userOpHash` | `bytes32` | hash of the user's request data. can be used as the basis for signature. | +| `_2` | `uint256` | - | + +#### Returns + +| Name | Type | Description | +| ---- | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `0` | `uint256` | packaged ValidationData structure. use `_packValidationData` and `_unpackValidationData` to encode and decode <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure, otherwise, an address of an "authorizer" contract. <6-byte> validUntil - last timestamp this operation is valid. 0 for "indefinite" <6-byte> validAfter - first timestamp this operation is valid If an account doesn't use time-range, it is enough to return SIG_VALIDATION_FAILED value (1) for signature failure. Note that the validation code cannot use block.timestamp (or block.number) directly. | + +
+ +## Internal Methods + +Any method labeled as `internal` serves as utility function within the contract. They can be used when writing solidity contracts that inherit from this contract. These methods can be extended or modified by overriding their internal behavior to suit specific needs. + +Internal functions cannot be called externally, whether from other smart contracts, dApp interfaces, or backend services. Their restricted accessibility ensures that they remain exclusively available within the context of the current contract, promoting controlled and encapsulated usage of these internal utilities. + +### \_extendableMsgData + +```solidity +function _extendableMsgData() internal view returns (bytes); +``` + +Returns the original `msg.data` passed to the extendable contract +without the appended `msg.sender` and `msg.value`. + +
+ +### \_extendableMsgSender + +```solidity +function _extendableMsgSender() internal view returns (address); +``` + +Returns the original `msg.sender` calling the extendable contract. + +
+ +### \_extendableMsgValue + +```solidity +function _extendableMsgValue() internal view returns (uint256); +``` + +Returns the original `msg.value` sent to the extendable contract. + +
diff --git a/docs/contracts/LSP17Extensions/OnERC721ReceivedExtension.md b/docs/contracts/LSP17Extensions/OnERC721ReceivedExtension.md new file mode 100644 index 000000000..d40d353e2 --- /dev/null +++ b/docs/contracts/LSP17Extensions/OnERC721ReceivedExtension.md @@ -0,0 +1,61 @@ + + + +# OnERC721ReceivedExtension + +:::info Standard Specifications + +[`LSP-17-Extensions`](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-17-Extensions.md) + +::: +:::info Solidity implementation + +[`OnERC721ReceivedExtension.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP17Extensions/OnERC721ReceivedExtension.sol) + +::: + +LSP17 Extension that can be attached to a LSP17Extendable contract to allow it to receive ERC721 tokens via `safeTransferFrom`. + +## Public Methods + +Public methods are accessible externally from users, allowing interaction with this function from dApps or other smart contracts. +When marked as 'public', a method can be called both externally and internally, on the other hand, when marked as 'external', a method can only be called externally. + +### onERC721Received + +:::note References + +- Specification details: [**LSP-17-Extensions**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-17-Extensions.md#,,,)) +- Solidity implementation: [`OnERC721ReceivedExtension.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP17Extensions/OnERC721ReceivedExtension.sol) +- Function signature: `,,,)` +- Function selector: `0x940e0af1` + +::: + +```solidity +function onERC721Received( + address, + address, + uint256, + bytes +) external nonpayable returns (bytes4); +``` + +See [`IERC721Receiver-onERC721Received`](#ierc721receiver-onerc721received). Always returns `IERC721Receiver.onERC721Received.selector`. + +#### Parameters + +| Name | Type | Description | +| ---- | :-------: | ----------- | +| `_0` | `address` | - | +| `_1` | `address` | - | +| `_2` | `uint256` | - | +| `_3` | `bytes` | - | + +#### Returns + +| Name | Type | Description | +| ---- | :------: | ----------- | +| `0` | `bytes4` | - | + +
diff --git a/dodoc/config.ts b/dodoc/config.ts index d81ec045b..9ac28dc9a 100644 --- a/dodoc/config.ts +++ b/dodoc/config.ts @@ -15,6 +15,8 @@ export const dodocConfig = { 'contracts/LSP16UniversalFactory/LSP16UniversalFactory.sol', 'contracts/LSP17ContractExtension/LSP17Extendable.sol', 'contracts/LSP17ContractExtension/LSP17Extension.sol', + 'contracts/LSP17Extensions/Extension4337.sol', + 'contracts/LSP17Extensions/OnERC721ReceivedExtension.sol', 'contracts/LSP20CallVerification/LSP20CallVerification.sol', 'contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol', 'contracts/LSP23LinkedContractsFactory/IPostDeploymentModule.sol', diff --git a/package-lock.json b/package-lock.json index 8d1136bc0..5a2881312 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.11.1", "license": "Apache-2.0", "dependencies": { + "@account-abstraction/contracts": "^0.6.0", "@erc725/smart-contracts": "^5.2.0", "@openzeppelin/contracts": "^4.9.2", "@openzeppelin/contracts-upgradeable": "^4.9.2", @@ -57,6 +58,11 @@ "web3": "^1.5.2" } }, + "node_modules/@account-abstraction/contracts": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@account-abstraction/contracts/-/contracts-0.6.0.tgz", + "integrity": "sha512-8ooRJuR7XzohMDM4MV34I12Ci2bmxfE9+cixakRL7lA4BAwJKQ3ahvd8FbJa9kiwkUPCUNtj+/zxDQWYYalLMQ==" + }, "node_modules/@ampproject/remapping": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", @@ -22295,6 +22301,11 @@ } }, "dependencies": { + "@account-abstraction/contracts": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@account-abstraction/contracts/-/contracts-0.6.0.tgz", + "integrity": "sha512-8ooRJuR7XzohMDM4MV34I12Ci2bmxfE9+cixakRL7lA4BAwJKQ3ahvd8FbJa9kiwkUPCUNtj+/zxDQWYYalLMQ==" + }, "@ampproject/remapping": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", diff --git a/package.json b/package.json index 47b2e7dd6..aa2a8b133 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "test:lsp11": "hardhat test --no-compile tests/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.test.ts", "test:lsp11init": "hardhat test --no-compile tests/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryInit.test.ts", "test:lsp17": "hardhat test --no-compile tests/LSP17ContractExtension/LSP17Extendable.test.ts", + "test:lsp17extensions": "hardhat test --no-compile tests/LSP17Extensions/**/*.test.ts", "test:lsp20": "hardhat test --no-compile tests/LSP20CallVerification/LSP6/LSP20WithLSP6.test.ts", "test:lsp20init": "hardhat test --no-compile tests/LSP20CallVerification/LSP6/LSP20WithLSP6Init.test.ts", "test:lsp23": "hardhat test --no-compile tests/LSP23LinkedContractsDeployment/LSP23LinkedContractsDeployment.test.ts", @@ -102,6 +103,7 @@ }, "homepage": "https://github.com/lukso-network/lsp-smart-contracts#readme", "dependencies": { + "@account-abstraction/contracts": "^0.6.0", "@erc725/smart-contracts": "^5.2.0", "@openzeppelin/contracts": "^4.9.2", "@openzeppelin/contracts-upgradeable": "^4.9.2", diff --git a/tests/LSP17Extensions/Extension4337/4337.test.ts b/tests/LSP17Extensions/Extension4337/4337.test.ts new file mode 100644 index 000000000..3a9f9ff68 --- /dev/null +++ b/tests/LSP17Extensions/Extension4337/4337.test.ts @@ -0,0 +1,219 @@ +import { ethers } from 'hardhat'; +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import { Signer } from 'ethers'; +import { EntryPoint__factory, EntryPoint } from '@account-abstraction/contracts'; + +import { BytesLike, parseEther } from 'ethers/lib/utils'; +import { expect } from 'chai'; +import { + Extension4337__factory, + LSP6KeyManager, + LSP6KeyManager__factory, + UniversalProfile, + UniversalProfile__factory, +} from '../../../types'; +import { deployEntryPoint, getBalance, isDeployed } from '../helpers/utils'; +import { ALL_PERMISSIONS, ERC725YDataKeys, OPERATION_TYPES } from '../../../constants'; +import { combinePermissions } from '../../utils/helpers'; +import { fillAndSign } from '../helpers/UserOp'; + +describe('4337', function () { + let bundler: SignerWithAddress; + let deployer: Signer; + let universalProfile: UniversalProfile; + let universalProfileAddress: string; + let keyManager: LSP6KeyManager; + let entryPoint: EntryPoint; + let controllerWith4337Permission: SignerWithAddress; + let controllerWithout4337Permission: SignerWithAddress; + let controllerWithOnly4337Permission: SignerWithAddress; + let transferCallData: string; + const Permission4337: BytesLike = + '0x0000000000000000000000000000000000000000000000000000000000800000'; + const amountToTransfer = 1; + + before('setup', async function () { + const provider = ethers.provider; + deployer = provider.getSigner(); + const deployerAddress = await deployer.getAddress(); + + [ + bundler, + controllerWith4337Permission, + controllerWithout4337Permission, + controllerWithOnly4337Permission, + ] = await ethers.getSigners(); + + universalProfile = await new UniversalProfile__factory(deployer).deploy( + await deployer.getAddress(), + { value: parseEther('1') }, + ); + universalProfileAddress = universalProfile.address; + + keyManager = await new LSP6KeyManager__factory(deployer).deploy(universalProfile.address); + + // transfer ownership to keyManager + await universalProfile.transferOwnership(keyManager.address); + + const dataKey = + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + deployerAddress.slice(2); + + await universalProfile.setData(dataKey, ALL_PERMISSIONS); + + const acceptOwnershipBytes = universalProfile.interface.encodeFunctionData('acceptOwnership'); + await keyManager.execute(acceptOwnershipBytes); + expect(await universalProfile.owner()).to.eq(keyManager.address); + + // deploy entrypoint + entryPoint = await deployEntryPoint(); + expect(await isDeployed(entryPoint.address)).to.eq(true); + + // give all permissions to entrypoint + const dataKeyEntryPointPermissions = + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + entryPoint.address.slice(2); + await universalProfile.setData(dataKeyEntryPointPermissions, ALL_PERMISSIONS); + + // deploy extension and attach it to universalProfile + const extension4337 = await new Extension4337__factory(deployer).deploy(entryPoint.address); + const validateUserOpSigHash = extension4337.interface.getSighash('validateUserOp'); + + const extensionDataKey = + ERC725YDataKeys.LSP17.LSP17ExtensionPrefix + + validateUserOpSigHash.slice(2) + + '00000000000000000000000000000000'; + + await universalProfile.setData(extensionDataKey, extension4337.address); + + // give permissions to controllers + const dataKeyWithPermission4337 = + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + controllerWith4337Permission.address.slice(2); + await universalProfile.setData( + dataKeyWithPermission4337, + combinePermissions(ALL_PERMISSIONS, Permission4337), + ); + + const dataKeyWithoutPermission4337 = + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + controllerWithout4337Permission.address.slice(2); + await universalProfile.setData(dataKeyWithoutPermission4337, ALL_PERMISSIONS); + + const dataKeyWithOnlyPermission4337 = + ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + + controllerWithOnly4337Permission.address.slice(2); + + await universalProfile.setData(dataKeyWithOnlyPermission4337, Permission4337); + + // execute calldata + transferCallData = universalProfile.interface.encodeFunctionData('execute', [ + OPERATION_TYPES.CALL, + ethers.constants.AddressZero, + amountToTransfer, + '0x1234', + ]); + + // stake on entrypoint + const stakeAmount = parseEther('1'); + await entryPoint.depositTo(universalProfileAddress, { value: stakeAmount }); + }); + + it('should pass', async function () { + const addressZeroBalanceBefore = await getBalance(ethers.constants.AddressZero); + + const userOperation = await fillAndSign( + { + sender: universalProfileAddress, + callData: transferCallData, + }, + controllerWith4337Permission, + entryPoint, + ); + + await entryPoint.handleOps([userOperation], bundler.address); + + const addressZeroBalanceAfter = await getBalance(ethers.constants.AddressZero); + + expect(addressZeroBalanceAfter - addressZeroBalanceBefore).to.eq(amountToTransfer); + }); + + it('should fail when calling from wrong entrypoint', async function () { + const anotherEntryPoint = await new EntryPoint__factory(deployer).deploy(); + + const userOperation = await fillAndSign( + { + sender: universalProfileAddress, + callData: transferCallData, + }, + controllerWith4337Permission, + entryPoint, + ); + + const opIndex = 0; //index into the array of ops to the failed one (in simulateValidation, this is always zero). + + await expect(anotherEntryPoint.handleOps([userOperation], bundler.address)) + .to.be.revertedWithCustomError(entryPoint, 'FailedOp') + .withArgs(opIndex, 'AA23 reverted: Only EntryPoint contract can call this'); + }); + + it('should fail when controller does not have 4337 permission', async function () { + const anotherEntryPoint = await new EntryPoint__factory(deployer).deploy(); + + const userOperation = await fillAndSign( + { + sender: universalProfileAddress, + callData: transferCallData, + }, + controllerWithout4337Permission, + entryPoint, + ); + + await expect( + anotherEntryPoint.handleOps([userOperation], bundler.address), + ).to.be.revertedWithCustomError(entryPoint, 'FailedOp'); + }); + + it('should fail when controller only has 4337 permission', async function () { + const userOperation = await fillAndSign( + { + sender: universalProfileAddress, + callData: transferCallData, + }, + controllerWithOnly4337Permission, + entryPoint, + ); + await expect( + entryPoint.handleOps([userOperation], bundler.address), + ).to.be.revertedWithCustomError(entryPoint, 'FailedOp'); + }); + + it('should fail on invalid userop', async function () { + let op = await fillAndSign( + { + sender: universalProfileAddress, + callData: transferCallData, + nonce: 1234, + }, + controllerWith4337Permission, + entryPoint, + ); + + await expect(entryPoint.handleOps([op], bundler.address)) + .to.revertedWithCustomError(entryPoint, 'FailedOp') + .withArgs(0, 'AA25 invalid account nonce'); + + op = await fillAndSign( + { + sender: universalProfileAddress, + callData: transferCallData, + }, + controllerWith4337Permission, + entryPoint, + ); + + // invalidate the signature + op.callGasLimit = 1; + await expect(entryPoint.handleOps([op], bundler.address)) + .to.revertedWithCustomError(entryPoint, 'FailedOp') + .withArgs(0, 'AA24 signature error'); + }); +}); diff --git a/tests/LSP17Extensions/helpers/Create2Factory.ts b/tests/LSP17Extensions/helpers/Create2Factory.ts new file mode 100644 index 000000000..abf7a43bd --- /dev/null +++ b/tests/LSP17Extensions/helpers/Create2Factory.ts @@ -0,0 +1,124 @@ +// from: https://github.com/Arachnid/deterministic-deployment-proxy +import { BigNumber, BigNumberish, ethers, Signer } from 'ethers'; +import { arrayify, hexConcat, hexlify, hexZeroPad, keccak256 } from 'ethers/lib/utils'; +import { Provider } from '@ethersproject/providers'; +import { TransactionRequest } from '@ethersproject/abstract-provider'; + +export class Create2Factory { + factoryDeployed = false; + + // from: https://github.com/Arachnid/deterministic-deployment-proxy + static readonly contractAddress = '0x4e59b44847b379578588920ca78fbf26c0b4956c'; + static readonly factoryTx = + '0xf8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222'; + static readonly factoryDeployer = '0x3fab184622dc19b6109349b94811493bf2a45362'; + static readonly deploymentGasPrice = 100e9; + static readonly deploymentGasLimit = 100000; + static readonly factoryDeploymentFee = ( + Create2Factory.deploymentGasPrice * Create2Factory.deploymentGasLimit + ).toString(); + + constructor( + readonly provider: Provider, + readonly signer = (provider as ethers.providers.JsonRpcProvider).getSigner(), + ) {} + + /** + * deploy a contract using our deterministic deployer. + * The deployer is deployed (unless it is already deployed) + * NOTE: this transaction will fail if already deployed. use getDeployedAddress to check it first. + * @param initCode delpoyment code. can be a hex string or factory.getDeploymentTransaction(..) + * @param salt specific salt for deployment + * @param gasLimit gas limit or 'estimate' to use estimateGas. by default, calculate gas based on data size. + */ + async deploy( + initCode: string | TransactionRequest, + salt: BigNumberish = 0, + gasLimit?: BigNumberish | 'estimate', + ): Promise { + await this.deployFactory(); + if (typeof initCode !== 'string') { + initCode = (initCode as TransactionRequest).data.toString(); + } + + const addr = Create2Factory.getDeployedAddress(initCode, salt); + if ((await this.provider.getCode(addr).then((code) => code.length)) > 2) { + return addr; + } + + const deployTx = { + to: Create2Factory.contractAddress, + data: this.getDeployTransactionCallData(initCode, salt), + }; + if (gasLimit === 'estimate') { + gasLimit = await this.signer.estimateGas(deployTx); + } + + if (gasLimit === undefined) { + gasLimit = + arrayify(initCode) + .map((x) => (x === 0 ? 4 : 16)) + .reduce((sum, x) => sum + x) + + (200 * initCode.length) / 2 + // actual is usually somewhat smaller (only deposited code, not entire constructor) + 6 * Math.ceil(initCode.length / 64) + // hash price. very minor compared to deposit costs + 32000 + + 21000; + + // deployer requires some extra gas + gasLimit = Math.floor((gasLimit * 64) / 63); + } + + const ret = await this.signer.sendTransaction({ ...deployTx, gasLimit }); + await ret.wait(); + if ((await this.provider.getCode(addr).then((code) => code.length)) === 2) { + throw new Error('failed to deploy'); + } + return addr; + } + + getDeployTransactionCallData(initCode: string, salt: BigNumberish = 0): string { + const saltBytes32 = hexZeroPad(hexlify(salt), 32); + return hexConcat([saltBytes32, initCode]); + } + + /** + * return the deployed address of this code. + * (the deployed address to be used by deploy() + * @param initCode + * @param salt + */ + static getDeployedAddress(initCode: string, salt: BigNumberish): string { + const saltBytes32 = hexZeroPad(hexlify(salt), 32); + return ( + '0x' + + keccak256( + hexConcat(['0xff', Create2Factory.contractAddress, saltBytes32, keccak256(initCode)]), + ).slice(-40) + ); + } + + // deploy the factory, if not already deployed. + async deployFactory(signer?: Signer): Promise { + if (await this._isFactoryDeployed()) { + return; + } + await (signer ?? this.signer).sendTransaction({ + to: Create2Factory.factoryDeployer, + value: BigNumber.from(Create2Factory.factoryDeploymentFee), + }); + await this.provider.sendTransaction(Create2Factory.factoryTx); + if (!(await this._isFactoryDeployed())) { + throw new Error('fatal: failed to deploy deterministic deployer'); + } + } + + async _isFactoryDeployed(): Promise { + if (!this.factoryDeployed) { + const deployed = await this.provider.getCode(Create2Factory.contractAddress); + if (deployed.length > 2) { + this.factoryDeployed = true; + } + } + return this.factoryDeployed; + } +} diff --git a/tests/LSP17Extensions/helpers/UserOp.ts b/tests/LSP17Extensions/helpers/UserOp.ts new file mode 100644 index 000000000..cb8b3141e --- /dev/null +++ b/tests/LSP17Extensions/helpers/UserOp.ts @@ -0,0 +1,251 @@ +import { arrayify, defaultAbiCoder, hexDataSlice, keccak256 } from 'ethers/lib/utils'; +import { BigNumber, Wallet } from 'ethers'; +import { AddressZero, callDataCost } from './utils'; +import { ecsign, toRpcSig, keccak256 as keccak256_buffer } from 'ethereumjs-util'; +import { Create2Factory } from './Create2Factory'; +import { EntryPoint } from '@account-abstraction/contracts'; +import { ethers } from 'ethers'; +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import * as typ from './solidityTypes'; + +export interface UserOperation { + sender: typ.address; + nonce: typ.uint256; + initCode: typ.bytes; + callData: typ.bytes; + callGasLimit: typ.uint256; + verificationGasLimit: typ.uint256; + preVerificationGas: typ.uint256; + maxFeePerGas: typ.uint256; + maxPriorityFeePerGas: typ.uint256; + paymasterAndData: typ.bytes; + signature: typ.bytes; +} + +export function packUserOp(op: UserOperation, forSignature = true): string { + if (forSignature) { + // Encoding the UserOperation object fields into a single string for signature + return defaultAbiCoder.encode( + [ + 'address', + 'uint256', + 'bytes32', + 'bytes32', + 'uint256', + 'uint256', + 'uint256', + 'uint256', + 'uint256', + 'bytes32', + ], + [ + op.sender, + op.nonce, + keccak256(op.initCode), + keccak256(op.callData), + op.callGasLimit, + op.verificationGasLimit, + op.preVerificationGas, + op.maxFeePerGas, + op.maxPriorityFeePerGas, + keccak256(op.paymasterAndData), + ], + ); + } else { + // Encoding the UserOperation object fields into a single string including the signature + return defaultAbiCoder.encode( + [ + 'address', + 'uint256', + 'bytes', + 'bytes', + 'uint256', + 'uint256', + 'uint256', + 'uint256', + 'uint256', + 'bytes', + 'bytes', + ], + [ + op.sender, + op.nonce, + op.initCode, + op.callData, + op.callGasLimit, + op.verificationGasLimit, + op.preVerificationGas, + op.maxFeePerGas, + op.maxPriorityFeePerGas, + op.paymasterAndData, + op.signature, + ], + ); + } +} + +export function getUserOpHash(op: UserOperation, entryPoint: string, chainId: number): string { + const userOpHash = keccak256(packUserOp(op, true)); + // Encoding the UserOperation hash, entryPoint address, and chainId for final hash computation + const enc = defaultAbiCoder.encode( + ['bytes32', 'address', 'uint256'], + [userOpHash, entryPoint, chainId], + ); + return keccak256(enc); +} + +export const DefaultsForUserOp: UserOperation = { + sender: AddressZero, + nonce: 0, + initCode: '0x', + callData: '0x', + callGasLimit: 0, + verificationGasLimit: 250000, + preVerificationGas: 21000, + maxFeePerGas: 0, + maxPriorityFeePerGas: 1e9, + paymasterAndData: '0x', + signature: '0x', +}; + +export function signUserOp( + op: UserOperation, + signer: Wallet, + entryPoint: string, + chainId: number, +): UserOperation { + const message = getUserOpHash(op, entryPoint, chainId); + const msg1 = Buffer.concat([ + Buffer.from('\x19Ethereum Signed Message:\n32', 'ascii'), + Buffer.from(arrayify(message)), + ]); + + const sig = ecsign(keccak256_buffer(msg1), Buffer.from(arrayify(signer.privateKey))); + // that's equivalent of: await signer.signMessage(message); + // (but without "async" + const signedMessage1 = toRpcSig(sig.v, sig.r, sig.s); + return { + ...op, + signature: signedMessage1, + }; +} + +export function fillUserOpDefaults( + op: Partial, + defaults = DefaultsForUserOp, +): UserOperation { + const partial: any = { ...op }; + + for (const key in partial) { + if (partial[key] == null) { + delete partial[key]; + } + } + const filled = { ...defaults, ...partial }; + return filled; +} + +// helper to fill structure: +// - default callGasLimit to estimate call from entryPoint to account +// if there is initCode: +// - calculate sender by eth_call the deployment code +// - default verificationGasLimit estimateGas of deployment code plus default 100000 +// no initCode: +// - update nonce from account.getNonce() +// entryPoint param is only required to fill in "sender address when specifying "initCode" +// nonce: assume contract as "getNonce()" function, and fill in. +// sender - only in case of construction: fill sender from initCode. +// callGasLimit: VERY crude estimation (by estimating call to account, and add rough entryPoint overhead +// verificationGasLimit: hard-code default at 100k. should add "create2" cost +export async function fillUserOp( + op: Partial, + signer: SignerWithAddress, + entryPoint?: EntryPoint, +): Promise { + const op1 = { ...op }; + const provider = entryPoint?.provider; + if (op.initCode != null) { + const initAddr = hexDataSlice(op1.initCode, 0, 20); + const initCallData = hexDataSlice(op1.initCode, 20); + if (op1.nonce == null) op1.nonce = 0; + if (op1.sender == null) { + if (initAddr.toLowerCase() === Create2Factory.contractAddress.toLowerCase()) { + const ctr = hexDataSlice(initCallData, 32); + const salt = hexDataSlice(initCallData, 0, 32); + op1.sender = Create2Factory.getDeployedAddress(ctr, salt); + } else { + if (provider == null) throw new Error('no entrypoint/provider'); + op1.sender = await entryPoint.callStatic + .getSenderAddress(op1.initCode) + .catch((e) => e.errorArgs.sender); + } + } + if (op1.verificationGasLimit == null) { + if (provider == null) throw new Error('no entrypoint/provider'); + const initEstimate = await provider.estimateGas({ + from: entryPoint?.address, + to: initAddr, + data: initCallData, + gasLimit: 10e6, + }); + op1.verificationGasLimit = BigNumber.from(DefaultsForUserOp.verificationGasLimit).add( + initEstimate, + ); + } + } + if (op1.nonce == null) { + if (provider == null) throw new Error('must have entryPoint to autofill nonce'); + + const signerKeyAsUint192 = ethers.BigNumber.from(signer.address).toHexString(); + + try { + op1.nonce = await entryPoint.getNonce(op1.sender, signerKeyAsUint192); + } catch { + op1.nonce = 0; + } + } + if (op1.callGasLimit == null && op.callData != null) { + if (provider == null) throw new Error('must have entryPoint for callGasLimit estimate'); + const gasEtimated = await provider.estimateGas({ + from: entryPoint?.address, + to: op1.sender, + data: op1.callData, + }); + + op1.callGasLimit = gasEtimated; + } + if (op1.maxFeePerGas == null) { + if (provider == null) throw new Error('must have entryPoint to autofill maxFeePerGas'); + const block = await provider.getBlock('latest'); + op1.maxFeePerGas = block.baseFeePerGas.add( + op1.maxPriorityFeePerGas ?? DefaultsForUserOp.maxPriorityFeePerGas, + ); + } + + if (op1.maxPriorityFeePerGas == null) { + op1.maxPriorityFeePerGas = DefaultsForUserOp.maxPriorityFeePerGas; + } + const op2 = fillUserOpDefaults(op1); + + if (op2.preVerificationGas.toString() === '0') { + op2.preVerificationGas = callDataCost(packUserOp(op2, false)); + } + return op2; +} + +export async function fillAndSign( + op: Partial, + signer: SignerWithAddress, + entryPoint?: EntryPoint, +): Promise { + const provider = entryPoint?.provider; + const op2 = await fillUserOp(op, signer, entryPoint); + + const chainId = await provider.getNetwork().then((net) => net.chainId); + const message = arrayify(getUserOpHash(op2, entryPoint.address, chainId)); + + return { + ...op2, + signature: await signer.signMessage(message), + }; +} diff --git a/tests/LSP17Extensions/helpers/solidityTypes.ts b/tests/LSP17Extensions/helpers/solidityTypes.ts new file mode 100644 index 000000000..5663a0166 --- /dev/null +++ b/tests/LSP17Extensions/helpers/solidityTypes.ts @@ -0,0 +1,10 @@ +// define the same export types as used by export typechain/ethers +import { BigNumberish } from 'ethers'; +import { BytesLike } from '@ethersproject/bytes'; + +export type address = string; +export type uint256 = BigNumberish; +export type uint = BigNumberish; +export type uint48 = BigNumberish; +export type bytes = BytesLike; +export type bytes32 = BytesLike; diff --git a/tests/LSP17Extensions/helpers/utils.ts b/tests/LSP17Extensions/helpers/utils.ts new file mode 100644 index 000000000..10c338d83 --- /dev/null +++ b/tests/LSP17Extensions/helpers/utils.ts @@ -0,0 +1,32 @@ +import { ethers } from 'hardhat'; +import { Create2Factory } from './Create2Factory'; +import { EntryPoint__factory, EntryPoint } from '@account-abstraction/contracts'; + +export const AddressZero = ethers.constants.AddressZero; + +export function callDataCost(data: string): number { + return ethers.utils + .arrayify(data) + .map((x) => (x === 0 ? 4 : 16)) + .reduce((sum, x) => sum + x); +} + +export async function deployEntryPoint(provider = ethers.provider): Promise { + const create2factory = new Create2Factory(provider); + const addr = await create2factory.deploy( + EntryPoint__factory.bytecode, + 0, + process.env.COVERAGE != null ? 20e6 : 8e6, + ); + return EntryPoint__factory.connect(addr, provider.getSigner()); +} + +export async function getBalance(address: string): Promise { + const balance = await ethers.provider.getBalance(address); + return parseInt(balance.toString()); +} + +export async function isDeployed(addr: string): Promise { + const code = await ethers.provider.getCode(addr); + return code.length > 2; +} From 07549e816bd886efe6c3d3a204b250c3d340ca59 Mon Sep 17 00:00:00 2001 From: Jean Cvllr <31145285+CJ42@users.noreply.github.com> Date: Tue, 10 Oct 2023 09:42:57 +0100 Subject: [PATCH 38/55] refactor: update contracts to allow compiling with solc versions `0.8.7`, `.6` and `.5` (#738) * fix: add missing `override` to allow compiling with solc < `0.8.7` * ci: test solc versions 0.8.7, .6 and .5 * ci: fix comparison check for solc 0.8.12 * ci: allow to run solc version CI manually --- .github/workflows/solc_version.yml | 34 +++++++---- .../LSP0ERC725AccountCore.sol | 6 +- .../LSP11BasicSocialRecoveryCore.sol | 56 ++++++++++++++----- .../LSP14Ownable2Step/LSP14Ownable2Step.sol | 4 +- contracts/LSP17Extensions/Extension4337.sol | 2 +- .../LSP1UniversalReceiverDelegateUP.sol | 2 +- .../LSP1UniversalReceiverDelegateVault.sol | 2 +- .../LSP23LinkedContractsFactory.sol | 4 ++ .../LSP6KeyManager/LSP6KeyManagerCore.sol | 18 +++--- .../LSP7DigitalAsset/LSP7DigitalAssetCore.sol | 18 +++--- .../LSP7DigitalAsset/presets/LSP7Mintable.sol | 2 +- .../presets/LSP7MintableInitAbstract.sol | 2 +- .../LSP8IdentifiableDigitalAssetCore.sol | 20 +++---- .../presets/LSP8Mintable.sol | 2 +- .../presets/LSP8MintableInitAbstract.sol | 2 +- contracts/LSP9Vault/LSP9VaultCore.sol | 4 +- .../FallbackExtensions/ERC165Extension.sol | 2 +- .../UniversalReceiverDelegateGasConsumer.sol | 2 +- .../UniversalReceiverDelegateRevert.sol | 2 +- ...iversalReceiverDelegateVaultReentrantA.sol | 2 +- ...iversalReceiverDelegateVaultReentrantB.sol | 2 +- scripts/ci/gas_benchmark.ts | 2 +- 22 files changed, 119 insertions(+), 71 deletions(-) diff --git a/.github/workflows/solc_version.yml b/.github/workflows/solc_version.yml index 48e660532..5cffe1bea 100644 --- a/.github/workflows/solc_version.yml +++ b/.github/workflows/solc_version.yml @@ -3,6 +3,16 @@ name: Solidity Compiler Versions on: + workflow_dispatch: + + # Used to check pragma settings for `.sol` files are correct before releasing + push: + branches: + - "develop" + # compare gas diff only when editing Solidity smart contract code + paths: + - "contracts/**/*.sol" + pull_request: types: [opened] @@ -16,10 +26,9 @@ jobs: strategy: matrix: solc: [ - # TODO: wait for a patch release of @erc725/smart-contracts to compile on these 3 versions - # "0.8.5", - # "0.8.6", - # "0.8.7", + "0.8.5", + "0.8.6", + "0.8.7", "0.8.8", "0.8.9", "0.8.10", @@ -55,17 +64,22 @@ jobs: solc-select install ${{ matrix.solc }} solc-select use ${{ matrix.solc }} + - name: Compare versions to filter contracts to compile + uses: madhead/semver-utils@latest + id: comparison + with: + version: ${{ matrix.solc }} + compare-to: 0.8.12 + - name: Compile Smart Contracts run: | - if [[ ${{ matrix.solc }} < 0.8.12 ]] + if [[ "<" == "${{ steps.comparison.outputs.comparison-result }}" ]] then - solc $(ls contracts/**/*.sol | grep -v "Compatible") --allow-paths $(pwd)/node_modules/ \ - @erc725/smart-contracts/=node_modules/@erc725/smart-contracts/ \ - @openzeppelin/=node_modules/@openzeppelin/ \ + solc $(ls contracts/**/*.sol | grep -v "Compatible" | grep -v "Extension4337") --allow-paths $(pwd)/node_modules/ \ + @=node_modules/@ \ solidity-bytes-utils/=node_modules/solidity-bytes-utils/ else solc contracts/**/*.sol \ - @erc725/smart-contracts/=node_modules/@erc725/smart-contracts/ \ - @openzeppelin/=node_modules/@openzeppelin/ \ + @=node_modules/@ \ solidity-bytes-utils/=node_modules/solidity-bytes-utils/ fi; diff --git a/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol b/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol index acf930d68..38bffcc20 100644 --- a/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol +++ b/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol @@ -138,7 +138,7 @@ abstract contract LSP0ERC725AccountCore is */ function batchCalls( bytes[] calldata data - ) public virtual returns (bytes[] memory results) { + ) public virtual override returns (bytes[] memory results) { results = new bytes[](data.length); for (uint256 i; i < data.length; ) { (bool success, bytes memory result) = address(this).delegatecall( @@ -415,7 +415,7 @@ abstract contract LSP0ERC725AccountCore is function universalReceiver( bytes32 typeId, bytes calldata receivedData - ) public payable virtual returns (bytes memory returnedValues) { + ) public payable virtual override returns (bytes memory returnedValues) { if (msg.value != 0) { emit ValueReceived(msg.sender, msg.value); } @@ -678,7 +678,7 @@ abstract contract LSP0ERC725AccountCore is function isValidSignature( bytes32 dataHash, bytes memory signature - ) public view virtual returns (bytes4 magicValue) { + ) public view virtual override returns (bytes4 magicValue) { address _owner = owner(); // If owner is a contract diff --git a/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryCore.sol b/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryCore.sol index 5becb85f2..0ce82e03c 100644 --- a/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryCore.sol +++ b/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryCore.sol @@ -85,42 +85,68 @@ abstract contract LSP11BasicSocialRecoveryCore is /** * @inheritdoc ILSP11BasicSocialRecovery */ - function target() public view virtual returns (address) { + function target() public view virtual override returns (address) { return _target; } /** * @inheritdoc ILSP11BasicSocialRecovery */ - function getRecoveryCounter() public view virtual returns (uint256) { + function getRecoveryCounter() + public + view + virtual + override + returns (uint256) + { return _recoveryCounter; } /** * @inheritdoc ILSP11BasicSocialRecovery */ - function getGuardians() public view virtual returns (address[] memory) { + function getGuardians() + public + view + virtual + override + returns (address[] memory) + { return _guardians.values(); } /** * @inheritdoc ILSP11BasicSocialRecovery */ - function isGuardian(address _address) public view virtual returns (bool) { + function isGuardian( + address _address + ) public view virtual override returns (bool) { return _guardians.contains(_address); } /** * @inheritdoc ILSP11BasicSocialRecovery */ - function getGuardiansThreshold() public view virtual returns (uint256) { + function getGuardiansThreshold() + public + view + virtual + override + returns (uint256) + { return _guardiansThreshold; } /** * @inheritdoc ILSP11BasicSocialRecovery */ - function getRecoverySecretHash() public view virtual returns (bytes32) { + function getRecoverySecretHash() + public + view + virtual + override + returns (bytes32) + { return _recoverySecretHash; } @@ -129,14 +155,16 @@ abstract contract LSP11BasicSocialRecoveryCore is */ function getGuardianChoice( address guardian - ) public view virtual returns (address) { + ) public view virtual override returns (address) { return _guardiansChoice[_recoveryCounter][guardian]; } /** * @inheritdoc ILSP11BasicSocialRecovery */ - function addGuardian(address newGuardian) public virtual onlyOwner { + function addGuardian( + address newGuardian + ) public virtual override onlyOwner { if (_guardians.contains(newGuardian)) revert GuardianAlreadyExist(newGuardian); @@ -147,7 +175,9 @@ abstract contract LSP11BasicSocialRecoveryCore is /** * @inheritdoc ILSP11BasicSocialRecovery */ - function removeGuardian(address existingGuardian) public virtual onlyOwner { + function removeGuardian( + address existingGuardian + ) public virtual override onlyOwner { if (!_guardians.contains(existingGuardian)) revert GuardianDoNotExist(existingGuardian); if (_guardians.length() == _guardiansThreshold) @@ -162,7 +192,7 @@ abstract contract LSP11BasicSocialRecoveryCore is */ function setGuardiansThreshold( uint256 newThreshold - ) public virtual onlyOwner { + ) public virtual override onlyOwner { if (newThreshold > _guardians.length()) revert ThresholdCannotBeHigherThanGuardiansNumber( newThreshold, @@ -179,7 +209,7 @@ abstract contract LSP11BasicSocialRecoveryCore is */ function setRecoverySecretHash( bytes32 newRecoverSecretHash - ) public virtual onlyOwner { + ) public virtual override onlyOwner { if (newRecoverSecretHash == bytes32(0)) revert SecretHashCannotBeZero(); _recoverySecretHash = newRecoverSecretHash; @@ -191,7 +221,7 @@ abstract contract LSP11BasicSocialRecoveryCore is */ function selectNewController( address addressSelected - ) public virtual onlyGuardians { + ) public virtual override onlyGuardians { uint256 currentRecoveryCounter = _recoveryCounter; _guardiansChoice[currentRecoveryCounter][msg.sender] = addressSelected; @@ -209,7 +239,7 @@ abstract contract LSP11BasicSocialRecoveryCore is address recoverer, string memory plainSecret, bytes32 newSecretHash - ) public virtual { + ) public virtual override { // caching storage variables uint256 currentRecoveryCounter = _recoveryCounter; address[] memory guardians = _guardians.values(); diff --git a/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol b/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol index 53f96f11a..b9dd4cf42 100644 --- a/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol +++ b/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol @@ -76,7 +76,7 @@ abstract contract LSP14Ownable2Step is ILSP14Ownable2Step, OwnableUnset { * * @custom:info If no ownership transfer is in progress, the pendingOwner will be `address(0).`. */ - function pendingOwner() public view virtual returns (address) { + function pendingOwner() public view virtual override returns (address) { return _pendingOwner; } @@ -110,7 +110,7 @@ abstract contract LSP14Ownable2Step is ILSP14Ownable2Step, OwnableUnset { * * @custom:requirements This function can only be called by the {pendingOwner()}. */ - function acceptOwnership() public virtual NotInTransferOwnership { + function acceptOwnership() public virtual override NotInTransferOwnership { address previousOwner = owner(); _acceptOwnership(); diff --git a/contracts/LSP17Extensions/Extension4337.sol b/contracts/LSP17Extensions/Extension4337.sol index 81cf154d3..7ea08b17d 100644 --- a/contracts/LSP17Extensions/Extension4337.sol +++ b/contracts/LSP17Extensions/Extension4337.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.9; +pragma solidity ^0.8.12; // interfaces import {IAccount} from "@account-abstraction/contracts/interfaces/IAccount.sol"; diff --git a/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol b/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol index 9746e154d..38374020b 100644 --- a/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol +++ b/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol @@ -79,7 +79,7 @@ contract LSP1UniversalReceiverDelegateUP is ERC165, ILSP1UniversalReceiver { function universalReceiver( bytes32 typeId, bytes memory /* data */ - ) public payable virtual returns (bytes memory) { + ) public payable virtual override returns (bytes memory) { // CHECK that we did not send any native tokens to the LSP1 Delegate, as it cannot transfer them back. if (msg.value != 0) { revert NativeTokensNotAccepted(); diff --git a/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol b/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol index e36960943..9cb28d511 100644 --- a/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol +++ b/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol @@ -63,7 +63,7 @@ contract LSP1UniversalReceiverDelegateVault is ERC165, ILSP1UniversalReceiver { function universalReceiver( bytes32 typeId, bytes memory /* data */ - ) public payable virtual returns (bytes memory) { + ) public payable virtual override returns (bytes memory) { // CHECK that we did not send any native tokens to the LSP1 Delegate, as it cannot transfer them back. if (msg.value != 0) { revert NativeTokensNotAccepted(); diff --git a/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol b/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol index de93f3a24..4239a1f29 100644 --- a/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol +++ b/contracts/LSP23LinkedContractsFactory/LSP23LinkedContractsFactory.sol @@ -23,6 +23,7 @@ contract LSP23LinkedContractsFactory is ILSP23LinkedContractsFactory { ) public payable + override returns ( address primaryContractAddress, address secondaryContractAddress @@ -81,6 +82,7 @@ contract LSP23LinkedContractsFactory is ILSP23LinkedContractsFactory { ) public payable + override returns ( address primaryContractAddress, address secondaryContractAddress @@ -140,6 +142,7 @@ contract LSP23LinkedContractsFactory is ILSP23LinkedContractsFactory { ) public view + override returns ( address primaryContractAddress, address secondaryContractAddress @@ -187,6 +190,7 @@ contract LSP23LinkedContractsFactory is ILSP23LinkedContractsFactory { ) public view + override returns ( address primaryContractAddress, address secondaryContractAddress diff --git a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol index a1ddadb37..01f38f260 100644 --- a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol +++ b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol @@ -101,7 +101,7 @@ abstract contract LSP6KeyManagerCore is /** * @inheritdoc ILSP6 */ - function target() public view returns (address) { + function target() public view override returns (address) { return _target; } @@ -136,7 +136,7 @@ abstract contract LSP6KeyManagerCore is function getNonce( address from, uint128 channelId - ) public view virtual returns (uint256) { + ) public view virtual override returns (uint256) { return LSP25MultiChannelNonce._getNonce(from, channelId); } @@ -151,7 +151,7 @@ abstract contract LSP6KeyManagerCore is function isValidSignature( bytes32 dataHash, bytes memory signature - ) public view virtual returns (bytes4 magicValue) { + ) public view virtual override returns (bytes4 magicValue) { // if isValidSignature fail, the error is catched in returnedError (address recoveredAddress, ECDSA.RecoverError returnedError) = ECDSA .tryRecover(dataHash, signature); @@ -177,7 +177,7 @@ abstract contract LSP6KeyManagerCore is */ function execute( bytes calldata payload - ) public payable virtual returns (bytes memory) { + ) public payable virtual override returns (bytes memory) { return _execute(msg.value, payload); } @@ -189,7 +189,7 @@ abstract contract LSP6KeyManagerCore is function executeBatch( uint256[] calldata values, bytes[] calldata payloads - ) public payable virtual returns (bytes[] memory) { + ) public payable virtual override returns (bytes[] memory) { if (values.length != payloads.length) { revert BatchExecuteParamsLengthMismatch(); } @@ -237,7 +237,7 @@ abstract contract LSP6KeyManagerCore is uint256 nonce, uint256 validityTimestamps, bytes calldata payload - ) public payable virtual returns (bytes memory) { + ) public payable virtual override returns (bytes memory) { return _executeRelayCall( signature, @@ -267,7 +267,7 @@ abstract contract LSP6KeyManagerCore is uint256[] calldata validityTimestamps, uint256[] calldata values, bytes[] calldata payloads - ) public payable virtual returns (bytes[] memory) { + ) public payable virtual override returns (bytes[] memory) { if ( signatures.length != nonces.length || nonces.length != validityTimestamps.length || @@ -323,7 +323,7 @@ abstract contract LSP6KeyManagerCore is address caller, uint256 msgValue, bytes calldata data - ) external virtual returns (bytes4) { + ) external virtual override returns (bytes4) { bool isSetData = bytes4(data) == IERC725Y.setData.selector || bytes4(data) == IERC725Y.setDataBatch.selector; @@ -373,7 +373,7 @@ abstract contract LSP6KeyManagerCore is function lsp20VerifyCallResult( bytes32 /*callHash*/, bytes memory /*result*/ - ) external virtual returns (bytes4) { + ) external virtual override returns (bytes4) { // If it's the target calling, set back the reentrancy guard // to false, if not return the magic value if (msg.sender == _target) { diff --git a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol index 4c9d2176d..98965dc63 100644 --- a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol +++ b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol @@ -71,14 +71,14 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { /** * @inheritdoc ILSP7DigitalAsset */ - function decimals() public view virtual returns (uint8) { + function decimals() public view virtual override returns (uint8) { return _isNonDivisible ? 0 : 18; } /** * @inheritdoc ILSP7DigitalAsset */ - function totalSupply() public view virtual returns (uint256) { + function totalSupply() public view virtual override returns (uint256) { return _existingTokens; } @@ -89,7 +89,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { */ function balanceOf( address tokenOwner - ) public view virtual returns (uint256) { + ) public view virtual override returns (uint256) { return _tokenOwnerBalances[tokenOwner]; } @@ -111,7 +111,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { address operator, uint256 amount, bytes memory operatorNotificationData - ) public virtual { + ) public virtual override { _updateOperator(msg.sender, operator, amount, operatorNotificationData); bytes memory lsp1Data = abi.encode( @@ -128,7 +128,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { function revokeOperator( address operator, bytes memory operatorNotificationData - ) public virtual { + ) public virtual override { _updateOperator(msg.sender, operator, 0, operatorNotificationData); bytes memory lsp1Data = abi.encode( @@ -145,7 +145,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { function authorizedAmountFor( address operator, address tokenOwner - ) public view virtual returns (uint256) { + ) public view virtual override returns (uint256) { if (tokenOwner == operator) { return _tokenOwnerBalances[tokenOwner]; } else { @@ -158,7 +158,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { */ function getOperatorsOf( address tokenOwner - ) public view virtual returns (address[] memory) { + ) public view virtual override returns (address[] memory) { return _operators[tokenOwner].values(); } @@ -173,7 +173,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { uint256 amount, bool force, bytes memory data - ) public virtual { + ) public virtual override { if (from == to) revert LSP7CannotSendToSelf(); if (msg.sender != from) { @@ -196,7 +196,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { uint256[] memory amount, bool[] memory force, bytes[] memory data - ) public virtual { + ) public virtual override { uint256 fromLength = from.length; if ( fromLength != to.length || diff --git a/contracts/LSP7DigitalAsset/presets/LSP7Mintable.sol b/contracts/LSP7DigitalAsset/presets/LSP7Mintable.sol index 952030f06..5091862cf 100644 --- a/contracts/LSP7DigitalAsset/presets/LSP7Mintable.sol +++ b/contracts/LSP7DigitalAsset/presets/LSP7Mintable.sol @@ -36,7 +36,7 @@ contract LSP7Mintable is LSP7DigitalAsset, ILSP7Mintable { uint256 amount, bool force, bytes memory data - ) public virtual onlyOwner { + ) public virtual override onlyOwner { _mint(to, amount, force, data); } } diff --git a/contracts/LSP7DigitalAsset/presets/LSP7MintableInitAbstract.sol b/contracts/LSP7DigitalAsset/presets/LSP7MintableInitAbstract.sol index 0720d9bf6..a32716124 100644 --- a/contracts/LSP7DigitalAsset/presets/LSP7MintableInitAbstract.sol +++ b/contracts/LSP7DigitalAsset/presets/LSP7MintableInitAbstract.sol @@ -47,7 +47,7 @@ abstract contract LSP7MintableInitAbstract is uint256 amount, bool force, bytes memory data - ) public virtual onlyOwner { + ) public virtual override onlyOwner { _mint(to, amount, force, data); } } diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol index 97ac6b16f..d4eebe28c 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol @@ -73,7 +73,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is /** * @inheritdoc ILSP8IdentifiableDigitalAsset */ - function totalSupply() public view virtual returns (uint256) { + function totalSupply() public view virtual override returns (uint256) { return _existingTokens; } @@ -84,7 +84,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is */ function balanceOf( address tokenOwner - ) public view virtual returns (uint256) { + ) public view virtual override returns (uint256) { return _ownedTokens[tokenOwner].length(); } @@ -93,7 +93,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is */ function tokenOwnerOf( bytes32 tokenId - ) public view virtual returns (address) { + ) public view virtual override returns (address) { address tokenOwner = _tokenOwners[tokenId]; if (tokenOwner == address(0)) { @@ -108,7 +108,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is */ function tokenIdsOf( address tokenOwner - ) public view virtual returns (bytes32[] memory) { + ) public view virtual override returns (bytes32[] memory) { return _ownedTokens[tokenOwner].values(); } @@ -121,7 +121,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is address operator, bytes32 tokenId, bytes memory operatorNotificationData - ) public virtual { + ) public virtual override { address tokenOwner = tokenOwnerOf(tokenId); if (tokenOwner != msg.sender) { @@ -161,7 +161,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is address operator, bytes32 tokenId, bytes memory operatorNotificationData - ) public virtual { + ) public virtual override { address tokenOwner = tokenOwnerOf(tokenId); if (tokenOwner != msg.sender) { @@ -197,7 +197,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is function isOperatorFor( address operator, bytes32 tokenId - ) public view virtual returns (bool) { + ) public view virtual override returns (bool) { _existsOrError(tokenId); return _isOperatorOrOwner(operator, tokenId); @@ -208,7 +208,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is */ function getOperatorsOf( bytes32 tokenId - ) public view virtual returns (address[] memory) { + ) public view virtual override returns (address[] memory) { _existsOrError(tokenId); return _operators[tokenId].values(); @@ -237,7 +237,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is bytes32 tokenId, bool force, bytes memory data - ) public virtual { + ) public virtual override { if (!_isOperatorOrOwner(msg.sender, tokenId)) { revert LSP8NotTokenOperator(tokenId, msg.sender); } @@ -254,7 +254,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is bytes32[] memory tokenId, bool[] memory force, bytes[] memory data - ) public virtual { + ) public virtual override { uint256 fromLength = from.length; if ( fromLength != to.length || diff --git a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol index 4a113bb47..66bc01675 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol @@ -44,7 +44,7 @@ contract LSP8Mintable is LSP8IdentifiableDigitalAsset, ILSP8Mintable { bytes32 tokenId, bool force, bytes memory data - ) public virtual onlyOwner { + ) public virtual override onlyOwner { _mint(to, tokenId, force, data); } } diff --git a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInitAbstract.sol index a7acd984b..b59f023ab 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8MintableInitAbstract.sol @@ -53,7 +53,7 @@ abstract contract LSP8MintableInitAbstract is bytes32 tokenId, bool force, bytes memory data - ) public virtual onlyOwner { + ) public virtual override onlyOwner { _mint(to, tokenId, force, data); } } diff --git a/contracts/LSP9Vault/LSP9VaultCore.sol b/contracts/LSP9Vault/LSP9VaultCore.sol index 15f8853da..574c2c976 100644 --- a/contracts/LSP9Vault/LSP9VaultCore.sol +++ b/contracts/LSP9Vault/LSP9VaultCore.sol @@ -138,7 +138,7 @@ contract LSP9VaultCore is */ function batchCalls( bytes[] calldata data - ) public virtual returns (bytes[] memory results) { + ) public virtual override returns (bytes[] memory results) { results = new bytes[](data.length); for (uint256 i; i < data.length; ) { (bool success, bytes memory result) = address(this).delegatecall( @@ -321,7 +321,7 @@ contract LSP9VaultCore is function universalReceiver( bytes32 typeId, bytes calldata receivedData - ) public payable virtual returns (bytes memory returnedValues) { + ) public payable virtual override returns (bytes memory returnedValues) { if (msg.value != 0) { emit ValueReceived(msg.sender, msg.value); } diff --git a/contracts/Mocks/FallbackExtensions/ERC165Extension.sol b/contracts/Mocks/FallbackExtensions/ERC165Extension.sol index 89baf4574..9e2907495 100644 --- a/contracts/Mocks/FallbackExtensions/ERC165Extension.sol +++ b/contracts/Mocks/FallbackExtensions/ERC165Extension.sol @@ -11,7 +11,7 @@ contract ERC165Extension is IERC165 { function supportsInterface( bytes4 interfaceId - ) public view virtual returns (bool) { + ) public pure override returns (bool) { return interfaceId == _RANDOM_INTERFACE_ID; } } diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateGasConsumer.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateGasConsumer.sol index ffdd9aa90..949d61566 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateGasConsumer.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateGasConsumer.sol @@ -23,7 +23,7 @@ contract UniversalReceiverDelegateGasConsumer is function universalReceiver( bytes32 /* typeId */, bytes memory /* data */ - ) public payable virtual returns (bytes memory) { + ) public payable override returns (bytes memory) { // solhint-disable no-empty-blocks for (uint256 i = 0; ; i++) { // nothing diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateRevert.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateRevert.sol index ffbfdcc3a..f19339e1c 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateRevert.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateRevert.sol @@ -20,7 +20,7 @@ contract UniversalReceiverDelegateRevert is ERC165, ILSP1UniversalReceiver { function universalReceiver( bytes32 /* typeId */, bytes memory /* data */ - ) public payable virtual returns (bytes memory) { + ) public payable override returns (bytes memory) { revert("I Revert"); } diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantA.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantA.sol index de7c3e122..58986264e 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantA.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantA.sol @@ -34,7 +34,7 @@ contract UniversalReceiverDelegateVaultReentrantA is function universalReceiver( bytes32 /* typeId */, bytes memory data - ) external payable returns (bytes memory) { + ) external payable override returns (bytes memory) { if (msg.value != 0) { revert NativeTokensNotAccepted(); } diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantB.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantB.sol index 9cb236ab2..73542a194 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantB.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantB.sol @@ -36,7 +36,7 @@ contract UniversalReceiverDelegateVaultReentrantB is function universalReceiver( bytes32 /* typeId */, bytes memory data - ) external payable returns (bytes memory) { + ) external payable override returns (bytes memory) { if (msg.value != 0) { revert NativeTokensNotAccepted(); } diff --git a/scripts/ci/gas_benchmark.ts b/scripts/ci/gas_benchmark.ts index 024a1b464..f7b0a9542 100644 --- a/scripts/ci/gas_benchmark.ts +++ b/scripts/ci/gas_benchmark.ts @@ -180,7 +180,7 @@ task('gas-benchmark', 'Benchmark gas usage of the smart contracts based on prede ⛽ I am the Gas Bot Reporter. I keep track of the gas costs of common interactions using Universal Profiles 🆙 ! 📊 Here is a summary of the gas cost with the code introduced by this PR. -## ⛽📊 Gas Benchmark Report +## ⛽📊 Gas Benchmark Report ### Deployment Costs From 4b87792707bbbe3c248da3d1146852079c4d0129 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Tue, 10 Oct 2023 09:47:00 +0100 Subject: [PATCH 39/55] ci: fix remapping for local path --- .github/workflows/solc_version.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/solc_version.yml b/.github/workflows/solc_version.yml index 5cffe1bea..2f25c4c45 100644 --- a/.github/workflows/solc_version.yml +++ b/.github/workflows/solc_version.yml @@ -77,7 +77,8 @@ jobs: then solc $(ls contracts/**/*.sol | grep -v "Compatible" | grep -v "Extension4337") --allow-paths $(pwd)/node_modules/ \ @=node_modules/@ \ - solidity-bytes-utils/=node_modules/solidity-bytes-utils/ + solidity-bytes-utils/=node_modules/solidity-bytes-utils/ \ + ../=$(pwd)/contracts/ else solc contracts/**/*.sol \ @=node_modules/@ \ From 624c4a6dfa0c5c83c94f0b5e952adc783098d12c Mon Sep 17 00:00:00 2001 From: "b00ste.lyx" <62855857+b00ste@users.noreply.github.com> Date: Tue, 10 Oct 2023 13:03:59 +0300 Subject: [PATCH 40/55] feat: allow sending value when using `setData(..)` through the LSP6 (#725) * feat: allow to send value while setting data + remove custom error * refactor: remove unecessary ternary operator * test: update tests * docs: update auto-generated docs --------- Co-authored-by: CJ42 --- .../LSP20CallVerification.sol | 3 +- contracts/LSP6KeyManager/LSP6Errors.sol | 8 ---- .../LSP6KeyManager/LSP6KeyManagerCore.sol | 23 ++++------ .../KeyManager/KeyManagerInternalsTester.sol | 10 ++--- .../LSP6KeyManager/LSP6KeyManager.md | 25 +---------- .../Interactions/BatchExecute.test.ts | 45 +++++++++---------- .../SetData/PermissionSetData.test.ts | 14 +++--- .../internals/Execute.internal.ts | 2 - 8 files changed, 43 insertions(+), 87 deletions(-) diff --git a/contracts/LSP20CallVerification/LSP20CallVerification.sol b/contracts/LSP20CallVerification/LSP20CallVerification.sol index 1a864c28e..d4571b764 100644 --- a/contracts/LSP20CallVerification/LSP20CallVerification.sol +++ b/contracts/LSP20CallVerification/LSP20CallVerification.sol @@ -44,8 +44,9 @@ abstract contract LSP20CallVerification { bytes4 magicValue = abi.decode(returnedData, (bytes4)); - if (bytes3(magicValue) != bytes3(ILSP20.lsp20VerifyCall.selector)) + if (bytes3(magicValue) != bytes3(ILSP20.lsp20VerifyCall.selector)) { revert LSP20InvalidMagicValue(false, returnedData); + } return magicValue[3] == 0x01; } diff --git a/contracts/LSP6KeyManager/LSP6Errors.sol b/contracts/LSP6KeyManager/LSP6Errors.sol index 3126cd933..c0c1e8ea1 100644 --- a/contracts/LSP6KeyManager/LSP6Errors.sol +++ b/contracts/LSP6KeyManager/LSP6Errors.sol @@ -199,14 +199,6 @@ error DelegateCallDisallowedViaKeyManager(); */ error InvalidPayload(bytes payload); -/** - * @notice Cannot sent native tokens while setting data. - * - * @dev Reverts when calling the `setData(byte32,bytes)` or `setData(bytes32[],bytes[]) functions - * on the linked {target} while sending value. - */ -error CannotSendValueToSetData(); - /** * @notice Calling the Key Manager address for this transaction is disallowed. * diff --git a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol index 01f38f260..802f3e238 100644 --- a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol +++ b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol @@ -46,8 +46,7 @@ import { InvalidPayload, InvalidRelayNonce, NoPermissionsSet, - InvalidERC725Function, - CannotSendValueToSetData + InvalidERC725Function } from "./LSP6Errors.sol"; import { @@ -335,7 +334,8 @@ abstract contract LSP6KeyManagerCore is caller ); - _verifyPermissions(targetContract, caller, msgValue, false, data); + _verifyPermissions(targetContract, caller, false, data); + emit PermissionsVerified(caller, msgValue, bytes4(data)); // if it's a setData call, do not invoke the `lsp20VerifyCallResult(..)` function @@ -357,7 +357,7 @@ abstract contract LSP6KeyManagerCore is ); } - _verifyPermissions(targetContract, caller, msgValue, false, data); + _verifyPermissions(targetContract, caller, false, data); // if it's a setData call, do not invoke the `lsp20VerifyCallResult(..)` function return @@ -401,13 +401,7 @@ abstract contract LSP6KeyManagerCore is msg.sender ); - _verifyPermissions( - targetContract, - msg.sender, - msgValue, - false, - payload - ); + _verifyPermissions(targetContract, msg.sender, false, payload); emit PermissionsVerified(msg.sender, msgValue, bytes4(payload)); @@ -478,7 +472,8 @@ abstract contract LSP6KeyManagerCore is signer ); - _verifyPermissions(targetContract, signer, msgValue, true, payload); + _verifyPermissions(targetContract, signer, true, payload); + emit PermissionsVerified(signer, msgValue, bytes4(payload)); bytes memory result = _executePayload( @@ -519,13 +514,13 @@ abstract contract LSP6KeyManagerCore is /** * @dev Verify if the `from` address is allowed to execute the `payload` on the {target} contract linked to this Key Manager. + * @param targetContract The contract that is owned by the Key Manager * @param from Either the caller of {execute} or the signer of {executeRelayCall}. * @param payload The abi-encoded function call to execute on the {target} contract. */ function _verifyPermissions( address targetContract, address from, - uint256 msgValue, bool isRelayedCall, bytes calldata payload ) internal view virtual { @@ -543,7 +538,6 @@ abstract contract LSP6KeyManagerCore is // ERC725Y.setData(bytes32,bytes) if (erc725Function == IERC725Y.setData.selector) { - if (msgValue != 0) revert CannotSendValueToSetData(); (bytes32 inputKey, bytes memory inputValue) = abi.decode( payload[4:], (bytes32, bytes) @@ -559,7 +553,6 @@ abstract contract LSP6KeyManagerCore is // ERC725Y.setDataBatch(bytes32[],bytes[]) } else if (erc725Function == IERC725Y.setDataBatch.selector) { - if (msgValue != 0) revert CannotSendValueToSetData(); (bytes32[] memory inputKeys, bytes[] memory inputValues) = abi .decode(payload[4:], (bytes32[], bytes[])); diff --git a/contracts/Mocks/KeyManager/KeyManagerInternalsTester.sol b/contracts/Mocks/KeyManager/KeyManagerInternalsTester.sol index d3125f966..12facc51f 100644 --- a/contracts/Mocks/KeyManager/KeyManagerInternalsTester.sol +++ b/contracts/Mocks/KeyManager/KeyManagerInternalsTester.sol @@ -113,12 +113,8 @@ contract KeyManagerInternalTester is LSP6KeyManager { return _addressPermission.hasPermission(_permissions); } - function verifyPermissions( - address from, - uint256 msgValue, - bytes calldata payload - ) public { - super._verifyPermissions(_target, from, msgValue, false, payload); + function verifyPermissions(address from, bytes calldata payload) public { + super._verifyPermissions(_target, from, false, payload); // This event is emitted just for a sake of not marking this function as `view`, // as Hardhat has a bug that does not catch error that occured from failed `abi.decode` @@ -126,6 +122,6 @@ contract KeyManagerInternalTester is LSP6KeyManager { // See these issues in the Github repository of Hardhat: // - https://github.com/NomicFoundation/hardhat/issues/3084 // - https://github.com/NomicFoundation/hardhat/issues/3475 - emit PermissionsVerified(from, msgValue, bytes4(payload)); + emit PermissionsVerified(from, 0, bytes4(payload)); } } diff --git a/docs/contracts/LSP6KeyManager/LSP6KeyManager.md b/docs/contracts/LSP6KeyManager/LSP6KeyManager.md index a316cd365..280ee3332 100644 --- a/docs/contracts/LSP6KeyManager/LSP6KeyManager.md +++ b/docs/contracts/LSP6KeyManager/LSP6KeyManager.md @@ -1167,7 +1167,6 @@ _Execute the `payload` passed to `execute(...)` or `executeRelayCall(...)`_ function _verifyPermissions( address targetContract, address from, - uint256 msgValue, bool isRelayedCall, bytes payload ) internal view; @@ -1179,9 +1178,8 @@ Verify if the `from` address is allowed to execute the `payload` on the [`target | Name | Type | Description | | ---------------- | :-------: | ------------------------------------------------------------------- | -| `targetContract` | `address` | - | +| `targetContract` | `address` | The contract that is owned by the Key Manager | | `from` | `address` | Either the caller of {execute} or the signer of {executeRelayCall}. | -| `msgValue` | `uint256` | - | | `isRelayedCall` | `bool` | - | | `payload` | `bytes` | The abi-encoded function call to execute on the {target} contract. | @@ -1310,27 +1308,6 @@ Reverts when calling the KeyManager through `execute(uint256,address,uint256,byt
-### CannotSendValueToSetData - -:::note References - -- Specification details: [**LSP-6-KeyManager**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-6-KeyManager.md#cannotsendvaluetosetdata) -- Solidity implementation: [`LSP6KeyManager.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP6KeyManager/LSP6KeyManager.sol) -- Error signature: `CannotSendValueToSetData()` -- Error hash: `0x59a529fc` - -::: - -```solidity -error CannotSendValueToSetData(); -``` - -_Cannot sent native tokens while setting data._ - -Reverts when calling the `setData(byte32,bytes)` or `setData(bytes32[],bytes[]) functions on the linked [`target`](#target) while sending value. - -
- ### DelegateCallDisallowedViaKeyManager :::note References diff --git a/tests/LSP6KeyManager/Interactions/BatchExecute.test.ts b/tests/LSP6KeyManager/Interactions/BatchExecute.test.ts index 97604cf17..315c01a94 100644 --- a/tests/LSP6KeyManager/Interactions/BatchExecute.test.ts +++ b/tests/LSP6KeyManager/Interactions/BatchExecute.test.ts @@ -430,8 +430,11 @@ export const shouldBehaveLikeBatchExecute = ( }); describe('if specifying some value for each values[index]', () => { - it('should revert with Key Manager error `CannotSendValueToSetData` when sending value while setting data', async () => { - const amountToFund = ethers.utils.parseEther('2'); + it('should pass when sending value while setting data', async () => { + const msgValues = [ethers.utils.parseEther('2'), ethers.utils.parseEther('2')]; + const totalMsgValue = msgValues.reduce((accumulator, currentValue) => + accumulator.add(currentValue), + ); const dataKeys = [ ethers.utils.keccak256(ethers.utils.toUtf8Bytes('key1')), @@ -439,10 +442,6 @@ export const shouldBehaveLikeBatchExecute = ( ]; const dataValues = ['0xaaaaaaaa', '0xbbbbbbbb']; - const keyManagerBalanceBefore = await ethers.provider.getBalance( - context.keyManager.address, - ); - const firstSetDataPayload = context.universalProfile.interface.encodeFunctionData( 'setData', [dataKeys[0], dataValues[0]], @@ -453,25 +452,15 @@ export const shouldBehaveLikeBatchExecute = ( [dataKeys[1], dataValues[1]], ); - // this error occurs when calling `setData(...)` with msg.value, - // since these functions on ERC725Y are not payable await expect( context.keyManager .connect(context.mainController) - .executeBatch([1, 1], [firstSetDataPayload, secondSetDataPayload], { - value: amountToFund, + .executeBatch(msgValues, [firstSetDataPayload, secondSetDataPayload], { + value: totalMsgValue, }), - ).to.be.revertedWithCustomError(context.keyManager, 'CannotSendValueToSetData'); - - const keyManagerBalanceAfter = await ethers.provider.getBalance( - context.keyManager.address, - ); + ).to.changeEtherBalances([context.universalProfile.address], [totalMsgValue]); - expect(keyManagerBalanceAfter).to.equal(keyManagerBalanceBefore); - - // the Key Manager must not hold any funds and must always forward any funds sent to it. - // it's balance must always be 0 after any execution - expect(await provider.getBalance(context.keyManager.address)).to.equal(0); + expect(await context.universalProfile.getDataBatch(dataKeys)).to.deep.equal(dataValues); }); }); }); @@ -504,10 +493,8 @@ export const shouldBehaveLikeBatchExecute = ( context.keyManager.connect(context.mainController).executeBatch(msgValues, payloads, { value: totalValues, }), - ).to.changeEtherBalances( - [context.universalProfile.address, recipient], - [0, msgValues[1]], - ); + ).to.changeEtherBalances([context.universalProfile.address, recipient], msgValues); + expect(await context.universalProfile.getData(dataKey)).to.equal(dataValue); }); }); @@ -535,11 +522,19 @@ export const shouldBehaveLikeBatchExecute = ( accumulator.add(currentValue), ); + await context.keyManager + .connect(context.mainController) + .executeBatch(msgValues, payloads, { + value: totalValues, + }); + await expect( context.keyManager.connect(context.mainController).executeBatch(msgValues, payloads, { value: totalValues, }), - ).to.be.revertedWithCustomError(context.keyManager, 'CannotSendValueToSetData'); + ).to.changeEtherBalances([context.universalProfile.address, recipient], msgValues); + + expect(await context.universalProfile.getData(dataKey)).to.equal(dataValue); }); }); }); diff --git a/tests/LSP6KeyManager/SetData/PermissionSetData.test.ts b/tests/LSP6KeyManager/SetData/PermissionSetData.test.ts index 1ba77695e..bb0154297 100644 --- a/tests/LSP6KeyManager/SetData/PermissionSetData.test.ts +++ b/tests/LSP6KeyManager/SetData/PermissionSetData.test.ts @@ -159,8 +159,8 @@ export const shouldBehaveLikePermissionSetData = (buildContext: () => Promise { - it('should revert with Key Manager error `CannotSendValueToSetData`', async () => { - const key = ethers.utils.keccak256(ethers.utils.toUtf8Bytes('My Key')); + it('should pass', async () => { + const key = ethers.utils.keccak256(ethers.utils.toUtf8Bytes('My First Key')); const value = ethers.utils.hexlify(ethers.utils.toUtf8Bytes('Hello Lukso!!!')); const payload = context.universalProfile.interface.encodeFunctionData('setData', [ @@ -172,7 +172,9 @@ export const shouldBehaveLikePermissionSetData = (buildContext: () => Promise Promise { - it('should revert with Key Manager error `CannotSendValueToSetData`', async () => { + it('should pass', async () => { const keys = [ ethers.utils.keccak256(ethers.utils.toUtf8Bytes('My First Key')), ethers.utils.keccak256(ethers.utils.toUtf8Bytes('My Second Key')), @@ -529,7 +531,9 @@ export const shouldBehaveLikePermissionSetData = (buildContext: () => Promise Promise Promise Date: Mon, 9 Oct 2023 11:38:36 +0100 Subject: [PATCH 41/55] perf: remove double `_exist` check in LSP8Core --- .../LSP8IdentifiableDigitalAssetCore.sol | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol index d4eebe28c..88ef5e908 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol @@ -285,6 +285,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is ) internal virtual { bool isRemoved = _operators[tokenId].remove(operator); if (!isRemoved) revert LSP8NonExistingOperator(operator, tokenId); + emit RevokedOperator( operator, tokenOwner, @@ -368,10 +369,6 @@ abstract contract LSP8IdentifiableDigitalAssetCore is revert LSP8CannotSendToAddressZero(); } - if (_exists(tokenId)) { - revert LSP8TokenIdAlreadyMinted(tokenId); - } - _beforeTokenTransfer(address(0), to, tokenId); // Check that `tokenId` was not minted inside the `_beforeTokenTransfer` hook From 6e894f53618b35044b3730f3ab1b102f09135f05 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Mon, 9 Oct 2023 15:53:30 +0100 Subject: [PATCH 42/55] refactor: adjust LSP7 storage layout like LSP8 --- .../LSP7DigitalAsset/LSP7DigitalAssetCore.sol | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol index 98965dc63..fdd1e2d54 100644 --- a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol +++ b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol @@ -50,21 +50,22 @@ import { */ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { using EnumerableSet for EnumerableSet.AddressSet; + // --- Storage + bool internal _isNonDivisible; + + uint256 internal _existingTokens; + // Mapping from `tokenOwner` to an `amount` of tokens mapping(address => uint256) internal _tokenOwnerBalances; - // Mapping a `tokenOwner` to an `operator` to `amount` of tokens. - mapping(address => mapping(address => uint256)) - internal _operatorAuthorizedAmount; - // Mapping an `address` to its authorized operator addresses. mapping(address => EnumerableSet.AddressSet) internal _operators; - uint256 internal _existingTokens; - - bool internal _isNonDivisible; + // Mapping a `tokenOwner` to an `operator` to `amount` of tokens. + mapping(address => mapping(address => uint256)) + internal _operatorAuthorizedAmount; // --- Token queries From 4e3adc24e233138b8f1471320e3b1bb3307ef524 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Tue, 10 Oct 2023 09:35:41 +0100 Subject: [PATCH 43/55] feat: add `_afterTokenTransfer` hook in LSP7 + LSP8 --- .../LSP7DigitalAsset/LSP7DigitalAssetCore.sol | 32 ++++++++++++++- .../LSP8IdentifiableDigitalAssetCore.sol | 40 ++++++++++++++++--- 2 files changed, 64 insertions(+), 8 deletions(-) diff --git a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol index fdd1e2d54..cc153f9b4 100644 --- a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol +++ b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol @@ -367,6 +367,10 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { /** * @dev Mints `amount` of tokens and transfers it to `to`. * + * @custom:info Any logic in the: + * - {_beforeTokenTransfer} function will run before updating the balances. + * - {_afterTokenTransfer} function will run after updating the balances, **but before notifying the recipient via LSP1**. + * * @param to The address to mint tokens for. * @param amount The amount of tokens to mint. * @param force A boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not. @@ -396,6 +400,8 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { emit Transfer(msg.sender, address(0), to, amount, force, data); + _afterTokenTransfer(address(0), to, amount); + bytes memory lsp1Data = abi.encode(address(0), to, amount, data); _notifyTokenReceiver(to, force, lsp1Data); } @@ -407,7 +413,9 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { * function, if they are contracts that support the LSP1 interface. Their `universalReceiver` function will receive * all the parameters in the calldata packed encoded. * - * Any logic in the {_beforeTokenTransfer} function will run before updating the balances. + * @custom:info Any logic in the: + * - {_beforeTokenTransfer} function will run before updating the balances. + * - {_afterTokenTransfer} function will run after updating the balances, **but before notifying the sender via LSP1**. * * @param from The address to burn tokens from its balance. * @param amount The amount of tokens to burn. @@ -454,6 +462,8 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { data: data }); + _afterTokenTransfer(from, address(0), amount); + bytes memory lsp1Data = abi.encode(from, address(0), amount, data); _notifyTokenSender(from, lsp1Data); } @@ -508,7 +518,9 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { * function, if they are contracts that support the LSP1 interface. Their `universalReceiver` function will receive * all the parameters in the calldata packed encoded. * - * Any logic in the {_beforeTokenTransfer} function will run before updating the balances. + * @custom:info Any logic in the: + * - {_beforeTokenTransfer} function will run before updating the balances. + * - {_afterTokenTransfer} function will run after updating the balances, **but before notifying the sender/recipient via LSP1**. * * @param from The address to decrease the balance. * @param to The address to increase the balance. @@ -546,6 +558,8 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { emit Transfer(msg.sender, from, to, amount, force, data); + _afterTokenTransfer(from, to, amount); + bytes memory lsp1Data = abi.encode(from, to, amount, data); _notifyTokenSender(from, lsp1Data); @@ -566,6 +580,20 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { uint256 amount // solhint-disable-next-line no-empty-blocks ) internal virtual {} + /** + * @dev Hook that is called after any token transfer, including minting and burning. + * Allows to run custom logic after updating balances, but **before notifiying sender/recipient** by overriding this function. + * + * @param from The sender address + * @param to The recipient address + * @param amount The amount of token to transfer + */ + function _afterTokenTransfer( + address from, + address to, + uint256 amount // solhint-disable-next-line no-empty-blocks + ) internal virtual {} + /** * @dev Attempt to notify the operator `operator` about the `amount` tokens being authorized with. * This is done by calling its {universalReceiver} function with the `_TYPEID_LSP7_TOKENOPERATOR` as typeId, if `operator` is a contract that supports the LSP1 interface. diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol index 88ef5e908..28a449069 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol @@ -348,15 +348,19 @@ abstract contract LSP8IdentifiableDigitalAssetCore is /** * @dev Create `tokenId` by minting it and transfers it to `to`. * - * @custom:requirements - * - `tokenId` must not exist and not have been already minted. - * - `to` cannot be the zero address. + * @custom:info Any logic in the: + * - {_beforeTokenTransfer} function will run before updating the balances and ownership of `tokenId`s. + * - {_afterTokenTransfer} function will run after updating the balances and ownership of `tokenId`s, **but before notifying the recipient via LSP1**. * * @param to The address that will receive the minted `tokenId`. * @param tokenId The token ID to create (= mint). * @param force When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard. * @param data Any additional data the caller wants included in the emitted event, and sent in the hook of the `to` address. * + * @custom:requirements + * - `tokenId` must not exist and not have been already minted. + * - `to` cannot be the zero address. + * @custom:events {Transfer} event with `address(0)` as `from` address. */ function _mint( @@ -384,6 +388,8 @@ abstract contract LSP8IdentifiableDigitalAssetCore is emit Transfer(msg.sender, address(0), to, tokenId, force, data); + _afterTokenTransfer(address(0), to, tokenId); + bytes memory lsp1Data = abi.encode(address(0), to, tokenId, data); _notifyTokenReceiver(to, force, lsp1Data); } @@ -396,7 +402,9 @@ abstract contract LSP8IdentifiableDigitalAssetCore is * function, if it is a contract that supports the LSP1 interface. Its {universalReceiver} function will receive * all the parameters in the calldata packed encoded. * - * Any logic in the {_beforeTokenTransfer} function will run before burning `tokenId` and updating the balances. + * @custom:info Any logic in the: + * - {_beforeTokenTransfer} function will run before updating the balances and ownership of `tokenId`s. + * - {_afterTokenTransfer} function will run after updating the balances and ownership of `tokenId`s, **but before notifying the sender via LSP1**. * * @param tokenId The token to burn. * @param data Any additional data the caller wants included in the emitted event, and sent in the LSP1 hook on the token owner's address. @@ -427,6 +435,8 @@ abstract contract LSP8IdentifiableDigitalAssetCore is emit Transfer(msg.sender, tokenOwner, address(0), tokenId, false, data); + _afterTokenTransfer(tokenOwner, address(0), tokenId); + bytes memory lsp1Data = abi.encode( tokenOwner, address(0), @@ -443,7 +453,9 @@ abstract contract LSP8IdentifiableDigitalAssetCore is * function, if they are contracts that support the LSP1 interface. Their `universalReceiver` function will receive * all the parameters in the calldata packed encoded. * - * Any logic in the {_beforeTokenTransfer} function will run before changing the owner of `tokenId`. + * @custom:info Any logic in the: + * - {_beforeTokenTransfer} function will run before updating the balances and ownership of `tokenId`s. + * - {_afterTokenTransfer} function will run after updating the balances and ownership of `tokenId`s, **but before notifying the sender/recipient via LSP1**. * * @param from The sender address. * @param to The recipient address. @@ -493,6 +505,8 @@ abstract contract LSP8IdentifiableDigitalAssetCore is emit Transfer(msg.sender, from, to, tokenId, force, data); + _afterTokenTransfer(from, to, tokenId); + bytes memory lsp1Data = abi.encode(from, to, tokenId, data); _notifyTokenSender(from, lsp1Data); @@ -501,7 +515,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is /** * @dev Hook that is called before any token transfer, including minting and burning. - * * Allows to run custom logic before updating balances and notifiying sender/recipient by overriding this function. + * Allows to run custom logic before updating balances and notifiying sender/recipient by overriding this function. * * @param from The sender address * @param to The recipient address @@ -513,6 +527,20 @@ abstract contract LSP8IdentifiableDigitalAssetCore is bytes32 tokenId // solhint-disable-next-line no-empty-blocks ) internal virtual {} + /** + * @dev Hook that is called after any token transfer, including minting and burning. + * Allows to run custom logic after updating balances, but **before notifiying sender/recipient via LSP1** by overriding this function. + * + * @param from The sender address + * @param to The recipient address + * @param tokenId The tokenId to transfer + */ + function _afterTokenTransfer( + address from, + address to, + bytes32 tokenId // solhint-disable-next-line no-empty-blocks + ) internal virtual {} + /** * @dev Attempt to notify the operator `operator` about the `tokenId` tokens being authorized. * This is done by calling its {universalReceiver} function with the `_TYPEID_LSP8_TOKENOPERATOR` as typeId, if `operator` is a contract that supports the LSP1 interface. From 2b475b25313185869c9ed9026c5c9f2a4e12cb53 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Tue, 10 Oct 2023 09:36:00 +0100 Subject: [PATCH 44/55] docs: update tokens docs for `_afterTokenTransfer` hook --- .../LSP7DigitalAsset/LSP7DigitalAsset.md | 55 +++++++++++++++++- .../extensions/LSP7Burnable.md | 55 +++++++++++++++++- .../extensions/LSP7CappedSupply.md | 45 ++++++++++++++- .../extensions/LSP7CompatibleERC20.md | 23 ++++++++ .../presets/LSP7CompatibleERC20Mintable.md | 23 ++++++++ .../LSP7DigitalAsset/presets/LSP7Mintable.md | 55 +++++++++++++++++- .../LSP8IdentifiableDigitalAsset.md | 56 ++++++++++++++++++- .../extensions/LSP8Burnable.md | 56 ++++++++++++++++++- .../extensions/LSP8CappedSupply.md | 46 ++++++++++++++- .../extensions/LSP8CompatibleERC721.md | 24 +++++++- .../extensions/LSP8Enumerable.md | 55 +++++++++++++++++- .../presets/LSP8CompatibleERC721Mintable.md | 24 +++++++- .../presets/LSP8Mintable.md | 56 ++++++++++++++++++- 13 files changed, 549 insertions(+), 24 deletions(-) diff --git a/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md b/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md index 101dc5629..1f5e332c7 100644 --- a/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md +++ b/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md @@ -833,6 +833,16 @@ If the amount is zero then the operator is being revoked, otherwise the operator ### \_mint +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances. + +- {\_afterTokenTransfer} function will run after updating the balances, **but before notifying the recipient via LSP1**. + +::: + ```solidity function _mint( address to, @@ -865,6 +875,16 @@ Mints `amount` of tokens and transfers it to `to`. ### \_burn +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances. + +- {\_afterTokenTransfer} function will run after updating the balances, **but before notifying the sender via LSP1**. + +::: + :::tip Hint In dApps, you can know which address is burning tokens by listening for the `Transfer` event and filter with the zero address as `to`. @@ -879,7 +899,6 @@ Burns (= destroys) `amount` of tokens, decrease the `from` balance. This is done Both the sender and recipient will be notified of the token transfer through the LSP1 [`universalReceiver`](#universalreceiver) function, if they are contracts that support the LSP1 interface. Their `universalReceiver` function will receive all the parameters in the calldata packed encoded. -Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will run before updating the balances.
@@ -923,6 +942,16 @@ Spend `amountToSpend` from the `operator`'s authorized on behalf of the `tokenOw ### \_transfer +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances. + +- {\_afterTokenTransfer} function will run after updating the balances, **but before notifying the sender/recipient via LSP1**. + +::: + ```solidity function _transfer( address from, @@ -938,7 +967,6 @@ of `to` by `+amount`. Both the sender and recipient will be notified of the token transfer through the LSP1 [`universalReceiver`](#universalreceiver) function, if they are contracts that support the LSP1 interface. Their `universalReceiver` function will receive all the parameters in the calldata packed encoded. -Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will run before updating the balances.
@@ -983,6 +1011,29 @@ Allows to run custom logic before updating balances and notifiying sender/recipi
+### \_afterTokenTransfer + +```solidity +function _afterTokenTransfer( + address from, + address to, + uint256 amount +) internal nonpayable; +``` + +Hook that is called after any token transfer, including minting and burning. +Allows to run custom logic after updating balances, but **before notifiying sender/recipient** by overriding this function. + +#### Parameters + +| Name | Type | Description | +| -------- | :-------: | ------------------------------- | +| `from` | `address` | The sender address | +| `to` | `address` | The recipient address | +| `amount` | `uint256` | The amount of token to transfer | + +
+ ### \_notifyTokenOperator ```solidity diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md index 2a2652731..34098c44b 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md @@ -858,6 +858,16 @@ If the amount is zero then the operator is being revoked, otherwise the operator ### \_mint +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances. + +- {\_afterTokenTransfer} function will run after updating the balances, **but before notifying the recipient via LSP1**. + +::: + ```solidity function _mint( address to, @@ -890,6 +900,16 @@ Mints `amount` of tokens and transfers it to `to`. ### \_burn +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances. + +- {\_afterTokenTransfer} function will run after updating the balances, **but before notifying the sender via LSP1**. + +::: + :::tip Hint In dApps, you can know which address is burning tokens by listening for the `Transfer` event and filter with the zero address as `to`. @@ -904,7 +924,6 @@ Burns (= destroys) `amount` of tokens, decrease the `from` balance. This is done Both the sender and recipient will be notified of the token transfer through the LSP1 [`universalReceiver`](#universalreceiver) function, if they are contracts that support the LSP1 interface. Their `universalReceiver` function will receive all the parameters in the calldata packed encoded. -Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will run before updating the balances.
@@ -948,6 +967,16 @@ Spend `amountToSpend` from the `operator`'s authorized on behalf of the `tokenOw ### \_transfer +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances. + +- {\_afterTokenTransfer} function will run after updating the balances, **but before notifying the sender/recipient via LSP1**. + +::: + ```solidity function _transfer( address from, @@ -963,7 +992,6 @@ of `to` by `+amount`. Both the sender and recipient will be notified of the token transfer through the LSP1 [`universalReceiver`](#universalreceiver) function, if they are contracts that support the LSP1 interface. Their `universalReceiver` function will receive all the parameters in the calldata packed encoded. -Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will run before updating the balances.
@@ -1008,6 +1036,29 @@ Allows to run custom logic before updating balances and notifiying sender/recipi
+### \_afterTokenTransfer + +```solidity +function _afterTokenTransfer( + address from, + address to, + uint256 amount +) internal nonpayable; +``` + +Hook that is called after any token transfer, including minting and burning. +Allows to run custom logic after updating balances, but **before notifiying sender/recipient** by overriding this function. + +#### Parameters + +| Name | Type | Description | +| -------- | :-------: | ------------------------------- | +| `from` | `address` | The sender address | +| `to` | `address` | The recipient address | +| `amount` | `uint256` | The amount of token to transfer | + +
+ ### \_notifyTokenOperator ```solidity diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md index cc2501eae..9ed5575a0 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md @@ -874,6 +874,16 @@ after `amount` of tokens have been minted. ### \_burn +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances. + +- {\_afterTokenTransfer} function will run after updating the balances, **but before notifying the sender via LSP1**. + +::: + :::tip Hint In dApps, you can know which address is burning tokens by listening for the `Transfer` event and filter with the zero address as `to`. @@ -888,7 +898,6 @@ Burns (= destroys) `amount` of tokens, decrease the `from` balance. This is done Both the sender and recipient will be notified of the token transfer through the LSP1 [`universalReceiver`](#universalreceiver) function, if they are contracts that support the LSP1 interface. Their `universalReceiver` function will receive all the parameters in the calldata packed encoded. -Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will run before updating the balances.
@@ -932,6 +941,16 @@ Spend `amountToSpend` from the `operator`'s authorized on behalf of the `tokenOw ### \_transfer +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances. + +- {\_afterTokenTransfer} function will run after updating the balances, **but before notifying the sender/recipient via LSP1**. + +::: + ```solidity function _transfer( address from, @@ -947,7 +966,6 @@ of `to` by `+amount`. Both the sender and recipient will be notified of the token transfer through the LSP1 [`universalReceiver`](#universalreceiver) function, if they are contracts that support the LSP1 interface. Their `universalReceiver` function will receive all the parameters in the calldata packed encoded. -Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will run before updating the balances.
@@ -992,6 +1010,29 @@ Allows to run custom logic before updating balances and notifiying sender/recipi
+### \_afterTokenTransfer + +```solidity +function _afterTokenTransfer( + address from, + address to, + uint256 amount +) internal nonpayable; +``` + +Hook that is called after any token transfer, including minting and burning. +Allows to run custom logic after updating balances, but **before notifiying sender/recipient** by overriding this function. + +#### Parameters + +| Name | Type | Description | +| -------- | :-------: | ------------------------------- | +| `from` | `address` | The sender address | +| `to` | `address` | The recipient address | +| `amount` | `uint256` | The amount of token to transfer | + +
+ ### \_notifyTokenOperator ```solidity diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md index b5892952b..135705795 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md @@ -1090,6 +1090,29 @@ Allows to run custom logic before updating balances and notifiying sender/recipi
+### \_afterTokenTransfer + +```solidity +function _afterTokenTransfer( + address from, + address to, + uint256 amount +) internal nonpayable; +``` + +Hook that is called after any token transfer, including minting and burning. +Allows to run custom logic after updating balances, but **before notifiying sender/recipient** by overriding this function. + +#### Parameters + +| Name | Type | Description | +| -------- | :-------: | ------------------------------- | +| `from` | `address` | The sender address | +| `to` | `address` | The recipient address | +| `amount` | `uint256` | The amount of token to transfer | + +
+ ### \_notifyTokenOperator ```solidity diff --git a/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md b/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md index 8a5d97d56..95238d92f 100644 --- a/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md +++ b/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md @@ -1124,6 +1124,29 @@ Allows to run custom logic before updating balances and notifiying sender/recipi
+### \_afterTokenTransfer + +```solidity +function _afterTokenTransfer( + address from, + address to, + uint256 amount +) internal nonpayable; +``` + +Hook that is called after any token transfer, including minting and burning. +Allows to run custom logic after updating balances, but **before notifiying sender/recipient** by overriding this function. + +#### Parameters + +| Name | Type | Description | +| -------- | :-------: | ------------------------------- | +| `from` | `address` | The sender address | +| `to` | `address` | The recipient address | +| `amount` | `uint256` | The amount of token to transfer | + +
+ ### \_notifyTokenOperator ```solidity diff --git a/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md b/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md index b9de110e4..eace4408b 100644 --- a/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md +++ b/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md @@ -895,6 +895,16 @@ If the amount is zero then the operator is being revoked, otherwise the operator ### \_mint +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances. + +- {\_afterTokenTransfer} function will run after updating the balances, **but before notifying the recipient via LSP1**. + +::: + ```solidity function _mint( address to, @@ -927,6 +937,16 @@ Mints `amount` of tokens and transfers it to `to`. ### \_burn +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances. + +- {\_afterTokenTransfer} function will run after updating the balances, **but before notifying the sender via LSP1**. + +::: + :::tip Hint In dApps, you can know which address is burning tokens by listening for the `Transfer` event and filter with the zero address as `to`. @@ -941,7 +961,6 @@ Burns (= destroys) `amount` of tokens, decrease the `from` balance. This is done Both the sender and recipient will be notified of the token transfer through the LSP1 [`universalReceiver`](#universalreceiver) function, if they are contracts that support the LSP1 interface. Their `universalReceiver` function will receive all the parameters in the calldata packed encoded. -Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will run before updating the balances.
@@ -985,6 +1004,16 @@ Spend `amountToSpend` from the `operator`'s authorized on behalf of the `tokenOw ### \_transfer +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances. + +- {\_afterTokenTransfer} function will run after updating the balances, **but before notifying the sender/recipient via LSP1**. + +::: + ```solidity function _transfer( address from, @@ -1000,7 +1029,6 @@ of `to` by `+amount`. Both the sender and recipient will be notified of the token transfer through the LSP1 [`universalReceiver`](#universalreceiver) function, if they are contracts that support the LSP1 interface. Their `universalReceiver` function will receive all the parameters in the calldata packed encoded. -Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will run before updating the balances.
@@ -1045,6 +1073,29 @@ Allows to run custom logic before updating balances and notifiying sender/recipi
+### \_afterTokenTransfer + +```solidity +function _afterTokenTransfer( + address from, + address to, + uint256 amount +) internal nonpayable; +``` + +Hook that is called after any token transfer, including minting and burning. +Allows to run custom logic after updating balances, but **before notifiying sender/recipient** by overriding this function. + +#### Parameters + +| Name | Type | Description | +| -------- | :-------: | ------------------------------- | +| `from` | `address` | The sender address | +| `to` | `address` | The recipient address | +| `amount` | `uint256` | The amount of token to transfer | + +
+ ### \_notifyTokenOperator ```solidity diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md b/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md index 64eb7b0b8..c72dd01d3 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md @@ -803,6 +803,16 @@ When `tokenId` does not exist then revert with an error. ### \_mint +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances and ownership of `tokenId`s. + +- {\_afterTokenTransfer} function will run after updating the balances and ownership of `tokenId`s, **but before notifying the recipient via LSP1**. + +::: + ```solidity function _mint( address to, @@ -835,6 +845,16 @@ Create `tokenId` by minting it and transfers it to `to`. ### \_burn +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances and ownership of `tokenId`s. + +- {\_afterTokenTransfer} function will run after updating the balances and ownership of `tokenId`s, **but before notifying the sender via LSP1**. + +::: + :::tip Hint In dApps, you can know which addresses are burning tokens by listening for the `Transfer` event and filter with the zero address as `to`. @@ -850,7 +870,6 @@ This will also clear all the operators allowed to transfer the `tokenId`. The owner of the `tokenId` will be notified about the `tokenId` being transferred through its LSP1 [`universalReceiver`](#universalreceiver) function, if it is a contract that supports the LSP1 interface. Its [`universalReceiver`](#universalreceiver) function will receive all the parameters in the calldata packed encoded. -Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will run before burning `tokenId` and updating the balances.
@@ -871,6 +890,16 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r ### \_transfer +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances and ownership of `tokenId`s. + +- {\_afterTokenTransfer} function will run after updating the balances and ownership of `tokenId`s, **but before notifying the sender/recipient via LSP1**. + +::: + :::danger This internal function does not check if the sender is authorized or not to operate on the `tokenId`. @@ -891,7 +920,6 @@ Change the owner of the `tokenId` from `from` to `to`. Both the sender and recipient will be notified of the `tokenId` being transferred through their LSP1 [`universalReceiver`](#universalreceiver) function, if they are contracts that support the LSP1 interface. Their `universalReceiver` function will receive all the parameters in the calldata packed encoded. -Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will run before changing the owner of `tokenId`.
@@ -924,8 +952,30 @@ function _beforeTokenTransfer( ``` Hook that is called before any token transfer, including minting and burning. +Allows to run custom logic before updating balances and notifiying sender/recipient by overriding this function. + +#### Parameters + +| Name | Type | Description | +| --------- | :-------: | -------------------------------------- | +| `from` | `address` | The sender address | +| `to` | `address` | @param tokenId The tokenId to transfer | +| `tokenId` | `bytes32` | The tokenId to transfer | + +
+ +### \_afterTokenTransfer + +```solidity +function _afterTokenTransfer( + address from, + address to, + bytes32 tokenId +) internal nonpayable; +``` -- Allows to run custom logic before updating balances and notifiying sender/recipient by overriding this function. +Hook that is called after any token transfer, including minting and burning. +Allows to run custom logic after updating balances, but **before notifiying sender/recipient via LSP1** by overriding this function. #### Parameters diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md index acfdb68cd..4f68d4008 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md @@ -829,6 +829,16 @@ When `tokenId` does not exist then revert with an error. ### \_mint +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances and ownership of `tokenId`s. + +- {\_afterTokenTransfer} function will run after updating the balances and ownership of `tokenId`s, **but before notifying the recipient via LSP1**. + +::: + ```solidity function _mint( address to, @@ -861,6 +871,16 @@ Create `tokenId` by minting it and transfers it to `to`. ### \_burn +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances and ownership of `tokenId`s. + +- {\_afterTokenTransfer} function will run after updating the balances and ownership of `tokenId`s, **but before notifying the sender via LSP1**. + +::: + :::tip Hint In dApps, you can know which addresses are burning tokens by listening for the `Transfer` event and filter with the zero address as `to`. @@ -876,7 +896,6 @@ This will also clear all the operators allowed to transfer the `tokenId`. The owner of the `tokenId` will be notified about the `tokenId` being transferred through its LSP1 [`universalReceiver`](#universalreceiver) function, if it is a contract that supports the LSP1 interface. Its [`universalReceiver`](#universalreceiver) function will receive all the parameters in the calldata packed encoded. -Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will run before burning `tokenId` and updating the balances.
@@ -897,6 +916,16 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r ### \_transfer +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances and ownership of `tokenId`s. + +- {\_afterTokenTransfer} function will run after updating the balances and ownership of `tokenId`s, **but before notifying the sender/recipient via LSP1**. + +::: + :::danger This internal function does not check if the sender is authorized or not to operate on the `tokenId`. @@ -917,7 +946,6 @@ Change the owner of the `tokenId` from `from` to `to`. Both the sender and recipient will be notified of the `tokenId` being transferred through their LSP1 [`universalReceiver`](#universalreceiver) function, if they are contracts that support the LSP1 interface. Their `universalReceiver` function will receive all the parameters in the calldata packed encoded. -Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will run before changing the owner of `tokenId`.
@@ -950,8 +978,30 @@ function _beforeTokenTransfer( ``` Hook that is called before any token transfer, including minting and burning. +Allows to run custom logic before updating balances and notifiying sender/recipient by overriding this function. + +#### Parameters + +| Name | Type | Description | +| --------- | :-------: | -------------------------------------- | +| `from` | `address` | The sender address | +| `to` | `address` | @param tokenId The tokenId to transfer | +| `tokenId` | `bytes32` | The tokenId to transfer | + +
+ +### \_afterTokenTransfer + +```solidity +function _afterTokenTransfer( + address from, + address to, + bytes32 tokenId +) internal nonpayable; +``` -- Allows to run custom logic before updating balances and notifiying sender/recipient by overriding this function. +Hook that is called after any token transfer, including minting and burning. +Allows to run custom logic after updating balances, but **before notifiying sender/recipient via LSP1** by overriding this function. #### Parameters diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md index 5946dd474..62310f99c 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md @@ -845,6 +845,16 @@ after a new `tokenId` has of tokens have been minted. ### \_burn +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances and ownership of `tokenId`s. + +- {\_afterTokenTransfer} function will run after updating the balances and ownership of `tokenId`s, **but before notifying the sender via LSP1**. + +::: + :::tip Hint In dApps, you can know which addresses are burning tokens by listening for the `Transfer` event and filter with the zero address as `to`. @@ -860,7 +870,6 @@ This will also clear all the operators allowed to transfer the `tokenId`. The owner of the `tokenId` will be notified about the `tokenId` being transferred through its LSP1 [`universalReceiver`](#universalreceiver) function, if it is a contract that supports the LSP1 interface. Its [`universalReceiver`](#universalreceiver) function will receive all the parameters in the calldata packed encoded. -Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will run before burning `tokenId` and updating the balances.
@@ -881,6 +890,16 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r ### \_transfer +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances and ownership of `tokenId`s. + +- {\_afterTokenTransfer} function will run after updating the balances and ownership of `tokenId`s, **but before notifying the sender/recipient via LSP1**. + +::: + :::danger This internal function does not check if the sender is authorized or not to operate on the `tokenId`. @@ -901,7 +920,6 @@ Change the owner of the `tokenId` from `from` to `to`. Both the sender and recipient will be notified of the `tokenId` being transferred through their LSP1 [`universalReceiver`](#universalreceiver) function, if they are contracts that support the LSP1 interface. Their `universalReceiver` function will receive all the parameters in the calldata packed encoded. -Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will run before changing the owner of `tokenId`.
@@ -934,8 +952,30 @@ function _beforeTokenTransfer( ``` Hook that is called before any token transfer, including minting and burning. +Allows to run custom logic before updating balances and notifiying sender/recipient by overriding this function. + +#### Parameters + +| Name | Type | Description | +| --------- | :-------: | -------------------------------------- | +| `from` | `address` | The sender address | +| `to` | `address` | @param tokenId The tokenId to transfer | +| `tokenId` | `bytes32` | The tokenId to transfer | + +
+ +### \_afterTokenTransfer + +```solidity +function _afterTokenTransfer( + address from, + address to, + bytes32 tokenId +) internal nonpayable; +``` -- Allows to run custom logic before updating balances and notifiying sender/recipient by overriding this function. +Hook that is called after any token transfer, including minting and burning. +Allows to run custom logic after updating balances, but **before notifiying sender/recipient via LSP1** by overriding this function. #### Parameters diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md index d1693dda6..e815cc233 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md @@ -1202,8 +1202,30 @@ function _beforeTokenTransfer( ``` Hook that is called before any token transfer, including minting and burning. +Allows to run custom logic before updating balances and notifiying sender/recipient by overriding this function. -- Allows to run custom logic before updating balances and notifiying sender/recipient by overriding this function. +#### Parameters + +| Name | Type | Description | +| --------- | :-------: | -------------------------------------- | +| `from` | `address` | The sender address | +| `to` | `address` | @param tokenId The tokenId to transfer | +| `tokenId` | `bytes32` | The tokenId to transfer | + +
+ +### \_afterTokenTransfer + +```solidity +function _afterTokenTransfer( + address from, + address to, + bytes32 tokenId +) internal nonpayable; +``` + +Hook that is called after any token transfer, including minting and burning. +Allows to run custom logic after updating balances, but **before notifiying sender/recipient via LSP1** by overriding this function. #### Parameters diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md index 36bc2804e..5bba28705 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md @@ -834,6 +834,16 @@ When `tokenId` does not exist then revert with an error. ### \_mint +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances and ownership of `tokenId`s. + +- {\_afterTokenTransfer} function will run after updating the balances and ownership of `tokenId`s, **but before notifying the recipient via LSP1**. + +::: + ```solidity function _mint( address to, @@ -866,6 +876,16 @@ Create `tokenId` by minting it and transfers it to `to`. ### \_burn +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances and ownership of `tokenId`s. + +- {\_afterTokenTransfer} function will run after updating the balances and ownership of `tokenId`s, **but before notifying the sender via LSP1**. + +::: + :::tip Hint In dApps, you can know which addresses are burning tokens by listening for the `Transfer` event and filter with the zero address as `to`. @@ -881,7 +901,6 @@ This will also clear all the operators allowed to transfer the `tokenId`. The owner of the `tokenId` will be notified about the `tokenId` being transferred through its LSP1 [`universalReceiver`](#universalreceiver) function, if it is a contract that supports the LSP1 interface. Its [`universalReceiver`](#universalreceiver) function will receive all the parameters in the calldata packed encoded. -Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will run before burning `tokenId` and updating the balances.
@@ -902,6 +921,16 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r ### \_transfer +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances and ownership of `tokenId`s. + +- {\_afterTokenTransfer} function will run after updating the balances and ownership of `tokenId`s, **but before notifying the sender/recipient via LSP1**. + +::: + :::danger This internal function does not check if the sender is authorized or not to operate on the `tokenId`. @@ -922,7 +951,6 @@ Change the owner of the `tokenId` from `from` to `to`. Both the sender and recipient will be notified of the `tokenId` being transferred through their LSP1 [`universalReceiver`](#universalreceiver) function, if they are contracts that support the LSP1 interface. Their `universalReceiver` function will receive all the parameters in the calldata packed encoded. -Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will run before changing the owner of `tokenId`.
@@ -964,6 +992,29 @@ function _beforeTokenTransfer(
+### \_afterTokenTransfer + +```solidity +function _afterTokenTransfer( + address from, + address to, + bytes32 tokenId +) internal nonpayable; +``` + +Hook that is called after any token transfer, including minting and burning. +Allows to run custom logic after updating balances, but **before notifiying sender/recipient via LSP1** by overriding this function. + +#### Parameters + +| Name | Type | Description | +| --------- | :-------: | -------------------------------------- | +| `from` | `address` | The sender address | +| `to` | `address` | @param tokenId The tokenId to transfer | +| `tokenId` | `bytes32` | The tokenId to transfer | + +
+ ### \_notifyTokenOperator ```solidity diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md index 33d19c009..6984f85dc 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md @@ -1244,8 +1244,30 @@ function _beforeTokenTransfer( ``` Hook that is called before any token transfer, including minting and burning. +Allows to run custom logic before updating balances and notifiying sender/recipient by overriding this function. -- Allows to run custom logic before updating balances and notifiying sender/recipient by overriding this function. +#### Parameters + +| Name | Type | Description | +| --------- | :-------: | -------------------------------------- | +| `from` | `address` | The sender address | +| `to` | `address` | @param tokenId The tokenId to transfer | +| `tokenId` | `bytes32` | The tokenId to transfer | + +
+ +### \_afterTokenTransfer + +```solidity +function _afterTokenTransfer( + address from, + address to, + bytes32 tokenId +) internal nonpayable; +``` + +Hook that is called after any token transfer, including minting and burning. +Allows to run custom logic after updating balances, but **before notifiying sender/recipient via LSP1** by overriding this function. #### Parameters diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md index e71fb2a68..c82402175 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md @@ -867,6 +867,16 @@ When `tokenId` does not exist then revert with an error. ### \_mint +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances and ownership of `tokenId`s. + +- {\_afterTokenTransfer} function will run after updating the balances and ownership of `tokenId`s, **but before notifying the recipient via LSP1**. + +::: + ```solidity function _mint( address to, @@ -899,6 +909,16 @@ Create `tokenId` by minting it and transfers it to `to`. ### \_burn +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances and ownership of `tokenId`s. + +- {\_afterTokenTransfer} function will run after updating the balances and ownership of `tokenId`s, **but before notifying the sender via LSP1**. + +::: + :::tip Hint In dApps, you can know which addresses are burning tokens by listening for the `Transfer` event and filter with the zero address as `to`. @@ -914,7 +934,6 @@ This will also clear all the operators allowed to transfer the `tokenId`. The owner of the `tokenId` will be notified about the `tokenId` being transferred through its LSP1 [`universalReceiver`](#universalreceiver) function, if it is a contract that supports the LSP1 interface. Its [`universalReceiver`](#universalreceiver) function will receive all the parameters in the calldata packed encoded. -Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will run before burning `tokenId` and updating the balances.
@@ -935,6 +954,16 @@ Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will r ### \_transfer +:::info + +Any logic in the: + +- {\_beforeTokenTransfer} function will run before updating the balances and ownership of `tokenId`s. + +- {\_afterTokenTransfer} function will run after updating the balances and ownership of `tokenId`s, **but before notifying the sender/recipient via LSP1**. + +::: + :::danger This internal function does not check if the sender is authorized or not to operate on the `tokenId`. @@ -955,7 +984,6 @@ Change the owner of the `tokenId` from `from` to `to`. Both the sender and recipient will be notified of the `tokenId` being transferred through their LSP1 [`universalReceiver`](#universalreceiver) function, if they are contracts that support the LSP1 interface. Their `universalReceiver` function will receive all the parameters in the calldata packed encoded. -Any logic in the [`_beforeTokenTransfer`](#_beforetokentransfer) function will run before changing the owner of `tokenId`.
@@ -988,8 +1016,30 @@ function _beforeTokenTransfer( ``` Hook that is called before any token transfer, including minting and burning. +Allows to run custom logic before updating balances and notifiying sender/recipient by overriding this function. + +#### Parameters + +| Name | Type | Description | +| --------- | :-------: | -------------------------------------- | +| `from` | `address` | The sender address | +| `to` | `address` | @param tokenId The tokenId to transfer | +| `tokenId` | `bytes32` | The tokenId to transfer | + +
+ +### \_afterTokenTransfer + +```solidity +function _afterTokenTransfer( + address from, + address to, + bytes32 tokenId +) internal nonpayable; +``` -- Allows to run custom logic before updating balances and notifiying sender/recipient by overriding this function. +Hook that is called after any token transfer, including minting and burning. +Allows to run custom logic after updating balances, but **before notifiying sender/recipient via LSP1** by overriding this function. #### Parameters From 0cd097604193957aeb2d6bf181d9193719621eac Mon Sep 17 00:00:00 2001 From: CJ42 Date: Fri, 13 Oct 2023 10:40:56 +0100 Subject: [PATCH 45/55] feat: add `data` param in `_before` and `_after` token transfer hooks --- .../LSP7DigitalAsset/LSP7DigitalAssetCore.sol | 20 +++++++------ .../LSP8IdentifiableDigitalAssetCore.sol | 20 +++++++------ .../extensions/LSP8Enumerable.sol | 12 ++++---- .../extensions/LSP8EnumerableInitAbstract.sol | 12 ++++---- .../LSP7DigitalAsset/LSP7DigitalAsset.md | 28 +++++++++++-------- .../extensions/LSP7Burnable.md | 28 +++++++++++-------- .../extensions/LSP7CappedSupply.md | 28 +++++++++++-------- .../extensions/LSP7CompatibleERC20.md | 28 +++++++++++-------- .../presets/LSP7CompatibleERC20Mintable.md | 28 +++++++++++-------- .../LSP7DigitalAsset/presets/LSP7Mintable.md | 28 +++++++++++-------- .../LSP8IdentifiableDigitalAsset.md | 8 ++++-- .../extensions/LSP8Burnable.md | 8 ++++-- .../extensions/LSP8CappedSupply.md | 8 ++++-- .../extensions/LSP8CompatibleERC721.md | 8 ++++-- .../extensions/LSP8Enumerable.md | 8 ++++-- .../presets/LSP8CompatibleERC721Mintable.md | 8 ++++-- .../presets/LSP8Mintable.md | 8 ++++-- 17 files changed, 174 insertions(+), 114 deletions(-) diff --git a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol index cc153f9b4..3f01760cf 100644 --- a/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol +++ b/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol @@ -391,7 +391,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { revert LSP7CannotSendWithAddressZero(); } - _beforeTokenTransfer(address(0), to, amount); + _beforeTokenTransfer(address(0), to, amount, data); // tokens being minted _existingTokens += amount; @@ -400,7 +400,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { emit Transfer(msg.sender, address(0), to, amount, force, data); - _afterTokenTransfer(address(0), to, amount); + _afterTokenTransfer(address(0), to, amount, data); bytes memory lsp1Data = abi.encode(address(0), to, amount, data); _notifyTokenReceiver(to, force, lsp1Data); @@ -445,7 +445,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { revert LSP7AmountExceedsBalance(balance, from, amount); } - _beforeTokenTransfer(from, address(0), amount); + _beforeTokenTransfer(from, address(0), amount, data); // tokens being burnt _existingTokens -= amount; @@ -462,7 +462,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { data: data }); - _afterTokenTransfer(from, address(0), amount); + _afterTokenTransfer(from, address(0), amount, data); bytes memory lsp1Data = abi.encode(from, address(0), amount, data); _notifyTokenSender(from, lsp1Data); @@ -551,14 +551,14 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { revert LSP7AmountExceedsBalance(balance, from, amount); } - _beforeTokenTransfer(from, to, amount); + _beforeTokenTransfer(from, to, amount, data); _tokenOwnerBalances[from] -= amount; _tokenOwnerBalances[to] += amount; emit Transfer(msg.sender, from, to, amount, force, data); - _afterTokenTransfer(from, to, amount); + _afterTokenTransfer(from, to, amount, data); bytes memory lsp1Data = abi.encode(from, to, amount, data); @@ -573,11 +573,13 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { * @param from The sender address * @param to The recipient address * @param amount The amount of token to transfer + * @param data The data sent alongside the transfer */ function _beforeTokenTransfer( address from, address to, - uint256 amount // solhint-disable-next-line no-empty-blocks + uint256 amount, + bytes memory data // solhint-disable-next-line no-empty-blocks ) internal virtual {} /** @@ -587,11 +589,13 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset { * @param from The sender address * @param to The recipient address * @param amount The amount of token to transfer + * @param data The data sent alongside the transfer */ function _afterTokenTransfer( address from, address to, - uint256 amount // solhint-disable-next-line no-empty-blocks + uint256 amount, + bytes memory data // solhint-disable-next-line no-empty-blocks ) internal virtual {} /** diff --git a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol index 28a449069..3a0d0e995 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol @@ -373,7 +373,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is revert LSP8CannotSendToAddressZero(); } - _beforeTokenTransfer(address(0), to, tokenId); + _beforeTokenTransfer(address(0), to, tokenId, data); // Check that `tokenId` was not minted inside the `_beforeTokenTransfer` hook if (_exists(tokenId)) { @@ -388,7 +388,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is emit Transfer(msg.sender, address(0), to, tokenId, force, data); - _afterTokenTransfer(address(0), to, tokenId); + _afterTokenTransfer(address(0), to, tokenId, data); bytes memory lsp1Data = abi.encode(address(0), to, tokenId, data); _notifyTokenReceiver(to, force, lsp1Data); @@ -419,7 +419,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is function _burn(bytes32 tokenId, bytes memory data) internal virtual { address tokenOwner = tokenOwnerOf(tokenId); - _beforeTokenTransfer(tokenOwner, address(0), tokenId); + _beforeTokenTransfer(tokenOwner, address(0), tokenId, data); // Re-fetch and update `tokenOwner` in case `tokenId` // was transferred inside the `_beforeTokenTransfer` hook @@ -435,7 +435,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is emit Transfer(msg.sender, tokenOwner, address(0), tokenId, false, data); - _afterTokenTransfer(tokenOwner, address(0), tokenId); + _afterTokenTransfer(tokenOwner, address(0), tokenId, data); bytes memory lsp1Data = abi.encode( tokenOwner, @@ -491,7 +491,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is revert LSP8CannotSendToAddressZero(); } - _beforeTokenTransfer(from, to, tokenId); + _beforeTokenTransfer(from, to, tokenId, data); // Re-fetch and update `tokenOwner` in case `tokenId` // was transferred inside the `_beforeTokenTransfer` hook @@ -505,7 +505,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is emit Transfer(msg.sender, from, to, tokenId, force, data); - _afterTokenTransfer(from, to, tokenId); + _afterTokenTransfer(from, to, tokenId, data); bytes memory lsp1Data = abi.encode(from, to, tokenId, data); @@ -520,11 +520,13 @@ abstract contract LSP8IdentifiableDigitalAssetCore is * @param from The sender address * @param to The recipient address * @param tokenId The tokenId to transfer + * @param data The data sent alongside the transfer */ function _beforeTokenTransfer( address from, address to, - bytes32 tokenId // solhint-disable-next-line no-empty-blocks + bytes32 tokenId, + bytes memory data // solhint-disable-next-line no-empty-blocks ) internal virtual {} /** @@ -534,11 +536,13 @@ abstract contract LSP8IdentifiableDigitalAssetCore is * @param from The sender address * @param to The recipient address * @param tokenId The tokenId to transfer + * @param data The data sent alongside the transfer */ function _afterTokenTransfer( address from, address to, - bytes32 tokenId // solhint-disable-next-line no-empty-blocks + bytes32 tokenId, + bytes memory data // solhint-disable-next-line no-empty-blocks ) internal virtual {} /** diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.sol index 4a25009ca..11ed39e20 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.sol @@ -4,11 +4,9 @@ pragma solidity ^0.8.4; // modules import { - LSP8IdentifiableDigitalAsset -} from "../LSP8IdentifiableDigitalAsset.sol"; -import { + LSP8IdentifiableDigitalAsset, LSP8IdentifiableDigitalAssetCore -} from "../LSP8IdentifiableDigitalAssetCore.sol"; +} from "../LSP8IdentifiableDigitalAsset.sol"; /** * @dev LSP8 extension that enables to enumerate over all the `tokenIds` ever minted. @@ -39,11 +37,13 @@ abstract contract LSP8Enumerable is LSP8IdentifiableDigitalAsset { * @param from The address sending the `tokenId` (`address(0)` when `tokenId` is being minted). * @param to The address receiving the `tokenId` (`address(0)` when `tokenId` is being burnt). * @param tokenId The bytes32 identifier of the token being transferred. + * @param data The data sent alongside the the token transfer. */ function _beforeTokenTransfer( address from, address to, - bytes32 tokenId + bytes32 tokenId, + bytes memory data ) internal virtual override(LSP8IdentifiableDigitalAssetCore) { // `tokenId` being minted if (from == address(0)) { @@ -65,6 +65,6 @@ abstract contract LSP8Enumerable is LSP8IdentifiableDigitalAsset { delete _tokenIndex[tokenId]; } - super._beforeTokenTransfer(from, to, tokenId); + super._beforeTokenTransfer(from, to, tokenId, data); } } diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8EnumerableInitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8EnumerableInitAbstract.sol index 18ca0e8fc..e898fc082 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8EnumerableInitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8EnumerableInitAbstract.sol @@ -4,11 +4,9 @@ pragma solidity ^0.8.4; // modules import { - LSP8IdentifiableDigitalAssetInitAbstract -} from "../LSP8IdentifiableDigitalAssetInitAbstract.sol"; -import { + LSP8IdentifiableDigitalAssetInitAbstract, LSP8IdentifiableDigitalAssetCore -} from "../LSP8IdentifiableDigitalAssetCore.sol"; +} from "../LSP8IdentifiableDigitalAssetInitAbstract.sol"; /** * @dev LSP8 extension. @@ -39,11 +37,13 @@ abstract contract LSP8EnumerableInitAbstract is * @param from The address sending the `tokenId` (`address(0)` when `tokenId` is being minted). * @param to The address receiving the `tokenId` (`address(0)` when `tokenId` is being burnt). * @param tokenId The bytes32 identifier of the token being transferred. + * @param data The data sent alongside the the token transfer. */ function _beforeTokenTransfer( address from, address to, - bytes32 tokenId + bytes32 tokenId, + bytes memory data ) internal virtual override(LSP8IdentifiableDigitalAssetCore) { if (from == address(0)) { uint256 index = totalSupply(); @@ -60,6 +60,6 @@ abstract contract LSP8EnumerableInitAbstract is delete _indexToken[lastIndex]; delete _tokenIndex[tokenId]; } - super._beforeTokenTransfer(from, to, tokenId); + super._beforeTokenTransfer(from, to, tokenId, data); } } diff --git a/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md b/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md index 1f5e332c7..fc8d7357c 100644 --- a/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md +++ b/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md @@ -994,7 +994,8 @@ all the parameters in the calldata packed encoded. function _beforeTokenTransfer( address from, address to, - uint256 amount + uint256 amount, + bytes data ) internal nonpayable; ``` @@ -1003,11 +1004,12 @@ Allows to run custom logic before updating balances and notifiying sender/recipi #### Parameters -| Name | Type | Description | -| -------- | :-------: | ------------------------------- | -| `from` | `address` | The sender address | -| `to` | `address` | The recipient address | -| `amount` | `uint256` | The amount of token to transfer | +| Name | Type | Description | +| -------- | :-------: | ------------------------------------ | +| `from` | `address` | The sender address | +| `to` | `address` | The recipient address | +| `amount` | `uint256` | The amount of token to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
@@ -1017,7 +1019,8 @@ Allows to run custom logic before updating balances and notifiying sender/recipi function _afterTokenTransfer( address from, address to, - uint256 amount + uint256 amount, + bytes data ) internal nonpayable; ``` @@ -1026,11 +1029,12 @@ Allows to run custom logic after updating balances, but **before notifiying send #### Parameters -| Name | Type | Description | -| -------- | :-------: | ------------------------------- | -| `from` | `address` | The sender address | -| `to` | `address` | The recipient address | -| `amount` | `uint256` | The amount of token to transfer | +| Name | Type | Description | +| -------- | :-------: | ------------------------------------ | +| `from` | `address` | The sender address | +| `to` | `address` | The recipient address | +| `amount` | `uint256` | The amount of token to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md index 34098c44b..1c0a68f4a 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md @@ -1019,7 +1019,8 @@ all the parameters in the calldata packed encoded. function _beforeTokenTransfer( address from, address to, - uint256 amount + uint256 amount, + bytes data ) internal nonpayable; ``` @@ -1028,11 +1029,12 @@ Allows to run custom logic before updating balances and notifiying sender/recipi #### Parameters -| Name | Type | Description | -| -------- | :-------: | ------------------------------- | -| `from` | `address` | The sender address | -| `to` | `address` | The recipient address | -| `amount` | `uint256` | The amount of token to transfer | +| Name | Type | Description | +| -------- | :-------: | ------------------------------------ | +| `from` | `address` | The sender address | +| `to` | `address` | The recipient address | +| `amount` | `uint256` | The amount of token to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
@@ -1042,7 +1044,8 @@ Allows to run custom logic before updating balances and notifiying sender/recipi function _afterTokenTransfer( address from, address to, - uint256 amount + uint256 amount, + bytes data ) internal nonpayable; ``` @@ -1051,11 +1054,12 @@ Allows to run custom logic after updating balances, but **before notifiying send #### Parameters -| Name | Type | Description | -| -------- | :-------: | ------------------------------- | -| `from` | `address` | The sender address | -| `to` | `address` | The recipient address | -| `amount` | `uint256` | The amount of token to transfer | +| Name | Type | Description | +| -------- | :-------: | ------------------------------------ | +| `from` | `address` | The sender address | +| `to` | `address` | The recipient address | +| `amount` | `uint256` | The amount of token to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md index 9ed5575a0..74423ec3b 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md @@ -993,7 +993,8 @@ all the parameters in the calldata packed encoded. function _beforeTokenTransfer( address from, address to, - uint256 amount + uint256 amount, + bytes data ) internal nonpayable; ``` @@ -1002,11 +1003,12 @@ Allows to run custom logic before updating balances and notifiying sender/recipi #### Parameters -| Name | Type | Description | -| -------- | :-------: | ------------------------------- | -| `from` | `address` | The sender address | -| `to` | `address` | The recipient address | -| `amount` | `uint256` | The amount of token to transfer | +| Name | Type | Description | +| -------- | :-------: | ------------------------------------ | +| `from` | `address` | The sender address | +| `to` | `address` | The recipient address | +| `amount` | `uint256` | The amount of token to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
@@ -1016,7 +1018,8 @@ Allows to run custom logic before updating balances and notifiying sender/recipi function _afterTokenTransfer( address from, address to, - uint256 amount + uint256 amount, + bytes data ) internal nonpayable; ``` @@ -1025,11 +1028,12 @@ Allows to run custom logic after updating balances, but **before notifiying send #### Parameters -| Name | Type | Description | -| -------- | :-------: | ------------------------------- | -| `from` | `address` | The sender address | -| `to` | `address` | The recipient address | -| `amount` | `uint256` | The amount of token to transfer | +| Name | Type | Description | +| -------- | :-------: | ------------------------------------ | +| `from` | `address` | The sender address | +| `to` | `address` | The recipient address | +| `amount` | `uint256` | The amount of token to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md index 135705795..e8e8c01d8 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md @@ -1073,7 +1073,8 @@ function _transfer( function _beforeTokenTransfer( address from, address to, - uint256 amount + uint256 amount, + bytes data ) internal nonpayable; ``` @@ -1082,11 +1083,12 @@ Allows to run custom logic before updating balances and notifiying sender/recipi #### Parameters -| Name | Type | Description | -| -------- | :-------: | ------------------------------- | -| `from` | `address` | The sender address | -| `to` | `address` | The recipient address | -| `amount` | `uint256` | The amount of token to transfer | +| Name | Type | Description | +| -------- | :-------: | ------------------------------------ | +| `from` | `address` | The sender address | +| `to` | `address` | The recipient address | +| `amount` | `uint256` | The amount of token to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
@@ -1096,7 +1098,8 @@ Allows to run custom logic before updating balances and notifiying sender/recipi function _afterTokenTransfer( address from, address to, - uint256 amount + uint256 amount, + bytes data ) internal nonpayable; ``` @@ -1105,11 +1108,12 @@ Allows to run custom logic after updating balances, but **before notifiying send #### Parameters -| Name | Type | Description | -| -------- | :-------: | ------------------------------- | -| `from` | `address` | The sender address | -| `to` | `address` | The recipient address | -| `amount` | `uint256` | The amount of token to transfer | +| Name | Type | Description | +| -------- | :-------: | ------------------------------------ | +| `from` | `address` | The sender address | +| `to` | `address` | The recipient address | +| `amount` | `uint256` | The amount of token to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
diff --git a/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md b/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md index 95238d92f..7d54b18cd 100644 --- a/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md +++ b/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md @@ -1107,7 +1107,8 @@ function _transfer( function _beforeTokenTransfer( address from, address to, - uint256 amount + uint256 amount, + bytes data ) internal nonpayable; ``` @@ -1116,11 +1117,12 @@ Allows to run custom logic before updating balances and notifiying sender/recipi #### Parameters -| Name | Type | Description | -| -------- | :-------: | ------------------------------- | -| `from` | `address` | The sender address | -| `to` | `address` | The recipient address | -| `amount` | `uint256` | The amount of token to transfer | +| Name | Type | Description | +| -------- | :-------: | ------------------------------------ | +| `from` | `address` | The sender address | +| `to` | `address` | The recipient address | +| `amount` | `uint256` | The amount of token to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
@@ -1130,7 +1132,8 @@ Allows to run custom logic before updating balances and notifiying sender/recipi function _afterTokenTransfer( address from, address to, - uint256 amount + uint256 amount, + bytes data ) internal nonpayable; ``` @@ -1139,11 +1142,12 @@ Allows to run custom logic after updating balances, but **before notifiying send #### Parameters -| Name | Type | Description | -| -------- | :-------: | ------------------------------- | -| `from` | `address` | The sender address | -| `to` | `address` | The recipient address | -| `amount` | `uint256` | The amount of token to transfer | +| Name | Type | Description | +| -------- | :-------: | ------------------------------------ | +| `from` | `address` | The sender address | +| `to` | `address` | The recipient address | +| `amount` | `uint256` | The amount of token to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
diff --git a/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md b/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md index eace4408b..cd3c72bc4 100644 --- a/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md +++ b/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md @@ -1056,7 +1056,8 @@ all the parameters in the calldata packed encoded. function _beforeTokenTransfer( address from, address to, - uint256 amount + uint256 amount, + bytes data ) internal nonpayable; ``` @@ -1065,11 +1066,12 @@ Allows to run custom logic before updating balances and notifiying sender/recipi #### Parameters -| Name | Type | Description | -| -------- | :-------: | ------------------------------- | -| `from` | `address` | The sender address | -| `to` | `address` | The recipient address | -| `amount` | `uint256` | The amount of token to transfer | +| Name | Type | Description | +| -------- | :-------: | ------------------------------------ | +| `from` | `address` | The sender address | +| `to` | `address` | The recipient address | +| `amount` | `uint256` | The amount of token to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
@@ -1079,7 +1081,8 @@ Allows to run custom logic before updating balances and notifiying sender/recipi function _afterTokenTransfer( address from, address to, - uint256 amount + uint256 amount, + bytes data ) internal nonpayable; ``` @@ -1088,11 +1091,12 @@ Allows to run custom logic after updating balances, but **before notifiying send #### Parameters -| Name | Type | Description | -| -------- | :-------: | ------------------------------- | -| `from` | `address` | The sender address | -| `to` | `address` | The recipient address | -| `amount` | `uint256` | The amount of token to transfer | +| Name | Type | Description | +| -------- | :-------: | ------------------------------------ | +| `from` | `address` | The sender address | +| `to` | `address` | The recipient address | +| `amount` | `uint256` | The amount of token to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md b/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md index c72dd01d3..b719713b1 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md @@ -947,7 +947,8 @@ all the parameters in the calldata packed encoded. function _beforeTokenTransfer( address from, address to, - bytes32 tokenId + bytes32 tokenId, + bytes data ) internal nonpayable; ``` @@ -961,6 +962,7 @@ Allows to run custom logic before updating balances and notifiying sender/recipi | `from` | `address` | The sender address | | `to` | `address` | @param tokenId The tokenId to transfer | | `tokenId` | `bytes32` | The tokenId to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
@@ -970,7 +972,8 @@ Allows to run custom logic before updating balances and notifiying sender/recipi function _afterTokenTransfer( address from, address to, - bytes32 tokenId + bytes32 tokenId, + bytes data ) internal nonpayable; ``` @@ -984,6 +987,7 @@ Allows to run custom logic after updating balances, but **before notifiying send | `from` | `address` | The sender address | | `to` | `address` | @param tokenId The tokenId to transfer | | `tokenId` | `bytes32` | The tokenId to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md index 4f68d4008..34559f01a 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md @@ -973,7 +973,8 @@ all the parameters in the calldata packed encoded. function _beforeTokenTransfer( address from, address to, - bytes32 tokenId + bytes32 tokenId, + bytes data ) internal nonpayable; ``` @@ -987,6 +988,7 @@ Allows to run custom logic before updating balances and notifiying sender/recipi | `from` | `address` | The sender address | | `to` | `address` | @param tokenId The tokenId to transfer | | `tokenId` | `bytes32` | The tokenId to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
@@ -996,7 +998,8 @@ Allows to run custom logic before updating balances and notifiying sender/recipi function _afterTokenTransfer( address from, address to, - bytes32 tokenId + bytes32 tokenId, + bytes data ) internal nonpayable; ``` @@ -1010,6 +1013,7 @@ Allows to run custom logic after updating balances, but **before notifiying send | `from` | `address` | The sender address | | `to` | `address` | @param tokenId The tokenId to transfer | | `tokenId` | `bytes32` | The tokenId to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md index 62310f99c..f4bae3e8d 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md @@ -947,7 +947,8 @@ all the parameters in the calldata packed encoded. function _beforeTokenTransfer( address from, address to, - bytes32 tokenId + bytes32 tokenId, + bytes data ) internal nonpayable; ``` @@ -961,6 +962,7 @@ Allows to run custom logic before updating balances and notifiying sender/recipi | `from` | `address` | The sender address | | `to` | `address` | @param tokenId The tokenId to transfer | | `tokenId` | `bytes32` | The tokenId to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
@@ -970,7 +972,8 @@ Allows to run custom logic before updating balances and notifiying sender/recipi function _afterTokenTransfer( address from, address to, - bytes32 tokenId + bytes32 tokenId, + bytes data ) internal nonpayable; ``` @@ -984,6 +987,7 @@ Allows to run custom logic after updating balances, but **before notifiying send | `from` | `address` | The sender address | | `to` | `address` | @param tokenId The tokenId to transfer | | `tokenId` | `bytes32` | The tokenId to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md index e815cc233..9e566f38f 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md @@ -1197,7 +1197,8 @@ function _transfer( function _beforeTokenTransfer( address from, address to, - bytes32 tokenId + bytes32 tokenId, + bytes data ) internal nonpayable; ``` @@ -1211,6 +1212,7 @@ Allows to run custom logic before updating balances and notifiying sender/recipi | `from` | `address` | The sender address | | `to` | `address` | @param tokenId The tokenId to transfer | | `tokenId` | `bytes32` | The tokenId to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
@@ -1220,7 +1222,8 @@ Allows to run custom logic before updating balances and notifiying sender/recipi function _afterTokenTransfer( address from, address to, - bytes32 tokenId + bytes32 tokenId, + bytes data ) internal nonpayable; ``` @@ -1234,6 +1237,7 @@ Allows to run custom logic after updating balances, but **before notifiying send | `from` | `address` | The sender address | | `to` | `address` | @param tokenId The tokenId to transfer | | `tokenId` | `bytes32` | The tokenId to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md index 5bba28705..5a5efaf42 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md @@ -978,7 +978,8 @@ all the parameters in the calldata packed encoded. function _beforeTokenTransfer( address from, address to, - bytes32 tokenId + bytes32 tokenId, + bytes data ) internal nonpayable; ``` @@ -989,6 +990,7 @@ function _beforeTokenTransfer( | `from` | `address` | The address sending the `tokenId` (`address(0)` when `tokenId` is being minted). | | `to` | `address` | @param tokenId The bytes32 identifier of the token being transferred. | | `tokenId` | `bytes32` | The bytes32 identifier of the token being transferred. | +| `data` | `bytes` | The data sent alongside the the token transfer. |
@@ -998,7 +1000,8 @@ function _beforeTokenTransfer( function _afterTokenTransfer( address from, address to, - bytes32 tokenId + bytes32 tokenId, + bytes data ) internal nonpayable; ``` @@ -1012,6 +1015,7 @@ Allows to run custom logic after updating balances, but **before notifiying send | `from` | `address` | The sender address | | `to` | `address` | @param tokenId The tokenId to transfer | | `tokenId` | `bytes32` | The tokenId to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md index 6984f85dc..b881c0643 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md @@ -1239,7 +1239,8 @@ function _transfer( function _beforeTokenTransfer( address from, address to, - bytes32 tokenId + bytes32 tokenId, + bytes data ) internal nonpayable; ``` @@ -1253,6 +1254,7 @@ Allows to run custom logic before updating balances and notifiying sender/recipi | `from` | `address` | The sender address | | `to` | `address` | @param tokenId The tokenId to transfer | | `tokenId` | `bytes32` | The tokenId to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
@@ -1262,7 +1264,8 @@ Allows to run custom logic before updating balances and notifiying sender/recipi function _afterTokenTransfer( address from, address to, - bytes32 tokenId + bytes32 tokenId, + bytes data ) internal nonpayable; ``` @@ -1276,6 +1279,7 @@ Allows to run custom logic after updating balances, but **before notifiying send | `from` | `address` | The sender address | | `to` | `address` | @param tokenId The tokenId to transfer | | `tokenId` | `bytes32` | The tokenId to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md index c82402175..565f464d4 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md @@ -1011,7 +1011,8 @@ all the parameters in the calldata packed encoded. function _beforeTokenTransfer( address from, address to, - bytes32 tokenId + bytes32 tokenId, + bytes data ) internal nonpayable; ``` @@ -1025,6 +1026,7 @@ Allows to run custom logic before updating balances and notifiying sender/recipi | `from` | `address` | The sender address | | `to` | `address` | @param tokenId The tokenId to transfer | | `tokenId` | `bytes32` | The tokenId to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
@@ -1034,7 +1036,8 @@ Allows to run custom logic before updating balances and notifiying sender/recipi function _afterTokenTransfer( address from, address to, - bytes32 tokenId + bytes32 tokenId, + bytes data ) internal nonpayable; ``` @@ -1048,6 +1051,7 @@ Allows to run custom logic after updating balances, but **before notifiying send | `from` | `address` | The sender address | | `to` | `address` | @param tokenId The tokenId to transfer | | `tokenId` | `bytes32` | The tokenId to transfer | +| `data` | `bytes` | The data sent alongside the transfer |
From 1ff7cd4e34a91c53ce72f19fb8d469d2ae0c9a09 Mon Sep 17 00:00:00 2001 From: "b00ste.lyx" <62855857+b00ste@users.noreply.github.com> Date: Fri, 13 Oct 2023 14:20:21 +0300 Subject: [PATCH 46/55] refactor!: remove `isEncodedArray(...)` from `LSP2utils.sol` (#746) * refactor: remove `isEncodedArray(...)` * tets: remove `isEncodedArray(...)` * docs: update auto generated docs --------- Co-authored-by: Jean Cvllr <31145285+CJ42@users.noreply.github.com> --- contracts/LSP2ERC725YJSONSchema/LSP2Utils.sol | 28 --- contracts/Mocks/LSP2UtilsLibraryTester.sol | 4 - .../LSP2ERC725YJSONSchema/LSP2Utils.md | 22 --- .../LSP2UtilsLibrary.test.ts | 165 +----------------- 4 files changed, 1 insertion(+), 218 deletions(-) diff --git a/contracts/LSP2ERC725YJSONSchema/LSP2Utils.sol b/contracts/LSP2ERC725YJSONSchema/LSP2Utils.sol index 1c1319b00..adabf11d7 100644 --- a/contracts/LSP2ERC725YJSONSchema/LSP2Utils.sol +++ b/contracts/LSP2ERC725YJSONSchema/LSP2Utils.sol @@ -6,9 +6,6 @@ import { IERC725Y } from "@erc725/smart-contracts/contracts/interfaces/IERC725Y.sol"; -// libraries -import {BytesLib} from "solidity-bytes-utils/contracts/BytesLib.sol"; - /** * @title LSP2 Utility library. * @author Jean Cavallera , Yamen Merhi , Daniel Afteni @@ -17,8 +14,6 @@ import {BytesLib} from "solidity-bytes-utils/contracts/BytesLib.sol"; * Based on LSP2 ERC725Y JSON Schema standard. */ library LSP2Utils { - using BytesLib for bytes; - /** * @dev Generates a data key of keyType Singleton by hashing the string `keyName`. As: * @@ -285,29 +280,6 @@ library LSP2Utils { return abi.encodePacked(bytes4(hashFunctionDigest), jsonDigest, url); } - /** - * @dev Verify if `data` is an abi-encoded array. - * - * @param data The bytes value to verify. - * - * @return `true` if the `data` represents an abi-encoded array, `false` otherwise. - */ - function isEncodedArray(bytes memory data) internal pure returns (bool) { - uint256 nbOfBytes = data.length; - - // there must be at least 32 x length bytes after offset - uint256 offset = uint256(bytes32(data)); - if (nbOfBytes < offset + 32) return false; - uint256 arrayLength = data.toUint256(offset); - - // 32 bytes word (= offset) - // + 32 bytes word (= array length) - // + remaining bytes that make each element of the array - if (nbOfBytes < (offset + 32 + (arrayLength * 32))) return false; - - return true; - } - /** * @dev Verify if `data` is a valid array of value encoded as a `CompactBytesArray` according to the LSP2 `CompactBytesArray` valueType specification. * diff --git a/contracts/Mocks/LSP2UtilsLibraryTester.sol b/contracts/Mocks/LSP2UtilsLibraryTester.sol index 289fc9542..02e514ff8 100644 --- a/contracts/Mocks/LSP2UtilsLibraryTester.sol +++ b/contracts/Mocks/LSP2UtilsLibraryTester.sol @@ -6,10 +6,6 @@ import {LSP2Utils} from "../LSP2ERC725YJSONSchema/LSP2Utils.sol"; contract LSP2UtilsLibraryTester { using LSP2Utils for *; - function isEncodedArray(bytes memory data) public pure returns (bool) { - return data.isEncodedArray(); - } - function isCompactBytesArray(bytes memory data) public pure returns (bool) { return data.isCompactBytesArray(); } diff --git a/docs/libraries/LSP2ERC725YJSONSchema/LSP2Utils.md b/docs/libraries/LSP2ERC725YJSONSchema/LSP2Utils.md index 34debe873..b6a5f5b8e 100644 --- a/docs/libraries/LSP2ERC725YJSONSchema/LSP2Utils.md +++ b/docs/libraries/LSP2ERC725YJSONSchema/LSP2Utils.md @@ -339,28 +339,6 @@ Generate a ASSETURL value content.
-### isEncodedArray - -```solidity -function isEncodedArray(bytes data) internal pure returns (bool); -``` - -Verify if `data` is an abi-encoded array. - -#### Parameters - -| Name | Type | Description | -| ------ | :-----: | -------------------------- | -| `data` | `bytes` | The bytes value to verify. | - -#### Returns - -| Name | Type | Description | -| ---- | :----: | ------------------------------------------------------------------------ | -| `0` | `bool` | `true` if the `data` represents an abi-encoded array, `false` otherwise. | - -
- ### isCompactBytesArray ```solidity diff --git a/tests/LSP2ERC725YJSONSchema/LSP2UtilsLibrary.test.ts b/tests/LSP2ERC725YJSONSchema/LSP2UtilsLibrary.test.ts index 316107c5a..51da0874f 100644 --- a/tests/LSP2ERC725YJSONSchema/LSP2UtilsLibrary.test.ts +++ b/tests/LSP2ERC725YJSONSchema/LSP2UtilsLibrary.test.ts @@ -3,7 +3,7 @@ import { ethers } from 'hardhat'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; import { LSP2UtilsLibraryTester, LSP2UtilsLibraryTester__factory } from '../../types'; -import { abiCoder, encodeCompactBytesArray } from '../utils/helpers'; +import { encodeCompactBytesArray } from '../utils/helpers'; describe('LSP2Utils', () => { let accounts: SignerWithAddress[]; @@ -14,169 +14,6 @@ describe('LSP2Utils', () => { lsp2Utils = await new LSP2UtilsLibraryTester__factory(accounts[0]).deploy(); }); - describe('isEncodedArray(...)', () => { - describe('testing different zero bytes 00 of various length', () => { - it('should return false for 1 x empty zero bytes', async () => { - const data = '0x00'; - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.false; - }); - - it('should return false for 10 x empty zero bytes', async () => { - const data = '0x00000000000000000000'; - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.false; - }); - - it('should return false for 20 x empty zero bytes', async () => { - const data = '0x0000000000000000000000000000000000000000'; - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.false; - }); - - it('should return false for 30 x empty zero bytes', async () => { - const data = '0x000000000000000000000000000000000000000000000000000000000000'; - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.false; - }); - - it('should return true for 32 x empty zero bytes', async () => { - const data = '0x0000000000000000000000000000000000000000000000000000000000000000'; - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.true; - }); - - it('should return true for 40 x empty zero bytes', async () => { - const data = - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000'; - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.true; - }); - - it('should return true for 64 x empty zero bytes', async () => { - const data = '0x' + '00'.repeat(64); - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.true; - }); - - it('should return true for 100 x empty zero bytes', async () => { - const data = '0x' + '00'.repeat(100); - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.true; - }); - }); - - describe('testing various non-zero bytes input', () => { - describe('when 32 bytes', () => { - it('should return false (`uint256` data = 32)', async () => { - const data = abiCoder.encode(['uint256'], [32]); - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.false; - }); - - it('should return false (`uint256` data = 12345)', async () => { - const data = abiCoder.encode(['uint256'], [12345]); - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.false; - }); - - it('should return false (`bytes32` data = 0xcafecafecafecafe...)', async () => { - const data = abiCoder.encode( - ['bytes32'], - ['0xcafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe'], - ); - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.false; - }); - }); - - describe('when less than 32 bytes', () => { - it('should return false with 4x random bytes', async () => { - const data = '0xaabbccdd'; - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.false; - }); - - it('should return false with 16x random bytes', async () => { - const data = '0x1234567890abcdef1234567890abcdef'; - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.false; - }); - }); - - describe('when abi-encoded array, with length = 0', () => { - it('should return true with 64 bytes -> offset = 0x20, length = 0 (null)', async () => { - const data = - '0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000'; - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.true; - }); - - it('should return true with 64 bytes -> offset = 0x20, length = 0 (null) + 10x extra zero bytes', async () => { - const data = - '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000'; - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.true; - }); - - it('should return true with 64 bytes -> offset = 0x20, length = 0 (null) + 10x extra random bytes', async () => { - const data = - '0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000aaaabbbbccccddddeeee'; - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.true; - }); - }); - - describe('when abi-encoded array, with length = 1', () => { - it('should return true with 1x array element - offset = 0x20, length = 1', async () => { - const data = - '0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0Ee7A142d267C1f36714E4a8F75612F20a79720'; - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.true; - }); - - it('should return true with 1x array element - offset = 0x20, length = 1, +5 custom bytes in the end', async () => { - const data = - '0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0Ee7A142d267C1f36714E4a8F75612F20a79720ffffffffff'; - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.true; - }); - - it('should return true with 1x array element - offset = 0x25 (+ 5 custom bytes in between), length = 1', async () => { - const data = - '0x0000000000000000000000000000000000000000000000000000000000000025ffffffffff0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0Ee7A142d267C1f36714E4a8F75612F20a79720'; - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.true; - }); - }); - - describe('when not correctly abi-encoded array, with length = 1', () => { - it('should return false with 1x array element - offset = 0x20, length = 1, but 31 bytes only', async () => { - const data = - '0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0Ee7A142d267C1f36714E4a8F75612F20a797'; - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.false; - }); - - it('should return false with 1x array element - offset = 0x20, length = 1, but 30 bytes only', async () => { - const data = - '0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0Ee7A142d267C1f36714E4a8F75612F20a7'; - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.false; - }); - }); - - describe('when correctly abi-encoded array, but the length does not match the number of elements', () => { - it('should return false when 1x array element, but length = 2', async () => { - const data = - '0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cafecafecafecafecafecafecafecafecafecafe'; - const result = await lsp2Utils.isEncodedArray(data); - expect(result).to.be.false; - }); - }); - }); - }); - describe('`isCompactBytesArray(...)`', () => { it('should return true with `0x` (equivalent to `[]`)', async () => { const data = '0x'; From dab41a1baf61876865191424a5e19548845f1630 Mon Sep 17 00:00:00 2001 From: Yamen Merhi Date: Fri, 13 Oct 2023 14:36:26 +0300 Subject: [PATCH 47/55] refactor!: Roll back to old `LSP1UniversalReceiverDelegate` Interface and functions (#741) * refactor!: re-apply old `universalReceiverDelegate` func sig * test!: change the test to use LSP1_DELEGATE way * docs: apply dodoc * chore: resolve linter * test: resolve failing tests * chore: fix typo in natspec * refactor: update `interfaceIds.ts` script * chore: update auto-generated docs * add suggested changes --------- Co-authored-by: b00ste Co-authored-by: Jean Cvllr <31145285+CJ42@users.noreply.github.com> --- constants.ts | 1 + .../LSP0ERC725AccountCore.sol | 43 +++++----- .../ILSP1UniversalReceiver.sol | 1 - .../ILSP1UniversalReceiverDelegate.sol | 24 ++++++ .../LSP1UniversalReceiver/LSP1Constants.sol | 1 + .../LSP1UniversalReceiver/LSP1Errors.sol | 6 -- .../LSP1UniversalReceiverDelegateUP.sol | 31 ++++--- .../LSP1UniversalReceiverDelegateVault.sol | 33 ++++---- contracts/LSP1UniversalReceiver/LSP1Utils.sol | 41 ---------- contracts/LSP9Vault/LSP9VaultCore.sol | 31 ++++--- .../UniversalReceiverDelegateDataUpdater.sol | 21 +++-- .../UniversalReceiverDelegateGasConsumer.sol | 22 ++--- .../UniversalReceiverDelegateRevert.sol | 25 +++--- ...niversalReceiverDelegateTokenReentrant.sol | 22 +++-- ...niversalReceiverDelegateVaultMalicious.sol | 19 +++-- ...iversalReceiverDelegateVaultReentrantA.sol | 23 +++--- ...iversalReceiverDelegateVaultReentrantB.sol | 25 +++--- .../UniversalReceiverDelegateVaultSetter.sol | 8 +- docs/_interface_ids_table.mdx | 39 ++++----- .../LSP0ERC725Account/LSP0ERC725Account.md | 2 +- .../LSP1UniversalReceiverDelegateUP.md | 80 ++++--------------- .../LSP1UniversalReceiverDelegateVault.md | 80 ++++--------------- docs/contracts/LSP9Vault/LSP9Vault.md | 2 +- docs/contracts/UniversalProfile.md | 2 +- .../LSP1UniversalReceiver/LSP1Utils.md | 33 -------- scripts/interfaceIds.ts | 9 ++- ...P1UniversalReceiverDelegateUP.behaviour.ts | 18 ----- ...niversalReceiverDelegateVault.behaviour.ts | 4 +- .../LSP6/Interactions/Security.test.ts | 13 ++- tests/LSP9Vault/LSP9Vault.behaviour.ts | 2 +- tests/Reentrancy/LSP6/LSP6Reentrancy.test.ts | 13 ++- 31 files changed, 274 insertions(+), 400 deletions(-) create mode 100644 contracts/LSP1UniversalReceiver/ILSP1UniversalReceiverDelegate.sol diff --git a/constants.ts b/constants.ts index 613937e7b..7f30a8c8a 100644 --- a/constants.ts +++ b/constants.ts @@ -26,6 +26,7 @@ export const INTERFACE_IDS = { ERC725Y: '0x629aa694', LSP0ERC725Account: '0x24871b3d', LSP1UniversalReceiver: '0x6bb56a14', + LSP1UniversalReceiverDelegate: '0xa245bbda', LSP6KeyManager: '0xe7424397', LSP7DigitalAsset: '0x05519512', LSP8IdentifiableDigitalAsset: '0x1ae9ba1f', diff --git a/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol b/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol index 38bffcc20..9b9e5e310 100644 --- a/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol +++ b/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol @@ -8,6 +8,10 @@ import { ILSP1UniversalReceiver } from "../LSP1UniversalReceiver/ILSP1UniversalReceiver.sol"; +import { + ILSP1UniversalReceiverDelegate as ILSP1Delegate +} from "../LSP1UniversalReceiver/ILSP1UniversalReceiverDelegate.sol"; + // libraries import {BytesLib} from "solidity-bytes-utils/contracts/BytesLib.sol"; import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; @@ -42,6 +46,7 @@ import { } from "./LSP0Constants.sol"; import { _INTERFACEID_LSP1, + _INTERFACEID_LSP1_DELEGATE, _LSP1_UNIVERSAL_RECEIVER_DELEGATE_PREFIX, _LSP1_UNIVERSAL_RECEIVER_DELEGATE_KEY } from "../LSP1UniversalReceiver/LSP1Constants.sol"; @@ -427,23 +432,20 @@ abstract contract LSP0ERC725AccountCore is bytes memory resultDefaultDelegate; if (lsp1DelegateValue.length >= 20) { - address universalReceiverDelegate = address( - bytes20(lsp1DelegateValue) - ); + address lsp1Delegate = address(bytes20(lsp1DelegateValue)); // Checking LSP1 InterfaceId support if ( - universalReceiverDelegate.supportsERC165InterfaceUnchecked( - _INTERFACEID_LSP1 + lsp1Delegate.supportsERC165InterfaceUnchecked( + _INTERFACEID_LSP1_DELEGATE ) ) { - // calling {universalReceiver} function on URD appending the caller and the value sent - resultDefaultDelegate = universalReceiverDelegate - .callUniversalReceiverWithCallerInfos( - typeId, - receivedData, + resultDefaultDelegate = ILSP1Delegate(lsp1Delegate) + .universalReceiverDelegate( msg.sender, - msg.value + msg.value, + typeId, + receivedData ); } } @@ -459,23 +461,20 @@ abstract contract LSP0ERC725AccountCore is bytes memory resultTypeIdDelegate; if (lsp1TypeIdDelegateValue.length >= 20) { - address universalReceiverDelegate = address( - bytes20(lsp1TypeIdDelegateValue) - ); + address lsp1Delegate = address(bytes20(lsp1TypeIdDelegateValue)); // Checking LSP1 InterfaceId support if ( - universalReceiverDelegate.supportsERC165InterfaceUnchecked( - _INTERFACEID_LSP1 + lsp1Delegate.supportsERC165InterfaceUnchecked( + _INTERFACEID_LSP1_DELEGATE ) ) { - // calling {universalReceiver} function on URD appending the caller and the value sent - resultTypeIdDelegate = universalReceiverDelegate - .callUniversalReceiverWithCallerInfos( - typeId, - receivedData, + resultTypeIdDelegate = ILSP1Delegate(lsp1Delegate) + .universalReceiverDelegate( msg.sender, - msg.value + msg.value, + typeId, + receivedData ); } } diff --git a/contracts/LSP1UniversalReceiver/ILSP1UniversalReceiver.sol b/contracts/LSP1UniversalReceiver/ILSP1UniversalReceiver.sol index 8243fec20..215bc5439 100644 --- a/contracts/LSP1UniversalReceiver/ILSP1UniversalReceiver.sol +++ b/contracts/LSP1UniversalReceiver/ILSP1UniversalReceiver.sol @@ -8,7 +8,6 @@ pragma solidity ^0.8.4; interface ILSP1UniversalReceiver { /** * @dev Emitted when the {universalReceiver} function was called with a specific `typeId` and some `receivedData` -s * @notice Address `from` called the `universalReceiver(...)` function while sending `value` LYX. Notification type (typeId): `typeId` - Data received: `receivedData`. * * @param from The address of the EOA or smart contract that called the {universalReceiver(...)} function. diff --git a/contracts/LSP1UniversalReceiver/ILSP1UniversalReceiverDelegate.sol b/contracts/LSP1UniversalReceiver/ILSP1UniversalReceiverDelegate.sol new file mode 100644 index 000000000..423686b7c --- /dev/null +++ b/contracts/LSP1UniversalReceiver/ILSP1UniversalReceiverDelegate.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.4; + +/** + * @title Interface of the LSP1 - Universal Receiver Delegate standard. + * @dev This interface allows contracts implementing the LSP1UniversalReceiver function to delegate the reaction logic to another contract or account. By doing so, the main logic doesn't need to reside within the `universalReceiver` function itself, offering modularity and flexibility. + */ +interface ILSP1UniversalReceiverDelegate { + /** + * @dev A delegate function that reacts to calls forwarded from the `universalReceiver(..)` function. This allows for modular handling of the logic based on the `typeId` and `data` provided by the initial caller. + * @notice Reacted on received notification forwarded from `universalReceiver` with `typeId` & `data`. + * + * @param sender The address of the EOA or smart contract that initially called the `universalReceiver` function. + * @param value The amount sent by the `sender` to the `universalReceiver` function. + * @param typeId The hash of a specific standard or a hook. + * @param data The arbitrary data received with the initial call to `universalReceiver`. + */ + function universalReceiverDelegate( + address sender, + uint256 value, + bytes32 typeId, + bytes memory data + ) external returns (bytes memory); +} diff --git a/contracts/LSP1UniversalReceiver/LSP1Constants.sol b/contracts/LSP1UniversalReceiver/LSP1Constants.sol index be8b0a73f..2a4fe0214 100644 --- a/contracts/LSP1UniversalReceiver/LSP1Constants.sol +++ b/contracts/LSP1UniversalReceiver/LSP1Constants.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.4; // --- ERC165 interface ids bytes4 constant _INTERFACEID_LSP1 = 0x6bb56a14; +bytes4 constant _INTERFACEID_LSP1_DELEGATE = 0xa245bbda; // --- ERC725Y Data Keys diff --git a/contracts/LSP1UniversalReceiver/LSP1Errors.sol b/contracts/LSP1UniversalReceiver/LSP1Errors.sol index 087473ab0..e336d1923 100644 --- a/contracts/LSP1UniversalReceiver/LSP1Errors.sol +++ b/contracts/LSP1UniversalReceiver/LSP1Errors.sol @@ -8,9 +8,3 @@ pragma solidity ^0.8.4; * @param caller The address of the EOA */ error CannotRegisterEOAsAsAssets(address caller); - -/** - * @dev Reverts when the {universalReceiver} function in the LSP1 Universal Receiver Delegate contract is called while sending some native tokens along the call (`msg.value` different than `0`) - * @notice Cannot send native tokens to {universalReceiver(...)} function of the delegated contract. - */ -error NativeTokensNotAccepted(); diff --git a/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol b/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol index 38374020b..889e1aa93 100644 --- a/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol +++ b/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol @@ -5,7 +5,9 @@ pragma solidity ^0.8.4; import { IERC725Y } from "@erc725/smart-contracts/contracts/interfaces/IERC725Y.sol"; -import {ILSP1UniversalReceiver} from "../ILSP1UniversalReceiver.sol"; +import { + ILSP1UniversalReceiverDelegate +} from "../ILSP1UniversalReceiverDelegate.sol"; import {ILSP7DigitalAsset} from "../../LSP7DigitalAsset/ILSP7DigitalAsset.sol"; // modules @@ -19,7 +21,7 @@ import {LSP5Utils} from "../../LSP5ReceivedAssets/LSP5Utils.sol"; import {LSP10Utils} from "../../LSP10ReceivedVaults/LSP10Utils.sol"; // constants -import {_INTERFACEID_LSP1} from "../LSP1Constants.sol"; +import {_INTERFACEID_LSP1_DELEGATE} from "../LSP1Constants.sol"; import { _TYPEID_LSP7_TOKENSSENDER, _TYPEID_LSP7_TOKENSRECIPIENT, @@ -36,10 +38,7 @@ import { } from "../../LSP9Vault/LSP9Constants.sol"; // errors -import { - NativeTokensNotAccepted, - CannotRegisterEOAsAsAssets -} from "../LSP1Errors.sol"; +import {CannotRegisterEOAsAsAssets} from "../LSP1Errors.sol"; /** * @title Implementation of a UniversalReceiverDelegate for the [LSP-0-ERC725Account] @@ -53,7 +52,10 @@ import { * - Writes the data keys representing the owned vaults from type [LSP-9-Vault] into your account storage, and removes them when transferring ownership to other accounts according to the [LSP-10-ReceivedVaults] Standard. * */ -contract LSP1UniversalReceiverDelegateUP is ERC165, ILSP1UniversalReceiver { +contract LSP1UniversalReceiverDelegateUP is + ERC165, + ILSP1UniversalReceiverDelegate +{ using ERC165Checker for address; /** @@ -76,17 +78,12 @@ contract LSP1UniversalReceiverDelegateUP is ERC165, ILSP1UniversalReceiver { * @param typeId Unique identifier for a specific notification. * @return The result of the reaction for `typeId`. */ - function universalReceiver( + function universalReceiverDelegate( + address notifier, + uint256 /*value*/, bytes32 typeId, bytes memory /* data */ - ) public payable virtual override returns (bytes memory) { - // CHECK that we did not send any native tokens to the LSP1 Delegate, as it cannot transfer them back. - if (msg.value != 0) { - revert NativeTokensNotAccepted(); - } - - address notifier = address(bytes20(msg.data[msg.data.length - 52:])); - + ) public virtual override returns (bytes memory) { // The notifier is supposed to be either the LSP7 or LSP8 or LSP9 contract // If it's EOA we revert to avoid registering the EOA as asset or vault (spam protection) // solhint-disable-next-line avoid-tx-origin @@ -271,7 +268,7 @@ contract LSP1UniversalReceiverDelegateUP is ERC165, ILSP1UniversalReceiver { bytes4 interfaceId ) public view virtual override returns (bool) { return - interfaceId == _INTERFACEID_LSP1 || + interfaceId == _INTERFACEID_LSP1_DELEGATE || super.supportsInterface(interfaceId); } } diff --git a/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol b/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol index 9cb28d511..8477cc5dc 100644 --- a/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol +++ b/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol @@ -5,7 +5,9 @@ pragma solidity ^0.8.4; import { IERC725Y } from "@erc725/smart-contracts/contracts/interfaces/IERC725Y.sol"; -import {ILSP1UniversalReceiver} from "../ILSP1UniversalReceiver.sol"; +import { + ILSP1UniversalReceiverDelegate +} from "../ILSP1UniversalReceiverDelegate.sol"; import {ILSP7DigitalAsset} from "../../LSP7DigitalAsset/ILSP7DigitalAsset.sol"; // modules @@ -15,7 +17,7 @@ import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; import {LSP5Utils} from "../../LSP5ReceivedAssets/LSP5Utils.sol"; // constants -import {_INTERFACEID_LSP1} from "../LSP1Constants.sol"; +import {_INTERFACEID_LSP1_DELEGATE} from "../LSP1Constants.sol"; import { _TYPEID_LSP7_TOKENSSENDER, _TYPEID_LSP7_TOKENSRECIPIENT, @@ -28,10 +30,7 @@ import { } from "../../LSP8IdentifiableDigitalAsset/LSP8Constants.sol"; // errors -import { - CannotRegisterEOAsAsAssets, - NativeTokensNotAccepted -} from "../LSP1Errors.sol"; +import {CannotRegisterEOAsAsAssets} from "../LSP1Errors.sol"; /** * @title Implementation of a UniversalReceiverDelegate for the [LSP9Vault] @@ -43,9 +42,12 @@ import { * * - Writes the data keys representing assets received from type [LSP-7-DigitalAsset] and [LSP-8-IdentifiableDigitalAsset] into the account storage, and removes them when the balance is zero according to the [LSP-5-ReceivedAssets] Standard. */ -contract LSP1UniversalReceiverDelegateVault is ERC165, ILSP1UniversalReceiver { +contract LSP1UniversalReceiverDelegateVault is + ERC165, + ILSP1UniversalReceiverDelegate +{ /** - * @inheritdoc ILSP1UniversalReceiver + * @inheritdoc ILSP1UniversalReceiverDelegate * @dev Handles two cases: * * Writes the received [LSP-7-DigitalAsset] or [LSP-8-IdentifiableDigitalAsset] assets into the vault storage according to the [LSP-5-ReceivedAssets] standard. @@ -60,17 +62,12 @@ contract LSP1UniversalReceiverDelegateVault is ERC165, ILSP1UniversalReceiver { * @param typeId Unique identifier for a specific notification. * @return The result of the reaction for `typeId`. */ - function universalReceiver( + function universalReceiverDelegate( + address notifier, + uint256 /*value*/, bytes32 typeId, bytes memory /* data */ - ) public payable virtual override returns (bytes memory) { - // CHECK that we did not send any native tokens to the LSP1 Delegate, as it cannot transfer them back. - if (msg.value != 0) { - revert NativeTokensNotAccepted(); - } - - address notifier = address(bytes20(msg.data[msg.data.length - 52:])); - + ) public virtual override returns (bytes memory) { // The notifier is supposed to be either the LSP7 or LSP8 contract // If it's EOA we revert to avoid registering the EOA as asset (spam protection) // solhint-disable-next-line avoid-tx-origin @@ -201,7 +198,7 @@ contract LSP1UniversalReceiverDelegateVault is ERC165, ILSP1UniversalReceiver { bytes4 interfaceId ) public view virtual override returns (bool) { return - interfaceId == _INTERFACEID_LSP1 || + interfaceId == _INTERFACEID_LSP1_DELEGATE || super.supportsInterface(interfaceId); } } diff --git a/contracts/LSP1UniversalReceiver/LSP1Utils.sol b/contracts/LSP1UniversalReceiver/LSP1Utils.sol index 0d3c2cd0a..cfd523f28 100644 --- a/contracts/LSP1UniversalReceiver/LSP1Utils.sol +++ b/contracts/LSP1UniversalReceiver/LSP1Utils.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.4; // libraries -import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; @@ -49,46 +48,6 @@ library LSP1Utils { } } - /** - * @dev Call a LSP1UniversalReceiverDelegate contract at `universalReceiverDelegate` address and append `msgSender` and `msgValue` - * as additional informations in the calldata. - * - * @param universalReceiverDelegate The address of the LSP1UniversalReceiverDelegate to delegate the `universalReceiver` function to. - * @param typeId A `bytes32` typeId. - * @param receivedData The data sent initially to the `universalReceiver` function. - * @param msgSender The address that initially called the `universalReceiver` function. - * @param msgValue The amount of native token received initially by the `universalReceiver` function. - * - * @return The data returned by the LSP1UniversalReceiverDelegate contract. - */ - function callUniversalReceiverWithCallerInfos( - address universalReceiverDelegate, - bytes32 typeId, - bytes calldata receivedData, - address msgSender, - uint256 msgValue - ) internal returns (bytes memory) { - bytes memory callData = abi.encodePacked( - abi.encodeWithSelector( - ILSP1.universalReceiver.selector, - typeId, - receivedData - ), - msgSender, - msgValue - ); - - (bool success, bytes memory result) = universalReceiverDelegate.call( - callData - ); - Address.verifyCallResult( - success, - result, - "Call to universalReceiver failed" - ); - return result.length != 0 ? abi.decode(result, (bytes)) : result; - } - /** * @notice Retrieving the value stored under the ERC725Y data key `LSP1UniversalReceiverDelegate`. * diff --git a/contracts/LSP9Vault/LSP9VaultCore.sol b/contracts/LSP9Vault/LSP9VaultCore.sol index 574c2c976..3e090c70d 100644 --- a/contracts/LSP9Vault/LSP9VaultCore.sol +++ b/contracts/LSP9Vault/LSP9VaultCore.sol @@ -5,6 +5,10 @@ pragma solidity ^0.8.4; import { ILSP1UniversalReceiver } from "../LSP1UniversalReceiver/ILSP1UniversalReceiver.sol"; + +import { + ILSP1UniversalReceiverDelegate +} from "../LSP1UniversalReceiver/ILSP1UniversalReceiverDelegate.sol"; import {ILSP9Vault} from "./ILSP9Vault.sol"; // libraries @@ -41,6 +45,7 @@ import { } from "@erc725/smart-contracts/contracts/constants.sol"; import { _INTERFACEID_LSP1, + _INTERFACEID_LSP1_DELEGATE, _LSP1_UNIVERSAL_RECEIVER_DELEGATE_PREFIX, _LSP1_UNIVERSAL_RECEIVER_DELEGATE_KEY } from "../LSP1UniversalReceiver/LSP1Constants.sol"; @@ -338,16 +343,17 @@ contract LSP9VaultCore is if ( universalReceiverDelegate.supportsERC165InterfaceUnchecked( - _INTERFACEID_LSP1 + _INTERFACEID_LSP1_DELEGATE ) ) { _reentrantDelegate = universalReceiverDelegate; - resultDefaultDelegate = universalReceiverDelegate - .callUniversalReceiverWithCallerInfos( - typeId, - receivedData, + resultDefaultDelegate = ILSP1UniversalReceiverDelegate( + universalReceiverDelegate + ).universalReceiverDelegate( msg.sender, - msg.value + msg.value, + typeId, + receivedData ); } } @@ -367,16 +373,17 @@ contract LSP9VaultCore is if ( universalReceiverDelegate.supportsERC165InterfaceUnchecked( - _INTERFACEID_LSP1 + _INTERFACEID_LSP1_DELEGATE ) ) { _reentrantDelegate = universalReceiverDelegate; - resultTypeIdDelegate = universalReceiverDelegate - .callUniversalReceiverWithCallerInfos( - typeId, - receivedData, + resultTypeIdDelegate = ILSP1UniversalReceiverDelegate( + universalReceiverDelegate + ).universalReceiverDelegate( msg.sender, - msg.value + msg.value, + typeId, + receivedData ); } } diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateDataUpdater.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateDataUpdater.sol index fb3623df7..e3dbe3634 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateDataUpdater.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateDataUpdater.sol @@ -5,6 +5,10 @@ pragma solidity ^0.8.4; import {ILSP6KeyManager} from "../../LSP6KeyManager/ILSP6KeyManager.sol"; import {LSP14Ownable2Step} from "../../LSP14Ownable2Step/LSP14Ownable2Step.sol"; +import { + ILSP1UniversalReceiverDelegate +} from "../../LSP1UniversalReceiver/ILSP1UniversalReceiverDelegate.sol"; + // modules import { ERC165Storage @@ -15,17 +19,24 @@ import { _TYPEID_LSP7_TOKENSSENDER } from "../../LSP7DigitalAsset/LSP7Constants.sol"; -import {_INTERFACEID_LSP1} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; +import { + _INTERFACEID_LSP1_DELEGATE +} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; -contract UniversalReceiverDelegateDataUpdater is ERC165Storage { +contract UniversalReceiverDelegateDataUpdater is + ERC165Storage, + ILSP1UniversalReceiverDelegate +{ constructor() { - _registerInterface(_INTERFACEID_LSP1); + _registerInterface(_INTERFACEID_LSP1_DELEGATE); } - function universalReceiver( + function universalReceiverDelegate( + address /*sender*/, + uint256 /*value*/, bytes32 typeId, bytes memory /* data */ - ) public virtual returns (bytes memory) { + ) public virtual override returns (bytes memory) { if (typeId == _TYPEID_LSP7_TOKENSSENDER) { address keyManager = LSP14Ownable2Step(msg.sender).owner(); bytes memory setDataPayload = abi.encodeWithSignature( diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateGasConsumer.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateGasConsumer.sol index 949d61566..56727ea6b 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateGasConsumer.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateGasConsumer.sol @@ -3,27 +3,31 @@ pragma solidity ^0.8.4; // interfaces import { - ILSP1UniversalReceiver -} from "../../LSP1UniversalReceiver/ILSP1UniversalReceiver.sol"; + ILSP1UniversalReceiverDelegate +} from "../../LSP1UniversalReceiver/ILSP1UniversalReceiverDelegate.sol"; import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; -import {_INTERFACEID_LSP1} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; +import { + _INTERFACEID_LSP1_DELEGATE +} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; /** * @dev This contract is used only for testing purposes */ contract UniversalReceiverDelegateGasConsumer is ERC165, - ILSP1UniversalReceiver + ILSP1UniversalReceiverDelegate { /** - * @inheritdoc ILSP1UniversalReceiver + * @inheritdoc ILSP1UniversalReceiverDelegate * @dev Allows to register arrayKeys and Map of incoming vaults and assets and removing them after being sent * @return result the return value of keyManager's execute function */ - function universalReceiver( - bytes32 /* typeId */, + function universalReceiverDelegate( + address /*sender*/, + uint256 /*value*/, + bytes32 /*typeId*/, bytes memory /* data */ - ) public payable override returns (bytes memory) { + ) public virtual override returns (bytes memory) { // solhint-disable no-empty-blocks for (uint256 i = 0; ; i++) { // nothing @@ -36,7 +40,7 @@ contract UniversalReceiverDelegateGasConsumer is bytes4 interfaceId ) public view virtual override returns (bool) { return - interfaceId == _INTERFACEID_LSP1 || + interfaceId == _INTERFACEID_LSP1_DELEGATE || super.supportsInterface(interfaceId); } } diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateRevert.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateRevert.sol index f19339e1c..e461d9acf 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateRevert.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateRevert.sol @@ -3,24 +3,31 @@ pragma solidity ^0.8.4; // interfaces import { - ILSP1UniversalReceiver -} from "../../LSP1UniversalReceiver/ILSP1UniversalReceiver.sol"; + ILSP1UniversalReceiverDelegate +} from "../../LSP1UniversalReceiver/ILSP1UniversalReceiverDelegate.sol"; import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; -import {_INTERFACEID_LSP1} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; +import { + _INTERFACEID_LSP1_DELEGATE +} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; /** * @dev This contract is used only for testing purposes */ -contract UniversalReceiverDelegateRevert is ERC165, ILSP1UniversalReceiver { +contract UniversalReceiverDelegateRevert is + ERC165, + ILSP1UniversalReceiverDelegate +{ /** - * @inheritdoc ILSP1UniversalReceiver + * @inheritdoc ILSP1UniversalReceiverDelegate * @dev Allows to register arrayKeys and Map of incoming vaults and assets and removing them after being sent * @return result the return value of keyManager's execute function */ - function universalReceiver( - bytes32 /* typeId */, + function universalReceiverDelegate( + address /*sender*/, + uint256 /*value*/, + bytes32 /*typeId*/, bytes memory /* data */ - ) public payable override returns (bytes memory) { + ) public virtual returns (bytes memory) { revert("I Revert"); } @@ -28,7 +35,7 @@ contract UniversalReceiverDelegateRevert is ERC165, ILSP1UniversalReceiver { bytes4 interfaceId ) public view virtual override returns (bool) { return - interfaceId == _INTERFACEID_LSP1 || + interfaceId == _INTERFACEID_LSP1_DELEGATE || super.supportsInterface(interfaceId); } } diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateTokenReentrant.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateTokenReentrant.sol index fe511af0a..e42b09760 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateTokenReentrant.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateTokenReentrant.sol @@ -7,6 +7,10 @@ import { } from "@erc725/smart-contracts/contracts/interfaces/IERC725X.sol"; import {ILSP6KeyManager} from "../../LSP6KeyManager/ILSP6KeyManager.sol"; +import { + ILSP1UniversalReceiverDelegate +} from "../../LSP1UniversalReceiver/ILSP1UniversalReceiverDelegate.sol"; + // modules import {ERC725Y} from "@erc725/smart-contracts/contracts/ERC725Y.sol"; import { @@ -22,21 +26,27 @@ import { _TYPEID_LSP8_TOKENSRECIPIENT } from "../../LSP8IdentifiableDigitalAsset/LSP8Constants.sol"; -import {_INTERFACEID_LSP1} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; +import { + _INTERFACEID_LSP1_DELEGATE +} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; /** * @dev This contract is used only for testing purposes */ -contract UniversalReceiverDelegateTokenReentrant is ERC165Storage { +contract UniversalReceiverDelegateTokenReentrant is + ERC165Storage, + ILSP1UniversalReceiverDelegate +{ constructor() { - _registerInterface(_INTERFACEID_LSP1); + _registerInterface(_INTERFACEID_LSP1_DELEGATE); } - function universalReceiver( + function universalReceiverDelegate( + address sender, + uint256 /*value*/, bytes32 typeId, bytes memory data - ) public payable virtual returns (bytes memory result) { - address sender = address(bytes20(msg.data[msg.data.length - 52:])); + ) public virtual override returns (bytes memory result) { if ( typeId == _TYPEID_LSP7_TOKENSRECIPIENT || typeId == _TYPEID_LSP8_TOKENSRECIPIENT diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultMalicious.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultMalicious.sol index c77b6e362..5d943463e 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultMalicious.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultMalicious.sol @@ -9,6 +9,10 @@ import { IERC725Y } from "@erc725/smart-contracts/contracts/interfaces/IERC725Y.sol"; +import { + ILSP1UniversalReceiverDelegate +} from "../../LSP1UniversalReceiver/ILSP1UniversalReceiverDelegate.sol"; + // modules import { ERC165Storage @@ -17,7 +21,7 @@ import {Address} from "@openzeppelin/contracts/utils/Address.sol"; // constants import { - _INTERFACEID_LSP1, + _INTERFACEID_LSP1_DELEGATE, _LSP1_UNIVERSAL_RECEIVER_DELEGATE_PREFIX } from "../../LSP1UniversalReceiver/LSP1Constants.sol"; import { @@ -31,15 +35,20 @@ import { /** * @dev This contract is used only for testing */ -contract UniversalReceiverDelegateVaultMalicious is ERC165Storage { +contract UniversalReceiverDelegateVaultMalicious is + ERC165Storage, + ILSP1UniversalReceiverDelegate +{ constructor() { - _registerInterface(_INTERFACEID_LSP1); + _registerInterface(_INTERFACEID_LSP1_DELEGATE); } - function universalReceiver( + function universalReceiverDelegate( + address /*sender*/, + uint256 /*value*/, bytes32 typeId, bytes memory data - ) public virtual returns (bytes memory) { + ) public virtual override returns (bytes memory) { if (typeId == keccak256(abi.encodePacked("setData"))) { if (data[0] == 0x00) { IERC725Y(msg.sender).setData( diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantA.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantA.sol index 58986264e..4e468f9c5 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantA.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantA.sol @@ -6,8 +6,8 @@ import { IERC725Y } from "@erc725/smart-contracts/contracts/interfaces/IERC725Y.sol"; import { - ILSP1UniversalReceiver -} from "../../LSP1UniversalReceiver/ILSP1UniversalReceiver.sol"; + ILSP1UniversalReceiverDelegate +} from "../../LSP1UniversalReceiver/ILSP1UniversalReceiverDelegate.sol"; // modules import { @@ -15,30 +15,27 @@ import { } from "@openzeppelin/contracts/utils/introspection/ERC165Storage.sol"; // constants -import {_INTERFACEID_LSP1} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; import { - NativeTokensNotAccepted -} from "../../LSP1UniversalReceiver/LSP1Errors.sol"; + _INTERFACEID_LSP1_DELEGATE +} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; /** * @dev This contract is used only for testing purposes */ contract UniversalReceiverDelegateVaultReentrantA is - ILSP1UniversalReceiver, + ILSP1UniversalReceiverDelegate, ERC165Storage { constructor() { - _registerInterface(_INTERFACEID_LSP1); + _registerInterface(_INTERFACEID_LSP1_DELEGATE); } - function universalReceiver( + function universalReceiverDelegate( + address /*sender*/, + uint256 /*value*/, bytes32 /* typeId */, bytes memory data - ) external payable override returns (bytes memory) { - if (msg.value != 0) { - revert NativeTokensNotAccepted(); - } - + ) external override returns (bytes memory) { bytes32[] memory keys = new bytes32[](1); bytes[] memory values = new bytes[](1); diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantB.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantB.sol index 73542a194..114806f0b 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantB.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultReentrantB.sol @@ -6,8 +6,8 @@ import { IERC725Y } from "@erc725/smart-contracts/contracts/interfaces/IERC725Y.sol"; import { - ILSP1UniversalReceiver -} from "../../LSP1UniversalReceiver/ILSP1UniversalReceiver.sol"; + ILSP1UniversalReceiverDelegate +} from "../../LSP1UniversalReceiver/ILSP1UniversalReceiverDelegate.sol"; // modules import { @@ -15,32 +15,27 @@ import { } from "@openzeppelin/contracts/utils/introspection/ERC165Storage.sol"; // constants -import {_INTERFACEID_LSP1} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; - -// errors import { - NativeTokensNotAccepted -} from "../../LSP1UniversalReceiver/LSP1Errors.sol"; + _INTERFACEID_LSP1_DELEGATE +} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; /** * @dev This contract is used only for testing purposes */ contract UniversalReceiverDelegateVaultReentrantB is - ILSP1UniversalReceiver, + ILSP1UniversalReceiverDelegate, ERC165Storage { constructor() { - _registerInterface(_INTERFACEID_LSP1); + _registerInterface(_INTERFACEID_LSP1_DELEGATE); } - function universalReceiver( + function universalReceiverDelegate( + address /*sender*/, + uint256 /*value*/, bytes32 /* typeId */, bytes memory data - ) external payable override returns (bytes memory) { - if (msg.value != 0) { - revert NativeTokensNotAccepted(); - } - + ) external override returns (bytes memory) { bytes32[] memory keys = new bytes32[](1); bytes[] memory values = new bytes[](1); diff --git a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultSetter.sol b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultSetter.sol index 9a19b9b08..b2f134c70 100644 --- a/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultSetter.sol +++ b/contracts/Mocks/UniversalReceivers/UniversalReceiverDelegateVaultSetter.sol @@ -12,17 +12,19 @@ import { } from "@openzeppelin/contracts/utils/introspection/ERC165Storage.sol"; // constants -import {_INTERFACEID_LSP1} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; +import { + _INTERFACEID_LSP1_DELEGATE +} from "../../LSP1UniversalReceiver/LSP1Constants.sol"; /** * @dev This contract is used only for testing purposes */ contract UniversalReceiverDelegateVaultSetter is ERC165Storage { constructor() { - _registerInterface(_INTERFACEID_LSP1); + _registerInterface(_INTERFACEID_LSP1_DELEGATE); } - function universalReceiver( + function universalReceiverDelegate( address vaultadd, bytes32 key, bytes memory value diff --git a/docs/_interface_ids_table.mdx b/docs/_interface_ids_table.mdx index 674870dac..242e85d86 100644 --- a/docs/_interface_ids_table.mdx +++ b/docs/_interface_ids_table.mdx @@ -1,19 +1,20 @@ -| Contract | Interface ID | Description | -| :------------------------------- | :----------: | :------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **ERC165** | `0x01ffc9a7` | Standard Interface Detection. | -| **ERC1271** | `0x1626ba7e` | Standard Signature Validation Method for Contracts. | -| **ERC725X** | `0x7545acac` | General executor. | -| **ERC725Y** | `0x629aa694` | General Data key-value store. | -| **LSP0ERC725Account** | `0x24871b3d` | Interface of the [LSP-0-ERC725Account] standard, an account based smart contract that represents an identity on-chain. | -| **LSP1UniversalReceiver** | `0x6bb56a14` | Interface of the LSP1 - Universal Receiver standard, an entry function for a contract to receive arbitrary information. | -| **LSP6KeyManager** | `0xe7424397` | Interface of the LSP6 - Key Manager standard, a contract acting as a controller of an ERC725 Account using predfined permissions. | -| **LSP7DigitalAsset** | `0x05519512` | Interface of the LSP7 - Digital Asset standard, a fungible digital asset. | -| **LSP8IdentifiableDigitalAsset** | `0x1ae9ba1f` | Interface of the LSP8 - Identifiable Digital Asset standard, a non-fungible digital asset. | -| **LSP9Vault** | `0x28af17e6` | Interface of LSP9 - Vault standard, a blockchain vault that can hold assets and interact with other smart contracts. | -| **LSP11BasicSocialRecovery** | `0x049a28f1` | Interface of the LSP11 - Basic Social Recovery standard, a contract to recover access control into an account. | -| **LSP14Ownable2Step** | `0x94be5999` | Interface of the LSP14 - Ownable 2-step standard, an extension of the [EIP173] (Ownable) standard with 2-step process to transfer or renounce ownership. | -| **LSP17Extendable** | `0xa918fa6b` | Module to add more functionalities to a contract using extensions. | -| **LSP17Extension** | `0xcee78b40` | Module to create a contract that can act as an extension. | -| **LSP20CallVerification** | `0x1a0eb6a5` | Implementation of a contract calling the verification functions according to LSP20 - Call Verification standard. | -| **LSP20CallVerifier** | `0xc9dfc532` | Interface for the LSP20 Call Verification standard, a set of functions intended to perform verifications on behalf of another contract. | -| **LSP25ExecuteRelayCall** | `0x5ac79908` | | +| Contract | Interface ID | Description | +| :-------------------------------- | :----------: | :------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **ERC165** | `0x01ffc9a7` | Standard Interface Detection. | +| **ERC1271** | `0x1626ba7e` | Standard Signature Validation Method for Contracts. | +| **ERC725X** | `0x7545acac` | General executor. | +| **ERC725Y** | `0x629aa694` | General Data key-value store. | +| **LSP0ERC725Account** | `0x24871b3d` | Interface of the [LSP-0-ERC725Account] standard, an account based smart contract that represents an identity on-chain. | +| **LSP1UniversalReceiver** | `0x6bb56a14` | Interface of the LSP1 - Universal Receiver standard, an entry function for a contract to receive arbitrary information. | +| **LSP1UniversalReceiverDelegate** | `0xa245bbda` | Interface of the LSP1 - Universal Receiver Delegate standard. | +| **LSP6KeyManager** | `0xe7424397` | Interface of the LSP6 - Key Manager standard, a contract acting as a controller of an ERC725 Account using predfined permissions. | +| **LSP7DigitalAsset** | `0x05519512` | Interface of the LSP7 - Digital Asset standard, a fungible digital asset. | +| **LSP8IdentifiableDigitalAsset** | `0x1ae9ba1f` | Interface of the LSP8 - Identifiable Digital Asset standard, a non-fungible digital asset. | +| **LSP9Vault** | `0x28af17e6` | Interface of LSP9 - Vault standard, a blockchain vault that can hold assets and interact with other smart contracts. | +| **LSP11BasicSocialRecovery** | `0x049a28f1` | Interface of the LSP11 - Basic Social Recovery standard, a contract to recover access control into an account. | +| **LSP14Ownable2Step** | `0x94be5999` | Interface of the LSP14 - Ownable 2-step standard, an extension of the [EIP173] (Ownable) standard with 2-step process to transfer or renounce ownership. | +| **LSP17Extendable** | `0xa918fa6b` | Module to add more functionalities to a contract using extensions. | +| **LSP17Extension** | `0xcee78b40` | Module to create a contract that can act as an extension. | +| **LSP20CallVerification** | `0x1a0eb6a5` | Implementation of a contract calling the verification functions according to LSP20 - Call Verification standard. | +| **LSP20CallVerifier** | `0xc9dfc532` | Interface for the LSP20 Call Verification standard, a set of functions intended to perform verifications on behalf of another contract. | +| **LSP25ExecuteRelayCall** | `0x5ac79908` | | diff --git a/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md b/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md index d0b664f76..aa0f9d948 100644 --- a/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md +++ b/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md @@ -1437,7 +1437,7 @@ event UniversalReceiver(address indexed from, uint256 indexed value, bytes32 ind - Data received: `receivedData`.\* -Emitted when the [`universalReceiver`](#universalreceiver) function was called with a specific `typeId` and some `receivedData` s +Emitted when the [`universalReceiver`](#universalreceiver) function was called with a specific `typeId` and some `receivedData` #### Parameters diff --git a/docs/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.md b/docs/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.md index 04af77971..63c0cd716 100644 --- a/docs/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.md +++ b/docs/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.md @@ -58,14 +58,14 @@ See [`IERC165-supportsInterface`](#ierc165-supportsinterface).
-### universalReceiver +### universalReceiverDelegate :::note References -- Specification details: [**LSP-1-UniversalReceiver**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-1-UniversalReceiver.md#universalreceiver) +- Specification details: [**LSP-1-UniversalReceiver**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-1-UniversalReceiver.md#universalreceiverdelegate) - Solidity implementation: [`LSP1UniversalReceiverDelegateUP.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol) -- Function signature: `universalReceiver(bytes32,)` -- Function selector: `0x534e72c8` +- Function signature: `universalReceiverDelegate(address,,bytes32,)` +- Function selector: `0xba924425` ::: @@ -83,10 +83,12 @@ When the data stored in the ERC725Y storage of the LSP0 contract is corrupted (\ ::: ```solidity -function universalReceiver( +function universalReceiverDelegate( + address notifier, + uint256, bytes32 typeId, bytes -) external payable returns (bytes); +) external nonpayable returns (bytes); ``` _Reacted on received notification with `typeId`._ @@ -106,10 +108,12 @@ _Reacted on received notification with `typeId`._ #### Parameters -| Name | Type | Description | -| -------- | :-------: | ---------------------------------------------- | -| `typeId` | `bytes32` | Unique identifier for a specific notification. | -| `_1` | `bytes` | - | +| Name | Type | Description | +| ---------- | :-------: | ---------------------------------------------- | +| `notifier` | `address` | - | +| `_1` | `uint256` | - | +| `typeId` | `bytes32` | Unique identifier for a specific notification. | +| `_3` | `bytes` | - | #### Returns @@ -219,41 +223,6 @@ Calls `bytes4(keccak256(setDataBatch(bytes32[],bytes[])))` without checking for
-## Events - -### UniversalReceiver - -:::note References - -- Specification details: [**LSP-1-UniversalReceiver**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-1-UniversalReceiver.md#universalreceiver) -- Solidity implementation: [`LSP1UniversalReceiverDelegateUP.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol) -- Event signature: `UniversalReceiver(address,uint256,bytes32,bytes,bytes)` -- Event topic hash: `0x9c3ba68eb5742b8e3961aea0afc7371a71bf433c8a67a831803b64c064a178c2` - -::: - -```solidity -event UniversalReceiver(address indexed from, uint256 indexed value, bytes32 indexed typeId, bytes receivedData, bytes returnedValue); -``` - -\*Address `from` called the `universalReceiver(...)` function while sending `value` LYX. Notification type (typeId): `typeId` - -- Data received: `receivedData`.\* - -Emitted when the [`universalReceiver`](#universalreceiver) function was called with a specific `typeId` and some `receivedData` s - -#### Parameters - -| Name | Type | Description | -| ---------------------- | :-------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `from` **`indexed`** | `address` | The address of the EOA or smart contract that called the {universalReceiver(...)} function. | -| `value` **`indexed`** | `uint256` | The amount sent to the {universalReceiver(...)} function. | -| `typeId` **`indexed`** | `bytes32` | A `bytes32` unique identifier (= _"hook"_)that describe the type of notification, information or transaction received by the contract. Can be related to a specific standard or a hook. | -| `receivedData` | `bytes` | Any arbitrary data that was sent to the {universalReceiver(...)} function. | -| `returnedValue` | `bytes` | The value returned by the {universalReceiver(...)} function. | - -
- ## Errors ### CannotRegisterEOAsAsAssets @@ -282,24 +251,3 @@ Reverts when EOA calls the [`universalReceiver(..)`](#universalreceiver) functio | `caller` | `address` | The address of the EOA |
- -### NativeTokensNotAccepted - -:::note References - -- Specification details: [**LSP-1-UniversalReceiver**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-1-UniversalReceiver.md#nativetokensnotaccepted) -- Solidity implementation: [`LSP1UniversalReceiverDelegateUP.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol) -- Error signature: `NativeTokensNotAccepted()` -- Error hash: `0x114b721a` - -::: - -```solidity -error NativeTokensNotAccepted(); -``` - -_Cannot send native tokens to [`universalReceiver(...)`](#universalreceiver) function of the delegated contract._ - -Reverts when the [`universalReceiver`](#universalreceiver) function in the LSP1 Universal Receiver Delegate contract is called while sending some native tokens along the call (`msg.value` different than `0`) - -
diff --git a/docs/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.md b/docs/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.md index ddedeaae3..d90649263 100644 --- a/docs/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.md +++ b/docs/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.md @@ -56,14 +56,14 @@ See [`IERC165-supportsInterface`](#ierc165-supportsinterface).
-### universalReceiver +### universalReceiverDelegate :::note References -- Specification details: [**LSP-1-UniversalReceiver**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-1-UniversalReceiver.md#universalreceiver) +- Specification details: [**LSP-1-UniversalReceiver**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-1-UniversalReceiver.md#universalreceiverdelegate) - Solidity implementation: [`LSP1UniversalReceiverDelegateVault.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol) -- Function signature: `universalReceiver(bytes32,)` -- Function selector: `0x534e72c8` +- Function signature: `universalReceiverDelegate(address,,bytes32,)` +- Function selector: `0xba924425` ::: @@ -75,10 +75,12 @@ See [`IERC165-supportsInterface`](#ierc165-supportsinterface). ::: ```solidity -function universalReceiver( +function universalReceiverDelegate( + address notifier, + uint256, bytes32 typeId, bytes -) external payable returns (bytes); +) external nonpayable returns (bytes); ``` _Reacted on received notification with `typeId`._ @@ -95,10 +97,12 @@ Handles two cases: Writes the received [LSP-7-DigitalAsset] or [LSP-8-Identifiab #### Parameters -| Name | Type | Description | -| -------- | :-------: | ---------------------------------------------- | -| `typeId` | `bytes32` | Unique identifier for a specific notification. | -| `_1` | `bytes` | - | +| Name | Type | Description | +| ---------- | :-------: | ---------------------------------------------- | +| `notifier` | `address` | - | +| `_1` | `uint256` | - | +| `typeId` | `bytes32` | Unique identifier for a specific notification. | +| `_3` | `bytes` | - | #### Returns @@ -176,41 +180,6 @@ Calls `bytes4(keccak256(setDataBatch(bytes32[],bytes[])))` without checking for
-## Events - -### UniversalReceiver - -:::note References - -- Specification details: [**LSP-1-UniversalReceiver**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-1-UniversalReceiver.md#universalreceiver) -- Solidity implementation: [`LSP1UniversalReceiverDelegateVault.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol) -- Event signature: `UniversalReceiver(address,uint256,bytes32,bytes,bytes)` -- Event topic hash: `0x9c3ba68eb5742b8e3961aea0afc7371a71bf433c8a67a831803b64c064a178c2` - -::: - -```solidity -event UniversalReceiver(address indexed from, uint256 indexed value, bytes32 indexed typeId, bytes receivedData, bytes returnedValue); -``` - -\*Address `from` called the `universalReceiver(...)` function while sending `value` LYX. Notification type (typeId): `typeId` - -- Data received: `receivedData`.\* - -Emitted when the [`universalReceiver`](#universalreceiver) function was called with a specific `typeId` and some `receivedData` s - -#### Parameters - -| Name | Type | Description | -| ---------------------- | :-------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `from` **`indexed`** | `address` | The address of the EOA or smart contract that called the {universalReceiver(...)} function. | -| `value` **`indexed`** | `uint256` | The amount sent to the {universalReceiver(...)} function. | -| `typeId` **`indexed`** | `bytes32` | A `bytes32` unique identifier (= _"hook"_)that describe the type of notification, information or transaction received by the contract. Can be related to a specific standard or a hook. | -| `receivedData` | `bytes` | Any arbitrary data that was sent to the {universalReceiver(...)} function. | -| `returnedValue` | `bytes` | The value returned by the {universalReceiver(...)} function. | - -
- ## Errors ### CannotRegisterEOAsAsAssets @@ -239,24 +208,3 @@ Reverts when EOA calls the [`universalReceiver(..)`](#universalreceiver) functio | `caller` | `address` | The address of the EOA |
- -### NativeTokensNotAccepted - -:::note References - -- Specification details: [**LSP-1-UniversalReceiver**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-1-UniversalReceiver.md#nativetokensnotaccepted) -- Solidity implementation: [`LSP1UniversalReceiverDelegateVault.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol) -- Error signature: `NativeTokensNotAccepted()` -- Error hash: `0x114b721a` - -::: - -```solidity -error NativeTokensNotAccepted(); -``` - -_Cannot send native tokens to [`universalReceiver(...)`](#universalreceiver) function of the delegated contract._ - -Reverts when the [`universalReceiver`](#universalreceiver) function in the LSP1 Universal Receiver Delegate contract is called while sending some native tokens along the call (`msg.value` different than `0`) - -
diff --git a/docs/contracts/LSP9Vault/LSP9Vault.md b/docs/contracts/LSP9Vault/LSP9Vault.md index 84821b6df..310e14cf2 100644 --- a/docs/contracts/LSP9Vault/LSP9Vault.md +++ b/docs/contracts/LSP9Vault/LSP9Vault.md @@ -1354,7 +1354,7 @@ event UniversalReceiver(address indexed from, uint256 indexed value, bytes32 ind - Data received: `receivedData`.\* -Emitted when the [`universalReceiver`](#universalreceiver) function was called with a specific `typeId` and some `receivedData` s +Emitted when the [`universalReceiver`](#universalreceiver) function was called with a specific `typeId` and some `receivedData` #### Parameters diff --git a/docs/contracts/UniversalProfile.md b/docs/contracts/UniversalProfile.md index 1516eb39e..e35e85e77 100644 --- a/docs/contracts/UniversalProfile.md +++ b/docs/contracts/UniversalProfile.md @@ -1380,7 +1380,7 @@ event UniversalReceiver(address indexed from, uint256 indexed value, bytes32 ind - Data received: `receivedData`.\* -Emitted when the [`universalReceiver`](#universalreceiver) function was called with a specific `typeId` and some `receivedData` s +Emitted when the [`universalReceiver`](#universalreceiver) function was called with a specific `typeId` and some `receivedData` #### Parameters diff --git a/docs/libraries/LSP1UniversalReceiver/LSP1Utils.md b/docs/libraries/LSP1UniversalReceiver/LSP1Utils.md index ff5954fab..c116ad6c8 100644 --- a/docs/libraries/LSP1UniversalReceiver/LSP1Utils.md +++ b/docs/libraries/LSP1UniversalReceiver/LSP1Utils.md @@ -47,39 +47,6 @@ supports the LSP1 interface.
-### callUniversalReceiverWithCallerInfos - -```solidity -function callUniversalReceiverWithCallerInfos( - address universalReceiverDelegate, - bytes32 typeId, - bytes receivedData, - address msgSender, - uint256 msgValue -) internal nonpayable returns (bytes); -``` - -Call a LSP1UniversalReceiverDelegate contract at `universalReceiverDelegate` address and append `msgSender` and `msgValue` -as additional informations in the calldata. - -#### Parameters - -| Name | Type | Description | -| --------------------------- | :-------: | ------------------------------------------------------------------------------------------------- | -| `universalReceiverDelegate` | `address` | The address of the LSP1UniversalReceiverDelegate to delegate the `universalReceiver` function to. | -| `typeId` | `bytes32` | A `bytes32` typeId. | -| `receivedData` | `bytes` | The data sent initially to the `universalReceiver` function. | -| `msgSender` | `address` | The address that initially called the `universalReceiver` function. | -| `msgValue` | `uint256` | The amount of native token received initially by the `universalReceiver` function. | - -#### Returns - -| Name | Type | Description | -| ---- | :-----: | ---------------------------------------------------------------- | -| `0` | `bytes` | The data returned by the LSP1UniversalReceiverDelegate contract. | - -
- ### getLSP1DelegateValue ```solidity diff --git a/scripts/interfaceIds.ts b/scripts/interfaceIds.ts index c1a4b41b7..e1f63fb65 100644 --- a/scripts/interfaceIds.ts +++ b/scripts/interfaceIds.ts @@ -31,8 +31,9 @@ async function main() { } else { const lspInterface = `I${contract}`; - // adjust the source path for LSP20 and LSP17 contracts + // adjust the source path for LSP1Delegate, LSP20 and LSP17 contracts const folders = { + LSP1UniversalReceiverDelegate: 'LSP1UniversalReceiver', LSP20CallVerifier: 'LSP20CallVerification', LSP17Extendable: 'LSP17ContractExtension', LSP17Extension: 'LSP17ContractExtension', @@ -40,7 +41,11 @@ async function main() { let folder; - if (contract === 'LSP20CallVerifier' || contract.startsWith('LSP17')) { + if ( + contract === 'LSP1UniversalReceiverDelegate' || + contract.startsWith('LSP17') || + contract === 'LSP20CallVerifier' + ) { folder = folders[contract]; } else { folder = contract; diff --git a/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP.behaviour.ts b/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP.behaviour.ts index 31ca3a20f..2fdfdfb82 100644 --- a/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP.behaviour.ts +++ b/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP.behaviour.ts @@ -3167,22 +3167,4 @@ export const shouldInitializeLikeLSP1Delegate = ( ); }); }); - describe('edge cases', () => { - describe('when sending value to universalReceiver(...)', () => { - it('should revert with custom error', async () => { - // value of 1 ethers - const value = ethers.utils.parseEther('1'); - await expect( - context.lsp1universalReceiverDelegateUP.universalReceiver( - LSP1_TYPE_IDS.LSP7Tokens_RecipientNotification, - '0x', - { value }, - ), - ).to.be.revertedWithCustomError( - context.lsp1universalReceiverDelegateUP, - 'NativeTokensNotAccepted', - ); - }); - }); - }); }; diff --git a/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault.behaviour.ts b/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault.behaviour.ts index c773e1e03..727852c19 100644 --- a/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault.behaviour.ts +++ b/tests/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault.behaviour.ts @@ -80,9 +80,9 @@ export const shouldBehaveLikeLSP1Delegate = (buildContext: () => Promise { + it('should support LSP1Delegate interface', async () => { const result = await context.lsp1universalReceiverDelegateVault.supportsInterface( - INTERFACE_IDS.LSP1UniversalReceiver, + INTERFACE_IDS.LSP1UniversalReceiverDelegate, ); expect(result).to.be.true; }); diff --git a/tests/LSP20CallVerification/LSP6/Interactions/Security.test.ts b/tests/LSP20CallVerification/LSP6/Interactions/Security.test.ts index 61880dc6f..00cd0946a 100644 --- a/tests/LSP20CallVerification/LSP6/Interactions/Security.test.ts +++ b/tests/LSP20CallVerification/LSP6/Interactions/Security.test.ts @@ -184,10 +184,15 @@ export const testSecurityScenarios = (buildContext: () => Promise Date: Fri, 13 Oct 2023 14:55:03 +0300 Subject: [PATCH 48/55] refactor: replace magic value with returnedStatus (#742) * refactor: replace magic value with returnedStatus * chore: add suggested changes --------- Co-authored-by: Jean Cvllr <31145285+CJ42@users.noreply.github.com> --- constants.ts | 4 +- contracts/LSP0ERC725Account/LSP0Constants.sol | 2 +- .../LSP0ERC725AccountCore.sol | 35 +++--- contracts/LSP17Extensions/Extension4337.sol | 6 +- .../ILSP20CallVerifier.sol | 4 +- .../LSP20CallVerification.sol | 30 +++-- .../LSP20CallVerification/LSP20Constants.sol | 6 +- .../LSP20CallVerification/LSP20Errors.sol | 6 +- .../LSP6KeyManager/LSP6KeyManagerCore.sol | 36 +++--- .../LSP20Owners/FallbackReturnMagicValue.sol | 2 +- .../FirstCallReturnExpandedInvalidValue.sol | 2 +- .../FirstCallReturnInvalidMagicValue.sol | 2 +- contracts/Mocks/MaliciousERC1271Wallet.sol | 2 +- .../LSP0ERC725Account/LSP0ERC725Account.md | 76 ++++++------- .../LSP20CallVerification.md | 8 +- .../LSP6KeyManager/LSP6KeyManager.md | 16 +-- docs/contracts/UniversalProfile.md | 76 ++++++------- .../LSP20CallVerification.behaviour.ts | 104 +++++++++--------- .../Interactions/AllowedStandards.test.ts | 4 +- .../Admin/PermissionSign.test.ts | 8 +- .../Interactions/AllowedStandards.test.ts | 4 +- .../Interactions/PermissionStaticCall.test.ts | 2 +- .../LSP6ControlledToken.test.ts | 2 +- tests/UniversalProfile.behaviour.ts | 2 +- 24 files changed, 224 insertions(+), 215 deletions(-) diff --git a/constants.ts b/constants.ts index 7f30a8c8a..eed5bfc63 100644 --- a/constants.ts +++ b/constants.ts @@ -48,7 +48,7 @@ export const INTERFACE_IDS = { * Can be used to check if a signature is valid or not. */ export const ERC1271_VALUES = { - MAGIC_VALUE: '0x1626ba7e', + SUCCESS_VALUE: '0x1626ba7e', FAIL_VALUE: '0xffffffff', }; @@ -59,7 +59,7 @@ export const ERC1271_VALUES = { * @dev values returned by the `lsp20VerifyCall` and `lsp20VerifyCallResult` functions of the LSP20 standard. * Can be used to check if a calldata payload was check and verified. */ -export const LSP20_MAGIC_VALUES = { +export const LSP20_SUCCESS_VALUES = { VERIFY_CALL: { // bytes3(keccak256("lsp20VerifyCall(address,address,uint256,bytes)")) + "0x00" NO_POST_VERIFICATION: '0x1a238000', diff --git a/contracts/LSP0ERC725Account/LSP0Constants.sol b/contracts/LSP0ERC725Account/LSP0Constants.sol index 98948eea4..b714b80d6 100644 --- a/contracts/LSP0ERC725Account/LSP0Constants.sol +++ b/contracts/LSP0ERC725Account/LSP0Constants.sol @@ -6,7 +6,7 @@ bytes4 constant _INTERFACEID_LSP0 = 0x24871b3d; bytes4 constant _INTERFACEID_ERC1271 = 0x1626ba7e; // ERC1271 - Standard Signature Validation -bytes4 constant _ERC1271_MAGICVALUE = 0x1626ba7e; +bytes4 constant _ERC1271_SUCCESSVALUE = 0x1626ba7e; bytes4 constant _ERC1271_FAILVALUE = 0xffffffff; // Ownerhsip Transfer Type IDs diff --git a/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol b/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol index 9b9e5e310..61f45c6bb 100644 --- a/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol +++ b/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol @@ -38,7 +38,7 @@ import { import { _INTERFACEID_LSP0, _INTERFACEID_ERC1271, - _ERC1271_MAGICVALUE, + _ERC1271_SUCCESSVALUE, _ERC1271_FAILVALUE, _TYPEID_LSP0_OwnershipTransferStarted, _TYPEID_LSP0_OwnershipTransferred_SenderNotification, @@ -205,7 +205,7 @@ abstract contract LSP0ERC725AccountCore is } // If the caller is not the owner, call {lsp20VerifyCall} on the owner - // Depending on the magicValue returned, a second call is done after execution + // Depending on the returnedStatus, a second call is done after execution bool verifyAfter = LSP20CallVerification._verifyCall(accountOwner); // Perform the execution @@ -269,7 +269,7 @@ abstract contract LSP0ERC725AccountCore is } // If the caller is not the owner, call {lsp20VerifyCall} on the owner - // Depending on the magicValue returned, a second call is done after execution + // Depending on the returnedStatus, a second call is done after execution bool verifyAfter = LSP20CallVerification._verifyCall(accountOwner); // Perform the execution @@ -316,7 +316,7 @@ abstract contract LSP0ERC725AccountCore is } // If the caller is not the owner, call {lsp20VerifyCall} on the owner - // Depending on the magicValue returned, a second call is done after setting data + // Depending on the returnedStatus, a second call is done after setting data bool verifyAfter = _verifyCall(accountOwner); _setData(dataKey, dataValue); @@ -369,7 +369,7 @@ abstract contract LSP0ERC725AccountCore is } // If the caller is not the owner, call {lsp20VerifyCall} on the owner - // Depending on the magicValue returned, a second call is done after setting data + // Depending on the returnedStatus, a second call is done after setting data bool verifyAfter = _verifyCall(accountOwner); for (uint256 i; i < dataKeys.length; ) { @@ -524,7 +524,7 @@ abstract contract LSP0ERC725AccountCore is _inTransferOwnership = false; } else { // If the caller is not the owner, call {lsp20VerifyCall} on the owner - // Depending on the magicValue returned, a second call is done after transferring ownership + // Depending on the returnedStatus, a second call is done after transferring ownership bool verifyAfter = _verifyCall(currentOwner); // set the transfer ownership lock @@ -598,7 +598,7 @@ abstract contract LSP0ERC725AccountCore is } // If the caller is not the owner, call {lsp20VerifyCall} on the owner - // Depending on the magicValue returned, a second call is done after transferring ownership + // Depending on the returnedStatus, a second call is done after transferring ownership bool verifyAfter = _verifyCall(accountOwner); address previousOwner = owner(); @@ -659,25 +659,25 @@ abstract contract LSP0ERC725AccountCore is * * 1. If the owner is an EOA, recovers an address from the hash and the signature provided: * - * - Returns the `magicValue` if the address recovered is the same as the owner, indicating that it was a valid signature. + * - Returns the `_ERC1271_SUCCESSVALUE` if the address recovered is the same as the owner, indicating that it was a valid signature. * - * - If the address is different, it returns the fail value indicating that the signature is not valid. + * - If the address is different, it returns the `_ERC1271_FAILVALUE` indicating that the signature is not valid. * * 2. If the owner is a smart contract, it forwards the call of {isValidSignature()} to the owner contract: * - * - If the contract fails or returns the fail value, the {isValidSignature()} on the account returns the fail value, indicating that the signature is not valid. + * - If the contract fails or returns the `_ERC1271_FAILVALUE`, the {isValidSignature()} on the account returns the `_ERC1271_FAILVALUE`, indicating that the signature is not valid. * - * - If the {isValidSignature()} on the owner returned the `magicValue`, the {isValidSignature()} on the account returns the `magicValue`, indicating that it's a valid signature. + * - If the {isValidSignature()} on the owner returned the `_ERC1271_SUCCESSVALUE`, the {isValidSignature()} on the account returns the `_ERC1271_SUCCESSVALUE`, indicating that it's a valid signature. * * @param dataHash The hash of the data to be validated. * @param signature A signature that can validate the previous parameter (Hash). * - * @return magicValue A `bytes4` value that indicates if the signature is valid or not. + * @return returnedStatus A `bytes4` value that indicates if the signature is valid or not. */ function isValidSignature( bytes32 dataHash, bytes memory signature - ) public view virtual override returns (bytes4 magicValue) { + ) public view virtual override returns (bytes4 returnedStatus) { address _owner = owner(); // If owner is a contract @@ -692,9 +692,10 @@ abstract contract LSP0ERC725AccountCore is bool isValid = (success && result.length == 32 && - abi.decode(result, (bytes32)) == bytes32(_ERC1271_MAGICVALUE)); + abi.decode(result, (bytes32)) == + bytes32(_ERC1271_SUCCESSVALUE)); - return isValid ? _ERC1271_MAGICVALUE : _ERC1271_FAILVALUE; + return isValid ? _ERC1271_SUCCESSVALUE : _ERC1271_FAILVALUE; } // If owner is an EOA else { @@ -707,11 +708,11 @@ abstract contract LSP0ERC725AccountCore is return _ERC1271_FAILVALUE; // if recovering is successful and the recovered address matches the owner's address, - // return the ERC1271 magic value. Otherwise, return the ERC1271 fail value + // return the ERC1271 success value. Otherwise, return the ERC1271 fail value // matches the address of the owner, otherwise return fail value return recoveredAddress == _owner - ? _ERC1271_MAGICVALUE + ? _ERC1271_SUCCESSVALUE : _ERC1271_FAILVALUE; } } diff --git a/contracts/LSP17Extensions/Extension4337.sol b/contracts/LSP17Extensions/Extension4337.sol index 7ea08b17d..d5fd38331 100644 --- a/contracts/LSP17Extensions/Extension4337.sol +++ b/contracts/LSP17Extensions/Extension4337.sol @@ -71,16 +71,16 @@ contract Extension4337 is LSP17Extension, IAccount { address owner = LSP14Ownable2Step(msg.sender).owner(); // verify that the recovered address can execute the userOp.callData - bytes4 magicValue = ILSP20CallVerifier(owner).lsp20VerifyCall({ + bytes4 returnedStatus = ILSP20CallVerifier(owner).lsp20VerifyCall({ callee: msg.sender, caller: recovered, value: 0, receivedCalldata: userOp.callData }); - // if the call verifier returns a different magic value, return signature validation failed + // if the returnedStatus is a value different than the success value, return signature validation failed if ( - bytes3(magicValue) != + bytes3(returnedStatus) != bytes3(ILSP20CallVerifier.lsp20VerifyCall.selector) ) { return _SIG_VALIDATION_FAILED; diff --git a/contracts/LSP20CallVerification/ILSP20CallVerifier.sol b/contracts/LSP20CallVerification/ILSP20CallVerifier.sol index e550a8fa9..2b1b97f88 100644 --- a/contracts/LSP20CallVerification/ILSP20CallVerifier.sol +++ b/contracts/LSP20CallVerification/ILSP20CallVerifier.sol @@ -8,7 +8,7 @@ pragma solidity ^0.8.4; */ interface ILSP20CallVerifier { /** - * @return magicValue MUST return the first 3 bytes of `lsp20VerifyCall(address,uint256,bytes)` function selector if the call to + * @return returnedStatus MUST return the first 3 bytes of `lsp20VerifyCall(address,uint256,bytes)` function selector if the call to * the function is allowed, concatened with a byte that determines if the lsp20VerifyCallResult function should * be called after the original function call. The byte that invoke the lsp20VerifyCallResult function is strictly `0x01`. * @@ -22,7 +22,7 @@ interface ILSP20CallVerifier { address caller, uint256 value, bytes memory receivedCalldata - ) external returns (bytes4 magicValue); + ) external returns (bytes4 returnedStatus); /** * @return MUST return the lsp20VerifyCallResult function selector if the call to the function is allowed diff --git a/contracts/LSP20CallVerification/LSP20CallVerification.sol b/contracts/LSP20CallVerification/LSP20CallVerification.sol index d4571b764..d23ac7810 100644 --- a/contracts/LSP20CallVerification/LSP20CallVerification.sol +++ b/contracts/LSP20CallVerification/LSP20CallVerification.sol @@ -7,7 +7,7 @@ import {ILSP20CallVerifier as ILSP20} from "./ILSP20CallVerifier.sol"; // errors import { - LSP20InvalidMagicValue, + LSP20CallVerificationFailed, LSP20CallingVerifierFailed, LSP20EOACannotVerifyCall } from "./LSP20Errors.sol"; @@ -16,13 +16,13 @@ import { * @title Implementation of a contract calling the verification functions according to LSP20 - Call Verification standard. * * @dev Module to be inherited used to verify the execution of functions according to a verifier address. - * Verification can happen before or after execution based on a magicValue. + * Verification can happen before or after execution based on a returnedStatus. */ abstract contract LSP20CallVerification { /** * @dev Calls {lsp20VerifyCall} function on the logicVerifier. - * Reverts in case the value returned does not match the magic value (lsp20VerifyCall selector) - * Returns whether a verification after the execution should happen based on the last byte of the magicValue + * Reverts in case the value returned does not match the success value (lsp20VerifyCall selector) + * Returns whether a verification after the execution should happen based on the last byte of the returnedStatus */ function _verifyCall( address logicVerifier @@ -42,18 +42,18 @@ abstract contract LSP20CallVerification { _validateCall(false, success, returnedData); - bytes4 magicValue = abi.decode(returnedData, (bytes4)); + bytes4 returnedStatus = abi.decode(returnedData, (bytes4)); - if (bytes3(magicValue) != bytes3(ILSP20.lsp20VerifyCall.selector)) { - revert LSP20InvalidMagicValue(false, returnedData); + if (bytes3(returnedStatus) != bytes3(ILSP20.lsp20VerifyCall.selector)) { + revert LSP20CallVerificationFailed(false, returnedData); } - return magicValue[3] == 0x01; + return returnedStatus[3] == 0x01; } /** * @dev Calls {lsp20VerifyCallResult} function on the logicVerifier. - * Reverts in case the value returned does not match the magic value (lsp20VerifyCallResult selector) + * Reverts in case the value returned does not match the success value (lsp20VerifyCallResult selector) */ function _verifyCallResult( address logicVerifier, @@ -79,7 +79,11 @@ abstract contract LSP20CallVerification { if ( abi.decode(returnedData, (bytes4)) != ILSP20.lsp20VerifyCallResult.selector - ) revert LSP20InvalidMagicValue(true, returnedData); + ) + revert LSP20CallVerificationFailed({ + postCall: true, + returnedData: returnedData + }); } function _validateCall( @@ -94,7 +98,11 @@ abstract contract LSP20CallVerification { if ( returnedData.length < 32 || bytes28(bytes32(returnedData) << 32) != bytes28(0) - ) revert LSP20InvalidMagicValue(postCall, returnedData); + ) + revert LSP20CallVerificationFailed({ + postCall: postCall, + returnedData: returnedData + }); } function _revertWithLSP20DefaultError( diff --git a/contracts/LSP20CallVerification/LSP20Constants.sol b/contracts/LSP20CallVerification/LSP20Constants.sol index 4134c6a89..d36869a57 100644 --- a/contracts/LSP20CallVerification/LSP20Constants.sol +++ b/contracts/LSP20CallVerification/LSP20Constants.sol @@ -8,10 +8,10 @@ bytes4 constant _INTERFACEID_LSP20_CALL_VERIFICATION = 0x1a0eb6a5; bytes4 constant _INTERFACEID_LSP20_CALL_VERIFIER = 0xc9dfc532; // bytes4(bytes.concat(bytes3(ILSP20.lsp20VerifyCall.selector), hex"01")) -bytes4 constant _LSP20_VERIFY_CALL_MAGIC_VALUE_WITH_POST_VERIFICATION = 0x1a238001; +bytes4 constant _LSP20_VERIFY_CALL_SUCCESS_VALUE_WITH_POST_VERIFICATION = 0x1a238001; // bytes4(bytes.concat(bytes3(ILSP20.lsp20VerifyCall.selector), hex"00")) -bytes4 constant _LSP20_VERIFY_CALL_MAGIC_VALUE_WITHOUT_POST_VERIFICATION = 0x1a238000; +bytes4 constant _LSP20_VERIFY_CALL_SUCCESS_VALUE_WITHOUT_POST_VERIFICATION = 0x1a238000; // bytes4(ILSP20.lsp20VerifyCallResult.selector) -bytes4 constant _LSP20_VERIFY_CALL_RESULT_MAGIC_VALUE = 0xd3fc45d3; +bytes4 constant _LSP20_VERIFY_CALL_RESULT_SUCCESS_VALUE = 0xd3fc45d3; diff --git a/contracts/LSP20CallVerification/LSP20Errors.sol b/contracts/LSP20CallVerification/LSP20Errors.sol index 4ed0d42e0..40e99bc4d 100644 --- a/contracts/LSP20CallVerification/LSP20Errors.sol +++ b/contracts/LSP20CallVerification/LSP20Errors.sol @@ -8,14 +8,14 @@ pragma solidity ^0.8.4; error LSP20CallingVerifierFailed(bool postCall); /** - * @dev reverts when the call to the owner does not return the magic value + * @dev reverts when the call to the owner does not return the LSP20 success value * @param postCall True if the execution call was done, False otherwise * @param returnedData The data returned by the call to the logic verifier */ -error LSP20InvalidMagicValue(bool postCall, bytes returnedData); +error LSP20CallVerificationFailed(bool postCall, bytes returnedData); /** - * @dev Reverts when the logic verifier is an Externally Owned Account (EOA) that cannot return the LSP20 magic value. + * @dev Reverts when the logic verifier is an Externally Owned Account (EOA) that cannot return the LSP20 success value. * @param logicVerifier The address of the logic verifier */ error LSP20EOACannotVerifyCall(address logicVerifier); diff --git a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol index 802f3e238..2fc1c117f 100644 --- a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol +++ b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol @@ -51,7 +51,7 @@ import { import { _INTERFACEID_ERC1271, - _ERC1271_MAGICVALUE, + _ERC1271_SUCCESSVALUE, _ERC1271_FAILVALUE } from "../LSP0ERC725Account/LSP0Constants.sol"; import { @@ -61,9 +61,9 @@ import { } from "./LSP6Constants.sol"; import { _INTERFACEID_LSP20_CALL_VERIFIER, - _LSP20_VERIFY_CALL_MAGIC_VALUE_WITHOUT_POST_VERIFICATION, - _LSP20_VERIFY_CALL_MAGIC_VALUE_WITH_POST_VERIFICATION, - _LSP20_VERIFY_CALL_RESULT_MAGIC_VALUE + _LSP20_VERIFY_CALL_SUCCESS_VALUE_WITHOUT_POST_VERIFICATION, + _LSP20_VERIFY_CALL_SUCCESS_VALUE_WITH_POST_VERIFICATION, + _LSP20_VERIFY_CALL_RESULT_SUCCESS_VALUE } from "../LSP20CallVerification/LSP20Constants.sol"; import {_INTERFACEID_LSP25} from "../LSP25ExecuteRelayCall/LSP25Constants.sol"; @@ -143,14 +143,14 @@ abstract contract LSP6KeyManagerCore is * @inheritdoc IERC1271 * * @dev Checks if a signature was signed by a controller that has the permission `SIGN`. - * If the signer is a controller with the permission `SIGN`, it will return the ERC1271 magic value. + * If the signer is a controller with the permission `SIGN`, it will return the ERC1271 success value. * - * @return magicValue `0x1626ba7e` on success, or `0xffffffff` on failure. + * @return returnedStatus `0x1626ba7e` on success, or `0xffffffff` on failure. */ function isValidSignature( bytes32 dataHash, bytes memory signature - ) public view virtual override returns (bytes4 magicValue) { + ) public view virtual override returns (bytes4 returnedStatus) { // if isValidSignature fail, the error is catched in returnedError (address recoveredAddress, ECDSA.RecoverError returnedError) = ECDSA .tryRecover(dataHash, signature); @@ -159,12 +159,12 @@ abstract contract LSP6KeyManagerCore is if (returnedError != ECDSA.RecoverError.NoError) return _ERC1271_FAILVALUE; - // if the address recovered has SIGN permission return the ERC1271 magic value, otherwise the fail value + // if the address recovered has SIGN permission return the ERC1271 success value, otherwise the fail value return ( ERC725Y(_target).getPermissionsFor(recoveredAddress).hasPermission( _PERMISSION_SIGN ) - ? _ERC1271_MAGICVALUE + ? _ERC1271_SUCCESSVALUE : _ERC1271_FAILVALUE ); } @@ -313,9 +313,9 @@ abstract contract LSP6KeyManagerCore is * Anyone can call this function to verify if the `caller` has the right permissions to perform the abi-encoded function call `data` * on the {`target`} contract (while sending `msgValue` alongside the call). * - * If the permissions have been verified successfully and `caller` is authorized, one of the following two LSP20 magic value will be returned: - * - `0x1a238000`: LSP20 magic value **without** post verification (last byte is `0x00`). - * - `0x1a238001`: LSP20 magic value **with** post-verification (last byte is `0x01`). + * If the permissions have been verified successfully and `caller` is authorized, one of the following two LSP20 success value will be returned: + * - `0x1a238000`: LSP20 success value **without** post verification (last byte is `0x00`). + * - `0x1a238001`: LSP20 success value **with** post-verification (last byte is `0x01`). */ function lsp20VerifyCall( address targetContract, @@ -341,8 +341,8 @@ abstract contract LSP6KeyManagerCore is // if it's a setData call, do not invoke the `lsp20VerifyCallResult(..)` function return isSetData || reentrancyStatus - ? _LSP20_VERIFY_CALL_MAGIC_VALUE_WITHOUT_POST_VERIFICATION - : _LSP20_VERIFY_CALL_MAGIC_VALUE_WITH_POST_VERIFICATION; + ? _LSP20_VERIFY_CALL_SUCCESS_VALUE_WITHOUT_POST_VERIFICATION + : _LSP20_VERIFY_CALL_SUCCESS_VALUE_WITH_POST_VERIFICATION; } /// @dev If a different address is invoking the verification, /// do not change the state or emit the event to allow read-only verification @@ -362,8 +362,8 @@ abstract contract LSP6KeyManagerCore is // if it's a setData call, do not invoke the `lsp20VerifyCallResult(..)` function return isSetData || reentrancyStatus - ? _LSP20_VERIFY_CALL_MAGIC_VALUE_WITHOUT_POST_VERIFICATION - : _LSP20_VERIFY_CALL_MAGIC_VALUE_WITH_POST_VERIFICATION; + ? _LSP20_VERIFY_CALL_SUCCESS_VALUE_WITHOUT_POST_VERIFICATION + : _LSP20_VERIFY_CALL_SUCCESS_VALUE_WITH_POST_VERIFICATION; } } @@ -375,11 +375,11 @@ abstract contract LSP6KeyManagerCore is bytes memory /*result*/ ) external virtual override returns (bytes4) { // If it's the target calling, set back the reentrancy guard - // to false, if not return the magic value + // to false, if not return the success value if (msg.sender == _target) { _nonReentrantAfter(msg.sender); } - return _LSP20_VERIFY_CALL_RESULT_MAGIC_VALUE; + return _LSP20_VERIFY_CALL_RESULT_SUCCESS_VALUE; } function _execute( diff --git a/contracts/Mocks/LSP20Owners/FallbackReturnMagicValue.sol b/contracts/Mocks/LSP20Owners/FallbackReturnMagicValue.sol index de1d904cd..40b829104 100644 --- a/contracts/Mocks/LSP20Owners/FallbackReturnMagicValue.sol +++ b/contracts/Mocks/LSP20Owners/FallbackReturnMagicValue.sol @@ -11,7 +11,7 @@ import { /** * @title sample contract used for testing */ -contract FallbackReturnMagicValue { +contract FallbackReturnSuccessValue { event FallbackCalled(bytes data); address public target; diff --git a/contracts/Mocks/LSP20Owners/FirstCallReturnExpandedInvalidValue.sol b/contracts/Mocks/LSP20Owners/FirstCallReturnExpandedInvalidValue.sol index 59ea77849..cb3d3d617 100644 --- a/contracts/Mocks/LSP20Owners/FirstCallReturnExpandedInvalidValue.sol +++ b/contracts/Mocks/LSP20Owners/FirstCallReturnExpandedInvalidValue.sol @@ -8,7 +8,7 @@ import { /** * @title sample contract used for testing */ -contract FirstCallReturnExpandedInvalidValue { +contract FirstCallReturnExpandedFailValue { event CallVerified(); address public target; diff --git a/contracts/Mocks/LSP20Owners/FirstCallReturnInvalidMagicValue.sol b/contracts/Mocks/LSP20Owners/FirstCallReturnInvalidMagicValue.sol index d2aaddff7..e1ccdb45c 100644 --- a/contracts/Mocks/LSP20Owners/FirstCallReturnInvalidMagicValue.sol +++ b/contracts/Mocks/LSP20Owners/FirstCallReturnInvalidMagicValue.sol @@ -7,7 +7,7 @@ import { /** * @title sample contract used for testing */ -contract FirstCallReturnInvalidMagicValue { +contract FirstCallReturnFailValue { event CallVerified(); address public target; diff --git a/contracts/Mocks/MaliciousERC1271Wallet.sol b/contracts/Mocks/MaliciousERC1271Wallet.sol index 7e264ec01..383f704ad 100644 --- a/contracts/Mocks/MaliciousERC1271Wallet.sol +++ b/contracts/Mocks/MaliciousERC1271Wallet.sol @@ -8,7 +8,7 @@ import {GenericExecutor} from "./GenericExecutor.sol"; */ contract ERC1271MaliciousMock is GenericExecutor { /** - * @dev Returns a malicious 4-byte magic value. + * @dev Returns a malicious 4-byte value. * @return bytes4 The malicious 4-byte magic value. */ function isValidSignature( diff --git a/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md b/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md index aa0f9d948..37453c285 100644 --- a/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md +++ b/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md @@ -491,7 +491,7 @@ Get in the ERC725Y storage the bytes data stored at multiple data keys `dataKeys function isValidSignature( bytes32 dataHash, bytes signature -) external view returns (bytes4 magicValue); +) external view returns (bytes4 returnedStatus); ``` _Achieves the goal of [EIP-1271] by validating signatures of smart contracts according to their own logic._ @@ -500,15 +500,15 @@ Handles two cases: 1. If the owner is an EOA, recovers an address from the hash and the signature provided: -- Returns the `magicValue` if the address recovered is the same as the owner, indicating that it was a valid signature. +- Returns the `_ERC1271_SUCCESSVALUE` if the address recovered is the same as the owner, indicating that it was a valid signature. -- If the address is different, it returns the fail value indicating that the signature is not valid. +- If the address is different, it returns the `_ERC1271_FAILVALUE` indicating that the signature is not valid. 2. If the owner is a smart contract, it forwards the call of [`isValidSignature()`](#isvalidsignature) to the owner contract: -- If the contract fails or returns the fail value, the [`isValidSignature()`](#isvalidsignature) on the account returns the fail value, indicating that the signature is not valid. +- If the contract fails or returns the `_ERC1271_FAILVALUE`, the [`isValidSignature()`](#isvalidsignature) on the account returns the `_ERC1271_FAILVALUE`, indicating that the signature is not valid. -- If the [`isValidSignature()`](#isvalidsignature) on the owner returned the `magicValue`, the [`isValidSignature()`](#isvalidsignature) on the account returns the `magicValue`, indicating that it's a valid signature. +- If the [`isValidSignature()`](#isvalidsignature) on the owner returned the `_ERC1271_SUCCESSVALUE`, the [`isValidSignature()`](#isvalidsignature) on the account returns the `_ERC1271_SUCCESSVALUE`, indicating that it's a valid signature. #### Parameters @@ -519,9 +519,9 @@ Handles two cases: #### Returns -| Name | Type | Description | -| ------------ | :------: | ----------------------------------------------------------------- | -| `magicValue` | `bytes4` | A `bytes4` value that indicates if the signature is valid or not. | +| Name | Type | Description | +| ---------------- | :------: | ----------------------------------------------------------------- | +| `returnedStatus` | `bytes4` | A `bytes4` value that indicates if the signature is valid or not. |
@@ -1192,8 +1192,8 @@ function _verifyCall( ``` Calls [`lsp20VerifyCall`](#lsp20verifycall) function on the logicVerifier. -Reverts in case the value returned does not match the magic value (lsp20VerifyCall selector) -Returns whether a verification after the execution should happen based on the last byte of the magicValue +Reverts in case the value returned does not match the success value (lsp20VerifyCall selector) +Returns whether a verification after the execution should happen based on the last byte of the returnedStatus
@@ -1207,7 +1207,7 @@ function _verifyCallResult( ``` Calls [`lsp20VerifyCallResult`](#lsp20verifycallresult) function on the logicVerifier. -Reverts in case the value returned does not match the magic value (lsp20VerifyCallResult selector) +Reverts in case the value returned does not match the success value (lsp20VerifyCallResult selector)
@@ -1745,6 +1745,32 @@ Reverts when pending owner accept ownership in the same transaction of transferr
+### LSP20CallVerificationFailed + +:::note References + +- Specification details: [**LSP-0-ERC725Account**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-0-ERC725Account.md#lsp20callverificationfailed) +- Solidity implementation: [`LSP0ERC725Account.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP0ERC725Account/LSP0ERC725Account.sol) +- Error signature: `LSP20CallVerificationFailed(bool,bytes)` +- Error hash: `0x00c28d0f` + +::: + +```solidity +error LSP20CallVerificationFailed(bool postCall, bytes returnedData); +``` + +reverts when the call to the owner does not return the LSP20 success value + +#### Parameters + +| Name | Type | Description | +| -------------- | :-----: | ---------------------------------------------------- | +| `postCall` | `bool` | True if the execution call was done, False otherwise | +| `returnedData` | `bytes` | The data returned by the call to the logic verifier | + +
+ ### LSP20CallingVerifierFailed :::note References @@ -1785,7 +1811,7 @@ reverts when the call to the owner fail with no revert reason error LSP20EOACannotVerifyCall(address logicVerifier); ``` -Reverts when the logic verifier is an Externally Owned Account (EOA) that cannot return the LSP20 magic value. +Reverts when the logic verifier is an Externally Owned Account (EOA) that cannot return the LSP20 success value. #### Parameters @@ -1795,32 +1821,6 @@ Reverts when the logic verifier is an Externally Owned Account (EOA) that cannot
-### LSP20InvalidMagicValue - -:::note References - -- Specification details: [**LSP-0-ERC725Account**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-0-ERC725Account.md#lsp20invalidmagicvalue) -- Solidity implementation: [`LSP0ERC725Account.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP0ERC725Account/LSP0ERC725Account.sol) -- Error signature: `LSP20InvalidMagicValue(bool,bytes)` -- Error hash: `0xd088ec40` - -::: - -```solidity -error LSP20InvalidMagicValue(bool postCall, bytes returnedData); -``` - -reverts when the call to the owner does not return the magic value - -#### Parameters - -| Name | Type | Description | -| -------------- | :-----: | ---------------------------------------------------- | -| `postCall` | `bool` | True if the execution call was done, False otherwise | -| `returnedData` | `bytes` | The data returned by the call to the logic verifier | - -
- ### NoExtensionFoundForFunctionSelector :::note References diff --git a/docs/contracts/LSP20CallVerification/LSP20CallVerification.md b/docs/contracts/LSP20CallVerification/LSP20CallVerification.md index 18ec93c78..c34f97ff7 100644 --- a/docs/contracts/LSP20CallVerification/LSP20CallVerification.md +++ b/docs/contracts/LSP20CallVerification/LSP20CallVerification.md @@ -16,7 +16,7 @@ > Implementation of a contract calling the verification functions according to LSP20 - Call Verification standard. -Module to be inherited used to verify the execution of functions according to a verifier address. Verification can happen before or after execution based on a magicValue. +Module to be inherited used to verify the execution of functions according to a verifier address. Verification can happen before or after execution based on a returnedStatus. ## Internal Methods @@ -33,8 +33,8 @@ function _verifyCall( ``` Calls [`lsp20VerifyCall`](#lsp20verifycall) function on the logicVerifier. -Reverts in case the value returned does not match the magic value (lsp20VerifyCall selector) -Returns whether a verification after the execution should happen based on the last byte of the magicValue +Reverts in case the value returned does not match the success value (lsp20VerifyCall selector) +Returns whether a verification after the execution should happen based on the last byte of the returnedStatus
@@ -48,7 +48,7 @@ function _verifyCallResult( ``` Calls [`lsp20VerifyCallResult`](#lsp20verifycallresult) function on the logicVerifier. -Reverts in case the value returned does not match the magic value (lsp20VerifyCallResult selector) +Reverts in case the value returned does not match the success value (lsp20VerifyCallResult selector)
diff --git a/docs/contracts/LSP6KeyManager/LSP6KeyManager.md b/docs/contracts/LSP6KeyManager/LSP6KeyManager.md index 280ee3332..6cbd38e0a 100644 --- a/docs/contracts/LSP6KeyManager/LSP6KeyManager.md +++ b/docs/contracts/LSP6KeyManager/LSP6KeyManager.md @@ -306,10 +306,10 @@ Get the nonce for a specific `from` address that can be used for signing relay t function isValidSignature( bytes32 dataHash, bytes signature -) external view returns (bytes4 magicValue); +) external view returns (bytes4 returnedStatus); ``` -Checks if a signature was signed by a controller that has the permission `SIGN`. If the signer is a controller with the permission `SIGN`, it will return the ERC1271 magic value. +Checks if a signature was signed by a controller that has the permission `SIGN`. If the signer is a controller with the permission `SIGN`, it will return the ERC1271 success value. #### Parameters @@ -320,9 +320,9 @@ Checks if a signature was signed by a controller that has the permission `SIGN`. #### Returns -| Name | Type | Description | -| ------------ | :------: | ---------------------------------------------------- | -| `magicValue` | `bytes4` | `0x1626ba7e` on success, or `0xffffffff` on failure. | +| Name | Type | Description | +| ---------------- | :------: | ---------------------------------------------------- | +| `returnedStatus` | `bytes4` | `0x1626ba7e` on success, or `0xffffffff` on failure. |
@@ -339,10 +339,10 @@ Checks if a signature was signed by a controller that has the permission `SIGN`. :::tip Hint -This function can call by any other address than the {`target`}. This allows to verify permissions in a _"read-only"_ manner. Anyone can call this function to verify if the `caller` has the right permissions to perform the abi-encoded function call `data` on the {`target`} contract (while sending `msgValue` alongside the call). If the permissions have been verified successfully and `caller` is authorized, one of the following two LSP20 magic value will be returned: +This function can call by any other address than the {`target`}. This allows to verify permissions in a _"read-only"_ manner. Anyone can call this function to verify if the `caller` has the right permissions to perform the abi-encoded function call `data` on the {`target`} contract (while sending `msgValue` alongside the call). If the permissions have been verified successfully and `caller` is authorized, one of the following two LSP20 success value will be returned: -- `0x1a238000`: LSP20 magic value **without** post verification (last byte is `0x00`). -- `0x1a238001`: LSP20 magic value **with** post-verification (last byte is `0x01`). +- `0x1a238000`: LSP20 success value **without** post verification (last byte is `0x00`). +- `0x1a238001`: LSP20 success value **with** post-verification (last byte is `0x01`). ::: diff --git a/docs/contracts/UniversalProfile.md b/docs/contracts/UniversalProfile.md index e35e85e77..01803f303 100644 --- a/docs/contracts/UniversalProfile.md +++ b/docs/contracts/UniversalProfile.md @@ -434,7 +434,7 @@ Get in the ERC725Y storage the bytes data stored at multiple data keys `dataKeys function isValidSignature( bytes32 dataHash, bytes signature -) external view returns (bytes4 magicValue); +) external view returns (bytes4 returnedStatus); ``` _Achieves the goal of [EIP-1271] by validating signatures of smart contracts according to their own logic._ @@ -443,15 +443,15 @@ Handles two cases: 1. If the owner is an EOA, recovers an address from the hash and the signature provided: -- Returns the `magicValue` if the address recovered is the same as the owner, indicating that it was a valid signature. +- Returns the `_ERC1271_SUCCESSVALUE` if the address recovered is the same as the owner, indicating that it was a valid signature. -- If the address is different, it returns the fail value indicating that the signature is not valid. +- If the address is different, it returns the `_ERC1271_FAILVALUE` indicating that the signature is not valid. 2. If the owner is a smart contract, it forwards the call of [`isValidSignature()`](#isvalidsignature) to the owner contract: -- If the contract fails or returns the fail value, the [`isValidSignature()`](#isvalidsignature) on the account returns the fail value, indicating that the signature is not valid. +- If the contract fails or returns the `_ERC1271_FAILVALUE`, the [`isValidSignature()`](#isvalidsignature) on the account returns the `_ERC1271_FAILVALUE`, indicating that the signature is not valid. -- If the [`isValidSignature()`](#isvalidsignature) on the owner returned the `magicValue`, the [`isValidSignature()`](#isvalidsignature) on the account returns the `magicValue`, indicating that it's a valid signature. +- If the [`isValidSignature()`](#isvalidsignature) on the owner returned the `_ERC1271_SUCCESSVALUE`, the [`isValidSignature()`](#isvalidsignature) on the account returns the `_ERC1271_SUCCESSVALUE`, indicating that it's a valid signature. #### Parameters @@ -462,9 +462,9 @@ Handles two cases: #### Returns -| Name | Type | Description | -| ------------ | :------: | ----------------------------------------------------------------- | -| `magicValue` | `bytes4` | A `bytes4` value that indicates if the signature is valid or not. | +| Name | Type | Description | +| ---------------- | :------: | ----------------------------------------------------------------- | +| `returnedStatus` | `bytes4` | A `bytes4` value that indicates if the signature is valid or not. |
@@ -1135,8 +1135,8 @@ function _verifyCall( ``` Calls [`lsp20VerifyCall`](#lsp20verifycall) function on the logicVerifier. -Reverts in case the value returned does not match the magic value (lsp20VerifyCall selector) -Returns whether a verification after the execution should happen based on the last byte of the magicValue +Reverts in case the value returned does not match the success value (lsp20VerifyCall selector) +Returns whether a verification after the execution should happen based on the last byte of the returnedStatus
@@ -1150,7 +1150,7 @@ function _verifyCallResult( ``` Calls [`lsp20VerifyCallResult`](#lsp20verifycallresult) function on the logicVerifier. -Reverts in case the value returned does not match the magic value (lsp20VerifyCallResult selector) +Reverts in case the value returned does not match the success value (lsp20VerifyCallResult selector)
@@ -1688,6 +1688,32 @@ Reverts when pending owner accept ownership in the same transaction of transferr
+### LSP20CallVerificationFailed + +:::note References + +- Specification details: [**UniversalProfile**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-3-UniversalProfile-Metadata.md#lsp20callverificationfailed) +- Solidity implementation: [`UniversalProfile.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/UniversalProfile.sol) +- Error signature: `LSP20CallVerificationFailed(bool,bytes)` +- Error hash: `0x00c28d0f` + +::: + +```solidity +error LSP20CallVerificationFailed(bool postCall, bytes returnedData); +``` + +reverts when the call to the owner does not return the LSP20 success value + +#### Parameters + +| Name | Type | Description | +| -------------- | :-----: | ---------------------------------------------------- | +| `postCall` | `bool` | True if the execution call was done, False otherwise | +| `returnedData` | `bytes` | The data returned by the call to the logic verifier | + +
+ ### LSP20CallingVerifierFailed :::note References @@ -1728,7 +1754,7 @@ reverts when the call to the owner fail with no revert reason error LSP20EOACannotVerifyCall(address logicVerifier); ``` -Reverts when the logic verifier is an Externally Owned Account (EOA) that cannot return the LSP20 magic value. +Reverts when the logic verifier is an Externally Owned Account (EOA) that cannot return the LSP20 success value. #### Parameters @@ -1738,32 +1764,6 @@ Reverts when the logic verifier is an Externally Owned Account (EOA) that cannot
-### LSP20InvalidMagicValue - -:::note References - -- Specification details: [**UniversalProfile**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-3-UniversalProfile-Metadata.md#lsp20invalidmagicvalue) -- Solidity implementation: [`UniversalProfile.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/UniversalProfile.sol) -- Error signature: `LSP20InvalidMagicValue(bool,bytes)` -- Error hash: `0xd088ec40` - -::: - -```solidity -error LSP20InvalidMagicValue(bool postCall, bytes returnedData); -``` - -reverts when the call to the owner does not return the magic value - -#### Parameters - -| Name | Type | Description | -| -------------- | :-----: | ---------------------------------------------------- | -| `postCall` | `bool` | True if the execution call was done, False otherwise | -| `returnedData` | `bytes` | The data returned by the call to the logic verifier | - -
- ### NoExtensionFoundForFunctionSelector :::note References diff --git a/tests/LSP20CallVerification/LSP20CallVerification.behaviour.ts b/tests/LSP20CallVerification/LSP20CallVerification.behaviour.ts index 6ec1ff3d8..c96c659ab 100644 --- a/tests/LSP20CallVerification/LSP20CallVerification.behaviour.ts +++ b/tests/LSP20CallVerification/LSP20CallVerification.behaviour.ts @@ -11,19 +11,19 @@ import { NotImplementingVerifyCall__factory, ImplementingFallback, ImplementingFallback__factory, - FallbackReturnMagicValue, - FallbackReturnMagicValue__factory, - FirstCallReturnExpandedInvalidValue, - FirstCallReturnExpandedInvalidValue__factory, - FirstCallReturnInvalidMagicValue, - FirstCallReturnInvalidMagicValue__factory, + FallbackReturnSuccessValue, + FallbackReturnSuccessValue__factory, + FirstCallReturnExpandedFailValue, + FirstCallReturnExpandedFailValue__factory, + FirstCallReturnFailValue, + FirstCallReturnFailValue__factory, LSP0ERC725Account, ILSP20CallVerifier, ILSP20CallVerifier__factory, } from '../../types'; // constants -import { LSP20_MAGIC_VALUES, OPERATION_TYPES } from '../../constants'; +import { LSP20_SUCCESS_VALUES, OPERATION_TYPES } from '../../constants'; export type LSP20TestContext = { accounts: SignerWithAddress[]; @@ -267,16 +267,16 @@ export const shouldBehaveLikeLSP20 = (buildContext: () => Promise { - let ownerContract: FallbackReturnMagicValue; + describe('that implement the fallback that return the success value', () => { + let ownerContract: FallbackReturnSuccessValue; before('deploying a new owner', async () => { - ownerContract = await new FallbackReturnMagicValue__factory( + ownerContract = await new FallbackReturnSuccessValue__factory( context.deployParams.owner, ).deploy(); @@ -307,10 +307,10 @@ export const shouldBehaveLikeLSP20 = (buildContext: () => Promise { - let ownerContract: FirstCallReturnExpandedInvalidValue; + let ownerContract: FirstCallReturnExpandedFailValue; before('deploying a new owner', async () => { - ownerContract = await new FirstCallReturnExpandedInvalidValue__factory( + ownerContract = await new FirstCallReturnExpandedFailValue__factory( context.deployParams.owner, ).deploy(); @@ -335,15 +335,15 @@ export const shouldBehaveLikeLSP20 = (buildContext: () => Promise { - let ownerContract: FirstCallReturnInvalidMagicValue; + describe("that implements verifyCall but doesn't return success value", () => { + let ownerContract: FirstCallReturnFailValue; before('deploying a new owner', async () => { - ownerContract = await new FirstCallReturnInvalidMagicValue__factory( + ownerContract = await new FirstCallReturnFailValue__factory( context.deployParams.owner, ).deploy(); @@ -367,23 +367,23 @@ export const shouldBehaveLikeLSP20 = (buildContext: () => Promise { - let firstCallReturnMagicValueContract: FakeContract; + describe("that implements verifyCall that returns a valid success value but doesn't invoke verifyCallResult", () => { + let firstCallReturnSuccessValueContract: FakeContract; let newUniversalProfile: UniversalProfile; before(async () => { - firstCallReturnMagicValueContract = await smock.fake(ILSP20CallVerifier__factory.abi); - firstCallReturnMagicValueContract.lsp20VerifyCall.returns( - LSP20_MAGIC_VALUES.VERIFY_CALL.NO_POST_VERIFICATION, + firstCallReturnSuccessValueContract = await smock.fake(ILSP20CallVerifier__factory.abi); + firstCallReturnSuccessValueContract.lsp20VerifyCall.returns( + LSP20_SUCCESS_VALUES.VERIFY_CALL.NO_POST_VERIFICATION, ); newUniversalProfile = await new UniversalProfile__factory(context.accounts[0]).deploy( - firstCallReturnMagicValueContract.address, + firstCallReturnSuccessValueContract.address, ); }); @@ -400,21 +400,21 @@ export const shouldBehaveLikeLSP20 = (buildContext: () => Promise { - let firstCallReturnMagicValueContract: FakeContract; + describe('that implements verifyCall that returns a valid success value with additional data after the first 32 bytes', () => { + let firstCallReturnSuccessValueContract: FakeContract; let newUniversalProfile: UniversalProfile; before(async () => { - firstCallReturnMagicValueContract = await smock.fake(ILSP20CallVerifier__factory.abi); - firstCallReturnMagicValueContract.lsp20VerifyCall.returns( - LSP20_MAGIC_VALUES.VERIFY_CALL.NO_POST_VERIFICATION + + firstCallReturnSuccessValueContract = await smock.fake(ILSP20CallVerifier__factory.abi); + firstCallReturnSuccessValueContract.lsp20VerifyCall.returns( + LSP20_SUCCESS_VALUES.VERIFY_CALL.NO_POST_VERIFICATION + '0'.repeat(56) + '0xcafecafecafecafecafecafecafecafecafecafe' + '0'.repeat(24), ); newUniversalProfile = await new UniversalProfile__factory(context.accounts[0]).deploy( - firstCallReturnMagicValueContract.address, + firstCallReturnSuccessValueContract.address, ); }); @@ -433,21 +433,21 @@ export const shouldBehaveLikeLSP20 = (buildContext: () => Promise { - let bothCallReturnMagicValueContract: FakeContract; + describe('that implements verifyCall and verifyCallResult and both return success value', () => { + let bothCallReturnSuccessValueContract: FakeContract; let newUniversalProfile: UniversalProfile; before(async () => { - bothCallReturnMagicValueContract = await smock.fake(ILSP20CallVerifier__factory.abi); - bothCallReturnMagicValueContract.lsp20VerifyCall.returns( - LSP20_MAGIC_VALUES.VERIFY_CALL.WITH_POST_VERIFICATION, + bothCallReturnSuccessValueContract = await smock.fake(ILSP20CallVerifier__factory.abi); + bothCallReturnSuccessValueContract.lsp20VerifyCall.returns( + LSP20_SUCCESS_VALUES.VERIFY_CALL.WITH_POST_VERIFICATION, ); - bothCallReturnMagicValueContract.lsp20VerifyCallResult.returns( - LSP20_MAGIC_VALUES.VERIFY_CALL_RESULT, + bothCallReturnSuccessValueContract.lsp20VerifyCallResult.returns( + LSP20_SUCCESS_VALUES.VERIFY_CALL_RESULT, ); newUniversalProfile = await new UniversalProfile__factory(context.accounts[0]).deploy( - bothCallReturnMagicValueContract.address, + bothCallReturnSuccessValueContract.address, ); }); @@ -464,27 +464,27 @@ export const shouldBehaveLikeLSP20 = (buildContext: () => Promise { - let bothCallReturnMagicValueContract: FakeContract; + describe('that implements verifyCall and verifyCallResult and both return success value plus additional data', () => { + let bothCallReturnSuccessValueContract: FakeContract; let newUniversalProfile: UniversalProfile; before(async () => { - bothCallReturnMagicValueContract = await smock.fake(ILSP20CallVerifier__factory.abi); - bothCallReturnMagicValueContract.lsp20VerifyCall.returns( - LSP20_MAGIC_VALUES.VERIFY_CALL.WITH_POST_VERIFICATION + + bothCallReturnSuccessValueContract = await smock.fake(ILSP20CallVerifier__factory.abi); + bothCallReturnSuccessValueContract.lsp20VerifyCall.returns( + LSP20_SUCCESS_VALUES.VERIFY_CALL.WITH_POST_VERIFICATION + '0'.repeat(56) + '0xcafecafecafecafecafecafecafecafecafecafe' + '0'.repeat(24), ); - bothCallReturnMagicValueContract.lsp20VerifyCallResult.returns( - LSP20_MAGIC_VALUES.VERIFY_CALL_RESULT + + bothCallReturnSuccessValueContract.lsp20VerifyCallResult.returns( + LSP20_SUCCESS_VALUES.VERIFY_CALL_RESULT + '0'.repeat(56) + '0xcafecafecafecafecafecafecafecafecafecafe' + '0'.repeat(24), ); newUniversalProfile = await new UniversalProfile__factory(context.accounts[0]).deploy( - bothCallReturnMagicValueContract.address, + bothCallReturnSuccessValueContract.address, ); }); @@ -503,14 +503,14 @@ export const shouldBehaveLikeLSP20 = (buildContext: () => Promise { + describe('that implements verifyCallResult but return fail value', () => { let secondCallReturnFailureContract: FakeContract; let newUniversalProfile: UniversalProfile; before(async () => { secondCallReturnFailureContract = await smock.fake(ILSP20CallVerifier__factory.abi); secondCallReturnFailureContract.lsp20VerifyCall.returns( - LSP20_MAGIC_VALUES.VERIFY_CALL.WITH_POST_VERIFICATION, + LSP20_SUCCESS_VALUES.VERIFY_CALL.WITH_POST_VERIFICATION, ); secondCallReturnFailureContract.lsp20VerifyCallResult.returns('0x00000000'); @@ -525,23 +525,23 @@ export const shouldBehaveLikeLSP20 = (buildContext: () => Promise { + describe('that implements verifyCallResult but return an expanded success value', () => { let secondCallReturnExpandedValueContract: FakeContract; let newUniversalProfile: UniversalProfile; before(async () => { secondCallReturnExpandedValueContract = await smock.fake(ILSP20CallVerifier__factory.abi); secondCallReturnExpandedValueContract.lsp20VerifyCall.returns( - LSP20_MAGIC_VALUES.VERIFY_CALL.WITH_POST_VERIFICATION, + LSP20_SUCCESS_VALUES.VERIFY_CALL.WITH_POST_VERIFICATION, ); secondCallReturnExpandedValueContract.lsp20VerifyCallResult.returns( ethers.utils.solidityPack( ['bytes4', 'bytes28'], - [LSP20_MAGIC_VALUES.VERIFY_CALL_RESULT, '0x' + '0'.repeat(56)], + [LSP20_SUCCESS_VALUES.VERIFY_CALL_RESULT, '0x' + '0'.repeat(56)], ), ); diff --git a/tests/LSP20CallVerification/LSP6/Interactions/AllowedStandards.test.ts b/tests/LSP20CallVerification/LSP6/Interactions/AllowedStandards.test.ts index 4fc81668d..bef718983 100644 --- a/tests/LSP20CallVerification/LSP6/Interactions/AllowedStandards.test.ts +++ b/tests/LSP20CallVerification/LSP6/Interactions/AllowedStandards.test.ts @@ -130,7 +130,7 @@ export const shouldBehaveLikeAllowedStandards = (buildContext: () => Promise { @@ -163,7 +163,7 @@ export const shouldBehaveLikeAllowedStandards = (buildContext: () => Promise Promise { @@ -60,7 +60,7 @@ export const shouldBehaveLikePermissionSign = (buildContext: () => Promise Promise { @@ -87,7 +87,7 @@ export const shouldBehaveLikePermissionSign = (buildContext: () => Promise Promise { @@ -185,7 +185,7 @@ export const shouldBehaveLikeAllowedStandards = (buildContext: () => Promise { diff --git a/tests/LSP6KeyManager/LSP6ControlledToken.test.ts b/tests/LSP6KeyManager/LSP6ControlledToken.test.ts index 3254e30f2..53f0e94b2 100644 --- a/tests/LSP6KeyManager/LSP6ControlledToken.test.ts +++ b/tests/LSP6KeyManager/LSP6ControlledToken.test.ts @@ -677,7 +677,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { const signature = await addressCanSign.signMessage('Some random message'); const validityOfTheSig = await context.keyManager.isValidSignature(dataHash, signature); - expect(validityOfTheSig).to.equal(ERC1271_VALUES.MAGIC_VALUE); + expect(validityOfTheSig).to.equal(ERC1271_VALUES.SUCCESS_VALUE); }); it('should not be allowed to sign messages for the token contract', async () => { diff --git a/tests/UniversalProfile.behaviour.ts b/tests/UniversalProfile.behaviour.ts index 1831cc4ad..758a33550 100644 --- a/tests/UniversalProfile.behaviour.ts +++ b/tests/UniversalProfile.behaviour.ts @@ -48,7 +48,7 @@ export const shouldBehaveLikeLSP3 = ( const signature = await signer.signMessage(dataToSign); const result = await context.universalProfile.isValidSignature(messageHash, signature); - expect(result).to.equal(ERC1271_VALUES.MAGIC_VALUE); + expect(result).to.equal(ERC1271_VALUES.SUCCESS_VALUE); }); it('should return fail value when verifying signature from non-owner', async () => { From 06b1f04f83158f27efb19670ed81f566d7b151ba Mon Sep 17 00:00:00 2001 From: b00ste Date: Thu, 12 Oct 2023 12:09:29 +0300 Subject: [PATCH 49/55] fix: bug in dodoc config, incorrect signature --- dodoc/config.ts | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/dodoc/config.ts b/dodoc/config.ts index 9ac28dc9a..d9f4059c8 100644 --- a/dodoc/config.ts +++ b/dodoc/config.ts @@ -194,21 +194,36 @@ const formatTextWithLists = (textToFormat: string) => { return formatedText; }; +const removeParameterNames = (content: string) => { + return content + .split(',') + .map((elem) => { + const trimmedElem = elem.trim(); + + if (trimmedElem.includes(' ')) { + return trimmedElem.substring(0, elem.trim().indexOf(' ')); + } else { + return trimmedElem; + } + }) + .toString(); +}; + const formatCode = (code: string, type: string) => { - let formatedCode = code + let formattedCode = code .substring(0, code.indexOf(')') + 1) .replace(`${type.toLowerCase()}`, '') .trim(); - if (!formatedCode.endsWith('()')) { - formatedCode = - formatedCode - .split(',') - .map((elem) => elem.trim().substring(0, elem.trim().indexOf(' '))) - .toString() + ')'; + if (!formattedCode.endsWith('()')) { + const start = `${formattedCode.split('(')[0]}(`; + const end = ')'; + const middle = formattedCode.replace(start, '').replace(end, ''); + + formattedCode = start + removeParameterNames(middle) + end; } - return formatedCode; + return formattedCode; }; const formatBulletPointsWithTitle = (textToFormat: string, title: string) => { From 777dd50cb876bd08cb487ffbcac799b03f2cb14d Mon Sep 17 00:00:00 2001 From: b00ste Date: Fri, 13 Oct 2023 16:47:26 +0300 Subject: [PATCH 50/55] chore: generate docs --- docs/contracts/LSP17Extensions/Extension4337.md | 4 ++-- docs/contracts/LSP17Extensions/OnERC721ReceivedExtension.md | 6 +++--- .../LSP1UniversalReceiverDelegateUP.md | 4 ++-- .../LSP1UniversalReceiverDelegateVault.md | 4 ++-- docs/contracts/LSP6KeyManager/LSP6KeyManager.md | 6 +++--- .../extensions/LSP8CompatibleERC721.md | 6 +++--- .../presets/LSP8CompatibleERC721Mintable.md | 6 +++--- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/contracts/LSP17Extensions/Extension4337.md b/docs/contracts/LSP17Extensions/Extension4337.md index 9c8b510c2..d54e97a2e 100644 --- a/docs/contracts/LSP17Extensions/Extension4337.md +++ b/docs/contracts/LSP17Extensions/Extension4337.md @@ -102,8 +102,8 @@ See [`IERC165-supportsInterface`](#ierc165-supportsinterface). - Specification details: [**LSP-17-Extensions**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-17-Extensions.md#validateuserop) - Solidity implementation: [`Extension4337.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP17Extensions/Extension4337.sol) -- Function signature: `validateUserOp(UserOperation,bytes32,)` -- Function selector: `0x68159319` +- Function signature: `validateUserOp(UserOperation,bytes32,uint256)` +- Function selector: `0xe86fc51e` ::: diff --git a/docs/contracts/LSP17Extensions/OnERC721ReceivedExtension.md b/docs/contracts/LSP17Extensions/OnERC721ReceivedExtension.md index d40d353e2..1f504f9a8 100644 --- a/docs/contracts/LSP17Extensions/OnERC721ReceivedExtension.md +++ b/docs/contracts/LSP17Extensions/OnERC721ReceivedExtension.md @@ -25,10 +25,10 @@ When marked as 'public', a method can be called both externally and internally, :::note References -- Specification details: [**LSP-17-Extensions**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-17-Extensions.md#,,,)) +- Specification details: [**LSP-17-Extensions**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-17-Extensions.md#onerc721received) - Solidity implementation: [`OnERC721ReceivedExtension.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP17Extensions/OnERC721ReceivedExtension.sol) -- Function signature: `,,,)` -- Function selector: `0x940e0af1` +- Function signature: `onERC721Received(address,address,uint256,bytes)` +- Function selector: `0x150b7a02` ::: diff --git a/docs/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.md b/docs/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.md index 63c0cd716..adb4cc5cd 100644 --- a/docs/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.md +++ b/docs/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.md @@ -64,8 +64,8 @@ See [`IERC165-supportsInterface`](#ierc165-supportsinterface). - Specification details: [**LSP-1-UniversalReceiver**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-1-UniversalReceiver.md#universalreceiverdelegate) - Solidity implementation: [`LSP1UniversalReceiverDelegateUP.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol) -- Function signature: `universalReceiverDelegate(address,,bytes32,)` -- Function selector: `0xba924425` +- Function signature: `universalReceiverDelegate(address,uint256,bytes32,bytes)` +- Function selector: `0xa245bbda` ::: diff --git a/docs/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.md b/docs/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.md index d90649263..3e50d0f82 100644 --- a/docs/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.md +++ b/docs/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.md @@ -62,8 +62,8 @@ See [`IERC165-supportsInterface`](#ierc165-supportsinterface). - Specification details: [**LSP-1-UniversalReceiver**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-1-UniversalReceiver.md#universalreceiverdelegate) - Solidity implementation: [`LSP1UniversalReceiverDelegateVault.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol) -- Function signature: `universalReceiverDelegate(address,,bytes32,)` -- Function selector: `0xba924425` +- Function signature: `universalReceiverDelegate(address,uint256,bytes32,bytes)` +- Function selector: `0xa245bbda` ::: diff --git a/docs/contracts/LSP6KeyManager/LSP6KeyManager.md b/docs/contracts/LSP6KeyManager/LSP6KeyManager.md index 6cbd38e0a..0dece3ec2 100644 --- a/docs/contracts/LSP6KeyManager/LSP6KeyManager.md +++ b/docs/contracts/LSP6KeyManager/LSP6KeyManager.md @@ -376,10 +376,10 @@ function lsp20VerifyCall( :::note References -- Specification details: [**LSP-6-KeyManager**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-6-KeyManager.md#,)) +- Specification details: [**LSP-6-KeyManager**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-6-KeyManager.md#lsp20verifycallresult) - Solidity implementation: [`LSP6KeyManager.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP6KeyManager/LSP6KeyManager.sol) -- Function signature: `,)` -- Function selector: `0x9f47dbd3` +- Function signature: `lsp20VerifyCallResult(bytes32,bytes)` +- Function selector: `0xd3fc45d3` ::: diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md index 9e566f38f..a4ff839c0 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md @@ -835,10 +835,10 @@ Returns the list of `tokenIds` for the `tokenOwner` address. :::note References -- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#)) +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#tokenuri) - Solidity implementation: [`LSP8CompatibleERC721.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol) -- Function signature: `)` -- Function selector: `0x59d76dc3` +- Function signature: `tokenURI(uint256)` +- Function selector: `0xc87b56dd` ::: diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md index b881c0643..7b2621f5e 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md @@ -877,10 +877,10 @@ Returns the list of `tokenIds` for the `tokenOwner` address. :::note References -- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#)) +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#tokenuri) - Solidity implementation: [`LSP8CompatibleERC721Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol) -- Function signature: `)` -- Function selector: `0x59d76dc3` +- Function signature: `tokenURI(uint256)` +- Function selector: `0xc87b56dd` ::: From 804779a5f7ac76b21695a00c622a7c0e5801192a Mon Sep 17 00:00:00 2001 From: Skima Harvey <64636974+skimaharvey@users.noreply.github.com> Date: Tue, 17 Oct 2023 10:33:41 +0100 Subject: [PATCH 51/55] feat: add lsp20 to acceptOwnership (#747) * feat: add lsp20 to acceptOwnership * refactor: make lsp14 variables internals * test: update test with lsp20 & acceptOwnership * perf: replace revert reason string with custom error for Not Pending Owner * refactor: rename LSP14 custom errors names * refactor: move verifyAfter after notification * test: update foundry tests * docs: update docs * test: move tests in LSP20/LSP6 * test: update error message in test * test: fix error message in LSP20 tests --------- Co-authored-by: CJ42 --- .../LSP0ERC725AccountCore.sol | 22 ++- contracts/LSP14Ownable2Step/LSP14Errors.sol | 10 +- .../LSP14Ownable2Step/LSP14Ownable2Step.sol | 20 +-- contracts/LSP6KeyManager/LSP6Errors.sol | 17 +-- .../LSP0ERC725Account/LSP0ERC725Account.md | 129 +++++++++++------- .../LSP14Ownable2Step/LSP14Ownable2Step.md | 45 ++++-- .../LSP6KeyManager/LSP6KeyManager.md | 4 +- docs/contracts/LSP9Vault/LSP9Vault.md | 129 +++++++++++------- docs/contracts/UniversalProfile.md | 129 +++++++++++------- .../LSP14Ownable2Step.behaviour.ts | 12 +- .../LSP20WithLSP14.behaviour.ts | 22 +-- .../LSP6/Admin/PermissionChangeOwner.test.ts | 56 +++++--- .../Admin/PermissionChangeOwner.test.ts | 11 +- .../TwoStepRenounceOwnership.sol | 11 +- 14 files changed, 380 insertions(+), 237 deletions(-) diff --git a/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol b/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol index 61f45c6bb..4ff55adb7 100644 --- a/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol +++ b/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol @@ -561,8 +561,20 @@ abstract contract LSP0ERC725AccountCore is */ function acceptOwnership() public virtual override NotInTransferOwnership { address previousOwner = owner(); + address pendingOwnerAddress = pendingOwner(); - _acceptOwnership(); + bool verifyAfter; + + if (msg.sender != pendingOwnerAddress) { + // If the caller is not the owner, call {lsp20VerifyCall} on the pending owner + // Depending on the successStatus returned, a second call is done after transferring ownership + verifyAfter = _verifyCall(pendingOwnerAddress); + + _setOwner(pendingOwnerAddress); + delete _pendingOwner; + } else { + _acceptOwnership(); + } // notify the previous owner if supports LSP1 previousOwner.tryNotifyUniversalReceiver( @@ -571,10 +583,16 @@ abstract contract LSP0ERC725AccountCore is ); // notify the pending owner if supports LSP1 - msg.sender.tryNotifyUniversalReceiver( + pendingOwnerAddress.tryNotifyUniversalReceiver( _TYPEID_LSP0_OwnershipTransferred_RecipientNotification, "" ); + + // If msg.sender != pendingOwnerAddress & verifyAfter is true, Call {lsp20VerifyCallResult} on the new owner + // The transferOwnership function does not return, second parameter of {_verifyCallResult} will be empty + if (verifyAfter) { + _verifyCallResult(pendingOwnerAddress, ""); + } } /** diff --git a/contracts/LSP14Ownable2Step/LSP14Errors.sol b/contracts/LSP14Ownable2Step/LSP14Errors.sol index 55a004a40..2544f9f44 100644 --- a/contracts/LSP14Ownable2Step/LSP14Errors.sol +++ b/contracts/LSP14Ownable2Step/LSP14Errors.sol @@ -8,7 +8,7 @@ pragma solidity ^0.8.4; * @param renounceOwnershipStart The start timestamp when one can confirm the renouncement of ownership. * @param renounceOwnershipEnd The end timestamp when one can confirm the renouncement of ownership. */ -error NotInRenounceOwnershipInterval( +error LSP14NotInRenounceOwnershipInterval( uint256 renounceOwnershipStart, uint256 renounceOwnershipEnd ); @@ -17,10 +17,16 @@ error NotInRenounceOwnershipInterval( * @dev Reverts when trying to transfer ownership to the `address(this)`. * @notice Cannot transfer ownership to the address of the contract itself. */ -error CannotTransferOwnershipToSelf(); +error LSP14CannotTransferOwnershipToSelf(); /** * @dev Reverts when pending owner accept ownership in the same transaction of transferring ownership. * @notice Cannot accept ownership in the same transaction with {transferOwnership(...)}. */ error LSP14MustAcceptOwnershipInSeparateTransaction(); + +/** + * @dev Reverts when the `caller` that is trying to accept ownership of the contract is not the pending owner. + * @param caller The address that tried to accept ownership. + */ +error LSP14CallerNotPendingOwner(address caller); diff --git a/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol b/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol index b9dd4cf42..124eb1a75 100644 --- a/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol +++ b/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol @@ -14,9 +14,10 @@ import {LSP1Utils} from "../LSP1UniversalReceiver/LSP1Utils.sol"; // errors import { + LSP14CallerNotPendingOwner, LSP14MustAcceptOwnershipInSeparateTransaction, - CannotTransferOwnershipToSelf, - NotInRenounceOwnershipInterval + LSP14CannotTransferOwnershipToSelf, + LSP14NotInRenounceOwnershipInterval } from "./LSP14Errors.sol"; // constants @@ -49,12 +50,12 @@ abstract contract LSP14Ownable2Step is ILSP14Ownable2Step, OwnableUnset { /** * @dev The block number saved when initiating the process of renouncing ownerhsip. */ - uint256 private _renounceOwnershipStartedAt; + uint256 internal _renounceOwnershipStartedAt; /** * @dev see {pendingOwner()} */ - address private _pendingOwner; + address internal _pendingOwner; /** * @dev The boolean that indicates whether the contract is in an active ownership transfer phase @@ -158,7 +159,8 @@ abstract contract LSP14Ownable2Step is ILSP14Ownable2Step, OwnableUnset { * @custom:requirements `newOwner` cannot be the address of the contract itself. */ function _transferOwnership(address newOwner) internal virtual { - if (newOwner == address(this)) revert CannotTransferOwnershipToSelf(); + if (newOwner == address(this)) + revert LSP14CannotTransferOwnershipToSelf(); _pendingOwner = newOwner; delete _renounceOwnershipStartedAt; @@ -168,10 +170,8 @@ abstract contract LSP14Ownable2Step is ILSP14Ownable2Step, OwnableUnset { * @dev Set the pending owner of the contract as the new owner. */ function _acceptOwnership() internal virtual { - require( - msg.sender == pendingOwner(), - "LSP14: caller is not the pendingOwner" - ); + if (msg.sender != pendingOwner()) + revert LSP14CallerNotPendingOwner(msg.sender); _setOwner(msg.sender); delete _pendingOwner; @@ -200,7 +200,7 @@ abstract contract LSP14Ownable2Step is ILSP14Ownable2Step, OwnableUnset { } if (currentBlock < confirmationPeriodStart) { - revert NotInRenounceOwnershipInterval( + revert LSP14NotInRenounceOwnershipInterval( confirmationPeriodStart, confirmationPeriodEnd ); diff --git a/contracts/LSP6KeyManager/LSP6Errors.sol b/contracts/LSP6KeyManager/LSP6Errors.sol index c0c1e8ea1..924c16068 100644 --- a/contracts/LSP6KeyManager/LSP6Errors.sol +++ b/contracts/LSP6KeyManager/LSP6Errors.sol @@ -73,8 +73,9 @@ error InvalidRelayNonce(address signer, uint256 invalidNonce, bytes signature); * - `setData(bytes32,bytes)` (ERC725Y) * - `setDataBatch(bytes32[],bytes[])` (ERC725Y) * - `execute(uint256,address,uint256,bytes)` (ERC725X) - * - `transferOwnership(address)` + * - `transferOwnership(address)` (LSP14) * - `acceptOwnership()` (LSP14) + * - `renounceOwnership()` (LSP14) * * @param invalidFunction The `bytes4` selector of the function that was attempted * to be called on the linked {target} but not recognised. @@ -206,20 +207,6 @@ error InvalidPayload(bytes payload); */ error CallingKeyManagerNotAllowed(); -/** - * @notice Relay call not valid yet. - * - * @dev Reverts when the start timestamp provided to {executeRelayCall} function is bigger than the current timestamp. - */ -error RelayCallBeforeStartTime(); - -/** - * @notice The date of the relay call expired. - * - * @dev Reverts when the period to execute the relay call has expired. - */ -error RelayCallExpired(); - /** * @notice Key Manager cannot be used as an LSP17 extension for LSP20 functions. * diff --git a/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md b/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md index 37453c285..2e402df28 100644 --- a/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md +++ b/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md @@ -1481,27 +1481,6 @@ Emitted when receiving native tokens. ## Errors -### CannotTransferOwnershipToSelf - -:::note References - -- Specification details: [**LSP-0-ERC725Account**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-0-ERC725Account.md#cannottransferownershiptoself) -- Solidity implementation: [`LSP0ERC725Account.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP0ERC725Account/LSP0ERC725Account.sol) -- Error signature: `CannotTransferOwnershipToSelf()` -- Error hash: `0x43b248cd` - -::: - -```solidity -error CannotTransferOwnershipToSelf(); -``` - -_Cannot transfer ownership to the address of the contract itself._ - -Reverts when trying to transfer ownership to the `address(this)`. - -
- ### ERC725X_ContractDeploymentFailed :::note References @@ -1724,6 +1703,52 @@ Reverts when there is not the same number of elements in the `datakeys` and `dat
+### LSP14CallerNotPendingOwner + +:::note References + +- Specification details: [**LSP-0-ERC725Account**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-0-ERC725Account.md#lsp14callernotpendingowner) +- Solidity implementation: [`LSP0ERC725Account.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP0ERC725Account/LSP0ERC725Account.sol) +- Error signature: `LSP14CallerNotPendingOwner(address)` +- Error hash: `0x451e4528` + +::: + +```solidity +error LSP14CallerNotPendingOwner(address caller); +``` + +Reverts when the `caller` that is trying to accept ownership of the contract is not the pending owner. + +#### Parameters + +| Name | Type | Description | +| -------- | :-------: | ------------------------------------------- | +| `caller` | `address` | The address that tried to accept ownership. | + +
+ +### LSP14CannotTransferOwnershipToSelf + +:::note References + +- Specification details: [**LSP-0-ERC725Account**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-0-ERC725Account.md#lsp14cannottransferownershiptoself) +- Solidity implementation: [`LSP0ERC725Account.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP0ERC725Account/LSP0ERC725Account.sol) +- Error signature: `LSP14CannotTransferOwnershipToSelf()` +- Error hash: `0xe052a6f8` + +::: + +```solidity +error LSP14CannotTransferOwnershipToSelf(); +``` + +_Cannot transfer ownership to the address of the contract itself._ + +Reverts when trying to transfer ownership to the `address(this)`. + +
+ ### LSP14MustAcceptOwnershipInSeparateTransaction :::note References @@ -1745,6 +1770,37 @@ Reverts when pending owner accept ownership in the same transaction of transferr
+### LSP14NotInRenounceOwnershipInterval + +:::note References + +- Specification details: [**LSP-0-ERC725Account**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-0-ERC725Account.md#lsp14notinrenounceownershipinterval) +- Solidity implementation: [`LSP0ERC725Account.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP0ERC725Account/LSP0ERC725Account.sol) +- Error signature: `LSP14NotInRenounceOwnershipInterval(uint256,uint256)` +- Error hash: `0x1b080942` + +::: + +```solidity +error LSP14NotInRenounceOwnershipInterval( + uint256 renounceOwnershipStart, + uint256 renounceOwnershipEnd +); +``` + +_Cannot confirm ownership renouncement yet. The ownership renouncement is allowed from: `renounceOwnershipStart` until: `renounceOwnershipEnd`._ + +Reverts when trying to renounce ownership before the initial confirmation delay. + +#### Parameters + +| Name | Type | Description | +| ------------------------ | :-------: | ----------------------------------------------------------------------- | +| `renounceOwnershipStart` | `uint256` | The start timestamp when one can confirm the renouncement of ownership. | +| `renounceOwnershipEnd` | `uint256` | The end timestamp when one can confirm the renouncement of ownership. | + +
+ ### LSP20CallVerificationFailed :::note References @@ -1845,34 +1901,3 @@ reverts when there is no extension for the function selector being called with | `functionSelector` | `bytes4` | - |
- -### NotInRenounceOwnershipInterval - -:::note References - -- Specification details: [**LSP-0-ERC725Account**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-0-ERC725Account.md#notinrenounceownershipinterval) -- Solidity implementation: [`LSP0ERC725Account.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP0ERC725Account/LSP0ERC725Account.sol) -- Error signature: `NotInRenounceOwnershipInterval(uint256,uint256)` -- Error hash: `0x8b9bf507` - -::: - -```solidity -error NotInRenounceOwnershipInterval( - uint256 renounceOwnershipStart, - uint256 renounceOwnershipEnd -); -``` - -_Cannot confirm ownership renouncement yet. The ownership renouncement is allowed from: `renounceOwnershipStart` until: `renounceOwnershipEnd`._ - -Reverts when trying to renounce ownership before the initial confirmation delay. - -#### Parameters - -| Name | Type | Description | -| ------------------------ | :-------: | ----------------------------------------------------------------------- | -| `renounceOwnershipStart` | `uint256` | The start timestamp when one can confirm the renouncement of ownership. | -| `renounceOwnershipEnd` | `uint256` | The end timestamp when one can confirm the renouncement of ownership. | - -
diff --git a/docs/contracts/LSP14Ownable2Step/LSP14Ownable2Step.md b/docs/contracts/LSP14Ownable2Step/LSP14Ownable2Step.md index cd4120269..2812d816a 100644 --- a/docs/contracts/LSP14Ownable2Step/LSP14Ownable2Step.md +++ b/docs/contracts/LSP14Ownable2Step/LSP14Ownable2Step.md @@ -403,19 +403,44 @@ Emitted when starting the [`renounceOwnership(..)`](#renounceownership) 2-step p ## Errors -### CannotTransferOwnershipToSelf +### LSP14CallerNotPendingOwner :::note References -- Specification details: [**LSP-14-Ownable2Step**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-14-Ownable2Step.md#cannottransferownershiptoself) +- Specification details: [**LSP-14-Ownable2Step**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-14-Ownable2Step.md#lsp14callernotpendingowner) - Solidity implementation: [`LSP14Ownable2Step.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol) -- Error signature: `CannotTransferOwnershipToSelf()` -- Error hash: `0x43b248cd` +- Error signature: `LSP14CallerNotPendingOwner(address)` +- Error hash: `0x451e4528` ::: ```solidity -error CannotTransferOwnershipToSelf(); +error LSP14CallerNotPendingOwner(address caller); +``` + +Reverts when the `caller` that is trying to accept ownership of the contract is not the pending owner. + +#### Parameters + +| Name | Type | Description | +| -------- | :-------: | ------------------------------------------- | +| `caller` | `address` | The address that tried to accept ownership. | + +
+ +### LSP14CannotTransferOwnershipToSelf + +:::note References + +- Specification details: [**LSP-14-Ownable2Step**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-14-Ownable2Step.md#lsp14cannottransferownershiptoself) +- Solidity implementation: [`LSP14Ownable2Step.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol) +- Error signature: `LSP14CannotTransferOwnershipToSelf()` +- Error hash: `0xe052a6f8` + +::: + +```solidity +error LSP14CannotTransferOwnershipToSelf(); ``` _Cannot transfer ownership to the address of the contract itself._ @@ -445,19 +470,19 @@ Reverts when pending owner accept ownership in the same transaction of transferr
-### NotInRenounceOwnershipInterval +### LSP14NotInRenounceOwnershipInterval :::note References -- Specification details: [**LSP-14-Ownable2Step**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-14-Ownable2Step.md#notinrenounceownershipinterval) +- Specification details: [**LSP-14-Ownable2Step**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-14-Ownable2Step.md#lsp14notinrenounceownershipinterval) - Solidity implementation: [`LSP14Ownable2Step.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol) -- Error signature: `NotInRenounceOwnershipInterval(uint256,uint256)` -- Error hash: `0x8b9bf507` +- Error signature: `LSP14NotInRenounceOwnershipInterval(uint256,uint256)` +- Error hash: `0x1b080942` ::: ```solidity -error NotInRenounceOwnershipInterval( +error LSP14NotInRenounceOwnershipInterval( uint256 renounceOwnershipStart, uint256 renounceOwnershipEnd ); diff --git a/docs/contracts/LSP6KeyManager/LSP6KeyManager.md b/docs/contracts/LSP6KeyManager/LSP6KeyManager.md index 0dece3ec2..fe2fd187a 100644 --- a/docs/contracts/LSP6KeyManager/LSP6KeyManager.md +++ b/docs/contracts/LSP6KeyManager/LSP6KeyManager.md @@ -1401,10 +1401,12 @@ Reverts when trying to call a function on the linked [`target`](#target), that i - `execute(uint256,address,uint256,bytes)` (ERC725X) -- `transferOwnership(address)` +- `transferOwnership(address)` (LSP14) - `acceptOwnership()` (LSP14) +- `renounceOwnership()` (LSP14) + #### Parameters | Name | Type | Description | diff --git a/docs/contracts/LSP9Vault/LSP9Vault.md b/docs/contracts/LSP9Vault/LSP9Vault.md index 310e14cf2..e7fc33623 100644 --- a/docs/contracts/LSP9Vault/LSP9Vault.md +++ b/docs/contracts/LSP9Vault/LSP9Vault.md @@ -1398,27 +1398,6 @@ Emitted when receiving native tokens. ## Errors -### CannotTransferOwnershipToSelf - -:::note References - -- Specification details: [**LSP-9-Vault**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-9-Vault.md#cannottransferownershiptoself) -- Solidity implementation: [`LSP9Vault.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP9Vault/LSP9Vault.sol) -- Error signature: `CannotTransferOwnershipToSelf()` -- Error hash: `0x43b248cd` - -::: - -```solidity -error CannotTransferOwnershipToSelf(); -``` - -_Cannot transfer ownership to the address of the contract itself._ - -Reverts when trying to transfer ownership to the `address(this)`. - -
- ### ERC725X_ContractDeploymentFailed :::note References @@ -1622,6 +1601,52 @@ Reverts when sending value to the [`setData`](#setdata) or [`setDataBatch`](#set
+### LSP14CallerNotPendingOwner + +:::note References + +- Specification details: [**LSP-9-Vault**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-9-Vault.md#lsp14callernotpendingowner) +- Solidity implementation: [`LSP9Vault.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP9Vault/LSP9Vault.sol) +- Error signature: `LSP14CallerNotPendingOwner(address)` +- Error hash: `0x451e4528` + +::: + +```solidity +error LSP14CallerNotPendingOwner(address caller); +``` + +Reverts when the `caller` that is trying to accept ownership of the contract is not the pending owner. + +#### Parameters + +| Name | Type | Description | +| -------- | :-------: | ------------------------------------------- | +| `caller` | `address` | The address that tried to accept ownership. | + +
+ +### LSP14CannotTransferOwnershipToSelf + +:::note References + +- Specification details: [**LSP-9-Vault**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-9-Vault.md#lsp14cannottransferownershiptoself) +- Solidity implementation: [`LSP9Vault.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP9Vault/LSP9Vault.sol) +- Error signature: `LSP14CannotTransferOwnershipToSelf()` +- Error hash: `0xe052a6f8` + +::: + +```solidity +error LSP14CannotTransferOwnershipToSelf(); +``` + +_Cannot transfer ownership to the address of the contract itself._ + +Reverts when trying to transfer ownership to the `address(this)`. + +
+ ### LSP14MustAcceptOwnershipInSeparateTransaction :::note References @@ -1643,6 +1668,37 @@ Reverts when pending owner accept ownership in the same transaction of transferr
+### LSP14NotInRenounceOwnershipInterval + +:::note References + +- Specification details: [**LSP-9-Vault**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-9-Vault.md#lsp14notinrenounceownershipinterval) +- Solidity implementation: [`LSP9Vault.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP9Vault/LSP9Vault.sol) +- Error signature: `LSP14NotInRenounceOwnershipInterval(uint256,uint256)` +- Error hash: `0x1b080942` + +::: + +```solidity +error LSP14NotInRenounceOwnershipInterval( + uint256 renounceOwnershipStart, + uint256 renounceOwnershipEnd +); +``` + +_Cannot confirm ownership renouncement yet. The ownership renouncement is allowed from: `renounceOwnershipStart` until: `renounceOwnershipEnd`._ + +Reverts when trying to renounce ownership before the initial confirmation delay. + +#### Parameters + +| Name | Type | Description | +| ------------------------ | :-------: | ----------------------------------------------------------------------- | +| `renounceOwnershipStart` | `uint256` | The start timestamp when one can confirm the renouncement of ownership. | +| `renounceOwnershipEnd` | `uint256` | The end timestamp when one can confirm the renouncement of ownership. | + +
+ ### LSP1DelegateNotAllowedToSetDataKey :::note References @@ -1694,34 +1750,3 @@ reverts when there is no extension for the function selector being called with | `functionSelector` | `bytes4` | - |
- -### NotInRenounceOwnershipInterval - -:::note References - -- Specification details: [**LSP-9-Vault**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-9-Vault.md#notinrenounceownershipinterval) -- Solidity implementation: [`LSP9Vault.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP9Vault/LSP9Vault.sol) -- Error signature: `NotInRenounceOwnershipInterval(uint256,uint256)` -- Error hash: `0x8b9bf507` - -::: - -```solidity -error NotInRenounceOwnershipInterval( - uint256 renounceOwnershipStart, - uint256 renounceOwnershipEnd -); -``` - -_Cannot confirm ownership renouncement yet. The ownership renouncement is allowed from: `renounceOwnershipStart` until: `renounceOwnershipEnd`._ - -Reverts when trying to renounce ownership before the initial confirmation delay. - -#### Parameters - -| Name | Type | Description | -| ------------------------ | :-------: | ----------------------------------------------------------------------- | -| `renounceOwnershipStart` | `uint256` | The start timestamp when one can confirm the renouncement of ownership. | -| `renounceOwnershipEnd` | `uint256` | The end timestamp when one can confirm the renouncement of ownership. | - -
diff --git a/docs/contracts/UniversalProfile.md b/docs/contracts/UniversalProfile.md index 01803f303..022af9d60 100644 --- a/docs/contracts/UniversalProfile.md +++ b/docs/contracts/UniversalProfile.md @@ -1424,27 +1424,6 @@ Emitted when receiving native tokens. ## Errors -### CannotTransferOwnershipToSelf - -:::note References - -- Specification details: [**UniversalProfile**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-3-UniversalProfile-Metadata.md#cannottransferownershiptoself) -- Solidity implementation: [`UniversalProfile.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/UniversalProfile.sol) -- Error signature: `CannotTransferOwnershipToSelf()` -- Error hash: `0x43b248cd` - -::: - -```solidity -error CannotTransferOwnershipToSelf(); -``` - -_Cannot transfer ownership to the address of the contract itself._ - -Reverts when trying to transfer ownership to the `address(this)`. - -
- ### ERC725X_ContractDeploymentFailed :::note References @@ -1667,6 +1646,52 @@ Reverts when there is not the same number of elements in the `datakeys` and `dat
+### LSP14CallerNotPendingOwner + +:::note References + +- Specification details: [**UniversalProfile**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-3-UniversalProfile-Metadata.md#lsp14callernotpendingowner) +- Solidity implementation: [`UniversalProfile.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/UniversalProfile.sol) +- Error signature: `LSP14CallerNotPendingOwner(address)` +- Error hash: `0x451e4528` + +::: + +```solidity +error LSP14CallerNotPendingOwner(address caller); +``` + +Reverts when the `caller` that is trying to accept ownership of the contract is not the pending owner. + +#### Parameters + +| Name | Type | Description | +| -------- | :-------: | ------------------------------------------- | +| `caller` | `address` | The address that tried to accept ownership. | + +
+ +### LSP14CannotTransferOwnershipToSelf + +:::note References + +- Specification details: [**UniversalProfile**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-3-UniversalProfile-Metadata.md#lsp14cannottransferownershiptoself) +- Solidity implementation: [`UniversalProfile.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/UniversalProfile.sol) +- Error signature: `LSP14CannotTransferOwnershipToSelf()` +- Error hash: `0xe052a6f8` + +::: + +```solidity +error LSP14CannotTransferOwnershipToSelf(); +``` + +_Cannot transfer ownership to the address of the contract itself._ + +Reverts when trying to transfer ownership to the `address(this)`. + +
+ ### LSP14MustAcceptOwnershipInSeparateTransaction :::note References @@ -1688,6 +1713,37 @@ Reverts when pending owner accept ownership in the same transaction of transferr
+### LSP14NotInRenounceOwnershipInterval + +:::note References + +- Specification details: [**UniversalProfile**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-3-UniversalProfile-Metadata.md#lsp14notinrenounceownershipinterval) +- Solidity implementation: [`UniversalProfile.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/UniversalProfile.sol) +- Error signature: `LSP14NotInRenounceOwnershipInterval(uint256,uint256)` +- Error hash: `0x1b080942` + +::: + +```solidity +error LSP14NotInRenounceOwnershipInterval( + uint256 renounceOwnershipStart, + uint256 renounceOwnershipEnd +); +``` + +_Cannot confirm ownership renouncement yet. The ownership renouncement is allowed from: `renounceOwnershipStart` until: `renounceOwnershipEnd`._ + +Reverts when trying to renounce ownership before the initial confirmation delay. + +#### Parameters + +| Name | Type | Description | +| ------------------------ | :-------: | ----------------------------------------------------------------------- | +| `renounceOwnershipStart` | `uint256` | The start timestamp when one can confirm the renouncement of ownership. | +| `renounceOwnershipEnd` | `uint256` | The end timestamp when one can confirm the renouncement of ownership. | + +
+ ### LSP20CallVerificationFailed :::note References @@ -1788,34 +1844,3 @@ reverts when there is no extension for the function selector being called with | `functionSelector` | `bytes4` | - |
- -### NotInRenounceOwnershipInterval - -:::note References - -- Specification details: [**UniversalProfile**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-3-UniversalProfile-Metadata.md#notinrenounceownershipinterval) -- Solidity implementation: [`UniversalProfile.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/UniversalProfile.sol) -- Error signature: `NotInRenounceOwnershipInterval(uint256,uint256)` -- Error hash: `0x8b9bf507` - -::: - -```solidity -error NotInRenounceOwnershipInterval( - uint256 renounceOwnershipStart, - uint256 renounceOwnershipEnd -); -``` - -_Cannot confirm ownership renouncement yet. The ownership renouncement is allowed from: `renounceOwnershipStart` until: `renounceOwnershipEnd`._ - -Reverts when trying to renounce ownership before the initial confirmation delay. - -#### Parameters - -| Name | Type | Description | -| ------------------------ | :-------: | ----------------------------------------------------------------------- | -| `renounceOwnershipStart` | `uint256` | The start timestamp when one can confirm the renouncement of ownership. | -| `renounceOwnershipEnd` | `uint256` | The end timestamp when one can confirm the renouncement of ownership. | - -
diff --git a/tests/LSP14Ownable2Step/LSP14Ownable2Step.behaviour.ts b/tests/LSP14Ownable2Step/LSP14Ownable2Step.behaviour.ts index c962c6914..727054d1a 100644 --- a/tests/LSP14Ownable2Step/LSP14Ownable2Step.behaviour.ts +++ b/tests/LSP14Ownable2Step/LSP14Ownable2Step.behaviour.ts @@ -75,7 +75,7 @@ export const shouldBehaveLikeLSP14 = ( context.contract .connect(context.deployParams.owner) .transferOwnership(context.contract.address), - ).to.be.revertedWithCustomError(context.contract, 'CannotTransferOwnershipToSelf'); + ).to.be.revertedWithCustomError(context.contract, 'LSP14CannotTransferOwnershipToSelf'); }); describe('it should still be allowed to call onlyOwner functions', () => { @@ -153,7 +153,7 @@ export const shouldBehaveLikeLSP14 = ( it('should revert when caller is not the pending owner', async () => { await expect( context.contract.connect(context.accounts[2]).acceptOwnership(), - ).to.be.revertedWith('LSP14: caller is not the pendingOwner'); + ).to.be.revertedWithCustomError(context.contract, 'LSP14CallerNotPendingOwner'); }); describe('when caller is the pending owner', () => { @@ -359,7 +359,7 @@ export const shouldBehaveLikeLSP14 = ( await network.provider.send('hardhat_mine', [ethers.utils.hexValue(98)]); await expect(context.contract.connect(context.deployParams.owner).renounceOwnership()) - .to.be.revertedWithCustomError(context.contract, 'NotInRenounceOwnershipInterval') + .to.be.revertedWithCustomError(context.contract, 'LSP14NotInRenounceOwnershipInterval') .withArgs( renounceOwnershipOnceReceipt.blockNumber + 200, renounceOwnershipOnceReceipt.blockNumber + 400, @@ -510,9 +510,9 @@ export const shouldBehaveLikeLSP14 = ( }); it('previous pendingOwner should not be able to call acceptOwnership(...) anymore', async () => { - await expect(context.contract.connect(newOwner).acceptOwnership()).to.be.revertedWith( - 'LSP14: caller is not the pendingOwner', - ); + await expect( + context.contract.connect(newOwner).acceptOwnership(), + ).to.be.revertedWithCustomError(context.contract, 'LSP14CallerNotPendingOwner'); }); }); }); diff --git a/tests/LSP20CallVerification/LSP20WithLSP14.behaviour.ts b/tests/LSP20CallVerification/LSP20WithLSP14.behaviour.ts index de7debaff..bd550f265 100644 --- a/tests/LSP20CallVerification/LSP20WithLSP14.behaviour.ts +++ b/tests/LSP20CallVerification/LSP20WithLSP14.behaviour.ts @@ -6,10 +6,12 @@ import { LSP0ERC725Account, UPWithInstantAcceptOwnership__factory, UPWithInstantAcceptOwnership, + LSP6KeyManager__factory, + LSP6KeyManager, } from '../../types'; // constants -import { OPERATION_TYPES } from '../../constants'; +import { ERC725YDataKeys, OPERATION_TYPES, PERMISSIONS } from '../../constants'; // helpers import { provider } from '../utils/helpers'; @@ -75,7 +77,7 @@ export const shouldBehaveLikeLSP14WithLSP20 = ( context.contract .connect(context.deployParams.owner) .transferOwnership(context.contract.address), - ).to.be.revertedWithCustomError(context.contract, 'CannotTransferOwnershipToSelf'); + ).to.be.revertedWithCustomError(context.contract, 'LSP14CannotTransferOwnershipToSelf'); }); describe('it should still be allowed to call onlyOwner functions', () => { @@ -151,9 +153,10 @@ export const shouldBehaveLikeLSP14WithLSP20 = ( describe('when calling acceptOwnership(...)', () => { it('should revert when caller is not the pending owner', async () => { - await expect( - context.contract.connect(context.accounts[2]).acceptOwnership(), - ).to.be.revertedWith('LSP14: caller is not the pendingOwner'); + const pendingOwner = await context.contract.pendingOwner(); + await expect(context.contract.connect(context.accounts[2]).acceptOwnership()) + .to.be.revertedWithCustomError(context.contract, 'LSP20EOACannotVerifyCall') + .withArgs(pendingOwner); }); describe('when caller is the pending owner', () => { @@ -365,7 +368,7 @@ export const shouldBehaveLikeLSP14WithLSP20 = ( await network.provider.send('hardhat_mine', [ethers.utils.hexValue(98)]); await expect(context.contract.connect(context.deployParams.owner).renounceOwnership()) - .to.be.revertedWithCustomError(context.contract, 'NotInRenounceOwnershipInterval') + .to.be.revertedWithCustomError(context.contract, 'LSP14NotInRenounceOwnershipInterval') .withArgs( renounceOwnershipOnceReceipt.blockNumber + 200, renounceOwnershipOnceReceipt.blockNumber + 400, @@ -521,9 +524,10 @@ export const shouldBehaveLikeLSP14WithLSP20 = ( }); it('previous pendingOwner should not be able to call acceptOwnership(...) anymore', async () => { - await expect(context.contract.connect(newOwner).acceptOwnership()).to.be.revertedWith( - 'LSP14: caller is not the pendingOwner', - ); + const pendingOwner = await context.contract.pendingOwner(); + await expect(context.contract.connect(newOwner).acceptOwnership()) + .to.be.revertedWithCustomError(context.contract, 'LSP20EOACannotVerifyCall') + .withArgs(pendingOwner); }); }); }); diff --git a/tests/LSP20CallVerification/LSP6/Admin/PermissionChangeOwner.test.ts b/tests/LSP20CallVerification/LSP6/Admin/PermissionChangeOwner.test.ts index c89b0cc22..961062800 100644 --- a/tests/LSP20CallVerification/LSP6/Admin/PermissionChangeOwner.test.ts +++ b/tests/LSP20CallVerification/LSP6/Admin/PermissionChangeOwner.test.ts @@ -54,7 +54,10 @@ export const shouldBehaveLikePermissionChangeOwner = ( context.universalProfile .connect(canChangeOwner) .transferOwnership(context.universalProfile.address), - ).to.be.revertedWithCustomError(context.universalProfile, 'CannotTransferOwnershipToSelf'); + ).to.be.revertedWithCustomError( + context.universalProfile, + 'LSP14CannotTransferOwnershipToSelf', + ); }); }); @@ -199,38 +202,49 @@ export const shouldBehaveLikePermissionChangeOwner = ( context.universalProfile.address, ); + const pendignOwner = await context.universalProfile.pendingOwner(); + const payload = context.universalProfile.interface.getSighash('acceptOwnership'); - await expect( - notPendingKeyManager.connect(context.mainController).execute(payload), - ).to.be.revertedWith('LSP14: caller is not the pendingOwner'); + await expect(notPendingKeyManager.connect(context.mainController).execute(payload)) + .to.be.revertedWithCustomError(context.universalProfile, 'LSP20EOACannotVerifyCall') + .withArgs(pendignOwner); }); }); - describe('when calling acceptOwnership(...) via the pending new KeyManager', () => { + describe('when calling acceptOwnership(...) directly on the contract', () => { let pendingOwner: string; - before(async () => { - await context.universalProfile - .connect(context.mainController) - .transferOwnership(newKeyManager.address); + describe('when pending owner is a new Key Manager', () => { + before(async () => { + await context.universalProfile + .connect(context.mainController) + .transferOwnership(newKeyManager.address); - pendingOwner = await context.universalProfile.pendingOwner(); + pendingOwner = await context.universalProfile.pendingOwner(); + }); - const acceptOwnershipPayload = - context.universalProfile.interface.getSighash('acceptOwnership'); + it('should not let you accept ownership if controller does not have permission `CHANGEOWNER`', async () => { + await expect(context.universalProfile.connect(cannotChangeOwner).acceptOwnership()) + .to.be.revertedWithCustomError(newKeyManager, 'NotAuthorised') + .withArgs(cannotChangeOwner.address, 'TRANSFEROWNERSHIP'); + }); - await newKeyManager.connect(context.mainController).execute(acceptOwnershipPayload); - }); + it('should let you accept ownership if controller has permission', async () => { + await context.universalProfile.connect(canChangeOwner).acceptOwnership(); - it("should have change the account's owner to the pendingOwner (= pending KeyManager)", async () => { - const updatedOwner = await context.universalProfile.owner(); - expect(updatedOwner).to.equal(pendingOwner); - }); + expect(await context.universalProfile.owner()).to.equal(newKeyManager.address); + }); + + it("should have change the account's owner to the pendingOwner (= pending KeyManager)", async () => { + const updatedOwner = await context.universalProfile.owner(); + expect(updatedOwner).to.equal(pendingOwner); + }); - it('should have cleared the pendingOwner after transfering ownership', async () => { - const newPendingOwner = await context.universalProfile.pendingOwner(); - expect(newPendingOwner).to.equal(ethers.constants.AddressZero); + it('should have cleared the pendingOwner after transfering ownership', async () => { + const newPendingOwner = await context.universalProfile.pendingOwner(); + expect(newPendingOwner).to.equal(ethers.constants.AddressZero); + }); }); }); diff --git a/tests/LSP6KeyManager/Admin/PermissionChangeOwner.test.ts b/tests/LSP6KeyManager/Admin/PermissionChangeOwner.test.ts index 44aa2c626..4922faf24 100644 --- a/tests/LSP6KeyManager/Admin/PermissionChangeOwner.test.ts +++ b/tests/LSP6KeyManager/Admin/PermissionChangeOwner.test.ts @@ -69,7 +69,10 @@ export const shouldBehaveLikePermissionChangeOwner = ( await expect( context.keyManager.connect(canChangeOwner).execute(transferOwnershipPayload), - ).to.be.revertedWithCustomError(context.universalProfile, 'CannotTransferOwnershipToSelf'); + ).to.be.revertedWithCustomError( + context.universalProfile, + 'LSP14CannotTransferOwnershipToSelf', + ); }); }); @@ -225,9 +228,9 @@ export const shouldBehaveLikePermissionChangeOwner = ( const payload = context.universalProfile.interface.getSighash('acceptOwnership'); - await expect( - notPendingKeyManager.connect(context.mainController).execute(payload), - ).to.be.revertedWith('LSP14: caller is not the pendingOwner'); + await expect(notPendingKeyManager.connect(context.mainController).execute(payload)) + .to.be.revertedWithCustomError(context.keyManager, 'NoPermissionsSet') + .withArgs(notPendingKeyManager.address); }); }); diff --git a/tests/foundry/LSP14Ownable2Step/TwoStepRenounceOwnership.sol b/tests/foundry/LSP14Ownable2Step/TwoStepRenounceOwnership.sol index a017a9fe8..1936d494d 100644 --- a/tests/foundry/LSP14Ownable2Step/TwoStepRenounceOwnership.sol +++ b/tests/foundry/LSP14Ownable2Step/TwoStepRenounceOwnership.sol @@ -5,6 +5,10 @@ import "forge-std/Test.sol"; import "@erc725/smart-contracts/contracts/constants.sol"; import "../../../contracts/LSP0ERC725Account/LSP0ERC725Account.sol"; +import { + LSP20EOACannotVerifyCall +} from "../../../contracts/LSP20CallVerification/LSP20Errors.sol"; + contract Implementation { // _pendingOwner is at slot 3 for LSP0ERC725Account bytes32[3] __gap; @@ -51,7 +55,12 @@ contract TwoStepRenounceOwnershipTest is Test { // Call acceptOwnership() to regain ownership should fail // as pendingOwner should be deleted on the second call of renounceOwnership again - vm.expectRevert("LSP14: caller is not the pendingOwner"); + vm.expectRevert( + abi.encodeWithSelector( + LSP20EOACannotVerifyCall.selector, + address(0) + ) + ); account.acceptOwnership(); } } From f82626d5f64efd396a40690687dfb5a2dc9c036e Mon Sep 17 00:00:00 2001 From: Jean Cvllr <31145285+CJ42@users.noreply.github.com> Date: Tue, 17 Oct 2023 13:27:03 +0100 Subject: [PATCH 52/55] refactor!: add extra parameter `requestor` to `lsp20VerifyCall` (#753) * refactor!: add `requestor` parameter to `lsp20VerifyCall` * test: update tests * docs: update auto-generated docs * refactor!: update LSP6 + LSP20 Call Verifier interface IDs * chore: update param name in LSP20 interface --- constants.ts | 12 +++++------ contracts/LSP17Extensions/Extension4337.sol | 5 +++-- .../ILSP20CallVerifier.sol | 18 +++++++++-------- .../LSP20CallVerification.sol | 3 ++- .../LSP20CallVerification/LSP20Constants.sol | 8 ++++---- contracts/LSP6KeyManager/LSP6Constants.sol | 2 +- .../LSP6KeyManager/LSP6KeyManagerCore.sol | 17 ++++++++-------- contracts/Mocks/ERC165Interfaces.sol | 3 +++ .../FirstCallReturnExpandedInvalidValue.sol | 8 ++++++-- .../FirstCallReturnInvalidMagicValue.sol | 1 + docs/_interface_ids_table.mdx | 4 ++-- .../LSP6KeyManager/LSP6KeyManager.md | 20 ++++++++++--------- .../LSP6/Interactions/PermissionCall.test.ts | 8 +++++++- .../LSP6/Interactions/Security.test.ts | 9 ++++++++- .../Interactions/PermissionCall.test.ts | 8 +++++++- .../LSP6KeyManager/LSP6SetDataTest.t.sol | 2 ++ 16 files changed, 82 insertions(+), 46 deletions(-) diff --git a/constants.ts b/constants.ts index eed5bfc63..18c3aaebf 100644 --- a/constants.ts +++ b/constants.ts @@ -27,7 +27,7 @@ export const INTERFACE_IDS = { LSP0ERC725Account: '0x24871b3d', LSP1UniversalReceiver: '0x6bb56a14', LSP1UniversalReceiverDelegate: '0xa245bbda', - LSP6KeyManager: '0xe7424397', + LSP6KeyManager: '0x23f34c62', LSP7DigitalAsset: '0x05519512', LSP8IdentifiableDigitalAsset: '0x1ae9ba1f', LSP9Vault: '0x28af17e6', @@ -36,7 +36,7 @@ export const INTERFACE_IDS = { LSP17Extendable: '0xa918fa6b', LSP17Extension: '0xcee78b40', LSP20CallVerification: '0x1a0eb6a5', - LSP20CallVerifier: '0xc9dfc532', + LSP20CallVerifier: '0x0d6ecac7', LSP25ExecuteRelayCall: '0x5ac79908', }; @@ -61,10 +61,10 @@ export const ERC1271_VALUES = { */ export const LSP20_SUCCESS_VALUES = { VERIFY_CALL: { - // bytes3(keccak256("lsp20VerifyCall(address,address,uint256,bytes)")) + "0x00" - NO_POST_VERIFICATION: '0x1a238000', - // bytes3(keccak256("lsp20VerifyCall(address,address,uint256,bytes)")) + "0x01" - WITH_POST_VERIFICATION: '0x1a238001', + // bytes3(keccak256("lsp20VerifyCall(address,address,address,uint256,bytes)")) + "0x00" + NO_POST_VERIFICATION: '0xde928f00', + // bytes3(keccak256("lsp20VerifyCall(address,address,address,uint256,bytes)")) + "0x01" + WITH_POST_VERIFICATION: '0xde928f01', }, // bytes4(keccak256("lsp20VerifyCallResult(bytes32,bytes)")) VERIFY_CALL_RESULT: '0xd3fc45d3', diff --git a/contracts/LSP17Extensions/Extension4337.sol b/contracts/LSP17Extensions/Extension4337.sol index d5fd38331..133abe0ad 100644 --- a/contracts/LSP17Extensions/Extension4337.sol +++ b/contracts/LSP17Extensions/Extension4337.sol @@ -72,10 +72,11 @@ contract Extension4337 is LSP17Extension, IAccount { // verify that the recovered address can execute the userOp.callData bytes4 returnedStatus = ILSP20CallVerifier(owner).lsp20VerifyCall({ - callee: msg.sender, + requestor: _ENTRY_POINT, + target: msg.sender, caller: recovered, value: 0, - receivedCalldata: userOp.callData + callData: userOp.callData }); // if the returnedStatus is a value different than the success value, return signature validation failed diff --git a/contracts/LSP20CallVerification/ILSP20CallVerifier.sol b/contracts/LSP20CallVerification/ILSP20CallVerifier.sol index 2b1b97f88..f23eee193 100644 --- a/contracts/LSP20CallVerification/ILSP20CallVerifier.sol +++ b/contracts/LSP20CallVerification/ILSP20CallVerifier.sol @@ -12,26 +12,28 @@ interface ILSP20CallVerifier { * the function is allowed, concatened with a byte that determines if the lsp20VerifyCallResult function should * be called after the original function call. The byte that invoke the lsp20VerifyCallResult function is strictly `0x01`. * - * @param callee The address of the contract that implements the `LSP20CallVerification` interface - * @param caller The address who called the function on the msg.sender + * @param requestor The address that requested to make the call to `target`. + * @param target The address of the contract that implements the `LSP20CallVerification` interface. + * @param caller The address who called the function on the `target` contract. * @param value The value sent by the caller to the function called on the msg.sender - * @param receivedCalldata The receivedCalldata sent by the caller to the msg.sender + * @param callData The calldata sent by the caller to the msg.sender */ function lsp20VerifyCall( - address callee, + address requestor, + address target, address caller, uint256 value, - bytes memory receivedCalldata + bytes memory callData ) external returns (bytes4 returnedStatus); /** * @return MUST return the lsp20VerifyCallResult function selector if the call to the function is allowed * - * @param callHash The keccak256 of the parameters of {lsp20VerifyCall} concatenated - * @param result The value result of the function called on the msg.sender + * @param callHash The keccak256 hash of the parameters of {lsp20VerifyCall} concatenated + * @param callResult The value result of the function called on the msg.sender */ function lsp20VerifyCallResult( bytes32 callHash, - bytes memory result + bytes memory callResult ) external returns (bytes4); } diff --git a/contracts/LSP20CallVerification/LSP20CallVerification.sol b/contracts/LSP20CallVerification/LSP20CallVerification.sol index d23ac7810..6a7732222 100644 --- a/contracts/LSP20CallVerification/LSP20CallVerification.sol +++ b/contracts/LSP20CallVerification/LSP20CallVerification.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.4; // interfaces - import {ILSP20CallVerifier as ILSP20} from "./ILSP20CallVerifier.sol"; // errors @@ -33,6 +32,7 @@ abstract contract LSP20CallVerification { (bool success, bytes memory returnedData) = logicVerifier.call( abi.encodeWithSelector( ILSP20.lsp20VerifyCall.selector, + msg.sender, address(this), msg.sender, msg.value, @@ -64,6 +64,7 @@ abstract contract LSP20CallVerification { ILSP20.lsp20VerifyCallResult.selector, keccak256( abi.encodePacked( + msg.sender, address(this), msg.sender, msg.value, diff --git a/contracts/LSP20CallVerification/LSP20Constants.sol b/contracts/LSP20CallVerification/LSP20Constants.sol index d36869a57..9837c368c 100644 --- a/contracts/LSP20CallVerification/LSP20Constants.sol +++ b/contracts/LSP20CallVerification/LSP20Constants.sol @@ -4,14 +4,14 @@ pragma solidity ^0.8.4; // bytes4(keccak256("LSP20CallVerification")) bytes4 constant _INTERFACEID_LSP20_CALL_VERIFICATION = 0x1a0eb6a5; -// `lsp20VerifyCall(address,address,uint256,bytes)` selector XOR `lsp20VerifyCallResult(bytes32,bytes)` selector -bytes4 constant _INTERFACEID_LSP20_CALL_VERIFIER = 0xc9dfc532; +// `lsp20VerifyCall(address,address,address,uint256,bytes)` selector XOR `lsp20VerifyCallResult(bytes32,bytes)` selector +bytes4 constant _INTERFACEID_LSP20_CALL_VERIFIER = 0x0d6ecac7; // bytes4(bytes.concat(bytes3(ILSP20.lsp20VerifyCall.selector), hex"01")) -bytes4 constant _LSP20_VERIFY_CALL_SUCCESS_VALUE_WITH_POST_VERIFICATION = 0x1a238001; +bytes4 constant _LSP20_VERIFY_CALL_SUCCESS_VALUE_WITH_POST_VERIFICATION = 0xde928f01; // bytes4(bytes.concat(bytes3(ILSP20.lsp20VerifyCall.selector), hex"00")) -bytes4 constant _LSP20_VERIFY_CALL_SUCCESS_VALUE_WITHOUT_POST_VERIFICATION = 0x1a238000; +bytes4 constant _LSP20_VERIFY_CALL_SUCCESS_VALUE_WITHOUT_POST_VERIFICATION = 0xde928f00; // bytes4(ILSP20.lsp20VerifyCallResult.selector) bytes4 constant _LSP20_VERIFY_CALL_RESULT_SUCCESS_VALUE = 0xd3fc45d3; diff --git a/contracts/LSP6KeyManager/LSP6Constants.sol b/contracts/LSP6KeyManager/LSP6Constants.sol index a7d26ede9..79d3fd7e1 100644 --- a/contracts/LSP6KeyManager/LSP6Constants.sol +++ b/contracts/LSP6KeyManager/LSP6Constants.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.4; // --- ERC165 interface ids -bytes4 constant _INTERFACEID_LSP6 = 0xe7424397; +bytes4 constant _INTERFACEID_LSP6 = 0x23f34c62; // --- ERC725Y Data Keys diff --git a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol index 2fc1c117f..0a25eec83 100644 --- a/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol +++ b/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol @@ -318,13 +318,14 @@ abstract contract LSP6KeyManagerCore is * - `0x1a238001`: LSP20 success value **with** post-verification (last byte is `0x01`). */ function lsp20VerifyCall( + address /* requestor */, address targetContract, address caller, uint256 msgValue, - bytes calldata data + bytes calldata callData ) external virtual override returns (bytes4) { - bool isSetData = bytes4(data) == IERC725Y.setData.selector || - bytes4(data) == IERC725Y.setDataBatch.selector; + bool isSetData = bytes4(callData) == IERC725Y.setData.selector || + bytes4(callData) == IERC725Y.setDataBatch.selector; // If target is invoking the verification, emit the event and change the reentrancy guard if (msg.sender == targetContract) { @@ -334,9 +335,9 @@ abstract contract LSP6KeyManagerCore is caller ); - _verifyPermissions(targetContract, caller, false, data); + _verifyPermissions(targetContract, caller, false, callData); - emit PermissionsVerified(caller, msgValue, bytes4(data)); + emit PermissionsVerified(caller, msgValue, bytes4(callData)); // if it's a setData call, do not invoke the `lsp20VerifyCallResult(..)` function return @@ -357,7 +358,7 @@ abstract contract LSP6KeyManagerCore is ); } - _verifyPermissions(targetContract, caller, false, data); + _verifyPermissions(targetContract, caller, false, callData); // if it's a setData call, do not invoke the `lsp20VerifyCallResult(..)` function return @@ -371,8 +372,8 @@ abstract contract LSP6KeyManagerCore is * @inheritdoc ILSP20 */ function lsp20VerifyCallResult( - bytes32 /*callHash*/, - bytes memory /*result*/ + bytes32 /* callHash */, + bytes memory /* callResult */ ) external virtual override returns (bytes4) { // If it's the target calling, set back the reentrancy guard // to false, if not return the success value diff --git a/contracts/Mocks/ERC165Interfaces.sol b/contracts/Mocks/ERC165Interfaces.sol index ca4480dba..4fcd847b3 100644 --- a/contracts/Mocks/ERC165Interfaces.sol +++ b/contracts/Mocks/ERC165Interfaces.sol @@ -121,6 +121,7 @@ contract CalculateLSPInterfaces { type(IERC1271).interfaceId ^ calculateInterfaceLSP20CallVerifier() ^ calculateInterfaceLSP25ExecuteRelayCall(); + require( interfaceId == _INTERFACEID_LSP6, "hardcoded _INTERFACEID_LSP6 does not match type(ILSP6).interfaceId" @@ -133,6 +134,7 @@ contract CalculateLSPInterfaces { bytes4 interfaceId = type(ILSP7).interfaceId ^ type(IERC725Y).interfaceId ^ calculateInterfaceLSP17Extendable(); + require( interfaceId == _INTERFACEID_LSP7, "hardcoded _INTERFACEID_LSP7 does not match type(ILSP7).interfaceId" @@ -145,6 +147,7 @@ contract CalculateLSPInterfaces { bytes4 interfaceId = type(ILSP8).interfaceId ^ type(IERC725Y).interfaceId ^ calculateInterfaceLSP17Extendable(); + require( interfaceId == _INTERFACEID_LSP8, "hardcoded _INTERFACEID_LSP8 does not match type(ILSP8).interfaceId" diff --git a/contracts/Mocks/LSP20Owners/FirstCallReturnExpandedInvalidValue.sol b/contracts/Mocks/LSP20Owners/FirstCallReturnExpandedInvalidValue.sol index cb3d3d617..320c08f45 100644 --- a/contracts/Mocks/LSP20Owners/FirstCallReturnExpandedInvalidValue.sol +++ b/contracts/Mocks/LSP20Owners/FirstCallReturnExpandedInvalidValue.sol @@ -14,14 +14,18 @@ contract FirstCallReturnExpandedFailValue { address public target; function lsp20VerifyCall( - address callee, + address requestor, + address targetContract, address caller, uint256 value, bytes memory data ) external returns (bytes32) { emit CallVerified(); - return keccak256(abi.encode(callee, caller, value, data)); + return + keccak256( + abi.encode(requestor, targetContract, caller, value, data) + ); } function acceptOwnership(address newTarget) external { diff --git a/contracts/Mocks/LSP20Owners/FirstCallReturnInvalidMagicValue.sol b/contracts/Mocks/LSP20Owners/FirstCallReturnInvalidMagicValue.sol index e1ccdb45c..c9e6b60a2 100644 --- a/contracts/Mocks/LSP20Owners/FirstCallReturnInvalidMagicValue.sol +++ b/contracts/Mocks/LSP20Owners/FirstCallReturnInvalidMagicValue.sol @@ -13,6 +13,7 @@ contract FirstCallReturnFailValue { address public target; function lsp20VerifyCall( + address, address, address, uint256, diff --git a/docs/_interface_ids_table.mdx b/docs/_interface_ids_table.mdx index 242e85d86..fbfb9856d 100644 --- a/docs/_interface_ids_table.mdx +++ b/docs/_interface_ids_table.mdx @@ -7,7 +7,7 @@ | **LSP0ERC725Account** | `0x24871b3d` | Interface of the [LSP-0-ERC725Account] standard, an account based smart contract that represents an identity on-chain. | | **LSP1UniversalReceiver** | `0x6bb56a14` | Interface of the LSP1 - Universal Receiver standard, an entry function for a contract to receive arbitrary information. | | **LSP1UniversalReceiverDelegate** | `0xa245bbda` | Interface of the LSP1 - Universal Receiver Delegate standard. | -| **LSP6KeyManager** | `0xe7424397` | Interface of the LSP6 - Key Manager standard, a contract acting as a controller of an ERC725 Account using predfined permissions. | +| **LSP6KeyManager** | `0x23f34c62` | Interface of the LSP6 - Key Manager standard, a contract acting as a controller of an ERC725 Account using predfined permissions. | | **LSP7DigitalAsset** | `0x05519512` | Interface of the LSP7 - Digital Asset standard, a fungible digital asset. | | **LSP8IdentifiableDigitalAsset** | `0x1ae9ba1f` | Interface of the LSP8 - Identifiable Digital Asset standard, a non-fungible digital asset. | | **LSP9Vault** | `0x28af17e6` | Interface of LSP9 - Vault standard, a blockchain vault that can hold assets and interact with other smart contracts. | @@ -16,5 +16,5 @@ | **LSP17Extendable** | `0xa918fa6b` | Module to add more functionalities to a contract using extensions. | | **LSP17Extension** | `0xcee78b40` | Module to create a contract that can act as an extension. | | **LSP20CallVerification** | `0x1a0eb6a5` | Implementation of a contract calling the verification functions according to LSP20 - Call Verification standard. | -| **LSP20CallVerifier** | `0xc9dfc532` | Interface for the LSP20 Call Verification standard, a set of functions intended to perform verifications on behalf of another contract. | +| **LSP20CallVerifier** | `0x0d6ecac7` | Interface for the LSP20 Call Verification standard, a set of functions intended to perform verifications on behalf of another contract. | | **LSP25ExecuteRelayCall** | `0x5ac79908` | | diff --git a/docs/contracts/LSP6KeyManager/LSP6KeyManager.md b/docs/contracts/LSP6KeyManager/LSP6KeyManager.md index fe2fd187a..a1b0b76df 100644 --- a/docs/contracts/LSP6KeyManager/LSP6KeyManager.md +++ b/docs/contracts/LSP6KeyManager/LSP6KeyManager.md @@ -332,8 +332,8 @@ Checks if a signature was signed by a controller that has the permission `SIGN`. - Specification details: [**LSP-6-KeyManager**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-6-KeyManager.md#lsp20verifycall) - Solidity implementation: [`LSP6KeyManager.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP6KeyManager/LSP6KeyManager.sol) -- Function signature: `lsp20VerifyCall(address,address,uint256,bytes)` -- Function selector: `0x1a2380e1` +- Function signature: `lsp20VerifyCall(address,address,address,uint256,bytes)` +- Function selector: `0xde928f14` ::: @@ -348,21 +348,23 @@ This function can call by any other address than the {`target`}. This allows to ```solidity function lsp20VerifyCall( + address, address targetContract, address caller, uint256 msgValue, - bytes data + bytes callData ) external nonpayable returns (bytes4); ``` #### Parameters -| Name | Type | Description | -| ---------------- | :-------: | ----------------------------------------------------- | -| `targetContract` | `address` | - | -| `caller` | `address` | The address who called the function on the msg.sender | -| `msgValue` | `uint256` | - | -| `data` | `bytes` | - | +| Name | Type | Description | +| ---------------- | :-------: | ------------------------------------------------------------- | +| `_0` | `address` | - | +| `targetContract` | `address` | - | +| `caller` | `address` | The address who called the function on the `target` contract. | +| `msgValue` | `uint256` | - | +| `callData` | `bytes` | The calldata sent by the caller to the msg.sender | #### Returns diff --git a/tests/LSP20CallVerification/LSP6/Interactions/PermissionCall.test.ts b/tests/LSP20CallVerification/LSP6/Interactions/PermissionCall.test.ts index ec906ccb9..a2aa9b93f 100644 --- a/tests/LSP20CallVerification/LSP6/Interactions/PermissionCall.test.ts +++ b/tests/LSP20CallVerification/LSP6/Interactions/PermissionCall.test.ts @@ -499,7 +499,13 @@ export const shouldBehaveLikePermissionCall = ( it('Should revert when caller calls the KeyManager through execute', async () => { const lsp20VerifyCallPayload = context.keyManager.interface.encodeFunctionData( 'lsp20VerifyCall', - [context.keyManager.address, context.accounts[2].address, 0, '0xaabbccdd'], // random arguments + [ + context.accounts[2].address, + context.keyManager.address, + context.accounts[2].address, + 0, + '0xaabbccdd', + ], // random arguments ); await expect( diff --git a/tests/LSP20CallVerification/LSP6/Interactions/Security.test.ts b/tests/LSP20CallVerification/LSP6/Interactions/Security.test.ts index 00cd0946a..8b39ce1a5 100644 --- a/tests/LSP20CallVerification/LSP6/Interactions/Security.test.ts +++ b/tests/LSP20CallVerification/LSP6/Interactions/Security.test.ts @@ -107,7 +107,13 @@ export const testSecurityScenarios = (buildContext: () => Promise { const lsp20VerifyCallPayload = context.keyManager.interface.encodeFunctionData( 'lsp20VerifyCall', - [context.keyManager.address, context.accounts[2].address, 0, '0xaabbccdd'], // random arguments + [ + context.accounts[2].address, + context.keyManager.address, + context.accounts[2].address, + 0, + '0xaabbccdd', + ], // random arguments ); await expect( @@ -297,6 +303,7 @@ export const testSecurityScenarios = (buildContext: () => Promise { const lsp20VerifyCallPayload = context.keyManager.interface.encodeFunctionData( 'lsp20VerifyCall', - [context.keyManager.address, context.accounts[2].address, 0, '0xaabbccdd'], // random arguments + [ + context.accounts[2].address, + context.keyManager.address, + context.accounts[2].address, + 0, + '0xaabbccdd', + ], // random arguments ); const executePayload = context.universalProfile.interface.encodeFunctionData('execute', [ diff --git a/tests/foundry/LSP6KeyManager/LSP6SetDataTest.t.sol b/tests/foundry/LSP6KeyManager/LSP6SetDataTest.t.sol index 0f8ef3959..729b284e3 100644 --- a/tests/foundry/LSP6KeyManager/LSP6SetDataTest.t.sol +++ b/tests/foundry/LSP6KeyManager/LSP6SetDataTest.t.sol @@ -103,6 +103,7 @@ contract LSP6SetDataTest is Test { // CHECK the LSP20 verification function reverts as well keyManager.lsp20VerifyCall( + malicious, address(universalProfile), malicious, 0, @@ -228,6 +229,7 @@ contract LSP6SetDataTest is Test { // CHECK the LSP20 verification function reverts as well keyManager.lsp20VerifyCall( + malicious, address(universalProfile), malicious, 0, From b1ad8dd3ae8e453f32e71c558e15fa95d75a170d Mon Sep 17 00:00:00 2001 From: Jean Cvllr <31145285+CJ42@users.noreply.github.com> Date: Tue, 17 Oct 2023 13:40:26 +0100 Subject: [PATCH 53/55] build: upgrade `@erc725/smart-contracts` to v6.0.0 (#751) * build: upgrade `@erc725` contracts to v6 * docs: update auto-generated docs * test: update Ownable custom error in tests * chore: remove unused imports --- docs/contracts/ERC725/ERC725.md | 56 +++++++++++++++++++ .../LSP0ERC725Account/LSP0ERC725Account.md | 6 ++ .../LSP11BasicSocialRecovery.md | 44 +++++++++++++++ .../LSP14Ownable2Step/LSP14Ownable2Step.md | 25 +++++++++ .../LSP4Compatibility.md | 44 +++++++++++++++ .../LSP4DigitalAssetMetadata.md | 44 +++++++++++++++ .../LSP7DigitalAsset/LSP7DigitalAsset.md | 44 +++++++++++++++ .../extensions/LSP7Burnable.md | 44 +++++++++++++++ .../extensions/LSP7CappedSupply.md | 44 +++++++++++++++ .../extensions/LSP7CompatibleERC20.md | 44 +++++++++++++++ .../presets/LSP7CompatibleERC20Mintable.md | 44 +++++++++++++++ .../LSP7DigitalAsset/presets/LSP7Mintable.md | 44 +++++++++++++++ .../LSP8IdentifiableDigitalAsset.md | 44 +++++++++++++++ .../extensions/LSP8Burnable.md | 44 +++++++++++++++ .../extensions/LSP8CappedSupply.md | 44 +++++++++++++++ .../extensions/LSP8CompatibleERC721.md | 44 +++++++++++++++ .../extensions/LSP8Enumerable.md | 44 +++++++++++++++ .../presets/LSP8CompatibleERC721Mintable.md | 44 +++++++++++++++ .../presets/LSP8Mintable.md | 44 +++++++++++++++ docs/contracts/LSP9Vault/LSP9Vault.md | 31 ++++++++++ docs/contracts/UniversalProfile.md | 6 ++ package-lock.json | 14 ++--- package.json | 2 +- .../LSP11BasicSocialRecovery.behaviour.ts | 25 +++++++-- .../LSP14Ownable2Step.behaviour.ts | 17 +++--- .../LSP20WithLSP14.behaviour.ts | 6 +- .../LSP6ControlledToken.test.ts | 6 +- .../LSP7DigitalAsset.behaviour.ts | 16 +++--- .../LSP7Mintable.behaviour.ts | 2 +- .../proxy/LSP7DigitalAssetInit.test.ts | 2 +- .../standard/LSP7DigitalAsset.test.ts | 10 ++-- .../LSP8IdentifiableDigitalAsset.behaviour.ts | 16 +++--- .../LSP8Mintable.behaviour.ts | 2 +- .../LSP8IdentifiableDigitalAssetInit.test.ts | 2 +- .../LSP8IdentifiableDigitalAsset.test.ts | 6 +- tests/LSP9Vault/LSP9Vault.test.ts | 4 +- tests/LSP9Vault/LSP9VaultInit.test.ts | 4 +- tests/UniversalProfile.test.ts | 4 +- tests/UniversalProfileInit.test.ts | 4 +- 39 files changed, 907 insertions(+), 63 deletions(-) diff --git a/docs/contracts/ERC725/ERC725.md b/docs/contracts/ERC725/ERC725.md index ebd40e6f9..e739783b1 100644 --- a/docs/contracts/ERC725/ERC725.md +++ b/docs/contracts/ERC725/ERC725.md @@ -134,6 +134,12 @@ Generic executor function to: ::: +:::caution Warning + +- The `msg.value` should not be trusted for any method called with `operationType`: `DELEGATECALL` (4). + +::: + ```solidity function executeBatch( uint256[] operationsType, @@ -564,6 +570,12 @@ Perform low-level staticcall (operation type = 3) ### \_executeDelegateCall +:::caution Warning + +The `msg.value` should not be trusted for any method called with `operationType`: `DELEGATECALL` (4). + +::: + ```solidity function _executeDelegateCall( address target, @@ -1053,3 +1065,47 @@ error ERC725Y_MsgValueDisallowed(); Reverts when sending value to the [`setData`](#setdata) or [`setDataBatch`](#setdatabatch) function.
+ +### OwnableCallerNotTheOwner + +:::note References + +- Specification details: [**ERC-725**](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-725.md#ownablecallernottheowner) +- Solidity implementation: [`ERC725.sol`](https://github.com/ERC725Alliance/ERC725/blob/main/implementations/contracts/ERC725.sol) +- Error signature: `OwnableCallerNotTheOwner(address)` +- Error hash: `0xbf1169c5` + +::: + +```solidity +error OwnableCallerNotTheOwner(address callerAddress); +``` + +Reverts when only the owner is allowed to call the function. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ---------------------------------------- | +| `callerAddress` | `address` | The address that tried to make the call. | + +
+ +### OwnableCannotSetZeroAddressAsOwner + +:::note References + +- Specification details: [**ERC-725**](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-725.md#ownablecannotsetzeroaddressasowner) +- Solidity implementation: [`ERC725.sol`](https://github.com/ERC725Alliance/ERC725/blob/main/implementations/contracts/ERC725.sol) +- Error signature: `OwnableCannotSetZeroAddressAsOwner()` +- Error hash: `0x1ad8836c` + +::: + +```solidity +error OwnableCannotSetZeroAddressAsOwner(); +``` + +Reverts when trying to set `address(0)` as the contract owner when deploying the contract, initializing it or transferring ownership of the contract. + +
diff --git a/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md b/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md index 2e402df28..5da23d51a 100644 --- a/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md +++ b/docs/contracts/LSP0ERC725Account/LSP0ERC725Account.md @@ -951,6 +951,12 @@ Perform low-level staticcall (operation type = 3) ### \_executeDelegateCall +:::caution Warning + +The `msg.value` should not be trusted for any method called with `operationType`: `DELEGATECALL` (4). + +::: + ```solidity function _executeDelegateCall( address target, diff --git a/docs/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.md b/docs/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.md index afeac358b..ce65e86c1 100644 --- a/docs/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.md +++ b/docs/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.md @@ -866,6 +866,50 @@ reverts when removing a guardian and the threshold is equal to the number of gua
+### OwnableCallerNotTheOwner + +:::note References + +- Specification details: [**LSP-11-BasicSocialRecovery**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-11-BasicSocialRecovery.md#ownablecallernottheowner) +- Solidity implementation: [`LSP11BasicSocialRecovery.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.sol) +- Error signature: `OwnableCallerNotTheOwner(address)` +- Error hash: `0xbf1169c5` + +::: + +```solidity +error OwnableCallerNotTheOwner(address callerAddress); +``` + +Reverts when only the owner is allowed to call the function. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ---------------------------------------- | +| `callerAddress` | `address` | The address that tried to make the call. | + +
+ +### OwnableCannotSetZeroAddressAsOwner + +:::note References + +- Specification details: [**LSP-11-BasicSocialRecovery**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-11-BasicSocialRecovery.md#ownablecannotsetzeroaddressasowner) +- Solidity implementation: [`LSP11BasicSocialRecovery.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.sol) +- Error signature: `OwnableCannotSetZeroAddressAsOwner()` +- Error hash: `0x1ad8836c` + +::: + +```solidity +error OwnableCannotSetZeroAddressAsOwner(); +``` + +Reverts when trying to set `address(0)` as the contract owner when deploying the contract, initializing it or transferring ownership of the contract. + +
+ ### SecretHashCannotBeZero :::note References diff --git a/docs/contracts/LSP14Ownable2Step/LSP14Ownable2Step.md b/docs/contracts/LSP14Ownable2Step/LSP14Ownable2Step.md index 2812d816a..a305eab1b 100644 --- a/docs/contracts/LSP14Ownable2Step/LSP14Ownable2Step.md +++ b/docs/contracts/LSP14Ownable2Step/LSP14Ownable2Step.md @@ -500,3 +500,28 @@ Reverts when trying to renounce ownership before the initial confirmation delay. | `renounceOwnershipEnd` | `uint256` | The end timestamp when one can confirm the renouncement of ownership. |
+ +### OwnableCallerNotTheOwner + +:::note References + +- Specification details: [**LSP-14-Ownable2Step**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-14-Ownable2Step.md#ownablecallernottheowner) +- Solidity implementation: [`LSP14Ownable2Step.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol) +- Error signature: `OwnableCallerNotTheOwner(address)` +- Error hash: `0xbf1169c5` + +::: + +```solidity +error OwnableCallerNotTheOwner(address callerAddress); +``` + +Reverts when only the owner is allowed to call the function. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ---------------------------------------- | +| `callerAddress` | `address` | The address that tried to make the call. | + +
diff --git a/docs/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.md b/docs/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.md index 1f8e99615..2b822c453 100644 --- a/docs/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.md +++ b/docs/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.md @@ -537,3 +537,47 @@ error ERC725Y_MsgValueDisallowed(); Reverts when sending value to the [`setData`](#setdata) or [`setDataBatch`](#setdatabatch) function.
+ +### OwnableCallerNotTheOwner + +:::note References + +- Specification details: [**LSP-4-DigitalAssetMetadata**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md#ownablecallernottheowner) +- Solidity implementation: [`LSP4Compatibility.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol) +- Error signature: `OwnableCallerNotTheOwner(address)` +- Error hash: `0xbf1169c5` + +::: + +```solidity +error OwnableCallerNotTheOwner(address callerAddress); +``` + +Reverts when only the owner is allowed to call the function. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ---------------------------------------- | +| `callerAddress` | `address` | The address that tried to make the call. | + +
+ +### OwnableCannotSetZeroAddressAsOwner + +:::note References + +- Specification details: [**LSP-4-DigitalAssetMetadata**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md#ownablecannotsetzeroaddressasowner) +- Solidity implementation: [`LSP4Compatibility.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol) +- Error signature: `OwnableCannotSetZeroAddressAsOwner()` +- Error hash: `0x1ad8836c` + +::: + +```solidity +error OwnableCannotSetZeroAddressAsOwner(); +``` + +Reverts when trying to set `address(0)` as the contract owner when deploying the contract, initializing it or transferring ownership of the contract. + +
diff --git a/docs/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.md b/docs/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.md index 0f5c8b1bf..15121dc6b 100644 --- a/docs/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.md +++ b/docs/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.md @@ -505,3 +505,47 @@ error LSP4TokenSymbolNotEditable(); Reverts when trying to edit the data key `LSP4TokenSymbol` after the digital asset contract has been deployed. The `LSP4TokenSymbol` data key is located inside the ERC725Y Data key-value store of the digital asset contract. It can be set only once inside the constructor/initializer when the digital asset contract is being deployed.
+ +### OwnableCallerNotTheOwner + +:::note References + +- Specification details: [**LSP-4-DigitalAssetMetadata**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md#ownablecallernottheowner) +- Solidity implementation: [`LSP4DigitalAssetMetadata.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.sol) +- Error signature: `OwnableCallerNotTheOwner(address)` +- Error hash: `0xbf1169c5` + +::: + +```solidity +error OwnableCallerNotTheOwner(address callerAddress); +``` + +Reverts when only the owner is allowed to call the function. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ---------------------------------------- | +| `callerAddress` | `address` | The address that tried to make the call. | + +
+ +### OwnableCannotSetZeroAddressAsOwner + +:::note References + +- Specification details: [**LSP-4-DigitalAssetMetadata**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md#ownablecannotsetzeroaddressasowner) +- Solidity implementation: [`LSP4DigitalAssetMetadata.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.sol) +- Error signature: `OwnableCannotSetZeroAddressAsOwner()` +- Error hash: `0x1ad8836c` + +::: + +```solidity +error OwnableCannotSetZeroAddressAsOwner(); +``` + +Reverts when trying to set `address(0)` as the contract owner when deploying the contract, initializing it or transferring ownership of the contract. + +
diff --git a/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md b/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md index fc8d7357c..047f5ab1a 100644 --- a/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md +++ b/docs/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md @@ -1729,3 +1729,47 @@ reverts when there is no extension for the function selector being called with | `functionSelector` | `bytes4` | - |
+ +### OwnableCallerNotTheOwner + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#ownablecallernottheowner) +- Solidity implementation: [`LSP7DigitalAsset.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol) +- Error signature: `OwnableCallerNotTheOwner(address)` +- Error hash: `0xbf1169c5` + +::: + +```solidity +error OwnableCallerNotTheOwner(address callerAddress); +``` + +Reverts when only the owner is allowed to call the function. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ---------------------------------------- | +| `callerAddress` | `address` | The address that tried to make the call. | + +
+ +### OwnableCannotSetZeroAddressAsOwner + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#ownablecannotsetzeroaddressasowner) +- Solidity implementation: [`LSP7DigitalAsset.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol) +- Error signature: `OwnableCannotSetZeroAddressAsOwner()` +- Error hash: `0x1ad8836c` + +::: + +```solidity +error OwnableCannotSetZeroAddressAsOwner(); +``` + +Reverts when trying to set `address(0)` as the contract owner when deploying the contract, initializing it or transferring ownership of the contract. + +
diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md index 1c0a68f4a..f0c7d2b96 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md @@ -1754,3 +1754,47 @@ reverts when there is no extension for the function selector being called with | `functionSelector` | `bytes4` | - |
+ +### OwnableCallerNotTheOwner + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#ownablecallernottheowner) +- Solidity implementation: [`LSP7Burnable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.sol) +- Error signature: `OwnableCallerNotTheOwner(address)` +- Error hash: `0xbf1169c5` + +::: + +```solidity +error OwnableCallerNotTheOwner(address callerAddress); +``` + +Reverts when only the owner is allowed to call the function. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ---------------------------------------- | +| `callerAddress` | `address` | The address that tried to make the call. | + +
+ +### OwnableCannotSetZeroAddressAsOwner + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#ownablecannotsetzeroaddressasowner) +- Solidity implementation: [`LSP7Burnable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.sol) +- Error signature: `OwnableCannotSetZeroAddressAsOwner()` +- Error hash: `0x1ad8836c` + +::: + +```solidity +error OwnableCannotSetZeroAddressAsOwner(); +``` + +Reverts when trying to set `address(0)` as the contract owner when deploying the contract, initializing it or transferring ownership of the contract. + +
diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md index 74423ec3b..028cf0a49 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md @@ -1770,3 +1770,47 @@ reverts when there is no extension for the function selector being called with | `functionSelector` | `bytes4` | - |
+ +### OwnableCallerNotTheOwner + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#ownablecallernottheowner) +- Solidity implementation: [`LSP7CappedSupply.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.sol) +- Error signature: `OwnableCallerNotTheOwner(address)` +- Error hash: `0xbf1169c5` + +::: + +```solidity +error OwnableCallerNotTheOwner(address callerAddress); +``` + +Reverts when only the owner is allowed to call the function. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ---------------------------------------- | +| `callerAddress` | `address` | The address that tried to make the call. | + +
+ +### OwnableCannotSetZeroAddressAsOwner + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#ownablecannotsetzeroaddressasowner) +- Solidity implementation: [`LSP7CappedSupply.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.sol) +- Error signature: `OwnableCannotSetZeroAddressAsOwner()` +- Error hash: `0x1ad8836c` + +::: + +```solidity +error OwnableCannotSetZeroAddressAsOwner(); +``` + +Reverts when trying to set `address(0)` as the contract owner when deploying the contract, initializing it or transferring ownership of the contract. + +
diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md index e8e8c01d8..2a4fa0a1a 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md @@ -1862,3 +1862,47 @@ reverts when there is no extension for the function selector being called with | `functionSelector` | `bytes4` | - |
+ +### OwnableCallerNotTheOwner + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#ownablecallernottheowner) +- Solidity implementation: [`LSP7CompatibleERC20.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol) +- Error signature: `OwnableCallerNotTheOwner(address)` +- Error hash: `0xbf1169c5` + +::: + +```solidity +error OwnableCallerNotTheOwner(address callerAddress); +``` + +Reverts when only the owner is allowed to call the function. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ---------------------------------------- | +| `callerAddress` | `address` | The address that tried to make the call. | + +
+ +### OwnableCannotSetZeroAddressAsOwner + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#ownablecannotsetzeroaddressasowner) +- Solidity implementation: [`LSP7CompatibleERC20.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol) +- Error signature: `OwnableCannotSetZeroAddressAsOwner()` +- Error hash: `0x1ad8836c` + +::: + +```solidity +error OwnableCannotSetZeroAddressAsOwner(); +``` + +Reverts when trying to set `address(0)` as the contract owner when deploying the contract, initializing it or transferring ownership of the contract. + +
diff --git a/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md b/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md index 7d54b18cd..232eda1a1 100644 --- a/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md +++ b/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md @@ -1896,3 +1896,47 @@ reverts when there is no extension for the function selector being called with | `functionSelector` | `bytes4` | - |
+ +### OwnableCallerNotTheOwner + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#ownablecallernottheowner) +- Solidity implementation: [`LSP7CompatibleERC20Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol) +- Error signature: `OwnableCallerNotTheOwner(address)` +- Error hash: `0xbf1169c5` + +::: + +```solidity +error OwnableCallerNotTheOwner(address callerAddress); +``` + +Reverts when only the owner is allowed to call the function. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ---------------------------------------- | +| `callerAddress` | `address` | The address that tried to make the call. | + +
+ +### OwnableCannotSetZeroAddressAsOwner + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#ownablecannotsetzeroaddressasowner) +- Solidity implementation: [`LSP7CompatibleERC20Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol) +- Error signature: `OwnableCannotSetZeroAddressAsOwner()` +- Error hash: `0x1ad8836c` + +::: + +```solidity +error OwnableCannotSetZeroAddressAsOwner(); +``` + +Reverts when trying to set `address(0)` as the contract owner when deploying the contract, initializing it or transferring ownership of the contract. + +
diff --git a/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md b/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md index cd3c72bc4..a178eff9e 100644 --- a/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md +++ b/docs/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md @@ -1791,3 +1791,47 @@ reverts when there is no extension for the function selector being called with | `functionSelector` | `bytes4` | - |
+ +### OwnableCallerNotTheOwner + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#ownablecallernottheowner) +- Solidity implementation: [`LSP7Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/presets/LSP7Mintable.sol) +- Error signature: `OwnableCallerNotTheOwner(address)` +- Error hash: `0xbf1169c5` + +::: + +```solidity +error OwnableCallerNotTheOwner(address callerAddress); +``` + +Reverts when only the owner is allowed to call the function. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ---------------------------------------- | +| `callerAddress` | `address` | The address that tried to make the call. | + +
+ +### OwnableCannotSetZeroAddressAsOwner + +:::note References + +- Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#ownablecannotsetzeroaddressasowner) +- Solidity implementation: [`LSP7Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/presets/LSP7Mintable.sol) +- Error signature: `OwnableCannotSetZeroAddressAsOwner()` +- Error hash: `0x1ad8836c` + +::: + +```solidity +error OwnableCannotSetZeroAddressAsOwner(); +``` + +Reverts when trying to set `address(0)` as the contract owner when deploying the contract, initializing it or transferring ownership of the contract. + +
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md b/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md index b719713b1..33a2ba6d7 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md @@ -1723,3 +1723,47 @@ reverts when there is no extension for the function selector being called with | `functionSelector` | `bytes4` | - |
+ +### OwnableCallerNotTheOwner + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#ownablecallernottheowner) +- Solidity implementation: [`LSP8IdentifiableDigitalAsset.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol) +- Error signature: `OwnableCallerNotTheOwner(address)` +- Error hash: `0xbf1169c5` + +::: + +```solidity +error OwnableCallerNotTheOwner(address callerAddress); +``` + +Reverts when only the owner is allowed to call the function. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ---------------------------------------- | +| `callerAddress` | `address` | The address that tried to make the call. | + +
+ +### OwnableCannotSetZeroAddressAsOwner + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#ownablecannotsetzeroaddressasowner) +- Solidity implementation: [`LSP8IdentifiableDigitalAsset.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol) +- Error signature: `OwnableCannotSetZeroAddressAsOwner()` +- Error hash: `0x1ad8836c` + +::: + +```solidity +error OwnableCannotSetZeroAddressAsOwner(); +``` + +Reverts when trying to set `address(0)` as the contract owner when deploying the contract, initializing it or transferring ownership of the contract. + +
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md index 34559f01a..181bbd5b7 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md @@ -1749,3 +1749,47 @@ reverts when there is no extension for the function selector being called with | `functionSelector` | `bytes4` | - |
+ +### OwnableCallerNotTheOwner + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#ownablecallernottheowner) +- Solidity implementation: [`LSP8Burnable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.sol) +- Error signature: `OwnableCallerNotTheOwner(address)` +- Error hash: `0xbf1169c5` + +::: + +```solidity +error OwnableCallerNotTheOwner(address callerAddress); +``` + +Reverts when only the owner is allowed to call the function. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ---------------------------------------- | +| `callerAddress` | `address` | The address that tried to make the call. | + +
+ +### OwnableCannotSetZeroAddressAsOwner + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#ownablecannotsetzeroaddressasowner) +- Solidity implementation: [`LSP8Burnable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.sol) +- Error signature: `OwnableCannotSetZeroAddressAsOwner()` +- Error hash: `0x1ad8836c` + +::: + +```solidity +error OwnableCannotSetZeroAddressAsOwner(); +``` + +Reverts when trying to set `address(0)` as the contract owner when deploying the contract, initializing it or transferring ownership of the contract. + +
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md index f4bae3e8d..53a5b5f12 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md @@ -1765,3 +1765,47 @@ reverts when there is no extension for the function selector being called with | `functionSelector` | `bytes4` | - |
+ +### OwnableCallerNotTheOwner + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#ownablecallernottheowner) +- Solidity implementation: [`LSP8CappedSupply.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.sol) +- Error signature: `OwnableCallerNotTheOwner(address)` +- Error hash: `0xbf1169c5` + +::: + +```solidity +error OwnableCallerNotTheOwner(address callerAddress); +``` + +Reverts when only the owner is allowed to call the function. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ---------------------------------------- | +| `callerAddress` | `address` | The address that tried to make the call. | + +
+ +### OwnableCannotSetZeroAddressAsOwner + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#ownablecannotsetzeroaddressasowner) +- Solidity implementation: [`LSP8CappedSupply.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.sol) +- Error signature: `OwnableCannotSetZeroAddressAsOwner()` +- Error hash: `0x1ad8836c` + +::: + +```solidity +error OwnableCannotSetZeroAddressAsOwner(); +``` + +Reverts when trying to set `address(0)` as the contract owner when deploying the contract, initializing it or transferring ownership of the contract. + +
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md index a4ff839c0..e7d8328f7 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md @@ -2099,3 +2099,47 @@ reverts when there is no extension for the function selector being called with | `functionSelector` | `bytes4` | - |
+ +### OwnableCallerNotTheOwner + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#ownablecallernottheowner) +- Solidity implementation: [`LSP8CompatibleERC721.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol) +- Error signature: `OwnableCallerNotTheOwner(address)` +- Error hash: `0xbf1169c5` + +::: + +```solidity +error OwnableCallerNotTheOwner(address callerAddress); +``` + +Reverts when only the owner is allowed to call the function. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ---------------------------------------- | +| `callerAddress` | `address` | The address that tried to make the call. | + +
+ +### OwnableCannotSetZeroAddressAsOwner + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#ownablecannotsetzeroaddressasowner) +- Solidity implementation: [`LSP8CompatibleERC721.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol) +- Error signature: `OwnableCannotSetZeroAddressAsOwner()` +- Error hash: `0x1ad8836c` + +::: + +```solidity +error OwnableCannotSetZeroAddressAsOwner(); +``` + +Reverts when trying to set `address(0)` as the contract owner when deploying the contract, initializing it or transferring ownership of the contract. + +
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md index 5a5efaf42..eea20e1d9 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md @@ -1751,3 +1751,47 @@ reverts when there is no extension for the function selector being called with | `functionSelector` | `bytes4` | - |
+ +### OwnableCallerNotTheOwner + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#ownablecallernottheowner) +- Solidity implementation: [`LSP8Enumerable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.sol) +- Error signature: `OwnableCallerNotTheOwner(address)` +- Error hash: `0xbf1169c5` + +::: + +```solidity +error OwnableCallerNotTheOwner(address callerAddress); +``` + +Reverts when only the owner is allowed to call the function. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ---------------------------------------- | +| `callerAddress` | `address` | The address that tried to make the call. | + +
+ +### OwnableCannotSetZeroAddressAsOwner + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#ownablecannotsetzeroaddressasowner) +- Solidity implementation: [`LSP8Enumerable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.sol) +- Error signature: `OwnableCannotSetZeroAddressAsOwner()` +- Error hash: `0x1ad8836c` + +::: + +```solidity +error OwnableCannotSetZeroAddressAsOwner(); +``` + +Reverts when trying to set `address(0)` as the contract owner when deploying the contract, initializing it or transferring ownership of the contract. + +
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md index 7b2621f5e..0e2b550cf 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md @@ -2166,3 +2166,47 @@ reverts when there is no extension for the function selector being called with | `functionSelector` | `bytes4` | - |
+ +### OwnableCallerNotTheOwner + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#ownablecallernottheowner) +- Solidity implementation: [`LSP8CompatibleERC721Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol) +- Error signature: `OwnableCallerNotTheOwner(address)` +- Error hash: `0xbf1169c5` + +::: + +```solidity +error OwnableCallerNotTheOwner(address callerAddress); +``` + +Reverts when only the owner is allowed to call the function. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ---------------------------------------- | +| `callerAddress` | `address` | The address that tried to make the call. | + +
+ +### OwnableCannotSetZeroAddressAsOwner + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#ownablecannotsetzeroaddressasowner) +- Solidity implementation: [`LSP8CompatibleERC721Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol) +- Error signature: `OwnableCannotSetZeroAddressAsOwner()` +- Error hash: `0x1ad8836c` + +::: + +```solidity +error OwnableCannotSetZeroAddressAsOwner(); +``` + +Reverts when trying to set `address(0)` as the contract owner when deploying the contract, initializing it or transferring ownership of the contract. + +
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md index 565f464d4..8f61176f7 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md @@ -1812,3 +1812,47 @@ reverts when there is no extension for the function selector being called with | `functionSelector` | `bytes4` | - |
+ +### OwnableCallerNotTheOwner + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#ownablecallernottheowner) +- Solidity implementation: [`LSP8Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol) +- Error signature: `OwnableCallerNotTheOwner(address)` +- Error hash: `0xbf1169c5` + +::: + +```solidity +error OwnableCallerNotTheOwner(address callerAddress); +``` + +Reverts when only the owner is allowed to call the function. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ---------------------------------------- | +| `callerAddress` | `address` | The address that tried to make the call. | + +
+ +### OwnableCannotSetZeroAddressAsOwner + +:::note References + +- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#ownablecannotsetzeroaddressasowner) +- Solidity implementation: [`LSP8Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol) +- Error signature: `OwnableCannotSetZeroAddressAsOwner()` +- Error hash: `0x1ad8836c` + +::: + +```solidity +error OwnableCannotSetZeroAddressAsOwner(); +``` + +Reverts when trying to set `address(0)` as the contract owner when deploying the contract, initializing it or transferring ownership of the contract. + +
diff --git a/docs/contracts/LSP9Vault/LSP9Vault.md b/docs/contracts/LSP9Vault/LSP9Vault.md index e7fc33623..0ad2d5255 100644 --- a/docs/contracts/LSP9Vault/LSP9Vault.md +++ b/docs/contracts/LSP9Vault/LSP9Vault.md @@ -909,6 +909,12 @@ Perform low-level staticcall (operation type = 3) ### \_executeDelegateCall +:::caution Warning + +The `msg.value` should not be trusted for any method called with `operationType`: `DELEGATECALL` (4). + +::: + ```solidity function _executeDelegateCall( address target, @@ -1750,3 +1756,28 @@ reverts when there is no extension for the function selector being called with | `functionSelector` | `bytes4` | - |
+ +### OwnableCallerNotTheOwner + +:::note References + +- Specification details: [**LSP-9-Vault**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-9-Vault.md#ownablecallernottheowner) +- Solidity implementation: [`LSP9Vault.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP9Vault/LSP9Vault.sol) +- Error signature: `OwnableCallerNotTheOwner(address)` +- Error hash: `0xbf1169c5` + +::: + +```solidity +error OwnableCallerNotTheOwner(address callerAddress); +``` + +Reverts when only the owner is allowed to call the function. + +#### Parameters + +| Name | Type | Description | +| --------------- | :-------: | ---------------------------------------- | +| `callerAddress` | `address` | The address that tried to make the call. | + +
diff --git a/docs/contracts/UniversalProfile.md b/docs/contracts/UniversalProfile.md index 022af9d60..180c43ddc 100644 --- a/docs/contracts/UniversalProfile.md +++ b/docs/contracts/UniversalProfile.md @@ -894,6 +894,12 @@ Perform low-level staticcall (operation type = 3) ### \_executeDelegateCall +:::caution Warning + +The `msg.value` should not be trusted for any method called with `operationType`: `DELEGATECALL` (4). + +::: + ```solidity function _executeDelegateCall( address target, diff --git a/package-lock.json b/package-lock.json index 5a2881312..8aa39ae15 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "Apache-2.0", "dependencies": { "@account-abstraction/contracts": "^0.6.0", - "@erc725/smart-contracts": "^5.2.0", + "@erc725/smart-contracts": "^6.0.0", "@openzeppelin/contracts": "^4.9.2", "@openzeppelin/contracts-upgradeable": "^4.9.2", "solidity-bytes-utils": "0.8.0" @@ -624,9 +624,9 @@ } }, "node_modules/@erc725/smart-contracts": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@erc725/smart-contracts/-/smart-contracts-5.2.0.tgz", - "integrity": "sha512-ML7eXO2l6GO847CKGTbSO7MxpfVpmZvVPA/4KutYwVkaZmPxB05WC2flPxUilUz7ws0S7xgyt50sPHLA1ffojA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@erc725/smart-contracts/-/smart-contracts-6.0.0.tgz", + "integrity": "sha512-6okutGGL9xbg/MSgAof2FU1UcSNE/z3p9TORlROVGaM3gi1A6FQQ7fDqtBYkPtvHureX8yS9gP7xPt3PRbP43Q==", "dependencies": { "@openzeppelin/contracts": "^4.9.3", "@openzeppelin/contracts-upgradeable": "^4.9.3", @@ -22742,9 +22742,9 @@ } }, "@erc725/smart-contracts": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@erc725/smart-contracts/-/smart-contracts-5.2.0.tgz", - "integrity": "sha512-ML7eXO2l6GO847CKGTbSO7MxpfVpmZvVPA/4KutYwVkaZmPxB05WC2flPxUilUz7ws0S7xgyt50sPHLA1ffojA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@erc725/smart-contracts/-/smart-contracts-6.0.0.tgz", + "integrity": "sha512-6okutGGL9xbg/MSgAof2FU1UcSNE/z3p9TORlROVGaM3gi1A6FQQ7fDqtBYkPtvHureX8yS9gP7xPt3PRbP43Q==", "requires": { "@openzeppelin/contracts": "^4.9.3", "@openzeppelin/contracts-upgradeable": "^4.9.3", diff --git a/package.json b/package.json index aa2a8b133..7a73a12a6 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "homepage": "https://github.com/lukso-network/lsp-smart-contracts#readme", "dependencies": { "@account-abstraction/contracts": "^0.6.0", - "@erc725/smart-contracts": "^5.2.0", + "@erc725/smart-contracts": "^6.0.0", "@openzeppelin/contracts": "^4.9.2", "@openzeppelin/contracts-upgradeable": "^4.9.2", "solidity-bytes-utils": "0.8.0" diff --git a/tests/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.behaviour.ts b/tests/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.behaviour.ts index c492e2de0..674f0b028 100644 --- a/tests/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.behaviour.ts +++ b/tests/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.behaviour.ts @@ -79,7 +79,10 @@ export const shouldBehaveLikeLSP11 = (buildContext: () => Promise { @@ -280,7 +283,10 @@ export const shouldBehaveLikeLSP11 = (buildContext: () => Promise { @@ -322,7 +328,10 @@ export const shouldBehaveLikeLSP11 = (buildContext: () => Promise { @@ -365,7 +374,10 @@ export const shouldBehaveLikeLSP11 = (buildContext: () => Promise { @@ -408,7 +420,10 @@ export const shouldBehaveLikeLSP11 = (buildContext: () => Promise { diff --git a/tests/LSP14Ownable2Step/LSP14Ownable2Step.behaviour.ts b/tests/LSP14Ownable2Step/LSP14Ownable2Step.behaviour.ts index 727054d1a..d317c2926 100644 --- a/tests/LSP14Ownable2Step/LSP14Ownable2Step.behaviour.ts +++ b/tests/LSP14Ownable2Step/LSP14Ownable2Step.behaviour.ts @@ -19,7 +19,7 @@ export type LSP14TestContext = { accounts: SignerWithAddress[]; contract: LSP9Vault; deployParams: { owner: SignerWithAddress }; - onlyOwnerRevertString: string; + onlyOwnerCustomError: string; }; export const shouldBehaveLikeLSP14 = ( @@ -145,7 +145,7 @@ export const shouldBehaveLikeLSP14 = ( await expect( context.contract.connect(randomAddress).transferOwnership(randomAddress.address), - ).to.be.revertedWith('Ownable: caller is not the owner'); + ).to.be.revertedWithCustomError(context.contract, 'OwnableCallerNotTheOwner'); }); }); @@ -197,7 +197,7 @@ export const shouldBehaveLikeLSP14 = ( await expect( context.contract.connect(previousOwner).setData(key, value), - ).to.be.revertedWith(context.onlyOwnerRevertString); + ).to.be.revertedWith(context.onlyOwnerCustomError); }); it('should revert when calling `execute(...)`', async () => { @@ -208,13 +208,13 @@ export const shouldBehaveLikeLSP14 = ( context.contract .connect(previousOwner) .execute(OPERATION_TYPES.CALL, recipient.address, amount, '0x'), - ).to.be.revertedWith('Ownable: caller is not the owner'); + ).to.be.revertedWithCustomError(context.contract, 'OwnableCallerNotTheOwner'); }); it('should revert when calling `renounceOwnership(...)`', async () => { await expect( context.contract.connect(previousOwner).renounceOwnership(), - ).to.be.revertedWith('Ownable: caller is not the owner'); + ).to.be.revertedWithCustomError(context.contract, 'OwnableCallerNotTheOwner'); }); }); @@ -254,7 +254,10 @@ export const shouldBehaveLikeLSP14 = ( it('should revert with custom message', async () => { const tx = context.contract.connect(context.accounts[5]).renounceOwnership(); - await expect(tx).to.be.revertedWith('Ownable: caller is not the owner'); + await expect(tx).to.be.revertedWithCustomError( + context.contract, + 'OwnableCallerNotTheOwner', + ); }); }); @@ -477,7 +480,7 @@ export const shouldBehaveLikeLSP14 = ( context.contract .connect(context.deployParams.owner) .execute(OPERATION_TYPES.CALL, recipient, amount, '0x'), - ).to.be.revertedWith('Ownable: caller is not the owner'); + ).to.be.revertedWithCustomError(context.contract, 'OwnableCallerNotTheOwner'); }); }); }); diff --git a/tests/LSP20CallVerification/LSP20WithLSP14.behaviour.ts b/tests/LSP20CallVerification/LSP20WithLSP14.behaviour.ts index bd550f265..860389cd7 100644 --- a/tests/LSP20CallVerification/LSP20WithLSP14.behaviour.ts +++ b/tests/LSP20CallVerification/LSP20WithLSP14.behaviour.ts @@ -6,12 +6,10 @@ import { LSP0ERC725Account, UPWithInstantAcceptOwnership__factory, UPWithInstantAcceptOwnership, - LSP6KeyManager__factory, - LSP6KeyManager, } from '../../types'; // constants -import { ERC725YDataKeys, OPERATION_TYPES, PERMISSIONS } from '../../constants'; +import { OPERATION_TYPES } from '../../constants'; // helpers import { provider } from '../utils/helpers'; @@ -21,7 +19,7 @@ export type LSP14CombinedWithLSP20TestContext = { accounts: SignerWithAddress[]; contract: LSP0ERC725Account; deployParams: { owner: SignerWithAddress }; - onlyOwnerRevertString: string; + onlyOwnerCustomError: string; }; export const shouldBehaveLikeLSP14WithLSP20 = ( diff --git a/tests/LSP6KeyManager/LSP6ControlledToken.test.ts b/tests/LSP6KeyManager/LSP6ControlledToken.test.ts index 53f0e94b2..19b98fa31 100644 --- a/tests/LSP6KeyManager/LSP6ControlledToken.test.ts +++ b/tests/LSP6KeyManager/LSP6ControlledToken.test.ts @@ -166,7 +166,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { await expect( context.keyManager.connect(context.mainController).execute(payload), - ).to.be.revertedWith('Ownable: caller is not the owner'); + ).to.be.revertedWithCustomError(context.token, 'OwnableCallerNotTheOwner'); }); it('should allow the new owner to call setData(..)', async () => { @@ -208,7 +208,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { await expect( context.keyManager.connect(context.mainController).execute(transferOwnershipPayload), - ).to.be.revertedWith('Ownable: caller is not the owner'); + ).to.be.revertedWithCustomError(context.token, 'OwnableCallerNotTheOwner'); }); it('should allow the new owner to call transferOwnership(..)', async () => { @@ -223,7 +223,7 @@ describe('When deploying LSP7 with LSP6 as owner', () => { await expect( context.keyManager.connect(context.mainController).execute(renounceOwnershipPayload), - ).to.be.revertedWith('Ownable: caller is not the owner'); + ).to.be.revertedWithCustomError(context.token, 'OwnableCallerNotTheOwner'); }); it('should allow the new owner to call renounceOwnership(..)', async () => { diff --git a/tests/LSP7DigitalAsset/LSP7DigitalAsset.behaviour.ts b/tests/LSP7DigitalAsset/LSP7DigitalAsset.behaviour.ts index da3dc0141..0d41e3c03 100644 --- a/tests/LSP7DigitalAsset/LSP7DigitalAsset.behaviour.ts +++ b/tests/LSP7DigitalAsset/LSP7DigitalAsset.behaviour.ts @@ -2160,7 +2160,7 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise { @@ -2172,21 +2172,21 @@ export const shouldBehaveLikeLSP7 = (buildContext: () => Promise { - await expect(context.lsp7.connect(oldOwner).renounceOwnership()).to.be.revertedWith( - 'Ownable: caller is not the owner', - ); + await expect( + context.lsp7.connect(oldOwner).renounceOwnership(), + ).to.be.revertedWithCustomError(context.lsp7, 'OwnableCallerNotTheOwner'); }); it('old owner should not be allowed to use `setData(..)`', async () => { const key = ethers.utils.keccak256(ethers.utils.toUtf8Bytes('key')); const value = ethers.utils.keccak256(ethers.utils.toUtf8Bytes('value')); - await expect(context.lsp7.connect(oldOwner).setData(key, value)).to.be.revertedWith( - 'Ownable: caller is not the owner', - ); + await expect( + context.lsp7.connect(oldOwner).setData(key, value), + ).to.be.revertedWithCustomError(context.lsp7, 'OwnableCallerNotTheOwner'); }); it('new owner should be allowed to use `transferOwnership(..)`', async () => { diff --git a/tests/LSP7DigitalAsset/LSP7Mintable.behaviour.ts b/tests/LSP7DigitalAsset/LSP7Mintable.behaviour.ts index 43d0f2dbf..c1e94a27e 100644 --- a/tests/LSP7DigitalAsset/LSP7Mintable.behaviour.ts +++ b/tests/LSP7DigitalAsset/LSP7Mintable.behaviour.ts @@ -82,7 +82,7 @@ export const shouldBehaveLikeLSP7Mintable = ( await expect( context.lsp7Mintable.connect(nonOwner).mint(nonOwner.address, amountToMint, true, '0x'), - ).to.be.revertedWith('Ownable: caller is not the owner'); + ).to.be.revertedWithCustomError(context.lsp7Mintable, 'OwnableCallerNotTheOwner'); }); }); diff --git a/tests/LSP7DigitalAsset/proxy/LSP7DigitalAssetInit.test.ts b/tests/LSP7DigitalAsset/proxy/LSP7DigitalAssetInit.test.ts index 84a364410..fc3c599d4 100644 --- a/tests/LSP7DigitalAsset/proxy/LSP7DigitalAssetInit.test.ts +++ b/tests/LSP7DigitalAsset/proxy/LSP7DigitalAssetInit.test.ts @@ -79,7 +79,7 @@ describe('LSP7DigitalAssetInit with proxy', () => { ethers.constants.AddressZero, false, ), - ).to.be.revertedWith('Ownable: new owner is the zero address'); + ).to.be.revertedWithCustomError(context.lsp7, 'OwnableCannotSetZeroAddressAsOwner'); }); describe('when initializing the contract', () => { diff --git a/tests/LSP7DigitalAsset/standard/LSP7DigitalAsset.test.ts b/tests/LSP7DigitalAsset/standard/LSP7DigitalAsset.test.ts index 94869a442..8447ea11b 100644 --- a/tests/LSP7DigitalAsset/standard/LSP7DigitalAsset.test.ts +++ b/tests/LSP7DigitalAsset/standard/LSP7DigitalAsset.test.ts @@ -86,13 +86,11 @@ describe('LSP7DigitalAsset with constructor', () => { newOwner: ethers.constants.AddressZero, }; + const contractToDeploy = new LSP7Tester__factory(accounts[0]); + await expect( - new LSP7Tester__factory(accounts[0]).deploy( - deployParams.name, - deployParams.symbol, - deployParams.newOwner, - ), - ).to.be.revertedWith('Ownable: new owner is the zero address'); + contractToDeploy.deploy(deployParams.name, deployParams.symbol, deployParams.newOwner), + ).to.be.revertedWithCustomError(contractToDeploy, 'OwnableCannotSetZeroAddressAsOwner'); }); describe('once the contract was deployed', () => { diff --git a/tests/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.behaviour.ts b/tests/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.behaviour.ts index 0e9cf9021..b0508f91f 100644 --- a/tests/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.behaviour.ts +++ b/tests/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.behaviour.ts @@ -1725,7 +1725,7 @@ export const shouldBehaveLikeLSP8 = ( const newOwner = context.accounts.anyone; await expect( context.lsp8.connect(newOwner).transferOwnership(newOwner.address), - ).to.be.revertedWith('Ownable: caller is not the owner'); + ).to.be.revertedWithCustomError(context.lsp8, 'OwnableCallerNotTheOwner'); }); it('should transfer ownership of the contract', async () => { @@ -1744,21 +1744,21 @@ export const shouldBehaveLikeLSP8 = ( const randomAddress = context.accounts.anyone.address; await expect( context.lsp8.connect(oldOwner).transferOwnership(randomAddress), - ).to.be.revertedWith('Ownable: caller is not the owner'); + ).to.be.revertedWithCustomError(context.lsp8, 'OwnableCallerNotTheOwner'); }); it('old owner should not be allowed to use `renounceOwnership(..)`', async () => { - await expect(context.lsp8.connect(oldOwner).renounceOwnership()).to.be.revertedWith( - 'Ownable: caller is not the owner', - ); + await expect( + context.lsp8.connect(oldOwner).renounceOwnership(), + ).to.be.revertedWithCustomError(context.lsp8, 'OwnableCallerNotTheOwner'); }); it('old owner should not be allowed to use `setData(..)`', async () => { const key = ethers.utils.keccak256(ethers.utils.toUtf8Bytes('key')); const value = ethers.utils.keccak256(ethers.utils.toUtf8Bytes('value')); - await expect(context.lsp8.connect(oldOwner).setData(key, value)).to.be.revertedWith( - 'Ownable: caller is not the owner', - ); + await expect( + context.lsp8.connect(oldOwner).setData(key, value), + ).to.be.revertedWithCustomError(context.lsp8, 'OwnableCallerNotTheOwner'); }); it('new owner should be allowed to use `transferOwnership(..)`', async () => { diff --git a/tests/LSP8IdentifiableDigitalAsset/LSP8Mintable.behaviour.ts b/tests/LSP8IdentifiableDigitalAsset/LSP8Mintable.behaviour.ts index 0c4d54e6a..da558a2ca 100644 --- a/tests/LSP8IdentifiableDigitalAsset/LSP8Mintable.behaviour.ts +++ b/tests/LSP8IdentifiableDigitalAsset/LSP8Mintable.behaviour.ts @@ -83,7 +83,7 @@ export const shouldBehaveLikeLSP8Mintable = ( context.lsp8Mintable .connect(nonOwner) .mint(context.accounts.tokenReceiver.address, randomTokenId, true, '0x'), - ).to.be.revertedWith('Ownable: caller is not the owner'); + ).to.be.revertedWithCustomError(context.lsp8Mintable, 'OwnableCallerNotTheOwner'); }); }); diff --git a/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8IdentifiableDigitalAssetInit.test.ts b/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8IdentifiableDigitalAssetInit.test.ts index cc58c704e..d016e2167 100644 --- a/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8IdentifiableDigitalAssetInit.test.ts +++ b/tests/LSP8IdentifiableDigitalAsset/proxy/LSP8IdentifiableDigitalAssetInit.test.ts @@ -74,7 +74,7 @@ describe('LSP8IdentifiableDigitalAssetInit with proxy', () => { ethers.constants.AddressZero, 0, ), - ).to.be.revertedWith('Ownable: new owner is the zero address'); + ).to.be.revertedWithCustomError(context.lsp8, 'OwnableCannotSetZeroAddressAsOwner'); }); describe('when initializing the contract', () => { diff --git a/tests/LSP8IdentifiableDigitalAsset/standard/LSP8IdentifiableDigitalAsset.test.ts b/tests/LSP8IdentifiableDigitalAsset/standard/LSP8IdentifiableDigitalAsset.test.ts index b1faa703c..3d5d14d07 100644 --- a/tests/LSP8IdentifiableDigitalAsset/standard/LSP8IdentifiableDigitalAsset.test.ts +++ b/tests/LSP8IdentifiableDigitalAsset/standard/LSP8IdentifiableDigitalAsset.test.ts @@ -85,14 +85,16 @@ describe('LSP8IdentifiableDigitalAsset with constructor', () => { newOwner: ethers.constants.AddressZero, }; + const contractToDeploy = new LSP8Tester__factory(accounts[0]); + await expect( - new LSP8Tester__factory(accounts[0]).deploy( + contractToDeploy.deploy( deployParams.name, deployParams.symbol, ethers.constants.AddressZero, LSP8_TOKEN_ID_TYPES.NUMBER, ), - ).to.be.revertedWith('Ownable: new owner is the zero address'); + ).to.be.revertedWithCustomError(contractToDeploy, 'OwnableCannotSetZeroAddressAsOwner'); }); describe('once the contract was deployed', () => { diff --git a/tests/LSP9Vault/LSP9Vault.test.ts b/tests/LSP9Vault/LSP9Vault.test.ts index ad2f28ed5..98d70c3a2 100644 --- a/tests/LSP9Vault/LSP9Vault.test.ts +++ b/tests/LSP9Vault/LSP9Vault.test.ts @@ -59,13 +59,13 @@ describe('LSP9Vault with constructor', () => { value: initialFunding, }); - const onlyOwnerRevertString = 'Only Owner or reentered Universal Receiver Delegate allowed'; + const onlyOwnerCustomError = 'Only Owner or reentered Universal Receiver Delegate allowed'; return { accounts, contract: lsp9Vault, deployParams, - onlyOwnerRevertString, + onlyOwnerCustomError, }; }; diff --git a/tests/LSP9Vault/LSP9VaultInit.test.ts b/tests/LSP9Vault/LSP9VaultInit.test.ts index 7eaab9ee6..4e7fc2560 100644 --- a/tests/LSP9Vault/LSP9VaultInit.test.ts +++ b/tests/LSP9Vault/LSP9VaultInit.test.ts @@ -126,13 +126,13 @@ describe('LSP9VaultInit with proxy', () => { const accounts = await ethers.getSigners(); await initializeProxy(context); - const onlyOwnerRevertString = 'Only Owner or reentered Universal Receiver Delegate allowed'; + const onlyOwnerCustomError = 'Only Owner or reentered Universal Receiver Delegate allowed'; return { accounts: accounts, contract: context.lsp9Vault, deployParams: { owner: context.accounts.owner }, - onlyOwnerRevertString, + onlyOwnerCustomError, }; }); diff --git a/tests/UniversalProfile.test.ts b/tests/UniversalProfile.test.ts index 01dcc7eab..f22bef997 100644 --- a/tests/UniversalProfile.test.ts +++ b/tests/UniversalProfile.test.ts @@ -72,9 +72,9 @@ describe('UniversalProfile with constructor', () => { { value: initialFunding }, ); - const onlyOwnerRevertString = 'Ownable: caller is not the owner'; + const onlyOwnerCustomError = 'OwnableCallerNotTheOwner'; - return { accounts, contract, deployParams, onlyOwnerRevertString }; + return { accounts, contract, deployParams, onlyOwnerCustomError }; }; const buildLSP17TestContext = async (): Promise => { diff --git a/tests/UniversalProfileInit.test.ts b/tests/UniversalProfileInit.test.ts index 5b73d1fcf..a0fbc0ef1 100644 --- a/tests/UniversalProfileInit.test.ts +++ b/tests/UniversalProfileInit.test.ts @@ -86,13 +86,13 @@ describe('UniversalProfileInit with proxy', () => { const universalProfile = universalProfileInit.attach(universalProfileProxy); - const onlyOwnerRevertString = 'Ownable: caller is not the owner'; + const onlyOwnerCustomError = 'OwnableCallerNotTheOwner'; return { accounts, contract: universalProfile, deployParams, - onlyOwnerRevertString, + onlyOwnerCustomError, }; }; From b038412c99d5149f25a83156322539e817e1575b Mon Sep 17 00:00:00 2001 From: Jean Cvllr <31145285+CJ42@users.noreply.github.com> Date: Tue, 17 Oct 2023 14:08:58 +0100 Subject: [PATCH 54/55] refactor!: remove `LSP4Compatibility` contract + ERC20 Compatible token interfaces `ILSP7CompatibleERC20` / `ILSP8CompatibleERC721` (#749) * refactor: inheritance of LSP7/8 Compatible * refactor!: remove `LSP4Compatibility` contract + interface * refactor!: remove ILSP7ERC20 and ILSP8ERC721 Compatible interfaces * fix: support ERC20 interfaces in `LSP7CompatibleERC20` * refactor: remove unecessary imports and overriden functions * docs: add `ERC20Metadata` in ignored interfaceIds --- .github/workflows/build-lint-test.yml | 1 - constants.ts | 1 + .../ILSP4Compatibility.sol | 25 - .../LSP4Compatibility.sol | 41 -- .../extensions/ILSP7CompatibleERC20.sol | 83 --- .../extensions/LSP7CompatibleERC20.sol | 155 +++-- .../LSP7CompatibleERC20InitAbstract.sol | 159 +++-- .../presets/LSP7CompatibleERC20Mintable.sol | 2 +- .../LSP7CompatibleERC20MintableInit.sol | 2 +- ...SP7CompatibleERC20MintableInitAbstract.sol | 2 +- .../extensions/ILSP8CompatibleERC721.sol | 175 ------ .../extensions/LSP8CompatibleERC721.sol | 205 ++++-- .../LSP8CompatibleERC721InitAbstract.sol | 213 +++++-- contracts/Mocks/ERC165Interfaces.sol | 17 +- .../Mocks/Tokens/LSP4CompatibilityTester.sol | 26 - .../LSP4Compatibility.md | 583 ------------------ .../extensions/LSP7CompatibleERC20.md | 126 ++-- .../presets/LSP7CompatibleERC20Mintable.md | 126 ++-- .../extensions/LSP8CompatibleERC721.md | 137 ++-- .../presets/LSP8CompatibleERC721Mintable.md | 137 ++-- dodoc/config.ts | 1 - hardhat.config.ts | 1 - package.json | 1 - scripts/interfaceIds.ts | 10 +- .../LSP4Compatibility.test.ts | 77 --- .../LSP7CompatibleERC20.behaviour.ts | 42 +- .../LSP8CompatibleERC721.behaviour.ts | 43 +- tests/Mocks/ERC165Interfaces.test.ts | 5 + 28 files changed, 922 insertions(+), 1474 deletions(-) delete mode 100644 contracts/LSP4DigitalAssetMetadata/ILSP4Compatibility.sol delete mode 100644 contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol delete mode 100644 contracts/LSP7DigitalAsset/extensions/ILSP7CompatibleERC20.sol delete mode 100644 contracts/LSP8IdentifiableDigitalAsset/extensions/ILSP8CompatibleERC721.sol delete mode 100644 contracts/Mocks/Tokens/LSP4CompatibilityTester.sol delete mode 100644 docs/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.md delete mode 100644 tests/LSP4DigitalAssetMetadata/LSP4Compatibility.test.ts diff --git a/.github/workflows/build-lint-test.yml b/.github/workflows/build-lint-test.yml index 99b5a8e54..d5cf13392 100644 --- a/.github/workflows/build-lint-test.yml +++ b/.github/workflows/build-lint-test.yml @@ -64,7 +64,6 @@ jobs: "upinit", "lsp1", "lsp2", - "lsp4", "lsp6", "lsp6init", "lsp7", diff --git a/constants.ts b/constants.ts index 18c3aaebf..c7802d7a8 100644 --- a/constants.ts +++ b/constants.ts @@ -17,6 +17,7 @@ export const INTERFACE_IDS = { ERC165: '0x01ffc9a7', ERC1271: '0x1626ba7e', ERC20: '0x36372b07', + ERC20Metadata: '0xa219a025', ERC223: '0x87d43052', ERC721: '0x80ac58cd', ERC721Metadata: '0x5b5e139f', diff --git a/contracts/LSP4DigitalAssetMetadata/ILSP4Compatibility.sol b/contracts/LSP4DigitalAssetMetadata/ILSP4Compatibility.sol deleted file mode 100644 index ede2d60a7..000000000 --- a/contracts/LSP4DigitalAssetMetadata/ILSP4Compatibility.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -pragma solidity ^0.8.4; - -// interfaces -import { - IERC725Y -} from "@erc725/smart-contracts/contracts/interfaces/IERC725Y.sol"; - -/** - * @dev LSP4 extension, for compatibility with clients & tools that expect ERC20/721. - */ -interface ILSP4Compatibility is IERC725Y { - /** - * @dev Returns the name of the token. - * @return The name of the token - */ - function name() external view returns (string memory); - - /** - * @dev Returns the symbol of the token, usually a shorter version of the name. - * @return The symbol of the token - */ - function symbol() external view returns (string memory); -} diff --git a/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol b/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol deleted file mode 100644 index fe661e18e..000000000 --- a/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.4; - -// interfaces -import {ILSP4Compatibility} from "./ILSP4Compatibility.sol"; - -// modules -import {ERC725YCore} from "@erc725/smart-contracts/contracts/ERC725YCore.sol"; - -// constants -import { - _LSP4_TOKEN_NAME_KEY, - _LSP4_TOKEN_SYMBOL_KEY -} from "./LSP4Constants.sol"; - -/** - * @title LSP4Compatibility - * @author Matthew Stevens - * @dev LSP4 extension, for compatibility with clients & tools that expect ERC20/721. - */ -abstract contract LSP4Compatibility is ILSP4Compatibility, ERC725YCore { - // --- Token queries - - /** - * @dev Returns the name of the token. - * @return The name of the token - */ - function name() public view virtual override returns (string memory) { - bytes memory data = _getData(_LSP4_TOKEN_NAME_KEY); - return string(data); - } - - /** - * @dev Returns the symbol of the token, usually a shorter version of the name. - * @return The symbol of the token - */ - function symbol() public view virtual override returns (string memory) { - bytes memory data = _getData(_LSP4_TOKEN_SYMBOL_KEY); - return string(data); - } -} diff --git a/contracts/LSP7DigitalAsset/extensions/ILSP7CompatibleERC20.sol b/contracts/LSP7DigitalAsset/extensions/ILSP7CompatibleERC20.sol deleted file mode 100644 index 38cdb68c6..000000000 --- a/contracts/LSP7DigitalAsset/extensions/ILSP7CompatibleERC20.sol +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -pragma solidity ^0.8.4; - -// interfaces -import {ILSP7DigitalAsset} from "../ILSP7DigitalAsset.sol"; - -/** - * @dev LSP7 extension, for compatibility for clients / tools that expect ERC20. - */ -interface ILSP7CompatibleERC20 is ILSP7DigitalAsset { - /** - * @dev ERC20 `Transfer` event emitted when `amount` tokens is transferred from `from` to `to`. - * To provide compatibility with indexing ERC20 events. - * - * @param from The sending address - * @param to The receiving address - * @param value The amount of tokens transfered. - */ - event Transfer(address indexed from, address indexed to, uint256 value); - - /** - * @dev ERC20 `Approval` event emitted when `owner` enables `spender` for `value` tokens. - * To provide compatibility with indexing ERC20 events. - * - * @param owner The account giving approval - * @param spender The account receiving approval - * @param value The amount of tokens `spender` has access to from `owner` - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 value - ); - - /* - * @dev Transfer function from the ERC20 standard interface. - - * @param to The address receiving tokens. - * @param amount The amount of tokens to transfer. - * - * @return `true` on successful transfer. - */ - function transfer(address to, uint256 amount) external returns (bool); - - /* - * @dev Transfer functions for operators from the ERC20 standard interface. - - * @param from The address sending tokens. - * @param to The address receiving tokens. - * @param amount The amount of tokens to transfer. - * - * @return `true` on successful transfer. - */ - function transferFrom( - address from, - address to, - uint256 amount - ) external returns (bool); - - /* - * @dev Approval function from th ERC20 standard interface. - - * @param operator The address to approve for `amount` - * @param amount The amount to approve. - * - * @return `true` on successful approval. - */ - function approve(address operator, uint256 amount) external returns (bool); - - /* - * @dev Function to get operator allowance allowed to spend on behalf of `tokenOwner` from the ERC20 standard interface. - - * @param tokenOwner The address of the token owner - * @param operator The address approved by the `tokenOwner` - * - * @return The amount `operator` is approved by `tokenOwner` - */ - function allowance( - address tokenOwner, - address operator - ) external view returns (uint256); -} diff --git a/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol b/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol index b9b0e473e..bc7cfa546 100644 --- a/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol +++ b/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol @@ -1,28 +1,25 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.12; +pragma solidity ^0.8.7; // interfaces -import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; -import {ILSP7CompatibleERC20} from "./ILSP7CompatibleERC20.sol"; +import { + IERC20Metadata, + IERC20 +} from "@openzeppelin/contracts/interfaces/IERC20Metadata.sol"; // modules +import {LSP7DigitalAssetCore, LSP7DigitalAsset} from "../LSP7DigitalAsset.sol"; + +// constants import { - LSP4Compatibility -} from "../../LSP4DigitalAssetMetadata/LSP4Compatibility.sol"; -import { - LSP7DigitalAsset, - LSP4DigitalAssetMetadata, - ERC725YCore -} from "../LSP7DigitalAsset.sol"; + _LSP4_TOKEN_NAME_KEY, + _LSP4_TOKEN_SYMBOL_KEY +} from "../../LSP4DigitalAssetMetadata/LSP4Constants.sol"; /** * @dev LSP7 extension, for compatibility for clients / tools that expect ERC20. */ -abstract contract LSP7CompatibleERC20 is - ILSP7CompatibleERC20, - LSP4Compatibility, - LSP7DigitalAsset -{ +abstract contract LSP7CompatibleERC20 is IERC20Metadata, LSP7DigitalAsset { /** * @notice Deploying a `LSP7CompatibleERC20` token contract with: token name = `name_`, token symbol = `symbol_`, and * address `newOwner_` as the token contract owner. @@ -38,22 +35,90 @@ abstract contract LSP7CompatibleERC20 is ) LSP7DigitalAsset(name_, symbol_, newOwner_, false) {} /** - * @inheritdoc LSP7DigitalAsset + * @inheritdoc IERC20Metadata + * @dev Returns the name of the token. + * For compatibility with clients & tools that expect ERC20. + * + * @return The name of the token */ - function supportsInterface( - bytes4 interfaceId + function name() public view virtual override returns (string memory) { + bytes memory data = _getData(_LSP4_TOKEN_NAME_KEY); + return string(data); + } + + /** + * @inheritdoc IERC20Metadata + * @dev Returns the symbol of the token, usually a shorter version of the name. + * For compatibility with clients & tools that expect ERC20. + * + * @return The symbol of the token + */ + function symbol() public view virtual override returns (string memory) { + bytes memory data = _getData(_LSP4_TOKEN_SYMBOL_KEY); + return string(data); + } + + /** + * @inheritdoc LSP7DigitalAssetCore + */ + function decimals() + public + view + virtual + override(IERC20Metadata, LSP7DigitalAssetCore) + returns (uint8) + { + return super.decimals(); + } + + /** + * @inheritdoc LSP7DigitalAssetCore + */ + function totalSupply() + public + view + virtual + override(IERC20, LSP7DigitalAssetCore) + returns (uint256) + { + return super.totalSupply(); + } + + /** + * @inheritdoc LSP7DigitalAssetCore + */ + function balanceOf( + address tokenOwner ) public view virtual - override(IERC165, ERC725YCore, LSP7DigitalAsset) - returns (bool) + override(IERC20, LSP7DigitalAssetCore) + returns (uint256) { - return super.supportsInterface(interfaceId); + return super.balanceOf(tokenOwner); + } + + /** + * @inheritdoc LSP7DigitalAsset + */ + function supportsInterface( + bytes4 interfaceId + ) public view virtual override returns (bool) { + return + interfaceId == type(IERC20).interfaceId || + interfaceId == type(IERC20Metadata).interfaceId || + super.supportsInterface(interfaceId); } /** - * @inheritdoc ILSP7CompatibleERC20 + * @inheritdoc IERC20 + * @dev Function to get operator allowance allowed to spend on behalf of `tokenOwner` from the ERC20 standard interface. + * + * @param tokenOwner The address of the token owner + * @param operator The address approved by the `tokenOwner` + * + * @return The amount `operator` is approved by `tokenOwner` */ function allowance( address tokenOwner, @@ -63,7 +128,13 @@ abstract contract LSP7CompatibleERC20 is } /** - * @inheritdoc ILSP7CompatibleERC20 + * @inheritdoc IERC20 + * @dev Approval function from th ERC20 standard interface. + * + * @param operator The address to approve for `amount` + * @param amount The amount to approve. + * + * @return `true` on successful approval. */ function approve( address operator, @@ -74,7 +145,14 @@ abstract contract LSP7CompatibleERC20 is } /** - * @inheritdoc ILSP7CompatibleERC20 + * @inheritdoc IERC20 + * @dev Transfer functions for operators from the ERC20 standard interface. + * + * @param from The address sending tokens. + * @param to The address receiving tokens. + * @param amount The amount of tokens to transfer. + * + * @return `true` on successful transfer. * * @custom:info This function uses the `force` parameter as `true` so that EOA and any contract can receive tokens. */ @@ -90,7 +168,13 @@ abstract contract LSP7CompatibleERC20 is // --- Overrides /** - * @inheritdoc ILSP7CompatibleERC20 + * @inheritdoc IERC20 + * @dev Transfer function from the ERC20 standard interface. + + * @param to The address receiving tokens. + * @param amount The amount of tokens to transfer. + * + * @return `true` on successful transfer. * * @custom:info This function uses the `force` parameter as `true` so that EOA and any contract can receive tokens. */ @@ -102,6 +186,9 @@ abstract contract LSP7CompatibleERC20 is return true; } + /** + * @inheritdoc LSP7DigitalAssetCore + */ function _updateOperator( address tokenOwner, address operator, @@ -114,7 +201,7 @@ abstract contract LSP7CompatibleERC20 is amount, operatorNotificationData ); - emit Approval(tokenOwner, operator, amount); + emit IERC20.Approval(tokenOwner, operator, amount); } /** @@ -129,7 +216,7 @@ abstract contract LSP7CompatibleERC20 is bool force, bytes memory data ) internal virtual override { - emit Transfer(from, to, amount); + emit IERC20.Transfer(from, to, amount); super._transfer(from, to, amount, force, data); } @@ -144,7 +231,7 @@ abstract contract LSP7CompatibleERC20 is bool force, bytes memory data ) internal virtual override { - emit Transfer(address(0), to, amount); + emit IERC20.Transfer(address(0), to, amount); super._mint(to, amount, force, data); } @@ -158,17 +245,7 @@ abstract contract LSP7CompatibleERC20 is uint256 amount, bytes memory data ) internal virtual override { - emit Transfer(from, address(0), amount); + emit IERC20.Transfer(from, address(0), amount); super._burn(from, amount, data); } - - /** - * @inheritdoc LSP4DigitalAssetMetadata - */ - function _setData( - bytes32 key, - bytes memory value - ) internal virtual override(LSP4DigitalAssetMetadata, ERC725YCore) { - super._setData(key, value); - } } diff --git a/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20InitAbstract.sol b/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20InitAbstract.sol index 4b64a16d3..840e537ed 100644 --- a/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20InitAbstract.sol +++ b/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20InitAbstract.sol @@ -1,26 +1,29 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.12; +pragma solidity ^0.8.7; // interfaces -import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; -import {ILSP7CompatibleERC20} from "./ILSP7CompatibleERC20.sol"; +import { + IERC20Metadata, + IERC20 +} from "@openzeppelin/contracts/interfaces/IERC20Metadata.sol"; // modules import { - LSP4Compatibility -} from "../../LSP4DigitalAssetMetadata/LSP4Compatibility.sol"; -import { - LSP7DigitalAssetInitAbstract, - LSP4DigitalAssetMetadataInitAbstract, - ERC725YCore + LSP7DigitalAssetCore, + LSP7DigitalAssetInitAbstract } from "../LSP7DigitalAssetInitAbstract.sol"; +// constants +import { + _LSP4_TOKEN_NAME_KEY, + _LSP4_TOKEN_SYMBOL_KEY +} from "../../LSP4DigitalAssetMetadata/LSP4Constants.sol"; + /** * @dev LSP7 extension, for compatibility for clients / tools that expect ERC20. */ abstract contract LSP7CompatibleERC20InitAbstract is - ILSP7CompatibleERC20, - LSP4Compatibility, + IERC20Metadata, LSP7DigitalAssetInitAbstract { /** @@ -45,32 +48,106 @@ abstract contract LSP7CompatibleERC20InitAbstract is } /** - * @inheritdoc LSP7DigitalAssetInitAbstract + * @inheritdoc IERC20Metadata + * @dev Returns the name of the token. + * For compatibility with clients & tools that expect ERC20. + * + * @return The name of the token */ - function supportsInterface( - bytes4 interfaceId + function name() public view virtual override returns (string memory) { + bytes memory data = _getData(_LSP4_TOKEN_NAME_KEY); + return string(data); + } + + /** + * @inheritdoc IERC20Metadata + * @dev Returns the symbol of the token, usually a shorter version of the name. + * For compatibility with clients & tools that expect ERC20. + * + * @return The symbol of the token + */ + function symbol() public view virtual override returns (string memory) { + bytes memory data = _getData(_LSP4_TOKEN_SYMBOL_KEY); + return string(data); + } + + /** + * @inheritdoc LSP7DigitalAssetCore + */ + function decimals() + public + view + virtual + override(IERC20Metadata, LSP7DigitalAssetCore) + returns (uint8) + { + return super.decimals(); + } + + /** + * @inheritdoc LSP7DigitalAssetCore + */ + function totalSupply() + public + view + virtual + override(IERC20, LSP7DigitalAssetCore) + returns (uint256) + { + return super.totalSupply(); + } + + /** + * @inheritdoc LSP7DigitalAssetCore + */ + function balanceOf( + address tokenOwner ) public view virtual - override(IERC165, ERC725YCore, LSP7DigitalAssetInitAbstract) - returns (bool) + override(IERC20, LSP7DigitalAssetCore) + returns (uint256) { - return super.supportsInterface(interfaceId); + return super.balanceOf(tokenOwner); } /** - * @inheritdoc ILSP7CompatibleERC20 + * @inheritdoc LSP7DigitalAssetInitAbstract + */ + function supportsInterface( + bytes4 interfaceId + ) public view virtual override returns (bool) { + return + interfaceId == type(IERC20).interfaceId || + interfaceId == type(IERC20Metadata).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @inheritdoc IERC20 + * @dev Function to get operator allowance allowed to spend on behalf of `tokenOwner` from the ERC20 standard interface. + * + * @param tokenOwner The address of the token owner + * @param operator The address approved by the `tokenOwner` + * + * @return The amount `operator` is approved by `tokenOwner` */ function allowance( address tokenOwner, address operator - ) public view virtual returns (uint256) { + ) public view virtual override returns (uint256) { return authorizedAmountFor(operator, tokenOwner); } /** - * @inheritdoc ILSP7CompatibleERC20 + * @inheritdoc IERC20 + * @dev Approval function from th ERC20 standard interface. + * + * @param operator The address to approve for `amount` + * @param amount The amount to approve. + * + * @return `true` on successful approval. */ function approve( address operator, @@ -81,7 +158,14 @@ abstract contract LSP7CompatibleERC20InitAbstract is } /** - * @inheritdoc ILSP7CompatibleERC20 + * @inheritdoc IERC20 + * @dev Transfer functions for operators from the ERC20 standard interface. + * + * @param from The address sending tokens. + * @param to The address receiving tokens. + * @param amount The amount of tokens to transfer. + * + * @return `true` on successful transfer. * * @custom:info This function uses the `force` parameter as `true` so that EOA and any contract can receive tokens. */ @@ -97,7 +181,13 @@ abstract contract LSP7CompatibleERC20InitAbstract is // --- Overrides /** - * @inheritdoc ILSP7CompatibleERC20 + * @inheritdoc IERC20 + * @dev Transfer function from the ERC20 standard interface. + * + * @param to The address receiving tokens. + * @param amount The amount of tokens to transfer. + * + * @return `true` on successful transfer. * * @custom:info This function uses the `force` parameter as `true` so that EOA and any contract can receive tokens. */ @@ -109,6 +199,9 @@ abstract contract LSP7CompatibleERC20InitAbstract is return true; } + /** + * @inheritdoc LSP7DigitalAssetCore + */ function _updateOperator( address tokenOwner, address operator, @@ -121,7 +214,7 @@ abstract contract LSP7CompatibleERC20InitAbstract is amount, operatorNotificationData ); - emit Approval(tokenOwner, operator, amount); + emit IERC20.Approval(tokenOwner, operator, amount); } /** @@ -136,7 +229,7 @@ abstract contract LSP7CompatibleERC20InitAbstract is bool force, bytes memory data ) internal virtual override { - emit Transfer(from, to, amount); + emit IERC20.Transfer(from, to, amount); super._transfer(from, to, amount, force, data); } @@ -151,7 +244,7 @@ abstract contract LSP7CompatibleERC20InitAbstract is bool force, bytes memory data ) internal virtual override { - emit Transfer(address(0), to, amount); + emit IERC20.Transfer(address(0), to, amount); super._mint(to, amount, force, data); } @@ -165,21 +258,7 @@ abstract contract LSP7CompatibleERC20InitAbstract is uint256 amount, bytes memory data ) internal virtual override { - emit Transfer(from, address(0), amount); + emit IERC20.Transfer(from, address(0), amount); super._burn(from, amount, data); } - - /** - * @inheritdoc LSP4DigitalAssetMetadataInitAbstract - */ - function _setData( - bytes32 key, - bytes memory value - ) - internal - virtual - override(LSP4DigitalAssetMetadataInitAbstract, ERC725YCore) - { - super._setData(key, value); - } } diff --git a/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol b/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol index 4595ed749..c3833e16e 100644 --- a/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol +++ b/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.12; +pragma solidity ^0.8.7; import {LSP7CompatibleERC20} from "../extensions/LSP7CompatibleERC20.sol"; diff --git a/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20MintableInit.sol b/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20MintableInit.sol index f75b4b758..83ace62b5 100644 --- a/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20MintableInit.sol +++ b/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20MintableInit.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.12; +pragma solidity ^0.8.7; // modules import { diff --git a/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20MintableInitAbstract.sol b/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20MintableInitAbstract.sol index 95b0bee2c..9b831d11a 100644 --- a/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20MintableInitAbstract.sol +++ b/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20MintableInitAbstract.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.12; +pragma solidity ^0.8.7; // modules import { diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/ILSP8CompatibleERC721.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/ILSP8CompatibleERC721.sol deleted file mode 100644 index 6548fee57..000000000 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/ILSP8CompatibleERC721.sol +++ /dev/null @@ -1,175 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.4; - -// interfaces -import { - ILSP8IdentifiableDigitalAsset -} from "../ILSP8IdentifiableDigitalAsset.sol"; - -// --- ERC165 interface ids -bytes4 constant _INTERFACEID_ERC721 = 0x80ac58cd; -bytes4 constant _INTERFACEID_ERC721METADATA = 0x5b5e139f; - -/** - * @dev LSP8 extension, for compatibility for clients / tools that expect ERC721. - */ -interface ILSP8CompatibleERC721 is ILSP8IdentifiableDigitalAsset { - /** - * @notice ERC721 `Transfer` compatible event emitted. Successfully transferred tokenId `tokenId` from `from` to `to`. - * - * @dev ERC721 `Transfer` event emitted when `tokenId` token is transferred from `from` to `to`. - * To provide compatibility with indexing ERC721 events. - * - * @param from The sending address. - * @param to The receiving address. - * @param tokenId The tokenId to transfer. - */ - event Transfer( - address indexed from, - address indexed to, - uint256 indexed tokenId - ); - - /** - * @notice ERC721 `Approval` compatible event emitted. Successfully approved operator `operator` to operate on tokenId `tokenId` on behalf of token owner `owner`. - * - * @dev ERC721 `Approval` event emitted when `owner` enables `operator` for `tokenId`. - * To provide compatibility with indexing ERC721 events. - * - * @param owner The address of the owner of the `tokenId`. - * @param operator The address set as operator. - * @param tokenId The approved tokenId. - */ - event Approval( - address indexed owner, - address indexed operator, - uint256 indexed tokenId - ); - - /** - * @notice ERC721 `ApprovalForAll` compatible event emitted. Successfully set "approved for all" status to `approved` for operator `operator` for token owner `owner`. - * - * @dev ERC721 `ApprovalForAll` event emitted when an `operator` is enabled or disabled for an owner - * to transfer any of its tokenIds. The operator can manage all NFTs of the owner. - * - * @param owner The address of the owner of tokenIds. - * @param operator The address set as operator. - * @param approved If `operator` is approved for all NFTs or not. - */ - event ApprovalForAll( - address indexed owner, - address indexed operator, - bool approved - ); - - /** - * @notice Calling `transferFrom` function on `ILSP8CompatibleERC721` contract. Transferring tokenId `tokenId` from address `from` to address `to`. - * - * @dev Transfer functions from the ERC721 standard interface. - * - * @param from The sending address. - * @param to The receiving address. - * @param tokenId The tokenId to transfer. - */ - function transferFrom(address from, address to, uint256 tokenId) external; - - /** - * @notice Calling `safeTransferFrom` function on `ILSP8CompatibleERC721` contract. Transferring tokenId `tokenId` from address `from` to address `to`. - * - * @dev Safe Transfer function without optional data from the ERC721 standard interface. - * - * @param from The sending address. - * @param to The receiving address. - * @param tokenId The tokenId to transfer. - */ - function safeTransferFrom( - address from, - address to, - uint256 tokenId - ) external; - - /** - * @notice Calling `safeTransferFrom` function with `data` on `ILSP8CompatibleERC721` contract. Transferring tokenId `tokenId` from address `from` to address `to`. - * - * @dev Safe Transfer function with optional data from the ERC721 standard interface. - * - * @param from The sending address. - * @param to The receiving address. - * @param tokenId The tokenId to transfer. - * @param data The data to be sent with the transfer. - */ - function safeTransferFrom( - address from, - address to, - uint256 tokenId, - bytes memory data - ) external; - - /** - * @notice Retrieving the address that own tokenId `tokenId`. - * - * @dev Compatible with ERC721 ownerOf. - * - * @param tokenId The tokenId to query. - * @return The owner of the tokenId. - */ - function ownerOf(uint256 tokenId) external view returns (address); - - /** - * @notice Calling `approve` function on `ILSP8CompatibleERC721` contract. Approving operator at address `operator` to transfer tokenId `tokenId` on behalf of its owner. - * - * @dev Approval function compatible with ERC721 `approve(address,uint256)`. - * - * @param operator The address to approve for `tokenId`. - * @param tokenId The tokenId to approve. - */ - function approve(address operator, uint256 tokenId) external; - - /** - * @notice Setting the "approval for all" status of operator `_operator` to `_approved` to allow it to transfer any tokenIds on behalf of `msg.sender`. - * - * @dev Enable or disable approval for a third party ("operator") to manage all of `msg.sender`'s assets. The contract MUST allow multiple operators per owner. - * - * @param _operator Address to add to the set of authorized operators. - * @param _approved True if the operator is approved, false to revoke approval. - * - * @custom:events {ApprovalForAll} event - */ - function setApprovalForAll(address _operator, bool _approved) external; - - /** - * @notice Retrieving the address other than the token owner that is approved to transfer tokenId `tokenId` on behalf of its owner. - * - * @dev Compatible with ERC721 getApproved. - * - * @param tokenId The tokenId to query. - * @return The address of the operator for `tokenId`. - */ - function getApproved(uint256 tokenId) external view returns (address); - - /* - * @notice Checking if address `operator` is approved to transfer any tokenId owned by address `owner`. - * - * @dev Compatible with ERC721 isApprovedForAll. - * - * @param owner The tokenOwner address to query. - * @param operator The operator address to query. - * - * @return Returns if the `operator` is allowed to manage all of the assets of `owner` - */ - function isApprovedForAll( - address owner, - address operator - ) external view returns (bool); - - /* - * @notice Retrieving the token URI of tokenId `tokenId`. - * - * @dev Compatible with ERC721Metadata tokenURI. - * - * @param tokenId The tokenId to query. - * - * @return The token URI. - */ - function tokenURI(uint256 tokenId) external returns (string memory); -} diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol index 6136f4cf1..0363756f3 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol @@ -5,11 +5,11 @@ pragma solidity ^0.8.12; import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import { IERC721Receiver -} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; -import {ILSP8CompatibleERC721} from "./ILSP8CompatibleERC721.sol"; +} from "@openzeppelin/contracts/interfaces/IERC721Receiver.sol"; import { - ILSP8IdentifiableDigitalAsset -} from "../ILSP8IdentifiableDigitalAsset.sol"; + IERC721Metadata, + IERC721 +} from "@openzeppelin/contracts/interfaces/IERC721Metadata.sol"; // libraries import { @@ -19,15 +19,9 @@ import {BytesLib} from "solidity-bytes-utils/contracts/BytesLib.sol"; // modules import { - LSP4Compatibility -} from "../../LSP4DigitalAssetMetadata/LSP4Compatibility.sol"; -import { - LSP8IdentifiableDigitalAsset, - ERC725YCore + LSP8IdentifiableDigitalAssetCore, + LSP8IdentifiableDigitalAsset } from "../LSP8IdentifiableDigitalAsset.sol"; -import { - LSP8IdentifiableDigitalAssetCore -} from "../LSP8IdentifiableDigitalAssetCore.sol"; // errors import { @@ -40,19 +34,16 @@ import { // constants import { - _LSP4_METADATA_KEY + _LSP4_METADATA_KEY, + _LSP4_TOKEN_NAME_KEY, + _LSP4_TOKEN_SYMBOL_KEY } from "../../LSP4DigitalAssetMetadata/LSP4Constants.sol"; -import { - _INTERFACEID_ERC721, - _INTERFACEID_ERC721METADATA -} from "././ILSP8CompatibleERC721.sol"; /** * @dev LSP8 extension, for compatibility for clients / tools that expect ERC721. */ abstract contract LSP8CompatibleERC721 is - ILSP8CompatibleERC721, - LSP4Compatibility, + IERC721Metadata, LSP8IdentifiableDigitalAsset { using EnumerableSet for EnumerableSet.AddressSet; @@ -77,6 +68,45 @@ abstract contract LSP8CompatibleERC721 is uint256 tokenIdType_ ) LSP8IdentifiableDigitalAsset(name_, symbol_, newOwner_, tokenIdType_) {} + /** + * @inheritdoc IERC721Metadata + * @dev Returns the name of the token. + * For compatibility with clients & tools that expect ERC721. + * + * @return The name of the token + */ + function name() public view virtual override returns (string memory) { + bytes memory data = _getData(_LSP4_TOKEN_NAME_KEY); + return string(data); + } + + /** + * @inheritdoc IERC721Metadata + * @dev Returns the symbol of the token, usually a shorter version of the name. + * For compatibility with clients & tools that expect ERC721. + * + * @return The symbol of the token + */ + function symbol() public view virtual override returns (string memory) { + bytes memory data = _getData(_LSP4_TOKEN_SYMBOL_KEY); + return string(data); + } + + /** + * @inheritdoc LSP8IdentifiableDigitalAssetCore + */ + function balanceOf( + address tokenOwner + ) + public + view + virtual + override(IERC721, LSP8IdentifiableDigitalAssetCore) + returns (uint256) + { + return super.balanceOf(tokenOwner); + } + /** * @inheritdoc LSP8IdentifiableDigitalAsset */ @@ -86,17 +116,22 @@ abstract contract LSP8CompatibleERC721 is public view virtual - override(IERC165, ERC725YCore, LSP8IdentifiableDigitalAsset) + override(IERC165, LSP8IdentifiableDigitalAsset) returns (bool) { return - interfaceId == _INTERFACEID_ERC721 || - interfaceId == _INTERFACEID_ERC721METADATA || + interfaceId == type(IERC721).interfaceId || + interfaceId == type(IERC721Metadata).interfaceId || super.supportsInterface(interfaceId); } - /* - * @inheritdoc ILSP8CompatibleERC721 + /** + * @inheritdoc IERC721Metadata + * @notice Retrieving the token URI of tokenId `tokenId`. + * + * @dev Compatible with ERC721Metadata tokenURI. Retrieve the tokenURI for a specific `tokenId`. + * + * @return The token URI. */ function tokenURI( uint256 /* tokenId */ @@ -115,18 +150,32 @@ abstract contract LSP8CompatibleERC721 is } /** - * @inheritdoc ILSP8CompatibleERC721 + * @inheritdoc IERC721 + * @notice Retrieving the address that own tokenId `tokenId`. + * + * @dev Compatible with ERC721 ownerOf. + * + * @param tokenId The tokenId to query. + * @return The owner of the tokenId. */ - function ownerOf(uint256 tokenId) public view virtual returns (address) { + function ownerOf( + uint256 tokenId + ) public view virtual override returns (address) { return tokenOwnerOf(bytes32(tokenId)); } /** - * @inheritdoc ILSP8CompatibleERC721 + * @inheritdoc IERC721 + * @notice Retrieving the address other than the token owner that is approved to transfer tokenId `tokenId` on behalf of its owner. + * + * @dev Compatible with ERC721 getApproved. + * + * @param tokenId The tokenId to query. + * @return The address of the operator for `tokenId`. */ function getApproved( uint256 tokenId - ) public view virtual returns (address) { + ) public view virtual override returns (address) { bytes32 tokenIdAsBytes32 = bytes32(tokenId); _existsOrError(tokenIdAsBytes32); @@ -146,32 +195,68 @@ abstract contract LSP8CompatibleERC721 is } } - /* - * @inheritdoc ILSP8CompatibleERC721 + /** + * @inheritdoc IERC721 + * @notice Checking if address `operator` is approved to transfer any tokenId owned by address `owner`. + * + * @dev Compatible with ERC721 isApprovedForAll. + * + * @param tokenOwner The tokenOwner address to query. + * @param operator The operator address to query. + * + * @return Returns if the `operator` is allowed to manage all of the assets of `owner` */ function isApprovedForAll( address tokenOwner, address operator - ) public view virtual returns (bool) { + ) public view virtual override returns (bool) { return _operatorApprovals[tokenOwner][operator]; } /** - * @inheritdoc ILSP8CompatibleERC721 + * @inheritdoc IERC721 + * @notice Calling `approve` function to approve operator at address `operator` to transfer tokenId `tokenId` on behalf of its owner. + * + * @dev Approval function compatible with ERC721 `approve(address,uint256)`. + * + * @param operator The address to approve for `tokenId`. + * @param tokenId The tokenId to approve. */ - function approve(address operator, uint256 tokenId) public virtual { + function approve( + address operator, + uint256 tokenId + ) public virtual override { authorizeOperator(operator, bytes32(tokenId), ""); } /** - * @dev See {_setApprovalForAll} + * @inheritdoc IERC721 + * @notice Setting the "approval for all" status of operator `_operator` to `_approved` to allow it to transfer any tokenIds on behalf of `msg.sender`. + * + * @dev Enable or disable approval for a third party ("operator") to manage all of `msg.sender`'s assets. The contract MUST allow multiple operators per owner. + * See {_setApprovalForAll} + * + * @param operator Address to add to the set of authorized operators. + * @param approved True if the operator is approved, false to revoke approval. + * + * @custom:events {ApprovalForAll} event */ - function setApprovalForAll(address operator, bool approved) public virtual { + function setApprovalForAll( + address operator, + bool approved + ) public virtual override { _setApprovalForAll(msg.sender, operator, approved); } /** - * @inheritdoc ILSP8CompatibleERC721 + * @inheritdoc IERC721 + * @notice Calling `transferFrom` function to transfer tokenId `tokenId` from address `from` to address `to`. + * + * @dev Transfer functions from the ERC721 standard interface. + * + * @param from The sending address. + * @param to The receiving address. + * @param tokenId The tokenId to transfer. * * @custom:info This function sets the `force` parameter to `true` so that EOAs and any contract can receive the `tokenId`. */ @@ -179,12 +264,19 @@ abstract contract LSP8CompatibleERC721 is address from, address to, uint256 tokenId - ) public virtual { + ) public virtual override { _transfer(from, to, bytes32(tokenId), true, ""); } /** - * @inheritdoc ILSP8CompatibleERC721 + * @inheritdoc IERC721 + * @notice Calling `safeTransferFrom` function to transfer tokenId `tokenId` from address `from` to address `to`. + * + * @dev Safe Transfer function without optional data from the ERC721 standard interface. + * + * @param from The sending address. + * @param to The receiving address. + * @param tokenId The tokenId to transfer. * * @custom:info This function sets the `force` parameter to `true` so that EOAs and any contract can receive the `tokenId`. */ @@ -192,12 +284,20 @@ abstract contract LSP8CompatibleERC721 is address from, address to, uint256 tokenId - ) public virtual { + ) public virtual override { _safeTransfer(from, to, tokenId, ""); } /** - * @inheritdoc ILSP8CompatibleERC721 + * @inheritdoc IERC721 + * @notice Calling `safeTransferFrom` function to transfer tokenId `tokenId` from address `from` to address `to`. + * + * @dev Safe Transfer function with optional data from the ERC721 standard interface. + * + * @param from The sending address. + * @param to The receiving address. + * @param tokenId The tokenId to transfer. + * @param data The data to be sent with the transfer. * * @custom:info This function sets the `force` parameter to `true` so that EOAs and any contract can receive the `tokenId`. */ @@ -206,14 +306,14 @@ abstract contract LSP8CompatibleERC721 is address to, uint256 tokenId, bytes memory data - ) public virtual { + ) public virtual override { _safeTransfer(from, to, tokenId, data); } // --- Overrides /** - * @inheritdoc ILSP8IdentifiableDigitalAsset + * @inheritdoc LSP8IdentifiableDigitalAssetCore * * @custom:events * - LSP7 {AuthorizedOperator} event. @@ -223,14 +323,7 @@ abstract contract LSP8CompatibleERC721 is address operator, bytes32 tokenId, bytes memory operatorNotificationData - ) - public - virtual - override( - ILSP8IdentifiableDigitalAsset, - LSP8IdentifiableDigitalAssetCore - ) - { + ) public virtual override { address tokenOwner = tokenOwnerOf(tokenId); if ( @@ -345,7 +438,7 @@ abstract contract LSP8CompatibleERC721 is } /** - * @dev Approve `operator` to operate on all tokens of `tokensOwner` + * @dev Approve `operator` to operate on all tokens of `tokensOwner`. * * @custom:events {ApprovalForAll} event. */ @@ -405,14 +498,4 @@ abstract contract LSP8CompatibleERC721 is } } } - - /** - * @inheritdoc LSP8IdentifiableDigitalAsset - */ - function _setData( - bytes32 key, - bytes memory value - ) internal virtual override(LSP8IdentifiableDigitalAsset, ERC725YCore) { - super._setData(key, value); - } } diff --git a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol index 851a0e361..2fd3f5210 100644 --- a/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol +++ b/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721InitAbstract.sol @@ -2,14 +2,14 @@ pragma solidity ^0.8.12; // interfaces -import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol"; import { IERC721Receiver -} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; -import {ILSP8CompatibleERC721} from "./ILSP8CompatibleERC721.sol"; +} from "@openzeppelin/contracts/interfaces/IERC721Receiver.sol"; import { - ILSP8IdentifiableDigitalAsset -} from "../ILSP8IdentifiableDigitalAsset.sol"; + IERC721Metadata, + IERC721 +} from "@openzeppelin/contracts/interfaces/IERC721Metadata.sol"; // libraries import { @@ -19,15 +19,9 @@ import {BytesLib} from "solidity-bytes-utils/contracts/BytesLib.sol"; // modules import { - LSP4Compatibility -} from "../../LSP4DigitalAssetMetadata/LSP4Compatibility.sol"; -import { - LSP8IdentifiableDigitalAssetInitAbstract, - ERC725YCore + LSP8IdentifiableDigitalAssetCore, + LSP8IdentifiableDigitalAssetInitAbstract } from "../LSP8IdentifiableDigitalAssetInitAbstract.sol"; -import { - LSP8IdentifiableDigitalAssetCore -} from "../LSP8IdentifiableDigitalAssetCore.sol"; // errors import { @@ -40,20 +34,17 @@ import { // constants import { - _LSP4_METADATA_KEY + _LSP4_METADATA_KEY, + _LSP4_TOKEN_NAME_KEY, + _LSP4_TOKEN_SYMBOL_KEY } from "../../LSP4DigitalAssetMetadata/LSP4Constants.sol"; -import { - _INTERFACEID_ERC721, - _INTERFACEID_ERC721METADATA -} from "./ILSP8CompatibleERC721.sol"; /** * @dev LSP8 extension, for compatibility for clients / tools that expect ERC721. */ abstract contract LSP8CompatibleERC721InitAbstract is - ILSP8CompatibleERC721, - LSP8IdentifiableDigitalAssetInitAbstract, - LSP4Compatibility + IERC721Metadata, + LSP8IdentifiableDigitalAssetInitAbstract { using EnumerableSet for EnumerableSet.AddressSet; @@ -85,6 +76,45 @@ abstract contract LSP8CompatibleERC721InitAbstract is ); } + /** + * @inheritdoc IERC721Metadata + * @dev Returns the name of the token. + * For compatibility with clients & tools that expect ERC721. + * + * @return The name of the token + */ + function name() public view virtual override returns (string memory) { + bytes memory data = _getData(_LSP4_TOKEN_NAME_KEY); + return string(data); + } + + /** + * @inheritdoc IERC721Metadata + * @dev Returns the symbol of the token, usually a shorter version of the name. + * For compatibility with clients & tools that expect ERC721. + * + * @return The symbol of the token + */ + function symbol() public view virtual override returns (string memory) { + bytes memory data = _getData(_LSP4_TOKEN_SYMBOL_KEY); + return string(data); + } + + /** + * @inheritdoc LSP8IdentifiableDigitalAssetCore + */ + function balanceOf( + address tokenOwner + ) + public + view + virtual + override(IERC721, LSP8IdentifiableDigitalAssetCore) + returns (uint256) + { + return super.balanceOf(tokenOwner); + } + /** * @inheritdoc LSP8IdentifiableDigitalAssetInitAbstract */ @@ -94,21 +124,26 @@ abstract contract LSP8CompatibleERC721InitAbstract is public view virtual - override(IERC165, ERC725YCore, LSP8IdentifiableDigitalAssetInitAbstract) + override(IERC165, LSP8IdentifiableDigitalAssetInitAbstract) returns (bool) { return - interfaceId == _INTERFACEID_ERC721 || - interfaceId == _INTERFACEID_ERC721METADATA || + interfaceId == type(IERC721).interfaceId || + interfaceId == type(IERC721Metadata).interfaceId || super.supportsInterface(interfaceId); } /** - * @inheritdoc ILSP8CompatibleERC721 + * @inheritdoc IERC721Metadata + * @notice Retrieving the token URI of tokenId `tokenId`. + * + * @dev Compatible with ERC721Metadata tokenURI. Retrieve the tokenURI for a specific `tokenId`. + * + * @return The token URI. */ function tokenURI( uint256 /* tokenId */ - ) public view virtual returns (string memory) { + ) public view virtual override returns (string memory) { bytes memory data = _getData(_LSP4_METADATA_KEY); // offset = bytes4(hashSig) + bytes32(contentHash) -> 4 + 32 = 36 @@ -123,18 +158,32 @@ abstract contract LSP8CompatibleERC721InitAbstract is } /** - * @inheritdoc ILSP8CompatibleERC721 + * @inheritdoc IERC721 + * @notice Retrieving the address that own tokenId `tokenId`. + * + * @dev Compatible with ERC721 ownerOf. + * + * @param tokenId The tokenId to query. + * @return The owner of the tokenId. */ - function ownerOf(uint256 tokenId) public view virtual returns (address) { + function ownerOf( + uint256 tokenId + ) public view virtual override returns (address) { return tokenOwnerOf(bytes32(tokenId)); } /** - * @inheritdoc ILSP8CompatibleERC721 + * @inheritdoc IERC721 + * @notice Retrieving the address other than the token owner that is approved to transfer tokenId `tokenId` on behalf of its owner. + * + * @dev Compatible with ERC721 getApproved. + * + * @param tokenId The tokenId to query. + * @return The address of the operator for `tokenId`. */ function getApproved( uint256 tokenId - ) public view virtual returns (address) { + ) public view virtual override returns (address) { bytes32 tokenIdAsBytes32 = bytes32(tokenId); _existsOrError(tokenIdAsBytes32); @@ -154,33 +203,69 @@ abstract contract LSP8CompatibleERC721InitAbstract is } } - /* - * @inheritdoc ILSP8CompatibleERC721 + /** + * @inheritdoc IERC721 + * @notice Checking if address `operator` is approved to transfer any tokenId owned by address `owner`. + * + * @dev Compatible with ERC721 isApprovedForAll. + * + * @param tokenOwner The tokenOwner address to query. + * @param operator The operator address to query. + * + * @return Returns if the `operator` is allowed to manage all of the assets of `owner` */ function isApprovedForAll( address tokenOwner, address operator - ) public view virtual returns (bool) { + ) public view virtual override returns (bool) { return _operatorApprovals[tokenOwner][operator]; } /** - * @inheritdoc ILSP8CompatibleERC721 + * @inheritdoc IERC721 + * @notice Calling `approve` function to approve operator at address `operator` to transfer tokenId `tokenId` on behalf of its owner. + * + * @dev Approval function compatible with ERC721 `approve(address,uint256)`. + * + * @param operator The address to approve for `tokenId`. + * @param tokenId The tokenId to approve. */ - function approve(address operator, uint256 tokenId) public virtual { + function approve( + address operator, + uint256 tokenId + ) public virtual override { authorizeOperator(operator, bytes32(tokenId), ""); emit Approval(tokenOwnerOf(bytes32(tokenId)), operator, tokenId); } /** - * @dev See {_setApprovalForAll} + * @inheritdoc IERC721 + * @notice Setting the "approval for all" status of operator `_operator` to `_approved` to allow it to transfer any tokenIds on behalf of `msg.sender`. + * + * @dev Enable or disable approval for a third party ("operator") to manage all of `msg.sender`'s assets. The contract MUST allow multiple operators per owner. + * See {_setApprovalForAll} + * + * @param operator Address to add to the set of authorized operators. + * @param approved True if the operator is approved, false to revoke approval. + * + * @custom:events {ApprovalForAll} event */ - function setApprovalForAll(address operator, bool approved) public virtual { + function setApprovalForAll( + address operator, + bool approved + ) public virtual override { _setApprovalForAll(msg.sender, operator, approved); } /** - * @inheritdoc ILSP8CompatibleERC721 + * @inheritdoc IERC721 + * @notice Calling `transferFrom` function to transfer tokenId `tokenId` from address `from` to address `to`. + * + * @dev Transfer functions from the ERC721 standard interface. + * + * @param from The sending address. + * @param to The receiving address. + * @param tokenId The tokenId to transfer. * * @custom:info This function sets the `force` parameter to `true` so that EOAs and any contract can receive the `tokenId`. */ @@ -188,12 +273,19 @@ abstract contract LSP8CompatibleERC721InitAbstract is address from, address to, uint256 tokenId - ) public virtual { + ) public virtual override { _transfer(from, to, bytes32(tokenId), true, ""); } /** - * @inheritdoc ILSP8CompatibleERC721 + * @inheritdoc IERC721 + * @notice Calling `safeTransferFrom` function to transfer tokenId `tokenId` from address `from` to address `to`. + * + * @dev Safe Transfer function without optional data from the ERC721 standard interface. + * + * @param from The sending address. + * @param to The receiving address. + * @param tokenId The tokenId to transfer. * * @custom:info This function sets the `force` parameter to `true` so that EOAs and any contract can receive the `tokenId`. */ @@ -201,12 +293,20 @@ abstract contract LSP8CompatibleERC721InitAbstract is address from, address to, uint256 tokenId - ) public virtual { + ) public virtual override { _safeTransfer(from, to, tokenId, ""); } /** - * @inheritdoc ILSP8CompatibleERC721 + * @inheritdoc IERC721 + * @notice Calling `safeTransferFrom` function with `data` to transfer tokenId `tokenId` from address `from` to address `to`. + * + * @dev Safe Transfer function with optional data from the ERC721 standard interface. + * + * @param from The sending address. + * @param to The receiving address. + * @param tokenId The tokenId to transfer. + * @param data The data to be sent with the transfer. * * @custom:info This function sets the `force` parameter to `true` so that EOAs and any contract can receive the `tokenId`. */ @@ -215,14 +315,14 @@ abstract contract LSP8CompatibleERC721InitAbstract is address to, uint256 tokenId, bytes memory data - ) public virtual { + ) public virtual override { _safeTransfer(from, to, tokenId, data); } // --- Overrides /** - * @inheritdoc ILSP8IdentifiableDigitalAsset + * @inheritdoc LSP8IdentifiableDigitalAssetCore * * @custom:events * - LSP7 {AuthorizedOperator} event. @@ -232,14 +332,7 @@ abstract contract LSP8CompatibleERC721InitAbstract is address operator, bytes32 tokenId, bytes memory operatorNotificationData - ) - public - virtual - override( - ILSP8IdentifiableDigitalAsset, - LSP8IdentifiableDigitalAssetCore - ) - { + ) public virtual override { address tokenOwner = tokenOwnerOf(tokenId); if ( @@ -354,7 +447,7 @@ abstract contract LSP8CompatibleERC721InitAbstract is } /** - * @dev Approve `operator` to operate on all tokens of `tokensOwner` + * @dev Approve `operator` to operate on all tokens of `tokensOwner`. * * @custom:events {ApprovalForAll} event. */ @@ -414,18 +507,4 @@ abstract contract LSP8CompatibleERC721InitAbstract is } } } - - /** - * @inheritdoc LSP8IdentifiableDigitalAssetInitAbstract - */ - function _setData( - bytes32 key, - bytes memory value - ) - internal - virtual - override(LSP8IdentifiableDigitalAssetInitAbstract, ERC725YCore) - { - super._setData(key, value); - } } diff --git a/contracts/Mocks/ERC165Interfaces.sol b/contracts/Mocks/ERC165Interfaces.sol index 4fcd847b3..54b90ab3c 100644 --- a/contracts/Mocks/ERC165Interfaces.sol +++ b/contracts/Mocks/ERC165Interfaces.sol @@ -13,13 +13,16 @@ import { OwnableUnset } from "@erc725/smart-contracts/contracts/custom/OwnableUnset.sol"; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; +import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import { + IERC20Metadata +} from "@openzeppelin/contracts/interfaces/IERC20Metadata.sol"; +import {IERC721} from "@openzeppelin/contracts/interfaces/IERC721.sol"; import { IERC721Metadata -} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; -import {IERC777} from "@openzeppelin/contracts/token/ERC777/IERC777.sol"; -import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; +} from "@openzeppelin/contracts/interfaces/IERC721Metadata.sol"; +import {IERC777} from "@openzeppelin/contracts/interfaces/IERC777.sol"; +import {IERC1155} from "@openzeppelin/contracts/interfaces/IERC1155.sol"; import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol"; import {IERC223} from "./Tokens/IERC223.sol"; @@ -278,6 +281,10 @@ contract CalculateERCInterfaces { return type(IERC20).interfaceId; } + function calculateInterfaceERC20Metadata() public pure returns (bytes4) { + return type(IERC20Metadata).interfaceId; + } + function calculateInterfaceERC721() public pure returns (bytes4) { return type(IERC721).interfaceId; } diff --git a/contracts/Mocks/Tokens/LSP4CompatibilityTester.sol b/contracts/Mocks/Tokens/LSP4CompatibilityTester.sol deleted file mode 100644 index 3edb6de8b..000000000 --- a/contracts/Mocks/Tokens/LSP4CompatibilityTester.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -pragma solidity ^0.8.4; - -// modules -import {ERC725Y} from "@erc725/smart-contracts/contracts/ERC725Y.sol"; -import { - LSP4Compatibility -} from "../../LSP4DigitalAssetMetadata/LSP4Compatibility.sol"; - -// constants -import { - _LSP4_TOKEN_NAME_KEY, - _LSP4_TOKEN_SYMBOL_KEY -} from "../../LSP4DigitalAssetMetadata/LSP4Constants.sol"; - -contract LSP4CompatibilityTester is ERC725Y, LSP4Compatibility { - constructor( - string memory name, - string memory symbol, - address newOwner - ) ERC725Y(newOwner) { - _setData(_LSP4_TOKEN_NAME_KEY, bytes(name)); - _setData(_LSP4_TOKEN_SYMBOL_KEY, bytes(symbol)); - } -} diff --git a/docs/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.md b/docs/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.md deleted file mode 100644 index 2b822c453..000000000 --- a/docs/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.md +++ /dev/null @@ -1,583 +0,0 @@ - - - -# LSP4Compatibility - -:::info Standard Specifications - -[`LSP-4-DigitalAssetMetadata`](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md) - -::: -:::info Solidity implementation - -[`LSP4Compatibility.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol) - -::: - -> LSP4Compatibility - -LSP4 extension, for compatibility with clients & tools that expect ERC20/721. - -## Public Methods - -Public methods are accessible externally from users, allowing interaction with this function from dApps or other smart contracts. -When marked as 'public', a method can be called both externally and internally, on the other hand, when marked as 'external', a method can only be called externally. - -### getData - -:::note References - -- Specification details: [**LSP-4-DigitalAssetMetadata**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md#getdata) -- Solidity implementation: [`LSP4Compatibility.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol) -- Function signature: `getData(bytes32)` -- Function selector: `0x54f6127f` - -::: - -```solidity -function getData(bytes32 dataKey) external view returns (bytes dataValue); -``` - -_Reading the ERC725Y storage for data key `dataKey` returned the following value: `dataValue`._ - -Get in the ERC725Y storage the bytes data stored at a specific data key `dataKey`. - -#### Parameters - -| Name | Type | Description | -| --------- | :-------: | --------------------------------------------- | -| `dataKey` | `bytes32` | The data key for which to retrieve the value. | - -#### Returns - -| Name | Type | Description | -| ----------- | :-----: | ---------------------------------------------------- | -| `dataValue` | `bytes` | The bytes value stored under the specified data key. | - -
- -### getDataBatch - -:::note References - -- Specification details: [**LSP-4-DigitalAssetMetadata**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md#getdatabatch) -- Solidity implementation: [`LSP4Compatibility.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol) -- Function signature: `getDataBatch(bytes32[])` -- Function selector: `0xdedff9c6` - -::: - -```solidity -function getDataBatch( - bytes32[] dataKeys -) external view returns (bytes[] dataValues); -``` - -_Reading the ERC725Y storage for data keys `dataKeys` returned the following values: `dataValues`._ - -Get in the ERC725Y storage the bytes data stored at multiple data keys `dataKeys`. - -#### Parameters - -| Name | Type | Description | -| ---------- | :---------: | ------------------------------------------ | -| `dataKeys` | `bytes32[]` | The array of keys which values to retrieve | - -#### Returns - -| Name | Type | Description | -| ------------ | :-------: | ----------------------------------------- | -| `dataValues` | `bytes[]` | The array of data stored at multiple keys | - -
- -### name - -:::note References - -- Specification details: [**LSP-4-DigitalAssetMetadata**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md#name) -- Solidity implementation: [`LSP4Compatibility.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol) -- Function signature: `name()` -- Function selector: `0x06fdde03` - -::: - -```solidity -function name() external view returns (string); -``` - -Returns the name of the token. - -#### Returns - -| Name | Type | Description | -| ---- | :------: | --------------------- | -| `0` | `string` | The name of the token | - -
- -### owner - -:::note References - -- Specification details: [**LSP-4-DigitalAssetMetadata**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md#owner) -- Solidity implementation: [`LSP4Compatibility.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol) -- Function signature: `owner()` -- Function selector: `0x8da5cb5b` - -::: - -```solidity -function owner() external view returns (address); -``` - -Returns the address of the current owner. - -#### Returns - -| Name | Type | Description | -| ---- | :-------: | ----------- | -| `0` | `address` | - | - -
- -### renounceOwnership - -:::note References - -- Specification details: [**LSP-4-DigitalAssetMetadata**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md#renounceownership) -- Solidity implementation: [`LSP4Compatibility.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol) -- Function signature: `renounceOwnership()` -- Function selector: `0x715018a6` - -::: - -```solidity -function renounceOwnership() external nonpayable; -``` - -Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner. - -
- -### setData - -:::note References - -- Specification details: [**LSP-4-DigitalAssetMetadata**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md#setdata) -- Solidity implementation: [`LSP4Compatibility.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol) -- Function signature: `setData(bytes32,bytes)` -- Function selector: `0x7f23690c` - -::: - -:::caution Warning - -**Note for developers:** despite the fact that this function is set as `payable`, if the function is not intended to receive value (= native tokens), **an additional check should be implemented to ensure that `msg.value` sent was equal to 0**. - -::: - -```solidity -function setData(bytes32 dataKey, bytes dataValue) external payable; -``` - -_Setting the following data key value pair in the ERC725Y storage. Data key: `dataKey`, data value: `dataValue`._ - -Sets a single bytes value `dataValue` in the ERC725Y storage for a specific data key `dataKey`. The function is marked as payable to enable flexibility on child contracts. For instance to implement a fee mechanism for setting specific data. - -
- -**Requirements:** - -- SHOULD only be callable by the [`owner`](#owner). - -
- -
- -**Emitted events:** - -- [`DataChanged`](#datachanged) event. - -
- -#### Parameters - -| Name | Type | Description | -| ----------- | :-------: | ------------------------------------------ | -| `dataKey` | `bytes32` | The data key for which to set a new value. | -| `dataValue` | `bytes` | The new bytes value to set. | - -
- -### setDataBatch - -:::note References - -- Specification details: [**LSP-4-DigitalAssetMetadata**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md#setdatabatch) -- Solidity implementation: [`LSP4Compatibility.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol) -- Function signature: `setDataBatch(bytes32[],bytes[])` -- Function selector: `0x97902421` - -::: - -:::caution Warning - -**Note for developers:** despite the fact that this function is set as `payable`, if the function is not intended to receive value (= native tokens), **an additional check should be implemented to ensure that `msg.value` sent was equal to 0**. - -::: - -```solidity -function setDataBatch(bytes32[] dataKeys, bytes[] dataValues) external payable; -``` - -_Setting the following data key value pairs in the ERC725Y storage. Data keys: `dataKeys`, data values: `dataValues`._ - -Batch data setting function that behaves the same as [`setData`](#setdata) but allowing to set multiple data key/value pairs in the ERC725Y storage in the same transaction. - -
- -**Requirements:** - -- SHOULD only be callable by the [`owner`](#owner) of the contract. - -
- -
- -**Emitted events:** - -- [`DataChanged`](#datachanged) event **for each data key/value pair set**. - -
- -#### Parameters - -| Name | Type | Description | -| ------------ | :---------: | ---------------------------------------------------- | -| `dataKeys` | `bytes32[]` | An array of data keys to set bytes values for. | -| `dataValues` | `bytes[]` | An array of bytes values to set for each `dataKeys`. | - -
- -### supportsInterface - -:::note References - -- Specification details: [**LSP-4-DigitalAssetMetadata**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md#supportsinterface) -- Solidity implementation: [`LSP4Compatibility.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol) -- Function signature: `supportsInterface(bytes4)` -- Function selector: `0x01ffc9a7` - -::: - -```solidity -function supportsInterface(bytes4 interfaceId) external view returns (bool); -``` - -See [`IERC165-supportsInterface`](#ierc165-supportsinterface). - -#### Parameters - -| Name | Type | Description | -| ------------- | :------: | ----------- | -| `interfaceId` | `bytes4` | - | - -#### Returns - -| Name | Type | Description | -| ---- | :----: | ----------- | -| `0` | `bool` | - | - -
- -### symbol - -:::note References - -- Specification details: [**LSP-4-DigitalAssetMetadata**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md#symbol) -- Solidity implementation: [`LSP4Compatibility.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol) -- Function signature: `symbol()` -- Function selector: `0x95d89b41` - -::: - -```solidity -function symbol() external view returns (string); -``` - -Returns the symbol of the token, usually a shorter version of the name. - -#### Returns - -| Name | Type | Description | -| ---- | :------: | ----------------------- | -| `0` | `string` | The symbol of the token | - -
- -### transferOwnership - -:::note References - -- Specification details: [**LSP-4-DigitalAssetMetadata**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md#transferownership) -- Solidity implementation: [`LSP4Compatibility.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol) -- Function signature: `transferOwnership(address)` -- Function selector: `0xf2fde38b` - -::: - -```solidity -function transferOwnership(address newOwner) external nonpayable; -``` - -Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner. - -#### Parameters - -| Name | Type | Description | -| ---------- | :-------: | ----------- | -| `newOwner` | `address` | - | - -
- -## Internal Methods - -Any method labeled as `internal` serves as utility function within the contract. They can be used when writing solidity contracts that inherit from this contract. These methods can be extended or modified by overriding their internal behavior to suit specific needs. - -Internal functions cannot be called externally, whether from other smart contracts, dApp interfaces, or backend services. Their restricted accessibility ensures that they remain exclusively available within the context of the current contract, promoting controlled and encapsulated usage of these internal utilities. - -### \_checkOwner - -```solidity -function _checkOwner() internal view; -``` - -Throws if the sender is not the owner. - -
- -### \_setOwner - -```solidity -function _setOwner(address newOwner) internal nonpayable; -``` - -Changes the owner if `newOwner` and oldOwner are different -This pattern is useful in inheritance. - -
- -### \_getData - -```solidity -function _getData(bytes32 dataKey) internal view returns (bytes dataValue); -``` - -Read the value stored under a specific `dataKey` inside the underlying ERC725Y storage, -represented as a mapping of `bytes32` data keys mapped to their `bytes` data values. - -```solidity -mapping(bytes32 => bytes) _store -``` - -#### Parameters - -| Name | Type | Description | -| --------- | :-------: | ----------------------------------------------------------------------- | -| `dataKey` | `bytes32` | A bytes32 data key to read the associated `bytes` value from the store. | - -#### Returns - -| Name | Type | Description | -| ----------- | :-----: | ----------------------------------------------------------------------------- | -| `dataValue` | `bytes` | The `bytes` value associated with the given `dataKey` in the ERC725Y storage. | - -
- -### \_setData - -```solidity -function _setData(bytes32 dataKey, bytes dataValue) internal nonpayable; -``` - -Write a `dataValue` to the underlying ERC725Y storage, represented as a mapping of -`bytes32` data keys mapped to their `bytes` data values. - -```solidity -mapping(bytes32 => bytes) _store -``` - -
- -**Emitted events:** - -- [`DataChanged`](#datachanged) event emitted after a successful `setData` call. - -
- -#### Parameters - -| Name | Type | Description | -| ----------- | :-------: | ------------------------------------------------------------------------------- | -| `dataKey` | `bytes32` | A bytes32 data key to write the associated `bytes` value to the store. | -| `dataValue` | `bytes` | The `bytes` value to associate with the given `dataKey` in the ERC725Y storage. | - -
- -## Events - -### DataChanged - -:::note References - -- Specification details: [**LSP-4-DigitalAssetMetadata**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md#datachanged) -- Solidity implementation: [`LSP4Compatibility.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol) -- Event signature: `DataChanged(bytes32,bytes)` -- Event topic hash: `0xece574603820d07bc9b91f2a932baadf4628aabcb8afba49776529c14a6104b2` - -::: - -```solidity -event DataChanged(bytes32 indexed dataKey, bytes dataValue); -``` - -_The following data key/value pair has been changed in the ERC725Y storage: Data key: `dataKey`, data value: `dataValue`._ - -Emitted when data at a specific `dataKey` was changed to a new value `dataValue`. - -#### Parameters - -| Name | Type | Description | -| ----------------------- | :-------: | -------------------------------------------- | -| `dataKey` **`indexed`** | `bytes32` | The data key for which a bytes value is set. | -| `dataValue` | `bytes` | The value to set for the given data key. | - -
- -### OwnershipTransferred - -:::note References - -- Specification details: [**LSP-4-DigitalAssetMetadata**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md#ownershiptransferred) -- Solidity implementation: [`LSP4Compatibility.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol) -- Event signature: `OwnershipTransferred(address,address)` -- Event topic hash: `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` - -::: - -```solidity -event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); -``` - -#### Parameters - -| Name | Type | Description | -| ----------------------------- | :-------: | ----------- | -| `previousOwner` **`indexed`** | `address` | - | -| `newOwner` **`indexed`** | `address` | - | - -
- -## Errors - -### ERC725Y_DataKeysValuesEmptyArray - -:::note References - -- Specification details: [**LSP-4-DigitalAssetMetadata**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md#erc725y_datakeysvaluesemptyarray) -- Solidity implementation: [`LSP4Compatibility.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol) -- Error signature: `ERC725Y_DataKeysValuesEmptyArray()` -- Error hash: `0x97da5f95` - -::: - -```solidity -error ERC725Y_DataKeysValuesEmptyArray(); -``` - -Reverts when one of the array parameter provided to [`setDataBatch`](#setdatabatch) function is an empty array. - -
- -### ERC725Y_DataKeysValuesLengthMismatch - -:::note References - -- Specification details: [**LSP-4-DigitalAssetMetadata**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md#erc725y_datakeysvalueslengthmismatch) -- Solidity implementation: [`LSP4Compatibility.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol) -- Error signature: `ERC725Y_DataKeysValuesLengthMismatch()` -- Error hash: `0x3bcc8979` - -::: - -```solidity -error ERC725Y_DataKeysValuesLengthMismatch(); -``` - -Reverts when there is not the same number of elements in the `datakeys` and `dataValues` array parameters provided when calling the [`setDataBatch`](#setdatabatch) function. - -
- -### ERC725Y_MsgValueDisallowed - -:::note References - -- Specification details: [**LSP-4-DigitalAssetMetadata**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md#erc725y_msgvaluedisallowed) -- Solidity implementation: [`LSP4Compatibility.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol) -- Error signature: `ERC725Y_MsgValueDisallowed()` -- Error hash: `0xf36ba737` - -::: - -```solidity -error ERC725Y_MsgValueDisallowed(); -``` - -Reverts when sending value to the [`setData`](#setdata) or [`setDataBatch`](#setdatabatch) function. - -
- -### OwnableCallerNotTheOwner - -:::note References - -- Specification details: [**LSP-4-DigitalAssetMetadata**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md#ownablecallernottheowner) -- Solidity implementation: [`LSP4Compatibility.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol) -- Error signature: `OwnableCallerNotTheOwner(address)` -- Error hash: `0xbf1169c5` - -::: - -```solidity -error OwnableCallerNotTheOwner(address callerAddress); -``` - -Reverts when only the owner is allowed to call the function. - -#### Parameters - -| Name | Type | Description | -| --------------- | :-------: | ---------------------------------------- | -| `callerAddress` | `address` | The address that tried to make the call. | - -
- -### OwnableCannotSetZeroAddressAsOwner - -:::note References - -- Specification details: [**LSP-4-DigitalAssetMetadata**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-4-DigitalAssetMetadata.md#ownablecannotsetzeroaddressasowner) -- Solidity implementation: [`LSP4Compatibility.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol) -- Error signature: `OwnableCannotSetZeroAddressAsOwner()` -- Error hash: `0x1ad8836c` - -::: - -```solidity -error OwnableCannotSetZeroAddressAsOwner(); -``` - -Reverts when trying to set `address(0)` as the contract owner when deploying the contract, initializing it or transferring ownership of the contract. - -
diff --git a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md index 2a4fa0a1a..3792dc399 100644 --- a/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md +++ b/docs/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.md @@ -93,18 +93,20 @@ function allowance( ) external view returns (uint256); ``` +Function to get operator allowance allowed to spend on behalf of `tokenOwner` from the ERC20 standard interface. + #### Parameters -| Name | Type | Description | -| ------------ | :-------: | ----------- | -| `tokenOwner` | `address` | - | -| `operator` | `address` | - | +| Name | Type | Description | +| ------------ | :-------: | ---------------------------------------- | +| `tokenOwner` | `address` | The address of the token owner | +| `operator` | `address` | The address approved by the `tokenOwner` | #### Returns -| Name | Type | Description | -| ---- | :-------: | ----------- | -| `0` | `uint256` | - | +| Name | Type | Description | +| ---- | :-------: | ------------------------------------------------- | +| `0` | `uint256` | The amount `operator` is approved by `tokenOwner` |
@@ -126,18 +128,20 @@ function approve( ) external nonpayable returns (bool); ``` +Approval function from th ERC20 standard interface. + #### Parameters -| Name | Type | Description | -| ---------- | :-------: | ----------- | -| `operator` | `address` | - | -| `amount` | `uint256` | - | +| Name | Type | Description | +| ---------- | :-------: | ----------------------------------- | +| `operator` | `address` | The address to approve for `amount` | +| `amount` | `uint256` | The amount to approve. | #### Returns -| Name | Type | Description | -| ---- | :----: | ----------- | -| `0` | `bool` | - | +| Name | Type | Description | +| ---- | :----: | ------------------------------ | +| `0` | `bool` | `true` on successful approval. |
@@ -496,7 +500,7 @@ Atomically increases the allowance granted to `operator` by the caller. This is function name() external view returns (string); ``` -Returns the name of the token. +Returns the name of the token. For compatibility with clients & tools that expect ERC20. #### Returns @@ -725,7 +729,7 @@ Returns true if this contract implements the interface defined by `interfaceId`. function symbol() external view returns (string); ``` -Returns the symbol of the token, usually a shorter version of the name. +Returns the symbol of the token, usually a shorter version of the name. For compatibility with clients & tools that expect ERC20. #### Returns @@ -819,18 +823,20 @@ function transfer( ) external nonpayable returns (bool); ``` +Transfer function from the ERC20 standard interface. + #### Parameters -| Name | Type | Description | -| -------- | :-------: | ----------- | -| `to` | `address` | - | -| `amount` | `uint256` | - | +| Name | Type | Description | +| -------- | :-------: | --------------------------------- | +| `to` | `address` | The address receiving tokens. | +| `amount` | `uint256` | The amount of tokens to transfer. | #### Returns -| Name | Type | Description | -| ---- | :----: | ----------- | -| `0` | `bool` | - | +| Name | Type | Description | +| ---- | :----: | ------------------------------ | +| `0` | `bool` | `true` on successful transfer. |
@@ -894,19 +900,21 @@ function transferFrom( ) external nonpayable returns (bool); ``` +Transfer functions for operators from the ERC20 standard interface. + #### Parameters -| Name | Type | Description | -| -------- | :-------: | ----------- | -| `from` | `address` | - | -| `to` | `address` | - | -| `amount` | `uint256` | - | +| Name | Type | Description | +| -------- | :-------: | --------------------------------- | +| `from` | `address` | The address sending tokens. | +| `to` | `address` | The address receiving tokens. | +| `amount` | `uint256` | The amount of tokens to transfer. | #### Returns -| Name | Type | Description | -| ---- | :----: | ----------- | -| `0` | `bool` | - | +| Name | Type | Description | +| ---- | :----: | ------------------------------ | +| `0` | `bool` | `true` on successful transfer. |
@@ -992,9 +1000,11 @@ mapping(bytes32 => bytes) _store ### \_setData ```solidity -function _setData(bytes32 key, bytes value) internal nonpayable; +function _setData(bytes32 dataKey, bytes dataValue) internal nonpayable; ``` +Save gas by emitting the [`DataChanged`](#datachanged) event with only the first 256 bytes of dataValue +
### \_updateOperator @@ -1262,11 +1272,11 @@ Emitted when the allowance of a `spender` for an `owner` is set by a call to [`a #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | --------------------------------------------------------- | -| `owner` **`indexed`** | `address` | The account giving approval | -| `spender` **`indexed`** | `address` | The account receiving approval | -| `value` | `uint256` | The amount of tokens `spender` has access to from `owner` | +| Name | Type | Description | +| ----------------------- | :-------: | ----------- | +| `owner` **`indexed`** | `address` | - | +| `spender` **`indexed`** | `address` | - | +| `value` | `uint256` | - |
@@ -1383,24 +1393,27 @@ Emitted when `tokenOwner` disables `operator` for `amount` tokens and set its [` - Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#transfer) - Solidity implementation: [`LSP7CompatibleERC20.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol) -- Event signature: `Transfer(address,address,uint256)` -- Event topic hash: `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` +- Event signature: `Transfer(address,address,address,uint256,bool,bytes)` +- Event topic hash: `0x3997e418d2cef0b3b0e907b1e39605c3f7d32dbd061e82ea5b4a770d46a160a6` ::: ```solidity -event Transfer(address indexed from, address indexed to, uint256 value); +event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool force, bytes data); ``` -Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero. +Emitted when the `from` transferred successfully `amount` of tokens to `to`. #### Parameters -| Name | Type | Description | -| -------------------- | :-------: | -------------------------------- | -| `from` **`indexed`** | `address` | The sending address | -| `to` **`indexed`** | `address` | The receiving address | -| `value` | `uint256` | The amount of tokens transfered. | +| Name | Type | Description | +| ------------------------ | :-------: | ---------------------------------------------------------------------------------------------------------------------------- | +| `operator` **`indexed`** | `address` | The address of the operator that executed the transfer. | +| `from` **`indexed`** | `address` | The address which tokens were sent from (balance decreased by `-amount`). | +| `to` **`indexed`** | `address` | The address that received the tokens (balance increased by `+amount`). | +| `amount` | `uint256` | The amount of tokens transferred. | +| `force` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `data` | `bytes` | Any additional data included by the caller during the transfer, and sent in the LSP1 hooks to the `from` and `to` addresses. |
@@ -1410,27 +1423,24 @@ Emitted when `value` tokens are moved from one account (`from`) to another (`to` - Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#transfer) - Solidity implementation: [`LSP7CompatibleERC20.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol) -- Event signature: `Transfer(address,address,address,uint256,bool,bytes)` -- Event topic hash: `0x3997e418d2cef0b3b0e907b1e39605c3f7d32dbd061e82ea5b4a770d46a160a6` +- Event signature: `Transfer(address,address,uint256)` +- Event topic hash: `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` ::: ```solidity -event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool force, bytes data); +event Transfer(address indexed from, address indexed to, uint256 value); ``` -Emitted when the `from` transferred successfully `amount` of tokens to `to`. +Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero. #### Parameters -| Name | Type | Description | -| ------------------------ | :-------: | ---------------------------------------------------------------------------------------------------------------------------- | -| `operator` **`indexed`** | `address` | The address of the operator that executed the transfer. | -| `from` **`indexed`** | `address` | The address which tokens were sent from (balance decreased by `-amount`). | -| `to` **`indexed`** | `address` | The address that received the tokens (balance increased by `+amount`). | -| `amount` | `uint256` | The amount of tokens transferred. | -| `force` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | -| `data` | `bytes` | Any additional data included by the caller during the transfer, and sent in the LSP1 hooks to the `from` and `to` addresses. | +| Name | Type | Description | +| -------------------- | :-------: | ----------- | +| `from` **`indexed`** | `address` | - | +| `to` **`indexed`** | `address` | - | +| `value` | `uint256` | - |
diff --git a/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md b/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md index 232eda1a1..63ac7291f 100644 --- a/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md +++ b/docs/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.md @@ -94,18 +94,20 @@ function allowance( ) external view returns (uint256); ``` +Function to get operator allowance allowed to spend on behalf of `tokenOwner` from the ERC20 standard interface. + #### Parameters -| Name | Type | Description | -| ------------ | :-------: | ----------- | -| `tokenOwner` | `address` | - | -| `operator` | `address` | - | +| Name | Type | Description | +| ------------ | :-------: | ---------------------------------------- | +| `tokenOwner` | `address` | The address of the token owner | +| `operator` | `address` | The address approved by the `tokenOwner` | #### Returns -| Name | Type | Description | -| ---- | :-------: | ----------- | -| `0` | `uint256` | - | +| Name | Type | Description | +| ---- | :-------: | ------------------------------------------------- | +| `0` | `uint256` | The amount `operator` is approved by `tokenOwner` |
@@ -127,18 +129,20 @@ function approve( ) external nonpayable returns (bool); ``` +Approval function from th ERC20 standard interface. + #### Parameters -| Name | Type | Description | -| ---------- | :-------: | ----------- | -| `operator` | `address` | - | -| `amount` | `uint256` | - | +| Name | Type | Description | +| ---------- | :-------: | ----------------------------------- | +| `operator` | `address` | The address to approve for `amount` | +| `amount` | `uint256` | The amount to approve. | #### Returns -| Name | Type | Description | -| ---- | :----: | ----------- | -| `0` | `bool` | - | +| Name | Type | Description | +| ---- | :----: | ------------------------------ | +| `0` | `bool` | `true` on successful approval. |
@@ -530,7 +534,7 @@ Public [`_mint`](#_mint) function only callable by the [`owner`](#owner). function name() external view returns (string); ``` -Returns the name of the token. +Returns the name of the token. For compatibility with clients & tools that expect ERC20. #### Returns @@ -759,7 +763,7 @@ Returns true if this contract implements the interface defined by `interfaceId`. function symbol() external view returns (string); ``` -Returns the symbol of the token, usually a shorter version of the name. +Returns the symbol of the token, usually a shorter version of the name. For compatibility with clients & tools that expect ERC20. #### Returns @@ -853,18 +857,20 @@ function transfer( ) external nonpayable returns (bool); ``` +Transfer function from the ERC20 standard interface. + #### Parameters -| Name | Type | Description | -| -------- | :-------: | ----------- | -| `to` | `address` | - | -| `amount` | `uint256` | - | +| Name | Type | Description | +| -------- | :-------: | --------------------------------- | +| `to` | `address` | The address receiving tokens. | +| `amount` | `uint256` | The amount of tokens to transfer. | #### Returns -| Name | Type | Description | -| ---- | :----: | ----------- | -| `0` | `bool` | - | +| Name | Type | Description | +| ---- | :----: | ------------------------------ | +| `0` | `bool` | `true` on successful transfer. |
@@ -928,19 +934,21 @@ function transferFrom( ) external nonpayable returns (bool); ``` +Transfer functions for operators from the ERC20 standard interface. + #### Parameters -| Name | Type | Description | -| -------- | :-------: | ----------- | -| `from` | `address` | - | -| `to` | `address` | - | -| `amount` | `uint256` | - | +| Name | Type | Description | +| -------- | :-------: | --------------------------------- | +| `from` | `address` | The address sending tokens. | +| `to` | `address` | The address receiving tokens. | +| `amount` | `uint256` | The amount of tokens to transfer. | #### Returns -| Name | Type | Description | -| ---- | :----: | ----------- | -| `0` | `bool` | - | +| Name | Type | Description | +| ---- | :----: | ------------------------------ | +| `0` | `bool` | `true` on successful transfer. |
@@ -1026,9 +1034,11 @@ mapping(bytes32 => bytes) _store ### \_setData ```solidity -function _setData(bytes32 key, bytes value) internal nonpayable; +function _setData(bytes32 dataKey, bytes dataValue) internal nonpayable; ``` +Save gas by emitting the [`DataChanged`](#datachanged) event with only the first 256 bytes of dataValue +
### \_updateOperator @@ -1296,11 +1306,11 @@ Emitted when the allowance of a `spender` for an `owner` is set by a call to [`a #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | --------------------------------------------------------- | -| `owner` **`indexed`** | `address` | The account giving approval | -| `spender` **`indexed`** | `address` | The account receiving approval | -| `value` | `uint256` | The amount of tokens `spender` has access to from `owner` | +| Name | Type | Description | +| ----------------------- | :-------: | ----------- | +| `owner` **`indexed`** | `address` | - | +| `spender` **`indexed`** | `address` | - | +| `value` | `uint256` | - |
@@ -1417,24 +1427,27 @@ Emitted when `tokenOwner` disables `operator` for `amount` tokens and set its [` - Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#transfer) - Solidity implementation: [`LSP7CompatibleERC20Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol) -- Event signature: `Transfer(address,address,uint256)` -- Event topic hash: `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` +- Event signature: `Transfer(address,address,address,uint256,bool,bytes)` +- Event topic hash: `0x3997e418d2cef0b3b0e907b1e39605c3f7d32dbd061e82ea5b4a770d46a160a6` ::: ```solidity -event Transfer(address indexed from, address indexed to, uint256 value); +event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool force, bytes data); ``` -Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero. +Emitted when the `from` transferred successfully `amount` of tokens to `to`. #### Parameters -| Name | Type | Description | -| -------------------- | :-------: | -------------------------------- | -| `from` **`indexed`** | `address` | The sending address | -| `to` **`indexed`** | `address` | The receiving address | -| `value` | `uint256` | The amount of tokens transfered. | +| Name | Type | Description | +| ------------------------ | :-------: | ---------------------------------------------------------------------------------------------------------------------------- | +| `operator` **`indexed`** | `address` | The address of the operator that executed the transfer. | +| `from` **`indexed`** | `address` | The address which tokens were sent from (balance decreased by `-amount`). | +| `to` **`indexed`** | `address` | The address that received the tokens (balance increased by `+amount`). | +| `amount` | `uint256` | The amount of tokens transferred. | +| `force` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `data` | `bytes` | Any additional data included by the caller during the transfer, and sent in the LSP1 hooks to the `from` and `to` addresses. |
@@ -1444,27 +1457,24 @@ Emitted when `value` tokens are moved from one account (`from`) to another (`to` - Specification details: [**LSP-7-DigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-7-DigitalAsset.md#transfer) - Solidity implementation: [`LSP7CompatibleERC20Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol) -- Event signature: `Transfer(address,address,address,uint256,bool,bytes)` -- Event topic hash: `0x3997e418d2cef0b3b0e907b1e39605c3f7d32dbd061e82ea5b4a770d46a160a6` +- Event signature: `Transfer(address,address,uint256)` +- Event topic hash: `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` ::: ```solidity -event Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool force, bytes data); +event Transfer(address indexed from, address indexed to, uint256 value); ``` -Emitted when the `from` transferred successfully `amount` of tokens to `to`. +Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero. #### Parameters -| Name | Type | Description | -| ------------------------ | :-------: | ---------------------------------------------------------------------------------------------------------------------------- | -| `operator` **`indexed`** | `address` | The address of the operator that executed the transfer. | -| `from` **`indexed`** | `address` | The address which tokens were sent from (balance decreased by `-amount`). | -| `to` **`indexed`** | `address` | The address that received the tokens (balance increased by `+amount`). | -| `amount` | `uint256` | The amount of tokens transferred. | -| `force` | `bool` | if the transferred enforced the `to` recipient address to be a contract that implements the LSP1 standard or not. | -| `data` | `bytes` | Any additional data included by the caller during the transfer, and sent in the LSP1 hooks to the `from` and `to` addresses. | +| Name | Type | Description | +| -------------------- | :-------: | ----------- | +| `from` **`indexed`** | `address` | - | +| `to` **`indexed`** | `address` | - | +| `value` | `uint256` | - |
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md index e7d8328f7..d82124210 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.md @@ -90,7 +90,7 @@ Reverts whenever someone tries to send native tokens to a LSP8 contract. function approve(address operator, uint256 tokenId) external nonpayable; ``` -_Calling `approve` function on `ILSP8CompatibleERC721` contract. Approving operator at address `operator` to transfer tokenId `tokenId` on behalf of its owner._ +_Calling `approve` function to approve operator at address `operator` to transfer tokenId `tokenId` on behalf of its owner._ Approval function compatible with ERC721 `approve(address,uint256)`. @@ -324,18 +324,22 @@ function isApprovedForAll( ) external view returns (bool); ``` +_Checking if address `operator` is approved to transfer any tokenId owned by address `owner`._ + +Compatible with ERC721 isApprovedForAll. + #### Parameters -| Name | Type | Description | -| ------------ | :-------: | ----------- | -| `tokenOwner` | `address` | - | -| `operator` | `address` | - | +| Name | Type | Description | +| ------------ | :-------: | -------------------------------- | +| `tokenOwner` | `address` | The tokenOwner address to query. | +| `operator` | `address` | The operator address to query. | #### Returns -| Name | Type | Description | -| ---- | :----: | ----------- | -| `0` | `bool` | - | +| Name | Type | Description | +| ---- | :----: | --------------------------------------------------------------------------- | +| `0` | `bool` | Returns if the `operator` is allowed to manage all of the assets of `owner` |
@@ -389,7 +393,7 @@ Returns whether `operator` address is an operator for a given `tokenId`. function name() external view returns (string); ``` -Returns the name of the token. +Returns the name of the token. For compatibility with clients & tools that expect ERC721. #### Returns @@ -532,7 +536,7 @@ function safeTransferFrom( ) external nonpayable; ``` -_Calling `safeTransferFrom` function on `ILSP8CompatibleERC721` contract. Transferring tokenId `tokenId` from address `from` to address `to`._ +_Calling `safeTransferFrom` function to transfer tokenId `tokenId` from address `from` to address `to`._ Safe Transfer function without optional data from the ERC721 standard interface. @@ -572,7 +576,7 @@ function safeTransferFrom( ) external nonpayable; ``` -_Calling `safeTransferFrom` function with `data` on `ILSP8CompatibleERC721` contract. Transferring tokenId `tokenId` from address `from` to address `to`._ +_Calling `safeTransferFrom` function to transfer tokenId `tokenId` from address `from` to address `to`._ Safe Transfer function with optional data from the ERC721 standard interface. @@ -602,14 +606,24 @@ Safe Transfer function with optional data from the ERC721 standard interface. function setApprovalForAll(address operator, bool approved) external nonpayable; ``` -See [`_setApprovalForAll`](#_setapprovalforall) +_Setting the "approval for all" status of operator `_operator` to `_approved` to allow it to transfer any tokenIds on behalf of `msg.sender`._ + +Enable or disable approval for a third party ("operator") to manage all of `msg.sender`'s assets. The contract MUST allow multiple operators per owner. See [`_setApprovalForAll`](#_setapprovalforall) + +
+ +**Emitted events:** + +- [`ApprovalForAll`](#approvalforall) event + +
#### Parameters -| Name | Type | Description | -| ---------- | :-------: | ----------- | -| `operator` | `address` | - | -| `approved` | `bool` | - | +| Name | Type | Description | +| ---------- | :-------: | ----------------------------------------------------------- | +| `operator` | `address` | Address to add to the set of authorized operators. | +| `approved` | `bool` | True if the operator is approved, false to revoke approval. |
@@ -759,7 +773,7 @@ Returns true if this contract implements the interface defined by `interfaceId`. function symbol() external view returns (string); ``` -Returns the symbol of the token, usually a shorter version of the name. +Returns the symbol of the token, usually a shorter version of the name. For compatibility with clients & tools that expect ERC721. #### Returns @@ -846,6 +860,10 @@ Returns the list of `tokenIds` for the `tokenOwner` address. function tokenURI(uint256) external view returns (string); ``` +_Retrieving the token URI of tokenId `tokenId`._ + +Compatible with ERC721Metadata tokenURI. Retrieve the tokenURI for a specific `tokenId`. + #### Parameters | Name | Type | Description | @@ -854,9 +872,9 @@ function tokenURI(uint256) external view returns (string); #### Returns -| Name | Type | Description | -| ---- | :------: | ----------- | -| `0` | `string` | - | +| Name | Type | Description | +| ---- | :------: | -------------- | +| `0` | `string` | The token URI. |
@@ -980,7 +998,7 @@ function transferFrom( ) external nonpayable; ``` -_Calling `transferFrom` function on `ILSP8CompatibleERC721` contract. Transferring tokenId `tokenId` from address `from` to address `to`._ +_Calling `transferFrom` function to transfer tokenId `tokenId` from address `from` to address `to`._ Transfer functions from the ERC721 standard interface. @@ -1076,9 +1094,12 @@ mapping(bytes32 => bytes) _store ### \_setData ```solidity -function _setData(bytes32 key, bytes value) internal nonpayable; +function _setData(bytes32 dataKey, bytes dataValue) internal nonpayable; ``` +The ERC725Y data key `_LSP8_TOKENID_TYPE_KEY` cannot be changed +once the identifiable digital asset contract has been deployed. +
### \_isOperatorOrOwner @@ -1372,7 +1393,7 @@ function _setApprovalForAll( ) internal nonpayable; ``` -Approve `operator` to operate on all tokens of `tokensOwner` +Approve `operator` to operate on all tokens of `tokensOwner`.
@@ -1398,20 +1419,18 @@ Approve `operator` to operate on all tokens of `tokensOwner` ::: ```solidity -event Approval(address indexed owner, address indexed operator, uint256 indexed tokenId); +event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); ``` -_ERC721 `Approval` compatible event emitted. Successfully approved operator `operator` to operate on tokenId `tokenId` on behalf of token owner `owner`._ - Emitted when the allowance of a `spender` for an `owner` is set by a call to [`approve`](#approve). `value` is the new allowance. #### Parameters -| Name | Type | Description | -| ------------------------ | :-------: | ---------------------------- | -| `owner` **`indexed`** | `address` | The account giving approval | -| `operator` **`indexed`** | `address` | The address set as operator. | -| `tokenId` **`indexed`** | `uint256` | The approved tokenId. | +| Name | Type | Description | +| ------------------------ | :-------: | ----------- | +| `owner` **`indexed`** | `address` | - | +| `approved` **`indexed`** | `address` | - | +| `tokenId` **`indexed`** | `uint256` | - |
@@ -1430,17 +1449,15 @@ Emitted when the allowance of a `spender` for an `owner` is set by a call to [`a event ApprovalForAll(address indexed owner, address indexed operator, bool approved); ``` -_ERC721 `ApprovalForAll` compatible event emitted. Successfully set "approved for all" status to `approved` for operator `operator` for token owner `owner`._ - Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to `approved`. #### Parameters -| Name | Type | Description | -| ------------------------ | :-------: | ---------------------------------------------- | -| `owner` **`indexed`** | `address` | The address of the owner of tokenIds. | -| `operator` **`indexed`** | `address` | The address set as operator. | -| `approved` | `bool` | If `operator` is approved for all NFTs or not. | +| Name | Type | Description | +| ------------------------ | :-------: | ----------- | +| `owner` **`indexed`** | `address` | - | +| `operator` **`indexed`** | `address` | - | +| `approved` | `bool` | - |
@@ -1558,26 +1575,27 @@ Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on i - Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#transfer) - Solidity implementation: [`LSP8CompatibleERC721.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol) -- Event signature: `Transfer(address,address,uint256)` -- Event topic hash: `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` +- Event signature: `Transfer(address,address,address,bytes32,bool,bytes)` +- Event topic hash: `0xb333c813a7426a7a11e2b190cad52c44119421594b47f6f32ace6d8c7207b2bf` ::: ```solidity -event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); +event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool force, bytes data); ``` -_ERC721 `Transfer` compatible event emitted. Successfully transferred tokenId `tokenId` from `from` to `to`._ - -Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero. +Emitted when `tokenId` token is transferred from the `from` to the `to` address. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ------------------------ | -| `from` **`indexed`** | `address` | The sending address | -| `to` **`indexed`** | `address` | The receiving address | -| `tokenId` **`indexed`** | `uint256` | The tokenId to transfer. | +| Name | Type | Description | +| ----------------------- | :-------: | ---------------------------------------------------------------------------------------------------------------------------------- | +| `operator` | `address` | The address of operator that sent the `tokenId` | +| `from` **`indexed`** | `address` | The previous owner of the `tokenId` | +| `to` **`indexed`** | `address` | The new owner of `tokenId` | +| `tokenId` **`indexed`** | `bytes32` | The tokenId that was transferred | +| `force` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `data` | `bytes` | Any additional data the caller included by the caller during the transfer, and sent in the hooks to the `from` and `to` addresses. |
@@ -1587,27 +1605,24 @@ Emitted when `value` tokens are moved from one account (`from`) to another (`to` - Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#transfer) - Solidity implementation: [`LSP8CompatibleERC721.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol) -- Event signature: `Transfer(address,address,address,bytes32,bool,bytes)` -- Event topic hash: `0xb333c813a7426a7a11e2b190cad52c44119421594b47f6f32ace6d8c7207b2bf` +- Event signature: `Transfer(address,address,uint256)` +- Event topic hash: `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` ::: ```solidity -event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool force, bytes data); +event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); ``` -Emitted when `tokenId` token is transferred from the `from` to the `to` address. +Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ---------------------------------------------------------------------------------------------------------------------------------- | -| `operator` | `address` | The address of operator that sent the `tokenId` | -| `from` **`indexed`** | `address` | The previous owner of the `tokenId` | -| `to` **`indexed`** | `address` | The new owner of `tokenId` | -| `tokenId` **`indexed`** | `bytes32` | The tokenId that was transferred | -| `force` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | -| `data` | `bytes` | Any additional data the caller included by the caller during the transfer, and sent in the hooks to the `from` and `to` addresses. | +| Name | Type | Description | +| ----------------------- | :-------: | ----------- | +| `from` **`indexed`** | `address` | - | +| `to` **`indexed`** | `address` | - | +| `tokenId` **`indexed`** | `uint256` | - |
diff --git a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md index 0e2b550cf..232dbd9d5 100644 --- a/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md +++ b/docs/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.md @@ -97,7 +97,7 @@ receive() external payable; function approve(address operator, uint256 tokenId) external nonpayable; ``` -_Calling `approve` function on `ILSP8CompatibleERC721` contract. Approving operator at address `operator` to transfer tokenId `tokenId` on behalf of its owner._ +_Calling `approve` function to approve operator at address `operator` to transfer tokenId `tokenId` on behalf of its owner._ Approval function compatible with ERC721 `approve(address,uint256)`. @@ -331,18 +331,22 @@ function isApprovedForAll( ) external view returns (bool); ``` +_Checking if address `operator` is approved to transfer any tokenId owned by address `owner`._ + +Compatible with ERC721 isApprovedForAll. + #### Parameters -| Name | Type | Description | -| ------------ | :-------: | ----------- | -| `tokenOwner` | `address` | - | -| `operator` | `address` | - | +| Name | Type | Description | +| ------------ | :-------: | -------------------------------- | +| `tokenOwner` | `address` | The tokenOwner address to query. | +| `operator` | `address` | The operator address to query. | #### Returns -| Name | Type | Description | -| ---- | :----: | ----------- | -| `0` | `bool` | - | +| Name | Type | Description | +| ---- | :----: | --------------------------------------------------------------------------- | +| `0` | `bool` | Returns if the `operator` is allowed to manage all of the assets of `owner` |
@@ -431,7 +435,7 @@ Public [`_mint`](#_mint) function only callable by the [`owner`](#owner). function name() external view returns (string); ``` -Returns the name of the token. +Returns the name of the token. For compatibility with clients & tools that expect ERC721. #### Returns @@ -574,7 +578,7 @@ function safeTransferFrom( ) external nonpayable; ``` -_Calling `safeTransferFrom` function on `ILSP8CompatibleERC721` contract. Transferring tokenId `tokenId` from address `from` to address `to`._ +_Calling `safeTransferFrom` function to transfer tokenId `tokenId` from address `from` to address `to`._ Safe Transfer function without optional data from the ERC721 standard interface. @@ -614,7 +618,7 @@ function safeTransferFrom( ) external nonpayable; ``` -_Calling `safeTransferFrom` function with `data` on `ILSP8CompatibleERC721` contract. Transferring tokenId `tokenId` from address `from` to address `to`._ +_Calling `safeTransferFrom` function to transfer tokenId `tokenId` from address `from` to address `to`._ Safe Transfer function with optional data from the ERC721 standard interface. @@ -644,14 +648,24 @@ Safe Transfer function with optional data from the ERC721 standard interface. function setApprovalForAll(address operator, bool approved) external nonpayable; ``` -See [`_setApprovalForAll`](#_setapprovalforall) +_Setting the "approval for all" status of operator `_operator` to `_approved` to allow it to transfer any tokenIds on behalf of `msg.sender`._ + +Enable or disable approval for a third party ("operator") to manage all of `msg.sender`'s assets. The contract MUST allow multiple operators per owner. See [`_setApprovalForAll`](#_setapprovalforall) + +
+ +**Emitted events:** + +- [`ApprovalForAll`](#approvalforall) event + +
#### Parameters -| Name | Type | Description | -| ---------- | :-------: | ----------- | -| `operator` | `address` | - | -| `approved` | `bool` | - | +| Name | Type | Description | +| ---------- | :-------: | ----------------------------------------------------------- | +| `operator` | `address` | Address to add to the set of authorized operators. | +| `approved` | `bool` | True if the operator is approved, false to revoke approval. |
@@ -801,7 +815,7 @@ Returns true if this contract implements the interface defined by `interfaceId`. function symbol() external view returns (string); ``` -Returns the symbol of the token, usually a shorter version of the name. +Returns the symbol of the token, usually a shorter version of the name. For compatibility with clients & tools that expect ERC721. #### Returns @@ -888,6 +902,10 @@ Returns the list of `tokenIds` for the `tokenOwner` address. function tokenURI(uint256) external view returns (string); ``` +_Retrieving the token URI of tokenId `tokenId`._ + +Compatible with ERC721Metadata tokenURI. Retrieve the tokenURI for a specific `tokenId`. + #### Parameters | Name | Type | Description | @@ -896,9 +914,9 @@ function tokenURI(uint256) external view returns (string); #### Returns -| Name | Type | Description | -| ---- | :------: | ----------- | -| `0` | `string` | - | +| Name | Type | Description | +| ---- | :------: | -------------- | +| `0` | `string` | The token URI. |
@@ -1022,7 +1040,7 @@ function transferFrom( ) external nonpayable; ``` -_Calling `transferFrom` function on `ILSP8CompatibleERC721` contract. Transferring tokenId `tokenId` from address `from` to address `to`._ +_Calling `transferFrom` function to transfer tokenId `tokenId` from address `from` to address `to`._ Transfer functions from the ERC721 standard interface. @@ -1118,9 +1136,12 @@ mapping(bytes32 => bytes) _store ### \_setData ```solidity -function _setData(bytes32 key, bytes value) internal nonpayable; +function _setData(bytes32 dataKey, bytes dataValue) internal nonpayable; ``` +The ERC725Y data key `_LSP8_TOKENID_TYPE_KEY` cannot be changed +once the identifiable digital asset contract has been deployed. +
### \_isOperatorOrOwner @@ -1414,7 +1435,7 @@ function _setApprovalForAll( ) internal nonpayable; ``` -Approve `operator` to operate on all tokens of `tokensOwner` +Approve `operator` to operate on all tokens of `tokensOwner`.
@@ -1440,20 +1461,18 @@ Approve `operator` to operate on all tokens of `tokensOwner` ::: ```solidity -event Approval(address indexed owner, address indexed operator, uint256 indexed tokenId); +event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); ``` -_ERC721 `Approval` compatible event emitted. Successfully approved operator `operator` to operate on tokenId `tokenId` on behalf of token owner `owner`._ - Emitted when the allowance of a `spender` for an `owner` is set by a call to [`approve`](#approve). `value` is the new allowance. #### Parameters -| Name | Type | Description | -| ------------------------ | :-------: | ---------------------------- | -| `owner` **`indexed`** | `address` | The account giving approval | -| `operator` **`indexed`** | `address` | The address set as operator. | -| `tokenId` **`indexed`** | `uint256` | The approved tokenId. | +| Name | Type | Description | +| ------------------------ | :-------: | ----------- | +| `owner` **`indexed`** | `address` | - | +| `approved` **`indexed`** | `address` | - | +| `tokenId` **`indexed`** | `uint256` | - |
@@ -1472,17 +1491,15 @@ Emitted when the allowance of a `spender` for an `owner` is set by a call to [`a event ApprovalForAll(address indexed owner, address indexed operator, bool approved); ``` -_ERC721 `ApprovalForAll` compatible event emitted. Successfully set "approved for all" status to `approved` for operator `operator` for token owner `owner`._ - Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to `approved`. #### Parameters -| Name | Type | Description | -| ------------------------ | :-------: | ---------------------------------------------- | -| `owner` **`indexed`** | `address` | The address of the owner of tokenIds. | -| `operator` **`indexed`** | `address` | The address set as operator. | -| `approved` | `bool` | If `operator` is approved for all NFTs or not. | +| Name | Type | Description | +| ------------------------ | :-------: | ----------- | +| `owner` **`indexed`** | `address` | - | +| `operator` **`indexed`** | `address` | - | +| `approved` | `bool` | - |
@@ -1600,26 +1617,27 @@ Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on i - Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#transfer) - Solidity implementation: [`LSP8CompatibleERC721Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol) -- Event signature: `Transfer(address,address,uint256)` -- Event topic hash: `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` +- Event signature: `Transfer(address,address,address,bytes32,bool,bytes)` +- Event topic hash: `0xb333c813a7426a7a11e2b190cad52c44119421594b47f6f32ace6d8c7207b2bf` ::: ```solidity -event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); +event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool force, bytes data); ``` -_ERC721 `Transfer` compatible event emitted. Successfully transferred tokenId `tokenId` from `from` to `to`._ - -Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero. +Emitted when `tokenId` token is transferred from the `from` to the `to` address. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ------------------------ | -| `from` **`indexed`** | `address` | The sending address | -| `to` **`indexed`** | `address` | The receiving address | -| `tokenId` **`indexed`** | `uint256` | The tokenId to transfer. | +| Name | Type | Description | +| ----------------------- | :-------: | ---------------------------------------------------------------------------------------------------------------------------------- | +| `operator` | `address` | The address of operator that sent the `tokenId` | +| `from` **`indexed`** | `address` | The previous owner of the `tokenId` | +| `to` **`indexed`** | `address` | The new owner of `tokenId` | +| `tokenId` **`indexed`** | `bytes32` | The tokenId that was transferred | +| `force` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | +| `data` | `bytes` | Any additional data the caller included by the caller during the transfer, and sent in the hooks to the `from` and `to` addresses. |
@@ -1629,27 +1647,24 @@ Emitted when `value` tokens are moved from one account (`from`) to another (`to` - Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#transfer) - Solidity implementation: [`LSP8CompatibleERC721Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol) -- Event signature: `Transfer(address,address,address,bytes32,bool,bytes)` -- Event topic hash: `0xb333c813a7426a7a11e2b190cad52c44119421594b47f6f32ace6d8c7207b2bf` +- Event signature: `Transfer(address,address,uint256)` +- Event topic hash: `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` ::: ```solidity -event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool force, bytes data); +event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); ``` -Emitted when `tokenId` token is transferred from the `from` to the `to` address. +Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero. #### Parameters -| Name | Type | Description | -| ----------------------- | :-------: | ---------------------------------------------------------------------------------------------------------------------------------- | -| `operator` | `address` | The address of operator that sent the `tokenId` | -| `from` **`indexed`** | `address` | The previous owner of the `tokenId` | -| `to` **`indexed`** | `address` | The new owner of `tokenId` | -| `tokenId` **`indexed`** | `bytes32` | The tokenId that was transferred | -| `force` | `bool` | If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not. | -| `data` | `bytes` | Any additional data the caller included by the caller during the transfer, and sent in the hooks to the `from` and `to` addresses. | +| Name | Type | Description | +| ----------------------- | :-------: | ----------- | +| `from` **`indexed`** | `address` | - | +| `to` **`indexed`** | `address` | - | +| `tokenId` **`indexed`** | `uint256` | - |
diff --git a/dodoc/config.ts b/dodoc/config.ts index d9f4059c8..02cb032b2 100644 --- a/dodoc/config.ts +++ b/dodoc/config.ts @@ -23,7 +23,6 @@ export const dodocConfig = { 'contracts/LSP25ExecuteRelayCall/LSP25MultiChannelNonce.sol', // tokens - 'contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol', 'contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.sol', 'contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol', 'contracts/LSP7DigitalAsset/extensions/LSP7Burnable.sol', diff --git a/hardhat.config.ts b/hardhat.config.ts index 175e5dad2..d621968aa 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -140,7 +140,6 @@ const config: HardhatUserConfig = { 'LSP11BasicSocialRecoveryInit', // ERC Compatible tokens // ------------------ - 'LSP4Compatibility', 'LSP7CompatibleERC20', 'LSP7CompatibleERC20InitAbstract', 'LSP7CompatibleERC20Mintable', diff --git a/package.json b/package.json index 7a73a12a6..ce39f3440 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,6 @@ "test:upinit": "hardhat test --no-compile tests/UniversalProfileInit.test.ts", "test:lsp1": "hardhat test --no-compile tests/LSP1UniversalReceiver/*.test.ts", "test:lsp2": "hardhat test --no-compile tests/LSP2ERC725YJSONSchema/LSP2UtilsLibrary.test.ts", - "test:lsp4": "hardhat test --no-compile tests/LSP4DigitalAssetMetadata/LSP4Compatibility.test.ts", "test:lsp6": "hardhat test --no-compile tests/LSP6KeyManager/LSP6KeyManager.test.ts", "test:lsp6init": "hardhat test --no-compile tests/LSP6KeyManager/LSP6KeyManagerInit.test.ts", "test:lsp7": "hardhat test --no-compile tests/LSP7DigitalAsset/standard/*.test.ts", diff --git a/scripts/interfaceIds.ts b/scripts/interfaceIds.ts index e1f63fb65..fb6c79a1a 100644 --- a/scripts/interfaceIds.ts +++ b/scripts/interfaceIds.ts @@ -11,7 +11,15 @@ const ercInterfaceDescriptions = { ERC725Y: 'General Data key-value store.', }; -const excludedInterfaces = ['ERC20', 'ERC223', 'ERC721', 'ERC721Metadata', 'ERC777', 'ERC1155']; +const excludedInterfaces = [ + 'ERC20', + 'ERC20Metadata', + 'ERC223', + 'ERC721', + 'ERC721Metadata', + 'ERC777', + 'ERC1155', +]; async function main() { const interfaces = Object.entries(INTERFACE_IDS); diff --git a/tests/LSP4DigitalAssetMetadata/LSP4Compatibility.test.ts b/tests/LSP4DigitalAssetMetadata/LSP4Compatibility.test.ts deleted file mode 100644 index fc3ced43e..000000000 --- a/tests/LSP4DigitalAssetMetadata/LSP4Compatibility.test.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { expect } from 'chai'; -import { ethers } from 'hardhat'; -import { LSP4CompatibilityTester, LSP4CompatibilityTester__factory } from '../../types'; - -import type { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; - -type LSP4CompatibilityTestAccounts = { - owner: SignerWithAddress; -}; - -const getNamedAccounts = async () => { - const [owner] = await ethers.getSigners(); - return { owner }; -}; - -type LSP4CompatibilityTestContext = { - accounts: LSP4CompatibilityTestAccounts; - lsp4Compatibility: LSP4CompatibilityTester; - deployParams: { - name: string; - symbol: string; - newOwner: string; - }; -}; - -describe('LSP4Compatibility', () => { - const buildTestContext = async (): Promise => { - const accounts = await getNamedAccounts(); - const deployParams = { - name: 'Much compat', - symbol: 'WOW', - newOwner: accounts.owner.address, - }; - - const lsp4Compatibility = await new LSP4CompatibilityTester__factory(accounts.owner).deploy( - deployParams.name, - deployParams.symbol, - deployParams.newOwner, - ); - - return { accounts, lsp4Compatibility, deployParams }; - }; - - describe('when using LSP4Compatibility', () => { - let context: LSP4CompatibilityTestContext; - - before(async () => { - context = await buildTestContext(); - }); - - it('should allow reading name', async () => { - // using compatibility getter -> returns(string) - const nameAsString = await context.lsp4Compatibility.name(); - expect(nameAsString).to.equal(context.deployParams.name); - - // using getData -> returns(bytes) - const nameAsBytes = await context.lsp4Compatibility.getData( - ethers.utils.keccak256(ethers.utils.toUtf8Bytes('LSP4TokenName')), - ); - - expect(ethers.utils.toUtf8String(nameAsBytes)).to.equal(context.deployParams.name); - }); - - it('should allow reading symbol', async () => { - // using compatibility getter -> returns(string) - const symbolAsString = await context.lsp4Compatibility.symbol(); - expect(symbolAsString).to.equal(context.deployParams.symbol); - - // using getData -> returns(bytes) - const symbolAsBytes = await context.lsp4Compatibility.getData( - ethers.utils.keccak256(ethers.utils.toUtf8Bytes('LSP4TokenSymbol')), - ); - - expect(ethers.utils.toUtf8String(symbolAsBytes)).to.equal(context.deployParams.symbol); - }); - }); -}); diff --git a/tests/LSP7DigitalAsset/LSP7CompatibleERC20.behaviour.ts b/tests/LSP7DigitalAsset/LSP7CompatibleERC20.behaviour.ts index 831a6ad1e..4c9c744d5 100644 --- a/tests/LSP7DigitalAsset/LSP7CompatibleERC20.behaviour.ts +++ b/tests/LSP7DigitalAsset/LSP7CompatibleERC20.behaviour.ts @@ -1285,8 +1285,18 @@ export const shouldInitializeLikeLSP7CompatibleERC20 = ( }); describe('when the contract was initialized', () => { - it('should have registered its ERC165 interface', async () => { - expect(await context.lsp7CompatibleERC20.supportsInterface(INTERFACE_IDS.LSP7DigitalAsset)); + it('should support ERC20 interface', async () => { + expect(await context.lsp7CompatibleERC20.supportsInterface(INTERFACE_IDS.ERC20)).to.be.true; + }); + + it('should support ERC20Metadata interface', async () => { + expect(await context.lsp7CompatibleERC20.supportsInterface(INTERFACE_IDS.ERC20Metadata)).to.be + .true; + }); + + it('should support LSP7 interface', async () => { + expect(await context.lsp7CompatibleERC20.supportsInterface(INTERFACE_IDS.LSP7DigitalAsset)).to + .be.true; }); it('should have set expected entries with ERC725Y.setData', async () => { @@ -1318,5 +1328,33 @@ export const shouldInitializeLikeLSP7CompatibleERC20 = ( .withArgs(symbolKey, expectedSymbolValue); expect(await context.lsp7CompatibleERC20.getData(symbolKey)).to.equal(expectedSymbolValue); }); + + describe('when using the functions from IERC20Metadata', () => { + it('should allow reading `name()`', async () => { + // using compatibility getter -> returns(string) + const nameAsString = await context.lsp7CompatibleERC20.name(); + expect(nameAsString).to.equal(context.deployParams.name); + + // using getData -> returns(bytes) + const nameAsBytes = await context.lsp7CompatibleERC20.getData( + ethers.utils.keccak256(ethers.utils.toUtf8Bytes('LSP4TokenName')), + ); + + expect(ethers.utils.toUtf8String(nameAsBytes)).to.equal(context.deployParams.name); + }); + + it('should allow reading `symbol()`', async () => { + // using compatibility getter -> returns(string) + const symbolAsString = await context.lsp7CompatibleERC20.symbol(); + expect(symbolAsString).to.equal(context.deployParams.symbol); + + // using getData -> returns(bytes) + const symbolAsBytes = await context.lsp7CompatibleERC20.getData( + ethers.utils.keccak256(ethers.utils.toUtf8Bytes('LSP4TokenSymbol')), + ); + + expect(ethers.utils.toUtf8String(symbolAsBytes)).to.equal(context.deployParams.symbol); + }); + }); }); }; diff --git a/tests/LSP8IdentifiableDigitalAsset/LSP8CompatibleERC721.behaviour.ts b/tests/LSP8IdentifiableDigitalAsset/LSP8CompatibleERC721.behaviour.ts index 44eaf4d7d..5fc815c1b 100644 --- a/tests/LSP8IdentifiableDigitalAsset/LSP8CompatibleERC721.behaviour.ts +++ b/tests/LSP8IdentifiableDigitalAsset/LSP8CompatibleERC721.behaviour.ts @@ -1270,14 +1270,21 @@ export const shouldInitializeLikeLSP8CompatibleERC721 = ( }); describe('when the contract was initialized', () => { - it('should have registered its ERC165 interface', async () => { + it('should support ERC721 interface', async () => { + expect(await context.lsp8CompatibleERC721.supportsInterface(INTERFACE_IDS.ERC721)).to.be.true; + }); + + it('should support ERC721Metadata interface', async () => { + expect(await context.lsp8CompatibleERC721.supportsInterface(INTERFACE_IDS.ERC721Metadata)).to + .be.true; + }); + + it('should support LSP8 interface', async () => { expect( await context.lsp8CompatibleERC721.supportsInterface( INTERFACE_IDS.LSP8IdentifiableDigitalAsset, ), - ); - expect(await context.lsp8CompatibleERC721.supportsInterface(INTERFACE_IDS.ERC721)); - expect(await context.lsp8CompatibleERC721.supportsInterface(INTERFACE_IDS.ERC721Metadata)); + ).to.be.true; }); it('should have set expected entries with ERC725Y.setData', async () => { @@ -1309,5 +1316,33 @@ export const shouldInitializeLikeLSP8CompatibleERC721 = ( .withArgs(symbolKey, expectedSymbolValue); expect(await context.lsp8CompatibleERC721.getData(symbolKey)).to.equal(expectedSymbolValue); }); + + describe('when using the functions from IERC721Metadata', () => { + it('should allow reading `name()`', async () => { + // using compatibility getter -> returns(string) + const nameAsString = await context.lsp8CompatibleERC721.name(); + expect(nameAsString).to.equal(context.deployParams.name); + + // using getData -> returns(bytes) + const nameAsBytes = await context.lsp8CompatibleERC721.getData( + ethers.utils.keccak256(ethers.utils.toUtf8Bytes('LSP4TokenName')), + ); + + expect(ethers.utils.toUtf8String(nameAsBytes)).to.equal(context.deployParams.name); + }); + + it('should allow reading `symbol()`', async () => { + // using compatibility getter -> returns(string) + const symbolAsString = await context.lsp8CompatibleERC721.symbol(); + expect(symbolAsString).to.equal(context.deployParams.symbol); + + // using getData -> returns(bytes) + const symbolAsBytes = await context.lsp8CompatibleERC721.getData( + ethers.utils.keccak256(ethers.utils.toUtf8Bytes('LSP4TokenSymbol')), + ); + + expect(ethers.utils.toUtf8String(symbolAsBytes)).to.equal(context.deployParams.symbol); + }); + }); }); }; diff --git a/tests/Mocks/ERC165Interfaces.test.ts b/tests/Mocks/ERC165Interfaces.test.ts index 07bb2be05..87d68d7b9 100644 --- a/tests/Mocks/ERC165Interfaces.test.ts +++ b/tests/Mocks/ERC165Interfaces.test.ts @@ -109,6 +109,11 @@ describe('Calculate ERC interfaces', () => { expect(result).to.equal(INTERFACE_IDS.ERC20); }); + it('ERC20Metadata', async () => { + const result = await contract.calculateInterfaceERC20Metadata(); + expect(result).to.equal(INTERFACE_IDS.ERC20Metadata); + }); + it('ERC223', async () => { const result = await contract.calculateInterfaceERC223(); expect(result).to.equal(INTERFACE_IDS.ERC223); From e2ec65aeba2aca8351d9a9e71e08e34a004ae483 Mon Sep 17 00:00:00 2001 From: Jean Cvllr <31145285+CJ42@users.noreply.github.com> Date: Wed, 18 Oct 2023 11:07:34 +0100 Subject: [PATCH 55/55] chore(release): 0.12.0-rc.0 (#754) --- CHANGELOG.md | 40 ++++++++++++++++++++++++++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32f4b0ca8..94c52c0c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,46 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [0.12.0-rc.0](https://github.com/lukso-network/lsp-smart-contracts/compare/v0.11.1...v0.12.0-rc.0) (2023-10-18) + +### ⚠ BREAKING CHANGES + +- remove `LSP4Compatibility` contract + ERC20 Compatible token interfaces `ILSP7CompatibleERC20` / `ILSP8CompatibleERC721` (#749) +- add extra parameter `requestor` to `lsp20VerifyCall` (#753) +- Roll back to old `LSP1UniversalReceiverDelegate` Interface and functions (#741) +- remove `isEncodedArray(...)` from `LSP2utils.sol` (#746) +- add callee params to lsp20 & EXECUTE_RELAY_CALL permission & mapping reentrancyStatus (#729) +- set LSP8 TokenId Type on deployment / initialization (#712) +- re-change param name from `allowNonLSP1Recipient` to `force` + +### Deprecation + +- re-change param name from `allowNonLSP1Recipient` to `force` ([d59a2ff](https://github.com/lukso-network/lsp-smart-contracts/commit/d59a2ff4712a5373ce72ba1ccd63b2d796f60cd9)) +- remove `isEncodedArray(...)` from `LSP2utils.sol` ([#746](https://github.com/lukso-network/lsp-smart-contracts/issues/746)) ([1ff7cd4](https://github.com/lukso-network/lsp-smart-contracts/commit/1ff7cd4e34a91c53ce72f19fb8d469d2ae0c9a09)) +- remove `LSP4Compatibility` contract + ERC20 Compatible token interfaces `ILSP7CompatibleERC20` / `ILSP8CompatibleERC721` ([#749](https://github.com/lukso-network/lsp-smart-contracts/issues/749)) ([b038412](https://github.com/lukso-network/lsp-smart-contracts/commit/b038412c99d5149f25a83156322539e817e1575b)) +- Roll back to old `LSP1UniversalReceiverDelegate` Interface and functions ([#741](https://github.com/lukso-network/lsp-smart-contracts/issues/741)) ([dab41a1](https://github.com/lukso-network/lsp-smart-contracts/commit/dab41a1baf61876865191424a5e19548845f1630)) +- set LSP8 TokenId Type on deployment / initialization ([#712](https://github.com/lukso-network/lsp-smart-contracts/issues/712)) ([67cb333](https://github.com/lukso-network/lsp-smart-contracts/commit/67cb3333256e31a0c432a9bcd62f08e83e969222)) + +### Features + +- add `_afterTokenTransfer` hook in LSP7 + LSP8 ([4e3adc2](https://github.com/lukso-network/lsp-smart-contracts/commit/4e3adc24e233138b8f1471320e3b1bb3307ef524)) +- add `data` param in `_before` and `_after` token transfer hooks ([0cd0976](https://github.com/lukso-network/lsp-smart-contracts/commit/0cd097604193957aeb2d6bf181d9193719621eac)) +- add `callee` params to lsp20 & `EXECUTE_RELAY_CALL` permission & `mapping reentrancyStatus` ([#729](https://github.com/lukso-network/lsp-smart-contracts/issues/729)) ([0ae4c83](https://github.com/lukso-network/lsp-smart-contracts/commit/0ae4c83d80227e53c614d46dce96f8b727822839)) +- add lsp20 to `acceptOwnership` in LSP0 ([#747](https://github.com/lukso-network/lsp-smart-contracts/issues/747)) ([804779a](https://github.com/lukso-network/lsp-smart-contracts/commit/804779a5f7ac76b21695a00c622a7c0e5801192a)) +- allow `endingTimestamp` to be 0 ([a8c730f](https://github.com/lukso-network/lsp-smart-contracts/commit/a8c730f608fdd585c94b69704272bdaec938a565)) +- allow `renounceOwnership()` through LSP6 ([dd74b56](https://github.com/lukso-network/lsp-smart-contracts/commit/dd74b56af54cc01a5e28b50feac2ce6659403cda)) +- allow sending value when using `setData(..)` through the LSP6 ([#725](https://github.com/lukso-network/lsp-smart-contracts/issues/725)) ([624c4a6](https://github.com/lukso-network/lsp-smart-contracts/commit/624c4a6dfa0c5c83c94f0b5e952adc783098d12c)) +- create Extension4337 ([#735](https://github.com/lukso-network/lsp-smart-contracts/issues/735)) ([d1df1d0](https://github.com/lukso-network/lsp-smart-contracts/commit/d1df1d0c106f47bd24427f1c20c3423a00bb993c)) +- add extra parameter `requestor` to `lsp20VerifyCall` ([#753](https://github.com/lukso-network/lsp-smart-contracts/pull/753)) ([f82626d](https://github.com/lukso-network/lsp-smart-contracts/commit/f82626d5f64efd396a40690687dfb5a2dc9c036e)) + +### Bug Fixes + +- add `receive()` function in LSP7 & LSP8 to silent compiler warning ([#711](https://github.com/lukso-network/lsp-smart-contracts/pull/711)) ([e6fb55d](https://github.com/lukso-network/lsp-smart-contracts/commit/e6fb55d9acc7bd63b9d66920f2f346ecf812c289)) +- bug in dodoc config, incorrect signature ([06b1f04](https://github.com/lukso-network/lsp-smart-contracts/commit/06b1f04f83158f27efb19670ed81f566d7b151ba)) +- return `bytes32(0)` when permission value retrieved is not exactly 32 bytes long ([7422ab0](https://github.com/lukso-network/lsp-smart-contracts/commit/7422ab053b27f1139dc8b917218bebd2407009b9)) +- ts configs and tests ([#733](https://github.com/lukso-network/lsp-smart-contracts/issues/733)) ([a977312](https://github.com/lukso-network/lsp-smart-contracts/commit/a977312f99a3f957e581f5b502ef818f033f3846)) +- update logic to check against controller permissions when setting its Allowed Calls or ERC725Y Data Keys ([#734](https://github.com/lukso-network/lsp-smart-contracts/issues/734)) ([0d43077](https://github.com/lukso-network/lsp-smart-contracts/commit/0d43077a96b542f645d50cf9389f26c292c8b39e)) + ## [0.11.1](https://github.com/lukso-network/lsp-smart-contracts/compare/v0.11.0-rc.1...v0.11.0) (2023-09-07) ### ⚠ BREAKING CHANGES diff --git a/package-lock.json b/package-lock.json index 8aa39ae15..595bc0b9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@lukso/lsp-smart-contracts", - "version": "0.11.1", + "version": "0.12.0-rc.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@lukso/lsp-smart-contracts", - "version": "0.11.1", + "version": "0.12.0-rc.0", "license": "Apache-2.0", "dependencies": { "@account-abstraction/contracts": "^0.6.0", diff --git a/package.json b/package.json index ce39f3440..7cd471ae7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@lukso/lsp-smart-contracts", - "version": "0.11.1", + "version": "0.12.0-rc.0", "description": "The reference implementation for universal profiles smart contracts", "directories": { "test": "test"