Skip to content

Commit debfecd

Browse files
committed
feat: add payable bool to lsp17 extension
1 parent 8ae907a commit debfecd

25 files changed

+209
-106
lines changed

contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol

+22-11
Original file line numberDiff line numberDiff line change
@@ -765,8 +765,9 @@ abstract contract LSP0ERC725AccountCore is
765765
/**
766766
* @dev Forwards the call to an extension mapped to a function selector.
767767
*
768-
* Calls {_getExtension} to get the address of the extension mapped to the function selector being
768+
* Calls {_getExtensionAndPayableBool} to get the address of the extension mapped to the function selector being
769769
* called on the account. If there is no extension, the `address(0)` will be returned.
770+
* Forwards the value sent with the call to the extension if the function selector is mapped to a payable extension.
770771
*
771772
* 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.
772773
*
@@ -786,7 +787,9 @@ abstract contract LSP0ERC725AccountCore is
786787
bytes calldata callData
787788
) internal virtual override returns (bytes memory) {
788789
// If there is a function selector
789-
address extension = _getExtension(msg.sig);
790+
(address extension, bool isPayable) = _getExtensionAndPayableBool(
791+
msg.sig
792+
);
790793

791794
// if no extension was found for bytes4(0) return don't revert
792795
if (msg.sig == bytes4(0) && extension == address(0)) return "";
@@ -795,9 +798,9 @@ abstract contract LSP0ERC725AccountCore is
795798
if (extension == address(0))
796799
revert NoExtensionFoundForFunctionSelector(msg.sig);
797800

798-
(bool success, bytes memory result) = extension.call(
799-
abi.encodePacked(callData, msg.sender, msg.value)
800-
);
801+
(bool success, bytes memory result) = extension.call{
802+
value: isPayable ? msg.value : 0
803+
}(abi.encodePacked(callData, msg.sender, msg.value));
801804

802805
if (success) {
803806
return result;
@@ -816,21 +819,29 @@ abstract contract LSP0ERC725AccountCore is
816819
* - {_LSP17_EXTENSION_PREFIX} + `<bytes4>` (Check [LSP2-ERC725YJSONSchema] for encoding the data key).
817820
* - If no extension is stored, returns the address(0).
818821
*/
819-
function _getExtension(
822+
function _getExtensionAndPayableBool(
820823
bytes4 functionSelector
821-
) internal view virtual override returns (address) {
824+
) internal view virtual override returns (address, bool) {
822825
// Generate the data key relevant for the functionSelector being called
823826
bytes32 mappedExtensionDataKey = LSP2Utils.generateMappingKey(
824827
_LSP17_EXTENSION_PREFIX,
825828
functionSelector
826829
);
827830

828-
// Check if there is an extension stored under the generated data key
829-
address extension = address(
830-
bytes20(ERC725YCore._getData(mappedExtensionDataKey))
831+
bytes memory extensionData = ERC725YCore._getData(
832+
mappedExtensionDataKey
831833
);
832834

833-
return extension;
835+
// Check if the extensionData is 21 bytes long (20 bytes of address + 1 byte as bool indicator to forwards the value)
836+
if (extensionData.length == 21) {
837+
// Check if the last byte is 1 (true)
838+
if (extensionData[20] == hex"01") {
839+
// Return the address of the extension
840+
return (address(bytes20(extensionData)), true);
841+
}
842+
}
843+
844+
return (address(bytes20(extensionData)), false);
834845
}
835846

836847
/**

contracts/LSP17ContractExtension/LSP17Extendable.sol

+11-8
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ abstract contract LSP17Extendable is ERC165 {
4444
function _supportsInterfaceInERC165Extension(
4545
bytes4 interfaceId
4646
) internal view virtual returns (bool) {
47-
address erc165Extension = _getExtension(
47+
(address erc165Extension, ) = _getExtensionAndPayableBool(
4848
ERC165.supportsInterface.selector
4949
);
5050
if (erc165Extension == address(0)) return false;
@@ -62,15 +62,16 @@ abstract contract LSP17Extendable is ERC165 {
6262
* To be overrided.
6363
* Up to the implementor contract to return an extension based on a function selector
6464
*/
65-
function _getExtension(
65+
function _getExtensionAndPayableBool(
6666
bytes4 functionSelector
67-
) internal view virtual returns (address);
67+
) internal view virtual returns (address, bool);
6868

6969
/**
7070
* @dev Forwards the call to an extension mapped to a function selector.
7171
*
72-
* Calls {_getExtension} to get the address of the extension mapped to the function selector being
72+
* Calls {_getExtensionAndPayableBool} to get the address of the extension mapped to the function selector being
7373
* called on the account. If there is no extension, the `address(0)` will be returned.
74+
* Forwards the value if the extension is payable.
7475
*
7576
* Reverts if there is no extension for the function being called.
7677
*
@@ -90,15 +91,17 @@ abstract contract LSP17Extendable is ERC165 {
9091
bytes calldata callData
9192
) internal virtual returns (bytes memory) {
9293
// If there is a function selector
93-
address extension = _getExtension(msg.sig);
94+
(address extension, bool isPayable) = _getExtensionAndPayableBool(
95+
msg.sig
96+
);
9497

9598
// if no extension was found, revert
9699
if (extension == address(0))
97100
revert NoExtensionFoundForFunctionSelector(msg.sig);
98101

99-
(bool success, bytes memory result) = extension.call(
100-
abi.encodePacked(callData, msg.sender, msg.value)
101-
);
102+
(bool success, bytes memory result) = extension.call{
103+
value: isPayable ? msg.value : 0
104+
}(abi.encodePacked(callData, msg.sender, msg.value));
102105

103106
if (success) {
104107
return result;

contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol

+7-5
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,9 @@ abstract contract LSP7DigitalAsset is
108108
/**
109109
* @dev Forwards the call with the received value to an extension mapped to a function selector.
110110
*
111-
* Calls {_getExtension} to get the address of the extension mapped to the function selector being
111+
* Calls {_getExtensionAndPayableBool} to get the address of the extension mapped to the function selector being
112112
* called on the account. If there is no extension, the address(0) will be returned.
113+
* Forwards the value if the extension is payable.
113114
*
114115
* Reverts if there is no extension for the function being called.
115116
*
@@ -124,7 +125,7 @@ abstract contract LSP7DigitalAsset is
124125
bytes calldata callData
125126
) internal virtual override returns (bytes memory) {
126127
// If there is a function selector
127-
address extension = _getExtension(msg.sig);
128+
(address extension, ) = _getExtensionAndPayableBool(msg.sig);
128129

129130
// if no extension was found, revert
130131
if (extension == address(0))
@@ -152,10 +153,11 @@ abstract contract LSP7DigitalAsset is
152153
* @dev Returns the extension address stored under the following data key:
153154
* - {_LSP17_EXTENSION_PREFIX} + `<bytes4>` (Check [LSP2-ERC725YJSONSchema] for encoding the data key).
154155
* - If no extension is stored, returns the address(0).
156+
* - we do not check that payable bool as in lsp7 standard we will always forward the value to the extension
155157
*/
156-
function _getExtension(
158+
function _getExtensionAndPayableBool(
157159
bytes4 functionSelector
158-
) internal view virtual override returns (address) {
160+
) internal view virtual override returns (address, bool) {
159161
// Generate the data key relevant for the functionSelector being called
160162
bytes32 mappedExtensionDataKey = LSP2Utils.generateMappingKey(
161163
_LSP17_EXTENSION_PREFIX,
@@ -169,7 +171,7 @@ abstract contract LSP7DigitalAsset is
169171
if (extensionAddress.length != 20 && extensionAddress.length != 0)
170172
revert InvalidExtensionAddress(extensionAddress);
171173

172-
return address(bytes20(extensionAddress));
174+
return (address(bytes20(extensionAddress)), true);
173175
}
174176

175177
/**

contracts/LSP7DigitalAsset/LSP7DigitalAssetInitAbstract.sol

+7-5
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,9 @@ abstract contract LSP7DigitalAssetInitAbstract is
103103
/**
104104
* @dev Forwards the call with the received value to an extension mapped to a function selector.
105105
*
106-
* Calls {_getExtension} to get the address of the extension mapped to the function selector being
106+
* Calls {_getExtensionAndPayableBool} to get the address of the extension mapped to the function selector being
107107
* called on the account. If there is no extension, the address(0) will be returned.
108+
* Forwards the value if the extension is payable.
108109
*
109110
* Reverts if there is no extension for the function being called.
110111
*
@@ -119,7 +120,7 @@ abstract contract LSP7DigitalAssetInitAbstract is
119120
bytes calldata callData
120121
) internal virtual override returns (bytes memory) {
121122
// If there is a function selector
122-
address extension = _getExtension(msg.sig);
123+
(address extension, ) = _getExtensionAndPayableBool(msg.sig);
123124

124125
// if no extension was found, revert
125126
if (extension == address(0))
@@ -147,10 +148,11 @@ abstract contract LSP7DigitalAssetInitAbstract is
147148
* @dev Returns the extension address stored under the following data key:
148149
* - {_LSP17_EXTENSION_PREFIX} + `<bytes4>` (Check [LSP2-ERC725YJSONSchema] for encoding the data key).
149150
* - If no extension is stored, returns the address(0).
151+
* - We do not check that payable bool as in lsp7 standard we will always forward the value to the extension
150152
*/
151-
function _getExtension(
153+
function _getExtensionAndPayableBool(
152154
bytes4 functionSelector
153-
) internal view virtual override returns (address) {
155+
) internal view virtual override returns (address, bool) {
154156
// Generate the data key relevant for the functionSelector being called
155157
bytes32 mappedExtensionDataKey = LSP2Utils.generateMappingKey(
156158
_LSP17_EXTENSION_PREFIX,
@@ -164,7 +166,7 @@ abstract contract LSP7DigitalAssetInitAbstract is
164166
if (extensionAddress.length != 20 && extensionAddress.length != 0)
165167
revert InvalidExtensionAddress(extensionAddress);
166168

167-
return address(bytes20(extensionAddress));
169+
return (address(bytes20(extensionAddress)), true);
168170
}
169171

170172
/**

contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol

+6-5
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,9 @@ abstract contract LSP8IdentifiableDigitalAsset is
130130
/**
131131
* @dev Forwards the call with the received value to an extension mapped to a function selector.
132132
*
133-
* Calls {_getExtension} to get the address of the extension mapped to the function selector being
133+
* Calls {_getExtensionAndPayableBool} to get the address of the extension mapped to the function selector being
134134
* called on the account. If there is no extension, the address(0) will be returned.
135+
* We will always forward the value to the extension, as the LSP8 contract is not supposed to hold any native tokens.
135136
*
136137
* Reverts if there is no extension for the function being called.
137138
*
@@ -146,7 +147,7 @@ abstract contract LSP8IdentifiableDigitalAsset is
146147
bytes calldata callData
147148
) internal virtual override returns (bytes memory) {
148149
// If there is a function selector
149-
address extension = _getExtension(msg.sig);
150+
(address extension, ) = _getExtensionAndPayableBool(msg.sig);
150151

151152
// if no extension was found, revert
152153
if (extension == address(0))
@@ -175,9 +176,9 @@ abstract contract LSP8IdentifiableDigitalAsset is
175176
* - {_LSP17_EXTENSION_PREFIX} + `<bytes4>` (Check [LSP2-ERC725YJSONSchema] for encoding the data key).
176177
* - If no extension is stored, returns the address(0).
177178
*/
178-
function _getExtension(
179+
function _getExtensionAndPayableBool(
179180
bytes4 functionSelector
180-
) internal view virtual override returns (address) {
181+
) internal view virtual override returns (address, bool) {
181182
// Generate the data key relevant for the functionSelector being called
182183
bytes32 mappedExtensionDataKey = LSP2Utils.generateMappingKey(
183184
_LSP17_EXTENSION_PREFIX,
@@ -191,7 +192,7 @@ abstract contract LSP8IdentifiableDigitalAsset is
191192
if (extensionAddress.length != 20 && extensionAddress.length != 0)
192193
revert InvalidExtensionAddress(extensionAddress);
193194

194-
return address(bytes20(extensionAddress));
195+
return (address(bytes20(extensionAddress)), true);
195196
}
196197

197198
/**

contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetInitAbstract.sol

+6-5
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,9 @@ abstract contract LSP8IdentifiableDigitalAssetInitAbstract is
133133
/**
134134
* @dev Forwards the call with the received value to an extension mapped to a function selector.
135135
*
136-
* Calls {_getExtension} to get the address of the extension mapped to the function selector being
136+
* Calls {_getExtensionAndPayableBool} to get the address of the extension mapped to the function selector being
137137
* called on the account. If there is no extension, the address(0) will be returned.
138+
* We will always forward the value to the extension, as the LSP8 contract is not supposed to hold any native tokens.
138139
*
139140
* Reverts if there is no extension for the function being called.
140141
*
@@ -149,7 +150,7 @@ abstract contract LSP8IdentifiableDigitalAssetInitAbstract is
149150
bytes calldata callData
150151
) internal virtual override returns (bytes memory) {
151152
// If there is a function selector
152-
address extension = _getExtension(msg.sig);
153+
(address extension, ) = _getExtensionAndPayableBool(msg.sig);
153154

154155
// if no extension was found, revert
155156
if (extension == address(0))
@@ -178,9 +179,9 @@ abstract contract LSP8IdentifiableDigitalAssetInitAbstract is
178179
* - {_LSP17_EXTENSION_PREFIX} + `<bytes4>` (Check [LSP2-ERC725YJSONSchema] for encoding the data key).
179180
* - If no extension is stored, returns the address(0).
180181
*/
181-
function _getExtension(
182+
function _getExtensionAndPayableBool(
182183
bytes4 functionSelector
183-
) internal view virtual override returns (address) {
184+
) internal view virtual override returns (address, bool) {
184185
// Generate the data key relevant for the functionSelector being called
185186
bytes32 mappedExtensionDataKey = LSP2Utils.generateMappingKey(
186187
_LSP17_EXTENSION_PREFIX,
@@ -194,7 +195,7 @@ abstract contract LSP8IdentifiableDigitalAssetInitAbstract is
194195
if (extensionAddress.length != 20 && extensionAddress.length != 0)
195196
revert InvalidExtensionAddress(extensionAddress);
196197

197-
return address(bytes20(extensionAddress));
198+
return (address(bytes20(extensionAddress)), true);
198199
}
199200

200201
/**

contracts/LSP9Vault/LSP9VaultCore.sol

+24-10
Original file line numberDiff line numberDiff line change
@@ -528,8 +528,9 @@ contract LSP9VaultCore is
528528
/**
529529
* @dev Forwards the call to an extension mapped to a function selector.
530530
*
531-
* Calls {_getExtension} to get the address of the extension mapped to the function selector being
531+
* Calls {_getExtensionAndPayableBool} to get the address of the extension mapped to the function selector being
532532
* called on the account. If there is no extension, the `address(0)` will be returned.
533+
* Forwards the value if the extension is payable.
533534
*
534535
* 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.
535536
*
@@ -549,7 +550,9 @@ contract LSP9VaultCore is
549550
bytes calldata callData
550551
) internal virtual override returns (bytes memory) {
551552
// If there is a function selector
552-
address extension = _getExtension(msg.sig);
553+
(address extension, bool isPayable) = _getExtensionAndPayableBool(
554+
msg.sig
555+
);
553556

554557
// if no extension was found for bytes4(0) return don't revert
555558
if (msg.sig == bytes4(0) && extension == address(0)) return "";
@@ -558,9 +561,9 @@ contract LSP9VaultCore is
558561
if (extension == address(0))
559562
revert NoExtensionFoundForFunctionSelector(msg.sig);
560563

561-
(bool success, bytes memory result) = extension.call(
562-
abi.encodePacked(callData, msg.sender, msg.value)
563-
);
564+
(bool success, bytes memory result) = extension.call{
565+
value: isPayable ? msg.value : 0
566+
}(abi.encodePacked(callData, msg.sender, msg.value));
564567

565568
if (success) {
566569
return result;
@@ -581,18 +584,29 @@ contract LSP9VaultCore is
581584
* - {_LSP17_EXTENSION_PREFIX} + `<bytes4>` (Check [LSP2-ERC725YJSONSchema] for encoding the data key).
582585
* - If no extension is stored, returns the address(0).
583586
*/
584-
function _getExtension(
587+
function _getExtensionAndPayableBool(
585588
bytes4 functionSelector
586-
) internal view virtual override returns (address) {
589+
) internal view virtual override returns (address, bool) {
590+
// Generate the data key relevant for the functionSelector being called
587591
bytes32 mappedExtensionDataKey = LSP2Utils.generateMappingKey(
588592
_LSP17_EXTENSION_PREFIX,
589593
functionSelector
590594
);
591595

592-
// Check if there is an extension for the function selector provided
593-
address extension = address(bytes20(_getData(mappedExtensionDataKey)));
596+
bytes memory extensionData = ERC725YCore._getData(
597+
mappedExtensionDataKey
598+
);
599+
600+
// Check if the extensionData is 21 bytes long (20 bytes of address + 1 byte as bool indicator ot forwards the value)
601+
if (extensionData.length == 21) {
602+
// Check if the last byte is 1 (true)
603+
if (extensionData[20] == hex"01") {
604+
// Return the address of the extension
605+
return (address(bytes20(extensionData)), true);
606+
}
607+
}
594608

595-
return extension;
609+
return (address(bytes20(extensionData)), false);
596610
}
597611

598612
/**

0 commit comments

Comments
 (0)