@lukso/lsp20-contracts 0.15.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,9 @@
1
+ # LSP20 Call Verification · [![npm version](https://img.shields.io/npm/v/@lukso/lsp20-contracts.svg?style=flat)](https://www.npmjs.com/package/@lukso/lsp20-contracts)
2
+
3
+ Package for the LSP20 Call Verification standard.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm i @lukso/lsp20-contracts
9
+ ```
@@ -0,0 +1,39 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.4;
3
+
4
+ /**
5
+ * @title Interface for the LSP20 Call Verification standard, a set of functions intended to perform verifications on behalf of another contract.
6
+ *
7
+ * @dev Interface to be inherited for contract supporting LSP20-CallVerification
8
+ */
9
+ interface ILSP20CallVerifier {
10
+ /**
11
+ * @return returnedStatus MUST return the first 3 bytes of `lsp20VerifyCall(address,uint256,bytes)` function selector if the call to
12
+ * the function is allowed, concatened with a byte that determines if the lsp20VerifyCallResult function should
13
+ * be called after the original function call. The byte that invoke the lsp20VerifyCallResult function is strictly `0x01`.
14
+ *
15
+ * @param requestor The address that requested to make the call to `target`.
16
+ * @param target The address of the contract that implements the `LSP20CallVerification` interface.
17
+ * @param caller The address who called the function on the `target` contract.
18
+ * @param value The value sent by the caller to the function called on the msg.sender
19
+ * @param callData The calldata sent by the caller to the msg.sender
20
+ */
21
+ function lsp20VerifyCall(
22
+ address requestor,
23
+ address target,
24
+ address caller,
25
+ uint256 value,
26
+ bytes memory callData
27
+ ) external returns (bytes4 returnedStatus);
28
+
29
+ /**
30
+ * @return MUST return the lsp20VerifyCallResult function selector if the call to the function is allowed
31
+ *
32
+ * @param callHash The keccak256 hash of the parameters of {lsp20VerifyCall} concatenated
33
+ * @param callResult The value result of the function called on the msg.sender
34
+ */
35
+ function lsp20VerifyCallResult(
36
+ bytes32 callHash,
37
+ bytes memory callResult
38
+ ) external returns (bytes4);
39
+ }
@@ -0,0 +1,120 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.4;
3
+
4
+ // interfaces
5
+ import {ILSP20CallVerifier as ILSP20} from "./ILSP20CallVerifier.sol";
6
+
7
+ // errors
8
+ import {
9
+ LSP20CallVerificationFailed,
10
+ LSP20CallingVerifierFailed,
11
+ LSP20EOACannotVerifyCall
12
+ } from "./LSP20Errors.sol";
13
+
14
+ /**
15
+ * @title Implementation of a contract calling the verification functions according to LSP20 - Call Verification standard.
16
+ *
17
+ * @dev Module to be inherited used to verify the execution of functions according to a verifier address.
18
+ * Verification can happen before or after execution based on a returnedStatus.
19
+ */
20
+ abstract contract LSP20CallVerification {
21
+ /**
22
+ * @dev Calls {lsp20VerifyCall} function on the logicVerifier.
23
+ *
24
+ * @custom:info
25
+ * - Reverts in case the value returned does not match the returned status (lsp20VerifyCall selector).
26
+ * - Returns whether a verification after the execution should happen based on the last byte of the `returnedStatus`.
27
+ * - Reverts with no reason if the data returned by `ILSP20(logicVerifier).lsp20VerifyCall(...)` cannot be decoded (_e.g:_ any other data type besides `bytes4`).
28
+ * See this link for more info: https://forum.soliditylang.org/t/call-for-feedback-the-future-of-try-catch-in-solidity/1497.
29
+ */
30
+ function _verifyCall(
31
+ address logicVerifier
32
+ ) internal virtual returns (bool verifyAfter) {
33
+ if (logicVerifier.code.length == 0) {
34
+ revert LSP20EOACannotVerifyCall(logicVerifier);
35
+ }
36
+
37
+ // Reverts with no reason if the returned data type is not a `bytes4` value
38
+ try
39
+ ILSP20(logicVerifier).lsp20VerifyCall(
40
+ msg.sender,
41
+ address(this),
42
+ msg.sender,
43
+ msg.value,
44
+ msg.data
45
+ )
46
+ returns (bytes4 returnedStatus) {
47
+ if (
48
+ bytes3(returnedStatus) !=
49
+ bytes3(ILSP20.lsp20VerifyCall.selector)
50
+ ) {
51
+ revert LSP20CallVerificationFailed({
52
+ postCall: false,
53
+ returnedStatus: returnedStatus
54
+ });
55
+ }
56
+
57
+ return returnedStatus[3] == 0x01;
58
+ } catch (bytes memory errorData) {
59
+ _revertWithLSP20DefaultError(false, errorData);
60
+ }
61
+ }
62
+
63
+ /**
64
+ * @dev Calls {lsp20VerifyCallResult} function on the logicVerifier.
65
+ *
66
+ * @custom:info
67
+ * - Reverts in case the value returned does not match the returned status (lsp20VerifyCallResult selector).
68
+ * - Reverts with no reason if the data returned by `ILSP20(logicVerifier).lsp20VerifyCallResult(...)` cannot be decoded (_e.g:_ any other data type besides `bytes4`).
69
+ * See this link for more info: https://forum.soliditylang.org/t/call-for-feedback-the-future-of-try-catch-in-solidity/1497.
70
+ */
71
+ function _verifyCallResult(
72
+ address logicVerifier,
73
+ bytes memory callResult
74
+ ) internal virtual {
75
+ // Reverts with no reason if the returned data type is not a `bytes4` value
76
+ try
77
+ ILSP20(logicVerifier).lsp20VerifyCallResult(
78
+ keccak256(
79
+ abi.encodePacked(
80
+ msg.sender,
81
+ address(this),
82
+ msg.sender,
83
+ msg.value,
84
+ msg.data
85
+ )
86
+ ),
87
+ callResult
88
+ )
89
+ returns (bytes4 returnedStatus) {
90
+ if (returnedStatus != ILSP20.lsp20VerifyCallResult.selector) {
91
+ revert LSP20CallVerificationFailed({
92
+ postCall: true,
93
+ returnedStatus: returnedStatus
94
+ });
95
+ }
96
+
97
+ return;
98
+ } catch (bytes memory errorData) {
99
+ _revertWithLSP20DefaultError(true, errorData);
100
+ }
101
+ }
102
+
103
+ function _revertWithLSP20DefaultError(
104
+ bool postCall,
105
+ bytes memory returnedData
106
+ ) internal pure virtual {
107
+ // Look for revert reason and bubble it up if present
108
+ if (returnedData.length != 0) {
109
+ // The easiest way to bubble the revert reason is using memory via assembly
110
+ // solhint-disable no-inline-assembly
111
+ /// @solidity memory-safe-assembly
112
+ assembly {
113
+ let returndata_size := mload(returnedData)
114
+ revert(add(32, returnedData), returndata_size)
115
+ }
116
+ } else {
117
+ revert LSP20CallingVerifierFailed(postCall);
118
+ }
119
+ }
120
+ }
@@ -0,0 +1,17 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.4;
3
+
4
+ // bytes4(keccak256("LSP20CallVerification"))
5
+ bytes4 constant _INTERFACEID_LSP20_CALL_VERIFICATION = 0x1a0eb6a5;
6
+
7
+ // `lsp20VerifyCall(address,address,address,uint256,bytes)` selector XOR `lsp20VerifyCallResult(bytes32,bytes)` selector
8
+ bytes4 constant _INTERFACEID_LSP20_CALL_VERIFIER = 0x0d6ecac7;
9
+
10
+ // bytes4(bytes.concat(bytes3(ILSP20.lsp20VerifyCall.selector), hex"01"))
11
+ bytes4 constant _LSP20_VERIFY_CALL_SUCCESS_VALUE_WITH_POST_VERIFICATION = 0xde928f01;
12
+
13
+ // bytes4(bytes.concat(bytes3(ILSP20.lsp20VerifyCall.selector), hex"00"))
14
+ bytes4 constant _LSP20_VERIFY_CALL_SUCCESS_VALUE_WITHOUT_POST_VERIFICATION = 0xde928f00;
15
+
16
+ // bytes4(ILSP20.lsp20VerifyCallResult.selector)
17
+ bytes4 constant _LSP20_VERIFY_CALL_RESULT_SUCCESS_VALUE = 0xd3fc45d3;
@@ -0,0 +1,21 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.4;
3
+
4
+ /**
5
+ * @dev reverts when the call to the owner fail with no revert reason
6
+ * @param postCall True if the execution call was done, False otherwise
7
+ */
8
+ error LSP20CallingVerifierFailed(bool postCall);
9
+
10
+ /**
11
+ * @dev reverts when the call to the owner does not return the LSP20 success value
12
+ * @param postCall True if the execution call was done, False otherwise
13
+ * @param returnedStatus The bytes4 decoded data returned by the logic verifier.
14
+ */
15
+ error LSP20CallVerificationFailed(bool postCall, bytes4 returnedStatus);
16
+
17
+ /**
18
+ * @dev Reverts when the logic verifier is an Externally Owned Account (EOA) that cannot return the LSP20 success value.
19
+ * @param logicVerifier The address of the logic verifier
20
+ */
21
+ error LSP20EOACannotVerifyCall(address logicVerifier);
package/dist/index.cjs ADDED
@@ -0,0 +1,18 @@
1
+ 'use strict';
2
+
3
+ const INTERFACE_ID_LSP20CallVerification = "0x1a0eb6a5";
4
+ const INTERFACE_ID_LSP20CallVerifier = "0x0d6ecac7";
5
+ const LSP20_SUCCESS_VALUES = {
6
+ VERIFY_CALL: {
7
+ // bytes3(keccak256("lsp20VerifyCall(address,address,address,uint256,bytes)")) + "0x00"
8
+ NO_POST_VERIFICATION: "0xde928f00",
9
+ // bytes3(keccak256("lsp20VerifyCall(address,address,address,uint256,bytes)")) + "0x01"
10
+ WITH_POST_VERIFICATION: "0xde928f01"
11
+ },
12
+ // bytes4(keccak256("lsp20VerifyCallResult(bytes32,bytes)"))
13
+ VERIFY_CALL_RESULT: "0xd3fc45d3"
14
+ };
15
+
16
+ exports.INTERFACE_ID_LSP20CallVerification = INTERFACE_ID_LSP20CallVerification;
17
+ exports.INTERFACE_ID_LSP20CallVerifier = INTERFACE_ID_LSP20CallVerifier;
18
+ exports.LSP20_SUCCESS_VALUES = LSP20_SUCCESS_VALUES;
@@ -0,0 +1,15 @@
1
+ declare const INTERFACE_ID_LSP20CallVerification = "0x1a0eb6a5";
2
+ declare const INTERFACE_ID_LSP20CallVerifier = "0x0d6ecac7";
3
+ /**
4
+ * @dev values returned by the `lsp20VerifyCall` and `lsp20VerifyCallResult` functions of the LSP20 standard.
5
+ * Can be used to check if a calldata payload was check and verified.
6
+ */
7
+ declare const LSP20_SUCCESS_VALUES: {
8
+ VERIFY_CALL: {
9
+ NO_POST_VERIFICATION: string;
10
+ WITH_POST_VERIFICATION: string;
11
+ };
12
+ VERIFY_CALL_RESULT: string;
13
+ };
14
+
15
+ export { INTERFACE_ID_LSP20CallVerification, INTERFACE_ID_LSP20CallVerifier, LSP20_SUCCESS_VALUES };
@@ -0,0 +1,15 @@
1
+ declare const INTERFACE_ID_LSP20CallVerification = "0x1a0eb6a5";
2
+ declare const INTERFACE_ID_LSP20CallVerifier = "0x0d6ecac7";
3
+ /**
4
+ * @dev values returned by the `lsp20VerifyCall` and `lsp20VerifyCallResult` functions of the LSP20 standard.
5
+ * Can be used to check if a calldata payload was check and verified.
6
+ */
7
+ declare const LSP20_SUCCESS_VALUES: {
8
+ VERIFY_CALL: {
9
+ NO_POST_VERIFICATION: string;
10
+ WITH_POST_VERIFICATION: string;
11
+ };
12
+ VERIFY_CALL_RESULT: string;
13
+ };
14
+
15
+ export { INTERFACE_ID_LSP20CallVerification, INTERFACE_ID_LSP20CallVerifier, LSP20_SUCCESS_VALUES };
@@ -0,0 +1,15 @@
1
+ declare const INTERFACE_ID_LSP20CallVerification = "0x1a0eb6a5";
2
+ declare const INTERFACE_ID_LSP20CallVerifier = "0x0d6ecac7";
3
+ /**
4
+ * @dev values returned by the `lsp20VerifyCall` and `lsp20VerifyCallResult` functions of the LSP20 standard.
5
+ * Can be used to check if a calldata payload was check and verified.
6
+ */
7
+ declare const LSP20_SUCCESS_VALUES: {
8
+ VERIFY_CALL: {
9
+ NO_POST_VERIFICATION: string;
10
+ WITH_POST_VERIFICATION: string;
11
+ };
12
+ VERIFY_CALL_RESULT: string;
13
+ };
14
+
15
+ export { INTERFACE_ID_LSP20CallVerification, INTERFACE_ID_LSP20CallVerifier, LSP20_SUCCESS_VALUES };
package/dist/index.mjs ADDED
@@ -0,0 +1,14 @@
1
+ const INTERFACE_ID_LSP20CallVerification = "0x1a0eb6a5";
2
+ const INTERFACE_ID_LSP20CallVerifier = "0x0d6ecac7";
3
+ const LSP20_SUCCESS_VALUES = {
4
+ VERIFY_CALL: {
5
+ // bytes3(keccak256("lsp20VerifyCall(address,address,address,uint256,bytes)")) + "0x00"
6
+ NO_POST_VERIFICATION: "0xde928f00",
7
+ // bytes3(keccak256("lsp20VerifyCall(address,address,address,uint256,bytes)")) + "0x01"
8
+ WITH_POST_VERIFICATION: "0xde928f01"
9
+ },
10
+ // bytes4(keccak256("lsp20VerifyCallResult(bytes32,bytes)"))
11
+ VERIFY_CALL_RESULT: "0xd3fc45d3"
12
+ };
13
+
14
+ export { INTERFACE_ID_LSP20CallVerification, INTERFACE_ID_LSP20CallVerifier, LSP20_SUCCESS_VALUES };
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@lukso/lsp20-contracts",
3
+ "version": "0.15.0-rc.0",
4
+ "description": "Package for the LSP20 Call Verification standard",
5
+ "license": "Apache-2.0",
6
+ "author": "",
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.mjs",
9
+ "typings": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "require": "./dist/index.cjs",
13
+ "import": "./dist/index.mjs",
14
+ "types": "./dist/index.d.ts"
15
+ },
16
+ "./artifacts/*": "./artifacts/*",
17
+ "./package.json": "./package.json"
18
+ },
19
+ "files": [
20
+ "contracts/**/*.sol",
21
+ "!contracts/Mocks/**/*.sol",
22
+ "artifacts/*.json",
23
+ "dist",
24
+ "./README.md"
25
+ ],
26
+ "keywords": [
27
+ "LUKSO",
28
+ "LSP",
29
+ "Blockchain",
30
+ "Standards",
31
+ "Smart Contracts",
32
+ "Ethereum",
33
+ "EVM",
34
+ "Solidity"
35
+ ],
36
+ "scripts": {
37
+ "build": "hardhat compile --show-stack-traces",
38
+ "build:js": "unbuild",
39
+ "clean": "hardhat clean && rm -Rf dist/",
40
+ "format": "prettier --write .",
41
+ "lint": "eslint . --ext .ts,.js",
42
+ "lint:solidity": "solhint 'contracts/**/*.sol' && prettier --check 'contracts/**/*.sol'"
43
+ }
44
+ }