-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
1,003 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -76,6 +76,7 @@ jobs: | |
"lsp11", | ||
"lsp11init", | ||
"lsp17", | ||
"lsp17extensions", | ||
"lsp20", | ||
"lsp20init", | ||
"lsp23", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 { | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 0 additions & 16 deletions
16
contracts/Mocks/FallbackExtensions/OnERC721ReceivedExtension.sol
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
<!-- This file is auto-generated. Do not edit! --> | ||
<!-- Check `@lukso-network/lsp-smart-contracts/CONTRIBUTING.md#solidity-code-comments` for more information. --> | ||
|
||
# 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` | - | | ||
|
||
<br/> | ||
|
||
### 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 | | ||
|
||
<br/> | ||
|
||
### 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` | - | | ||
|
||
<br/> | ||
|
||
### 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. | | ||
|
||
<br/> | ||
|
||
## 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`. | ||
|
||
<br/> | ||
|
||
### \_extendableMsgSender | ||
|
||
```solidity | ||
function _extendableMsgSender() internal view returns (address); | ||
``` | ||
|
||
Returns the original `msg.sender` calling the extendable contract. | ||
|
||
<br/> | ||
|
||
### \_extendableMsgValue | ||
|
||
```solidity | ||
function _extendableMsgValue() internal view returns (uint256); | ||
``` | ||
|
||
Returns the original `msg.value` sent to the extendable contract. | ||
|
||
<br/> |
61 changes: 61 additions & 0 deletions
61
docs/contracts/LSP17Extensions/OnERC721ReceivedExtension.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
<!-- This file is auto-generated. Do not edit! --> | ||
<!-- Check `@lukso-network/lsp-smart-contracts/CONTRIBUTING.md#solidity-code-comments` for more information. --> | ||
|
||
# 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` | - | | ||
|
||
<br/> |
Oops, something went wrong.