Skip to content

Commit 6408975

Browse files
authored
Merge d806bee into adc64e1
2 parents adc64e1 + d806bee commit 6408975

File tree

51 files changed

+885
-366
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+885
-366
lines changed

CONTRIBUTING.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ E.g.:
159159

160160
```solidity
161161
/**
162-
* @custom:events {ValueReceived} event when someone tranfers native tokens to the contract.
162+
* @custom:events {UniversalReceiver} event when someone tranfers native tokens to the contract.
163163
*/
164164
```
165165

@@ -168,7 +168,7 @@ E.g.:
168168
```solidity
169169
/**
170170
* @custom:events
171-
* - {ValueReceived} event when someone tranfers native tokens to the contract.
171+
* - {UniversalReceiver} event when someone tranfers native tokens to the contract.
172172
* - {Executes} event when the function is executed without any issues.
173173
*/
174174
```

constants.ts

+6
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,9 @@ export const PERMISSIONS = {
319319
* (e.g: token transfer, vault transfer, ownership transfer, etc...)
320320
*/
321321
export const LSP1_TYPE_IDS = {
322+
// keccak256('LSP0ValueReceived')
323+
LSP0ValueReceived: '0x9c4705229491d365fb5434052e12a386d6771d976bea61070a8c694e8affea3d',
324+
322325
// keccak256('LSP0OwnershipTransferStarted')
323326
LSP0OwnershipTransferStarted:
324327
'0xe17117c9d2665d1dbeb479ed8058bbebde3c50ac50e2e65619f60006caac6926',
@@ -355,6 +358,9 @@ export const LSP1_TYPE_IDS = {
355358
LSP8Tokens_OperatorNotification:
356359
'0x8a1c15a8799f71b547e08e2bcb2e85257e81b0a07eee2ce6712549eef1f00970',
357360

361+
// keccak256('LSP9ValueReceived')
362+
LSP9ValueReceived: '0x468cd1581d7bc001c3b685513d2b929b55437be34700410383d58f3aa1ea0abc',
363+
358364
// keccak256('LSP9OwnershipTransferStarted')
359365
LSP9OwnershipTransferStarted:
360366
'0xaefd43f45fed1bcd8992f23c803b6f4ec45cf6b62b0d404d565f290a471e763f',

contracts/LSP0ERC725Account/ILSP0ERC725Account.sol

-8
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,6 @@ pragma solidity ^0.8.4;
77
* @author Fabian Vogelsteller <[email protected]>, Jean Cavallera (CJ42)
88
*/
99
interface ILSP0ERC725Account {
10-
/**
11-
* @notice `value` native tokens received from `sender`.
12-
* @dev Emitted when receiving native tokens.
13-
* @param sender The address that sent some native tokens to this contract.
14-
* @param value The amount of native tokens received.
15-
*/
16-
event ValueReceived(address indexed sender, uint256 indexed value);
17-
1810
/**
1911
* @notice Executing the following batch of abi-encoded function calls on the contract: `data`.
2012
*

contracts/LSP0ERC725Account/LSP0Constants.sol

+5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ bytes4 constant _INTERFACEID_ERC1271 = 0x1626ba7e;
99
bytes4 constant _ERC1271_SUCCESSVALUE = 0x1626ba7e;
1010
bytes4 constant _ERC1271_FAILVALUE = 0xffffffff;
1111

12+
// --- Native Token Type Id
13+
14+
// keccak256('LSP0ValueReceived')
15+
bytes32 constant _TYPEID_LSP0_VALUE_RECEIVED = 0x9c4705229491d365fb5434052e12a386d6771d976bea61070a8c694e8affea3d;
16+
1217
// Ownerhsip Transfer Type IDs
1318

1419
// keccak256('LSP0OwnershipTransferStarted')

contracts/LSP0ERC725Account/LSP0ERC725Account.sol

+12-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import {
77
OwnableUnset
88
} from "@erc725/smart-contracts/contracts/custom/OwnableUnset.sol";
99

10+
// constants
11+
12+
import {_TYPEID_LSP0_VALUE_RECEIVED} from "./LSP0Constants.sol";
13+
1014
/**
1115
* @title Deployable Implementation of [LSP-0-ERC725Account] Standard.
1216
*
@@ -29,12 +33,18 @@ contract LSP0ERC725Account is LSP0ERC725AccountCore {
2933
* @param initialOwner The owner of the contract.
3034
*
3135
* @custom:events
32-
* - {ValueReceived} event when funding the contract on deployment.
36+
* - {UniversalReceiver} event when funding the contract on deployment.
3337
* - {OwnershipTransferred} event when `initialOwner` is set as the contract {owner}.
3438
*/
3539
constructor(address initialOwner) payable {
3640
if (msg.value != 0) {
37-
emit ValueReceived(msg.sender, msg.value);
41+
emit UniversalReceiver(
42+
msg.sender,
43+
msg.value,
44+
_TYPEID_LSP0_VALUE_RECEIVED,
45+
"",
46+
""
47+
);
3848
}
3949

4050
OwnableUnset._setOwner(initialOwner);

contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol

+73-30
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import {
4141
_INTERFACEID_ERC1271,
4242
_ERC1271_SUCCESSVALUE,
4343
_ERC1271_FAILVALUE,
44+
_TYPEID_LSP0_VALUE_RECEIVED,
4445
_TYPEID_LSP0_OwnershipTransferStarted,
4546
_TYPEID_LSP0_OwnershipTransferred_SenderNotification,
4647
_TYPEID_LSP0_OwnershipTransferred_RecipientNotification
@@ -94,11 +95,11 @@ abstract contract LSP0ERC725AccountCore is
9495
* - When receiving some native tokens without any additional data.
9596
* - On empty calls to the contract.
9697
*
97-
* @custom:events {ValueReceived} event when receiving native tokens.
98+
* @custom:events {UniversalReceiver} event when receiving native tokens.
9899
*/
99100
receive() external payable virtual {
100101
if (msg.value != 0) {
101-
emit ValueReceived(msg.sender, msg.value);
102+
universalReceiver(_TYPEID_LSP0_VALUE_RECEIVED, "");
102103
}
103104
}
104105

@@ -121,17 +122,16 @@ abstract contract LSP0ERC725AccountCore is
121122
*
122123
* 2. If the data sent to this function is of length less than 4 bytes (not a function selector), return.
123124
*
124-
* @custom:events {ValueReceived} event when receiving native tokens.
125+
* @custom:events {UniversalReceiver} event when receiving native tokens and extension function selector is not found or not payable.
125126
*/
126127
// solhint-disable-next-line no-complex-fallback
127128
fallback(
128129
bytes calldata callData
129130
) external payable virtual returns (bytes memory) {
130-
if (msg.value != 0) {
131-
emit ValueReceived(msg.sender, msg.value);
132-
}
133-
134131
if (msg.data.length < 4) {
132+
// if value is associated with the extension call, use the universalReceiver
133+
if (msg.value != 0)
134+
universalReceiver(_TYPEID_LSP0_VALUE_RECEIVED, callData);
135135
return "";
136136
}
137137

@@ -187,7 +187,7 @@ abstract contract LSP0ERC725AccountCore is
187187
* @custom:events
188188
* - {Executed} event for each call that uses under `operationType`: `CALL` (0), `STATICCALL` (3) and `DELEGATECALL` (4).
189189
* - {ContractCreated} event, when a contract is created under `operationType`: `CREATE` (1) and `CREATE2` (2).
190-
* - {ValueReceived} event when receiving native tokens.
190+
* - {UniversalReceiver} event when receiving native tokens.
191191
*/
192192
function execute(
193193
uint256 operationType,
@@ -196,7 +196,13 @@ abstract contract LSP0ERC725AccountCore is
196196
bytes memory data
197197
) public payable virtual override returns (bytes memory) {
198198
if (msg.value != 0) {
199-
emit ValueReceived(msg.sender, msg.value);
199+
emit UniversalReceiver(
200+
msg.sender,
201+
msg.value,
202+
_TYPEID_LSP0_VALUE_RECEIVED,
203+
abi.encodePacked(msg.sig),
204+
""
205+
);
200206
}
201207

202208
address accountOwner = owner();
@@ -245,7 +251,7 @@ abstract contract LSP0ERC725AccountCore is
245251
* @custom:events
246252
* - {Executed} event for each call that uses under `operationType`: `CALL` (0), `STATICCALL` (3) and `DELEGATECALL` (4). (each iteration)
247253
* - {ContractCreated} event, when a contract is created under `operationType`: `CREATE` (1) and `CREATE2` (2) (each iteration)
248-
* - {ValueReceived} event when receiving native tokens.
254+
* - {UniversalReceiver} event when receiving native tokens.
249255
*/
250256
function executeBatch(
251257
uint256[] memory operationsType,
@@ -254,7 +260,13 @@ abstract contract LSP0ERC725AccountCore is
254260
bytes[] memory datas
255261
) public payable virtual override returns (bytes[] memory) {
256262
if (msg.value != 0) {
257-
emit ValueReceived(msg.sender, msg.value);
263+
emit UniversalReceiver(
264+
msg.sender,
265+
msg.value,
266+
_TYPEID_LSP0_VALUE_RECEIVED,
267+
abi.encodePacked(msg.sig),
268+
""
269+
);
258270
}
259271

260272
address accountOwner = owner();
@@ -299,15 +311,21 @@ abstract contract LSP0ERC725AccountCore is
299311
* @custom:requirements Can be only called by the {owner} or by an authorised address that pass the verification check performed on the owner.
300312
*
301313
* @custom:events
302-
* - {ValueReceived} event when receiving native tokens.
314+
* - {UniversalReceiver} event when receiving native tokens.
303315
* - {DataChanged} event.
304316
*/
305317
function setData(
306318
bytes32 dataKey,
307319
bytes memory dataValue
308320
) public payable virtual override {
309321
if (msg.value != 0) {
310-
emit ValueReceived(msg.sender, msg.value);
322+
emit UniversalReceiver(
323+
msg.sender,
324+
msg.value,
325+
_TYPEID_LSP0_VALUE_RECEIVED,
326+
abi.encodePacked(msg.sig),
327+
""
328+
);
311329
}
312330

313331
address accountOwner = owner();
@@ -336,15 +354,21 @@ abstract contract LSP0ERC725AccountCore is
336354
* @custom:requirements Can be only called by the {owner} or by an authorised address that pass the verification check performed on the owner.
337355
*
338356
* @custom:events
339-
* - {ValueReceived} event when receiving native tokens.
357+
* - {UniversalReceiver} event when receiving native tokens.
340358
* - {DataChanged} event. (on each iteration of setting data)
341359
*/
342360
function setDataBatch(
343361
bytes32[] memory dataKeys,
344362
bytes[] memory dataValues
345363
) public payable virtual override {
346364
if (msg.value != 0) {
347-
emit ValueReceived(msg.sender, msg.value);
365+
emit UniversalReceiver(
366+
msg.sender,
367+
msg.value,
368+
_TYPEID_LSP0_VALUE_RECEIVED,
369+
abi.encodePacked(msg.sig),
370+
""
371+
);
348372
}
349373

350374
if (dataKeys.length != dataValues.length) {
@@ -416,15 +440,15 @@ abstract contract LSP0ERC725AccountCore is
416440
* @return returnedValues The ABI encoded return value of the LSP1UniversalReceiverDelegate call and the LSP1TypeIdDelegate call.
417441
*
418442
* @custom:events
419-
* - {ValueReceived} when receiving native tokens.
443+
* - {UniversalReceiver} when receiving native tokens.
420444
* - {UniversalReceiver} event with the function parameters, call options, and the response of the UniversalReceiverDelegates (URD) contract that was called.
421445
*/
422446
function universalReceiver(
423447
bytes32 typeId,
424-
bytes calldata receivedData
448+
bytes memory receivedData
425449
) public payable virtual override returns (bytes memory returnedValues) {
426-
if (msg.value != 0) {
427-
emit ValueReceived(msg.sender, msg.value);
450+
if (msg.value != 0 && (typeId != _TYPEID_LSP0_VALUE_RECEIVED)) {
451+
universalReceiver(_TYPEID_LSP0_VALUE_RECEIVED, msg.data);
428452
}
429453

430454
// Query the ERC725Y storage with the data key {_LSP1_UNIVERSAL_RECEIVER_DELEGATE_KEY}
@@ -742,8 +766,9 @@ abstract contract LSP0ERC725AccountCore is
742766
/**
743767
* @dev Forwards the call to an extension mapped to a function selector.
744768
*
745-
* Calls {_getExtension} to get the address of the extension mapped to the function selector being
769+
* Calls {_getExtensionAndForwardValue} to get the address of the extension mapped to the function selector being
746770
* called on the account. If there is no extension, the `address(0)` will be returned.
771+
* Forwards the value sent with the call to the extension if the function selector is mapped to a payable extension.
747772
*
748773
* 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.
749774
*
@@ -763,7 +788,14 @@ abstract contract LSP0ERC725AccountCore is
763788
bytes calldata callData
764789
) internal virtual override returns (bytes memory) {
765790
// If there is a function selector
766-
address extension = _getExtension(msg.sig);
791+
(
792+
address extension,
793+
bool isForwardingValue
794+
) = _getExtensionAndForwardValue(msg.sig);
795+
796+
// if value is associated with the extension call and extension function selector is not payable, use the universalReceiver
797+
if (msg.value != 0 && !isForwardingValue)
798+
universalReceiver(_TYPEID_LSP0_VALUE_RECEIVED, callData);
767799

768800
// if no extension was found for bytes4(0) return don't revert
769801
if (msg.sig == bytes4(0) && extension == address(0)) return "";
@@ -772,9 +804,9 @@ abstract contract LSP0ERC725AccountCore is
772804
if (extension == address(0))
773805
revert NoExtensionFoundForFunctionSelector(msg.sig);
774806

775-
(bool success, bytes memory result) = extension.call(
776-
abi.encodePacked(callData, msg.sender, msg.value)
777-
);
807+
(bool success, bytes memory result) = extension.call{
808+
value: isForwardingValue ? msg.value : 0
809+
}(abi.encodePacked(callData, msg.sender, msg.value));
778810

779811
if (success) {
780812
return result;
@@ -793,21 +825,32 @@ abstract contract LSP0ERC725AccountCore is
793825
* - {_LSP17_EXTENSION_PREFIX} + `<bytes4>` (Check [LSP2-ERC725YJSONSchema] for encoding the data key).
794826
* - If no extension is stored, returns the address(0).
795827
*/
796-
function _getExtension(
828+
function _getExtensionAndForwardValue(
797829
bytes4 functionSelector
798-
) internal view virtual override returns (address) {
830+
) internal view virtual override returns (address, bool) {
799831
// Generate the data key relevant for the functionSelector being called
800832
bytes32 mappedExtensionDataKey = LSP2Utils.generateMappingKey(
801833
_LSP17_EXTENSION_PREFIX,
802834
functionSelector
803835
);
804836

805-
// Check if there is an extension stored under the generated data key
806-
address extension = address(
807-
bytes20(ERC725YCore._getData(mappedExtensionDataKey))
837+
bytes memory extensionData = ERC725YCore._getData(
838+
mappedExtensionDataKey
808839
);
809840

810-
return extension;
841+
// CHECK if the `extensionData` is 21 bytes long
842+
// - 20 bytes = extension's address
843+
// - 1 byte `0x01` as a boolean indicating if the contract should forward the value to the extension or not
844+
if (extensionData.length == 21) {
845+
// If the last byte is set to `0x01` (`true`)
846+
// this indicates that the contract should forward the value to the extension
847+
if (extensionData[20] == 0x01) {
848+
// Return the address of the extension
849+
return (address(bytes20(extensionData)), true);
850+
}
851+
}
852+
853+
return (address(bytes20(extensionData)), false);
811854
}
812855

813856
/**

contracts/LSP0ERC725Account/LSP0ERC725AccountInit.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ contract LSP0ERC725AccountInit is LSP0ERC725AccountInitAbstract {
3838
* @param initialOwner The owner of the contract.
3939
*
4040
* @custom:events
41-
* - {ValueReceived} event when funding the contract on deployment.
41+
* - {UniversalReceiver} event when funding the contract on deployment.
4242
* - {OwnershipTransferred} event when `initialOwner` is set as the contract {owner}.
4343
*/
4444
function initialize(

contracts/LSP0ERC725Account/LSP0ERC725AccountInitAbstract.sol

+11-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import {
1010
OwnableUnset
1111
} from "@erc725/smart-contracts/contracts/custom/OwnableUnset.sol";
1212

13+
// constants
14+
import {_TYPEID_LSP0_VALUE_RECEIVED} from "./LSP0Constants.sol";
15+
1316
/**
1417
* @title Inheritable Proxy Implementation of [LSP-0-ERC725Account] Standard.
1518
*
@@ -27,14 +30,20 @@ abstract contract LSP0ERC725AccountInitAbstract is
2730
* @custom:warning ERC725X & ERC725Y parent contracts are not initialised as they don't have non-zero initial state. If you decide to add non-zero initial state to any of those contracts, you must initialize them here.
2831
*
2932
* @custom:events
30-
* - {ValueReceived} event when funding the contract on deployment.
33+
* - {UniversalReceiver} event when funding the contract on deployment.
3134
* - {OwnershipTransferred} event when `initialOwner` is set as the contract {owner}.
3235
*/
3336
function _initialize(
3437
address initialOwner
3538
) internal virtual onlyInitializing {
3639
if (msg.value != 0) {
37-
emit ValueReceived(msg.sender, msg.value);
40+
emit UniversalReceiver(
41+
msg.sender,
42+
msg.value,
43+
_TYPEID_LSP0_VALUE_RECEIVED,
44+
"",
45+
""
46+
);
3847
}
3948
OwnableUnset._setOwner(initialOwner);
4049
}

0 commit comments

Comments
 (0)