Skip to content

Commit

Permalink
Merge branch 'main' into contracts-docs-sync
Browse files Browse the repository at this point in the history
  • Loading branch information
CJ42 authored Oct 23, 2023
2 parents b9c90a6 + 1dc988b commit 39de59d
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 28 deletions.
20 changes: 7 additions & 13 deletions docs/guides/universal-receiver-delegate/create-custom-urd-1.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ pragma solidity ^0.8.11;
// interfaces
import { IERC725X } from "@erc725/smart-contracts/contracts/interfaces/IERC725X.sol";
import { ILSP1UniversalReceiver } from "@lukso/lsp-smart-contracts/contracts/LSP1UniversalReceiver/ILSP1UniversalReceiver.sol";
import { ILSP1UniversalReceiverDelegate } from "@lukso/lsp-smart-contracts/contracts/LSP1UniversalReceiver/ILSP1UniversalReceiverDelegate.sol";
import { ILSP7DigitalAsset } from "@lukso/lsp-smart-contracts/contracts/LSP7DigitalAsset/ILSP7DigitalAsset.sol";
// modules
Expand All @@ -107,7 +107,7 @@ import "@lukso/lsp-smart-contracts/contracts/LSP1UniversalReceiver/LSP1Errors.so
contract LSP1URDForwarderMethod1 is
ERC165,
ILSP1UniversalReceiver
ILSP1UniversalReceiverDelegate
{
// CHECK onlyOwner
Expand Down Expand Up @@ -162,14 +162,11 @@ contract LSP1URDForwarderMethod1 is
}
function universalReceiver(
address notifier,
uint256 value,
bytes32 typeId,
bytes memory data
) public payable virtual returns (bytes memory) {
// CHECK that we did not send any native tokens to the LSP1 Delegate, as it cannot transfer them back.
if (msg.value != 0) {
revert NativeTokensNotAccepted();
}
) public virtual returns (bytes memory) {
// CHECK that the caller is an ERC725Account (e.g: a UniversalProfile)
// by checking it supports the LSP0 interface
// by checking its interface support
Expand All @@ -182,9 +179,6 @@ contract LSP1URDForwarderMethod1 is
return "Caller is not a LSP0";
}
// GET the address of the notifier from the calldata (e.g., the LSP7 Token)
address notifier = address(bytes20(msg.data[msg.data.length - 52:]));
// CHECK that notifier is a contract with a `balanceOf` method
// and that msg.sender (the UP) has a positive balance
if (notifier.code.length > 0) {
Expand Down Expand Up @@ -238,7 +232,7 @@ contract LSP1URDForwarderMethod1 is
bytes4 interfaceId
) public view virtual override returns (bool) {
return
interfaceId == _INTERFACEID_LSP1 ||
interfaceId == _INTERFACEID_LSP1_DELEGATE ||
super.supportsInterface(interfaceId);
}
}
Expand Down Expand Up @@ -296,7 +290,7 @@ cp contracts/LSP1URDForwarderMethod1 contracts/LSP1URDForwarderMethod2.sol
// ...
contract LSP1URDForwarderMethod2 is
ERC165,
ILSP1UniversalReceiver
ILSP1UniversalReceiverDelegate
{
// ...
```
Expand Down
24 changes: 15 additions & 9 deletions docs/learn/dapp-developer/siwe.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,19 @@ Therefore, if the message you want to sign complies with this standard, the LUKS
<div style={{textAlign: 'center'}}>

<img
src="/img/learn/siwe.png"
alt="Example of Sign-In with Ethereum screen"
src="/img/learn/siwe2.png"
alt="Example of Sign-In with Ethereum, first screen"
width="400"
/>
<img
src="/img/learn/siwe1.png"
alt="Example of Sign-In with Ethereum, second screen"
width="400"
/>

</div>

## 1. Get the Universal Profile address
## Get the Universal Profile address

```js
import Web3 from 'web3';
Expand All @@ -33,11 +38,11 @@ await web3.eth.requestAccounts();
const accounts = await web3.eth.getAccounts();
```

## 2. Sign the message
## Sign the message

Once you have access to the Universal Profile address, you can request a signature. The UP Browser Extension will sign the message with the controller key used by the extension (a smart contract can't sign).
Once you have access to the Universal Profile address, you can request a signature. The UP Browser Extension will sign the message with the controller key used by the extension (a smart contract can't sign by itself).
:::tip
If you need further explanation on the `SiWeMessage` properties, please have a look at the [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) specification.
If you need further explanation on the `SiweMessage` properties, please have a look at the [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) specification.
:::

```js
Expand Down Expand Up @@ -67,14 +72,15 @@ const signature = await web3.eth.sign(siweMessage, accounts[0]);
// 0x38c53...
```

## 3. Verify the signature on the user's Universal Profile
## Verify the signature on the user's Universal Profile

Your Dapp has now received a message signed by the controller address of the Universal Profile. To finalise the login, you need to verify if the message was signed by an address which has the `SIGN` permission for this UP.

To do so, you can use the [`isValidSignature(...)`](../../contracts/contracts/UniversalProfile.md#isvalidsignature) function to check if the signature was signed ([EIP-1271](https://eips.ethereum.org/EIPS/eip-1271)) by an EOA that has the [`SIGN` permission](../../standards/universal-profile/lsp6-key-manager#permissions) over the Universal Profile.
To do so, you can use the [`isValidSignature(...)`](../../contracts/contracts/UniversalProfile.md#isvalidsignature) function ([EIP-1271](https://eips.ethereum.org/EIPS/eip-1271)) to check the signature.

```js
// If the signature is valid it should return the succes value 0x1626ba7e, then, the message was signed by an EOA which has a SIGN permission for this Universal Profile.
// If the signature is valid it should return the succes value 0x1626ba7e.
// Then, the message was signed by an EOA which has a SIGN (https://github.com/lukso-network/standards/universal-profile/lsp6-key-manager#permissions)permission for this Universal Profile.
// For additional details, check https://eips.ethereum.org/EIPS/eip-1271
const isValidSignature = await myUniversalProfileContract.methods
.isValidSignature(hashedMessage, signature)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,27 +29,29 @@ Therefore, it is advised not to hardcode how the smart contract should handle an

:::success recommendation

Smart contracts implementing the [LSP1-UniversalReceiverDelegate](#) standard SHOULD **register** the **[LSP1UniversalReceiver InterfaceId](../../contracts/interface-ids.md) using ERC165**. This way, other contracts can be aware that the contract supports the LSP1 standard.
Smart contracts implementing the [LSP1-UniversalReceiverDelegate](#) standard SHOULD **register** the **[LSP1UniversalReceiverDelegate InterfaceId](../../contracts/interface-ids.md) using ERC165**. This way, other contracts can be aware that the contract supports the LSP1-UniversalReceiverDelegate standard.

:::

This standard defines a contract called **UniversalReceiverDelegate** containing a single function named `universalReceiver(...)` that should be called by the `universalReceiver(..)` function with:
This standard defines a contract called **UniversalReceiverDelegate** containing a single function named `universalReceiverDelegate(...)` that should be called by the `universalReceiver(..)` function with:

- address `caller` is the address calling the `universalReceiver` function.

- uint256 `value` is the amount of value sent to the `universalReceiver` function.

- bytes32 `typeId`: the typeId passed to the `universalReceiver(...)` function.

- bytes `data`: the data passed to the `universalReceiver(...)` function.

> NB: It is possible to send extra calldata from the main `universalReceiver(..)` function to the `universalReceiver(..)` function on the UniversalReceiverDelegate.
### How Delegation works

Delegation in the context of smart contracts implementing the `universalReceiver(...)` function allows for flexibility in handling specific calls without hardcoding the logic within the primary contract. While the exact implementation of delegation is up to the individual contract, there are some common steps involved in the process.

1- Query the **UniversalReceiverDelegate** address: Typically, the address of the **UniversalReceiverDelegate** contract is stored in the primary contract's storage. When the `universalReceiver(...)` function is called, the address is retrieved to facilitate delegation.

2- Check for LSP1 support: Before making any calls to the UniversalReceiverDelegate contract, it's essential to ensure that the contract supports the LSP1 standard. This can be done by checking for the **LSP1UniversalReceiver InterfaceId** using ERC165.
2- Check for LSP1Delegate support: Before making any calls to the UniversalReceiverDelegate contract, it's essential to ensure that the contract supports the LSP1Delegate standard. This can be done by checking for the **LSP1UniversalReceiverDelegate InterfaceId** using ERC165.

3- Call the UniversalReceiverDelegate's `universalReceiver(..)` function: Once LSP1 support is confirmed, the primary contract's `universalReceiver(...)` function can delegate the call to the UniversalReceiverDelegate's `universalReceiver(...)` function. This allows the primary contract to utilize the logic implemented in the delegate contract.
3- Call the UniversalReceiverDelegate's `universalReceiverDelegate(..)` function: Once LSP1Delegate support is confirmed, the primary contract's `universalReceiver(...)` function can delegate the call to the UniversalReceiverDelegate's `universalReceiverDelegate(...)` function. This allows the primary contract to utilize the logic implemented in the delegate contract.

Delegation can be implemented in various ways, depending on the developer's requirements. Some possible delegation strategies include:

Expand Down
Binary file removed static/img/learn/siwe.png
Binary file not shown.
Binary file added static/img/learn/siwe1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/img/learn/siwe2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 39de59d

Please sign in to comment.