From 8d5a5cc20b76554b32a1190e0897408c6fef2ce1 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Fri, 6 Oct 2023 17:32:24 +0100 Subject: [PATCH 1/3] improve explanations of parameters for execute Relay Call guide --- .../key-manager/execute-relay-transactions.md | 105 +++++++++++++----- .../universal-profile/lsp6-key-manager.md | 8 +- 2 files changed, 81 insertions(+), 32 deletions(-) diff --git a/docs/guides/key-manager/execute-relay-transactions.md b/docs/guides/key-manager/execute-relay-transactions.md index ae6da976e0..c6517dd222 100644 --- a/docs/guides/key-manager/execute-relay-transactions.md +++ b/docs/guides/key-manager/execute-relay-transactions.md @@ -66,12 +66,11 @@ import KeyManagerContract from '@lukso/lsp-smart-contracts/artifacts/LSP6KeyMana import { EIP191Signer } from '@lukso/eip191-signer.js'; import Web3 from 'web3'; -// This is the version relative to the LSP6 standard, defined as the number 6. -import { LSP6_VERSION } from '@lukso/lsp-smart-contracts/constants'; +// This is the version relative to the LSP25 standard, defined as the number 25. +import { LSP25_VERSION } from '@lukso/lsp-smart-contracts/constants'; const web3 = new Web3('https://rpc.testnet.lukso.network'); const universalProfileAddress = '0x...'; -const msgValue = 0; // Amount of native tokens to be sent const recipientAddress = '0x...'; // setup the Universal Profile controller account @@ -89,14 +88,13 @@ import KeyManagerContract from '@lukso/lsp-smart-contracts/artifacts/LSP6KeyMana import { EIP191Signer } from '@lukso/eip191-signer.js'; import { ethers } from 'ethers'; -// This is the version relative to the LSP6 standard, defined as the number 6. -import { LSP6_VERSION } from '@lukso/lsp-smart-contracts/constants'; +// This is the version relative to the LSP25 standard, defined as the number 25. +import { LSP25_VERSION } from '@lukso/lsp-smart-contracts/constants'; const provider = new ethers.providers.JsonRpcProvider( 'https://rpc.testnet.lukso.network', ); const universalProfileAddress = '0x...'; -const msgValue = 0; // Amount of native tokens to be sent const recipientAddress = '0x...'; // setup the Universal Profile controller account @@ -189,12 +187,13 @@ const channelId = 0; const nonce = await keyManager.methods.getNonce(controllerAccount.address, channelId).call(); const validityTimestamps = 0; // no validity timestamp set +const msgValue = 0; // Amount of native tokens to fund the UP with while calling const abiPayload = universalProfile.methods .execute( 0, // Operation type: CALL recipientAddress, - msgValue, + web3.utils.toWei(3), // transfer 3 LYX to recipient '0x', // Data ) .encodeABI(); @@ -211,11 +210,12 @@ const channelId = 0; const nonce = await keyManager.getNonce(controllerAccount.address, channelId); const validityTimestamps = 0; // no validity timestamp set +const msgValue = 0; // Amount of native tokens to fund the UP with while calling const abiPayload = universalProfile.interface.encodeFunctionData('execute', [ 0, // Operation type: CALL recipientAddress, - msgValue, + ethers.utils.parseEther('3'), // transfer 3 LYX to recipient '0x', // Data ]); ``` @@ -249,13 +249,22 @@ For more information check: [**How to sign relay transactions?**](../../standard ```typescript title="Sign the transaction" const chainId = await web3.eth.getChainId(); +// prettier-ignore let encodedMessage = web3.utils.encodePacked( - { value: LSP6_VERSION, type: 'uint256' }, - { value: chainId, type: 'uint256' }, - { value: nonce, type: 'uint256' }, - { value: validityTimestamps, type: 'uint256' }, - { value: msgValue, type: 'uint256' }, - { value: abiPayload, type: 'bytes' }, + // MUST be number `25` + { value: LSP25_VERSION, type: 'uint256' }, // `0x0000000000000000000000000000000000000000000000000000000000000019` + // e.g: `4201` for LUKSO Testnet + { value: chainId, type: 'uint256' }, // `0x0000000000000000000000000000000000000000000000000000000000001069` + // e.g: nonce nb 5 + { value: nonce, type: 'uint256' }, // `0x0000000000000000000000000000000000000000000000000000000000000005` + // e.g: valid until 1st January 2025 at midnight (GMT). + // Timestamp = 1735689600 + { value: validityTimestamps, type: 'uint256' }, // `0x0000000000000000000000000000000000000000000000000000000067748580` + // e.g: not funding the contract with any LYX (0) + { value: msgValue, type: 'uint256' }, // `0x0000000000000000000000000000000000000000000000000000000000000000` + // e.g: execute(uint256,address,uint256,bytes) + // send 3 LYX to address `0xcafecafecafecafeafecafecafecafeafecafecafecafeafecafecafecafe` + { value: abiPayload, type: 'bytes' }, // `0x44c028fe0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cafecafecafecafecafecafecafecafecafecafe00000000000000000000000000000000000000000000000029a2241af62c000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000` ); let eip191Signer = new EIP191Signer(); @@ -274,9 +283,24 @@ let { signature } = await eip191Signer.signDataWithIntendedValidator( ```typescript title="Sign the transaction" const { chainId } = await provider.getNetwork(); +// prettier-ignore let encodedMessage = ethers.utils.solidityPack( ['uint256', 'uint256', 'uint256', 'uint256', 'uint256', 'bytes'], - [LSP6_VERSION, chainId, nonce, validityTimestamps, msgValue, abiPayload], + [ + // MUST be number `25` + LSP25_VERSION, // `0x0000000000000000000000000000000000000000000000000000000000000019` + // e.g: `4201` for LUKSO Testnet + chainId, // `0x0000000000000000000000000000000000000000000000000000000000001069` + // e.g: nonce nb 5 + nonce, // `0x0000000000000000000000000000000000000000000000000000000000000005` + // e.g: valid until 1st January 2025 at midnight (GMT). + // Timestamp = 1735689600 + validityTimestamps, // `0x0000000000000000000000000000000000000000000000000000000067748580` + // e.g: not funding the contract with any LYX (0) + msgValue, // `0x0000000000000000000000000000000000000000000000000000000000000000` + // e.g: execute(uint256,address,uint256,bytes) -> send 3 LYX to address `0xcafecafecafecafeafecafecafecafeafecafecafecafeafecafecafecafe` + abiPayload, // `0x44c028fe0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cafecafecafecafecafecafecafecafecafecafe00000000000000000000000000000000000000000000000029a2241af62c000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000` + ], ); let eip191Signer = new EIP191Signer(); @@ -367,12 +391,11 @@ import KeyManagerContract from '@lukso/lsp-smart-contracts/artifacts/LSP6KeyMana import { EIP191Signer } from '@lukso/eip191-signer.js'; import Web3 from 'web3'; -// This is the version relative to the LSP6 standard, defined as the number 6. -import { LSP6_VERSION } from '@lukso/lsp-smart-contracts/constants'; +// This is the version relative to the LSP25 standard, defined as the number 25. +import { LSP25_VERSION } from '@lukso/lsp-smart-contracts/constants'; const web3 = new Web3('https://rpc.testnet.lukso.network'); const universalProfileAddress = '0x...'; -const msgValue = 0; // Amount of native tokens to be sent const recipientAddress = '0x...'; // setup the Universal Profile controller account @@ -396,25 +419,36 @@ const nonce = await keyManager.methods .call(); const validityTimestamps = 0; // no validity timestamp set +const msgValue = 0; // Amount of native tokens to fund the UP with while calling +// send 3 LYX to recipient const abiPayload = universalProfile.methods .execute( 0, // Operation type: CALL recipientAddress, - msgValue, + web3.utils.toWei(3), // transfer 3 LYX to recipient '0x', // Data ) .encodeABI(); const chainId = await web3.eth.getChainId(); +// prettier-ignore let encodedMessage = web3.utils.encodePacked( - { value: LSP6_VERSION, type: 'uint256' }, - { value: chainId, type: 'uint256' }, - { value: nonce, type: 'uint256' }, - { value: validityTimestamps, type: 'uint256' }, - { value: msgValue, type: 'uint256' }, - { value: abiPayload, type: 'bytes' }, + // MUST be number `25` + { value: LSP25_VERSION, type: 'uint256' }, // `0x0000000000000000000000000000000000000000000000000000000000000019` + // e.g: `4201` for LUKSO Testnet + { value: chainId, type: 'uint256' }, // `0x0000000000000000000000000000000000000000000000000000000000001069` + // e.g: nonce nb 5 + { value: nonce, type: 'uint256' }, // `0x0000000000000000000000000000000000000000000000000000000000000005` + // e.g: valid until 1st January 2025 at midnight (GMT). + // Timestamp = 1735689600 + { value: validityTimestamps, type: 'uint256' }, // `0x0000000000000000000000000000000000000000000000000000000067748580` + // e.g: not funding the contract with any LYX (0) + { value: msgValue, type: 'uint256' }, // `0x0000000000000000000000000000000000000000000000000000000000000000` + // e.g: execute(uint256,address,uint256,bytes) + // send 3 LYX to address `0xcafecafecafecafeafecafecafecafeafecafecafecafeafecafecafecafe` + { value: abiPayload, type: 'bytes' }, // `0x44c028fe0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cafecafecafecafecafecafecafecafecafecafe00000000000000000000000000000000000000000000000029a2241af62c000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000` ); let eip191Signer = new EIP191Signer(); @@ -443,8 +477,8 @@ import KeyManagerContract from '@lukso/lsp-smart-contracts/artifacts/LSP6KeyMana import { EIP191Signer } from '@lukso/eip191-signer.js'; import { ethers } from 'ethers'; -// This is the version relative to the LSP6 standard, defined as the number 6. -import { LSP6_VERSION } from '@lukso/lsp-smart-contracts/constants'; +// This is the version relative to the LSP25 standard, defined as the number 25. +import { LSP25_VERSION } from '@lukso/lsp-smart-contracts/constants'; const provider = new ethers.providers.JsonRpcProvider( 'https://rpc.testnet.lukso.network', @@ -486,9 +520,24 @@ const abiPayload = universalProfile.interface.encodeFunctionData('execute', [ const { chainId } = await provider.getNetwork(); +// prettier-ignore let encodedMessage = ethers.utils.solidityPack( ['uint256', 'uint256', 'uint256', 'uint256', 'uint256', 'bytes'], - [LSP6_VERSION, chainId, nonce, validityTimestamps, msgValue, abiPayload], + [ + // MUST be number `25` + LSP25_VERSION, // `0x0000000000000000000000000000000000000000000000000000000000000019` + // e.g: `4201` for LUKSO Testnet + chainId, // `0x0000000000000000000000000000000000000000000000000000000000001069` + // e.g: nonce nb 5 + nonce, // `0x0000000000000000000000000000000000000000000000000000000000000005` + // e.g: valid until 1st January 2025 at midnight (GMT). + // Timestamp = 1735689600 + validityTimestamps, // `0x0000000000000000000000000000000000000000000000000000000067748580` + // e.g: not funding the contract with any LYX (0) + msgValue, // `0x0000000000000000000000000000000000000000000000000000000000000000` + // e.g: execute(uint256,address,uint256,bytes) -> send 3 LYX to address `0xcafecafecafecafeafecafecafecafeafecafecafecafeafecafecafecafe` + abiPayload, // `0x44c028fe0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cafecafecafecafecafecafecafecafecafecafe00000000000000000000000000000000000000000000000029a2241af62c000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000` + ], ); let eip191Signer = new EIP191Signer(); diff --git a/docs/standards/universal-profile/lsp6-key-manager.md b/docs/standards/universal-profile/lsp6-key-manager.md index 84aeba8f1e..86064f7514 100644 --- a/docs/standards/universal-profile/lsp6-key-manager.md +++ b/docs/standards/universal-profile/lsp6-key-manager.md @@ -851,8 +851,8 @@ To obtain a valid signature that can be used by anyone to execute a relayed tran - 1. the **payload** (an abi-encoded function call) to be executed on the linked account. - 2. the **chain id** of the blockchain where the `payload` will be executed. - 3. the address of the [`LSP6KeyManager`](../../contracts/contracts/LSP6KeyManager/LSP6KeyManager.md) smart contract where the **payload** will be executed. - d. the Key Manager **nonce** of the controller. - - 4. the `validityTimestamps`, composed of 2 x `uint128` concatenated together, where: + - 4. the Key Manager **nonce** of the controller. + - 5. the `validityTimestamps`, composed of 2 x `uint128` concatenated together, where: 4.1. the left-side `uint128` corresponds to the timestamp from which the relay call is valid from. @@ -869,7 +869,7 @@ To obtain a valid signature that can be used by anyone to execute a relayed tran The relay transactions are signed using the [**version 0 of EIP191**](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-191.md#version-0x00). The relay call data that you want to sign **MUST** be the _keccak256 hash digest_ of the following elements _(bytes values)_ concatenated together. ```javascript -0x19 <0x00> +0x19 <0x00> ``` | Message elements | Details | @@ -877,7 +877,7 @@ The relay transactions are signed using the [**version 0 of EIP191**](https://gi | `0x19` | Byte used to ensure that the _relay call signed data_ is not a valid RLP. | | `0x00` | The [**version 0 of EIP191**](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-191.md#version-0x00). | | `KeyManager address` | The address of the Key Manager that will execute the relay call. | -| `LSP6_VERSION` | The version of the Key Manager that will execute the relay call, as a `uint256`. (Current version of LSP6 Key Manager is **6**) | +| `LSP25_VERSION` | The `uint256` number **25** that defines the current version of the LSP25 Execute Relay Call standard. | | `chainId` | The chain id of the blockchain where the Key Manager is deployed, as `uint256`. | | `nonce` | The unique [**nonce**](https://github.com/lukso-network/LIPs/blob/main/LSPs/LSP-6-KeyManager.md#getnonce) for the payload. | | `validityTimestamps` | Two `uint128` timestamps concatenated, the first timestamp determines from when the payload can be executed, the second timestamp delimits the end of the validity of the payload. If `validityTimestamps` is 0, the checks of the timestamps are skipped | From caf13ecafc227024bd98795854b789bd8115e986 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Wed, 8 Nov 2023 17:03:40 +0000 Subject: [PATCH 2/3] chore: add Contract page for ExecuteRelayCall --- docs/contracts/overview/ExecuteRelayCall.md | 62 +++++++++++++++++++ .../universal-profile/lsp6-key-manager.md | 2 +- src/components/ContractCardsGallery/index.tsx | 2 +- 3 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 docs/contracts/overview/ExecuteRelayCall.md diff --git a/docs/contracts/overview/ExecuteRelayCall.md b/docs/contracts/overview/ExecuteRelayCall.md new file mode 100644 index 0000000000..998e8c8523 --- /dev/null +++ b/docs/contracts/overview/ExecuteRelayCall.md @@ -0,0 +1,62 @@ +--- +sidebar_position: 5 +--- + +# Execute Relay Call + +## Validity timestamps + +:::info + +Use this website to generate validity timestamps for specific date and time. + +::: + +It is possible to make signatures for relay executions valid for specific time periods. This is done by constructing a **validity timestamp** that can be passed as the `uint256 validityTimestamp` parameter to `executeRelayCall` and `executeRelayCallBatch` functions. + +Below are examples of constructing different **validity timestamps**: + +### Example 1: only from a specific date / time. + +Valid only from the 1st June 2024 (midnight). + +Timestamp for _1st June 2024_ = `1717200000` (decimal) = `0x665A6480` (hex) + +``` + valid from timestamp 1717200000 + vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv +0x000000000000000000000000665A648000000000000000000000000000000000 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + valid until indefinitely +``` + +### Example 2: set an expiry date + +Valid until 31st January 2025, 5pm CET. + +Timestamp for _31st January 2025 (5pm CET)_ = `1738339200` (decimal) = `0x679CF380` (hex) + + +``` + valid from anytime + vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv +0x00000000000000000000000000000000000000000000000000000000679CF380 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + valid until 31st January 2025 (5pm CET) +``` + +### Example 3: valid during a specific period + + +Valid from 1st January 2024 (midnight CET) to 1st April 2024 (midnight CET) + +- Timestamp for _1st January 2024 (midnight)_ = `1704063600` (decimal) = `0x6591F270` (hex) +- Timestamp for _1st April 2024 (midnight)_ = `1711926000` (decimal) = `0x6609EAF0` (hex) + +``` + valid from + vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv +0x0000000000000000000000006591F2700000000000000000000000006609EAF0 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + valid until +``` \ No newline at end of file diff --git a/docs/standards/universal-profile/lsp6-key-manager.md b/docs/standards/universal-profile/lsp6-key-manager.md index 4e9cdef78c..28a561ba7c 100644 --- a/docs/standards/universal-profile/lsp6-key-manager.md +++ b/docs/standards/universal-profile/lsp6-key-manager.md @@ -828,7 +828,7 @@ Dapps can then leverage the relay execution features to create their own busines ![LSP6 Key Manager Relay Service](/img/standards/lsp6/lsp6-relay-execution.jpeg) -An essential aspect to consider in relay execution is the time validity of the execution signature. It's sometimes beneficial to limit the execution to be valid within a specific timeframe to prevent potential security risks. For example, if a user signs a relay transaction and the signature is stolen or compromised, the attacker could potentially use this signature indefinitely if there's no validity period set. +An essential aspect to consider in relay execution is the time validity of the execution signature. It's sometimes beneficial to limit the execution to be valid within a specific time frame to prevent potential security risks. For example, if a user signs a relay transaction and the signature is stolen or compromised, the attacker could potentially use this signature indefinitely if there's no validity period set. To mitigate such risks, adding an optional validity timestamp to the signature could mark the start date and expiry date of its effectiveness. Once the timestamp has passed, the signature is no longer valid, rendering the relay transaction unusable. diff --git a/src/components/ContractCardsGallery/index.tsx b/src/components/ContractCardsGallery/index.tsx index 3a9558c5d9..215431782e 100644 --- a/src/components/ContractCardsGallery/index.tsx +++ b/src/components/ContractCardsGallery/index.tsx @@ -46,7 +46,7 @@ const Contracts_AccountsInteraction = [ }, { name: '⛽ LSP25 Execute Relay Call', - url: '', + url: './overview/ExecuteRelayCall', urlABI: './contracts/LSP25ExecuteRelayCall/LSP25MultiChannelNonce', description: 'Add Meta Transactions on your contract to enable gas-less transactions and more easily onboard new users.', From 548e2d4c733c5fd88d1c94bf42463efc5b6792a2 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Wed, 8 Nov 2023 17:14:12 +0000 Subject: [PATCH 3/3] improve explanations --- docs/contracts/overview/ExecuteRelayCall.md | 6 +++--- .../key-manager/execute-relay-transactions.md | 11 ++++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/contracts/overview/ExecuteRelayCall.md b/docs/contracts/overview/ExecuteRelayCall.md index 998e8c8523..c52ba6da5d 100644 --- a/docs/contracts/overview/ExecuteRelayCall.md +++ b/docs/contracts/overview/ExecuteRelayCall.md @@ -4,7 +4,7 @@ sidebar_position: 5 # Execute Relay Call -## Validity timestamps +## Validity timestamps :::info @@ -16,7 +16,7 @@ It is possible to make signatures for relay executions valid for specific time p Below are examples of constructing different **validity timestamps**: -### Example 1: only from a specific date / time. +### Example 1: from a specific date / time Valid only from the 1st June 2024 (midnight). @@ -30,7 +30,7 @@ Timestamp for _1st June 2024_ = `1717200000` (decimal) = `0x665A6480` (hex) valid until indefinitely ``` -### Example 2: set an expiry date +### Example 2: set an expiry date Valid until 31st January 2025, 5pm CET. diff --git a/docs/learn/expert-guides/key-manager/execute-relay-transactions.md b/docs/learn/expert-guides/key-manager/execute-relay-transactions.md index 29cf5ea41e..a2d67ba038 100644 --- a/docs/learn/expert-guides/key-manager/execute-relay-transactions.md +++ b/docs/learn/expert-guides/key-manager/execute-relay-transactions.md @@ -178,7 +178,10 @@ Encode the ABI of the transaction you want to be executed. In this case, a LYX t :::tip -For more information about _validity timestamps_ check [**How to sign relay transactions?**](../../../standards/universal-profile/lsp6-key-manager.md#how-to-sign-relay-transactions) +The `validityTimestamp` can take different forms. For more information about _validity timestamps_, see the following pages: + +- section [**Execute Relay Calls > Validity Timestamps**](../../../contracts/overview/ExecuteRelayCall.md#validity-timestamps) in our **Contracts** docs. +- [**How to sign relay transactions?**](../../../standards/universal-profile/lsp6-key-manager.md#how-to-sign-relay-transactions) ::: @@ -261,7 +264,8 @@ let encodedMessage = web3.utils.encodePacked( { value: LSP25_VERSION, type: 'uint256' }, // `0x0000000000000000000000000000000000000000000000000000000000000019` // e.g: `4201` for LUKSO Testnet { value: chainId, type: 'uint256' }, // `0x0000000000000000000000000000000000000000000000000000000000001069` - // e.g: nonce nb 5 + // e.g: nonce number 5 of the signer key X + // (the private key associated with the address of the controller that want to execute the payload) { value: nonce, type: 'uint256' }, // `0x0000000000000000000000000000000000000000000000000000000000000005` // e.g: valid until 1st January 2025 at midnight (GMT). // Timestamp = 1735689600 @@ -297,7 +301,8 @@ let encodedMessage = ethers.utils.solidityPack( LSP25_VERSION, // `0x0000000000000000000000000000000000000000000000000000000000000019` // e.g: `4201` for LUKSO Testnet chainId, // `0x0000000000000000000000000000000000000000000000000000000000001069` - // e.g: nonce nb 5 + // e.g: nonce number 5 of the signer key X + // (the private key associated with the address of the controller that want to execute the payload) nonce, // `0x0000000000000000000000000000000000000000000000000000000000000005` // e.g: valid until 1st January 2025 at midnight (GMT). // Timestamp = 1735689600