Skip to content

Commit

Permalink
Merge a1a4cda into 0d43077
Browse files Browse the repository at this point in the history
  • Loading branch information
skimaharvey authored Oct 9, 2023
2 parents 0d43077 + a1a4cda commit ccd283d
Show file tree
Hide file tree
Showing 16 changed files with 1,003 additions and 18 deletions.
1 change: 1 addition & 0 deletions .github/workflows/build-lint-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ jobs:
"lsp11",
"lsp11init",
"lsp17",
"lsp17extensions",
"lsp20",
"lsp20init",
"lsp23",
Expand Down
100 changes: 100 additions & 0 deletions contracts/LSP17Extensions/Extension4337.sol
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;
}
}
15 changes: 15 additions & 0 deletions contracts/LSP17Extensions/OnERC721ReceivedExtension.sol
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 {

}
2 changes: 1 addition & 1 deletion contracts/LSP2ERC725YJSONSchema/LSP2Utils.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-3.0
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.4;

// interfaces
Expand Down
16 changes: 0 additions & 16 deletions contracts/Mocks/FallbackExtensions/OnERC721ReceivedExtension.sol

This file was deleted.

2 changes: 1 addition & 1 deletion contracts/Mocks/Tokens/RequireCallbackToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
173 changes: 173 additions & 0 deletions docs/contracts/LSP17Extensions/Extension4337.md
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 docs/contracts/LSP17Extensions/OnERC721ReceivedExtension.md
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/>
Loading

0 comments on commit ccd283d

Please sign in to comment.