Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LSP24] Multichain Address Resolution #212

Open
YamenMerhi opened this issue Jun 20, 2023 · 5 comments
Open

[LSP24] Multichain Address Resolution #212

YamenMerhi opened this issue Jun 20, 2023 · 5 comments

Comments

@YamenMerhi
Copy link
Member

Proposing a standard related to Multichain Address Resolution to start by querying the storage of an ERC725Y contract. The resolution can happen to the ERC725Y contract itself, or other addresses. Verification of the resolution will be based on the ERC725Y contract on both chains, by making the ERC725Y contracts point to each other

To have a background of how the resolution happens with ENS: https://eips.ethereum.org/EIPS/eip-2304

Feedback about the logic of the standard is welcomed (not typo/grammatical/vocab error as this is not a PR) 🤝


lip: ?
title: Multichain Address Resolution
author: [Your Name] <[Your Email]>
discussions-to:
status: Draft
type: LSP
created: 2023-06-19
requires: ERC725Y, LSP2

Simple Summary

This standard describes a set of ERC725Y data key-value pairs that allow resolution of addresses on different chains, and a mechanism for verifying the claim of address resolution.

Abstract

The LSP24MultichainAddressResolution data key will allow resolution of addresses on other chains based on an address or a standard hash.

Motivation

For EVM chains, if an address is an Externally Owned Account (EOA) it is known that the controller of this EOA can control it across different chains. But for smart contracts it's different, even with having contracts at the same address across different chains, it's possible to have different contracts, which makes having a contract at same address on different chains does not guarantee that these contracts are the same.

It is essential to have a mechanism that resolve an address from a chain to another one, making it possible to resolve contract addresses to their equivalents on other EVM chains, and normal addresses to other chains, even non EVM ones such as Bitcoin, Ripple, Solana, etc..

Specification

Address Resolution

Every contract that supports the LSP24MultichainAddressResolution standard MUST have the following data key:

LSP24MultichainAddressResolution

{
     "name": "LSP24MultichainAddressResolution:<bytes4>:<address|bytes32>",
     "key": "0x049b19b87a61<bytes4>00<address>",
     "keyType": "MappingWithGrouping",
     "valueType": "bytes",
     "valueContent": "Address|Bytes"
}
  • The data key is constructed from 2 dynamic parts:

    • The first dynamic part is bytes4 which represent the chain of the address resolved
    • The second dynamic part is either the address to lookup on another chain or a bytes32 hash of a specific standard.
  • The data value stored under this data key is the address in the native format of the network of the address resolved. Each network could have a different representation of the address encoding, for example, bitcoin address encoding is different than EVM address encoding.

The bytes4 chain representation and its respective address encoding can be found and added to the table at the end of the specification. For example:

Network Bytes4 representation Address Encoding
LUKSO TBD ChecksummedHex
Ethereum TBD ChecksummedHex
Bitcoin TBD P2PKH(0x00), P2SH(0x05), SegWit(‘bc’)
... ... ...

Example 1

Suppose an ERC725Y contract deployed on LUKSO Mainnet, and we want to resolve its corresponding address on Ethereum Mainnet. Here's how we would proceed:

  1. We start by identifying the bytes4 representation of the Ethereum Mainnet chain, let's say for instance, it's 0xffffffff.

  2. Next, we need the address of the ERC725Y contract on LUKSO Mainnet. In our example, let's consider it to be 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.

  3. Using the above details, we can construct the data key as follows: 0x049b19b87a61ffffffff00aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.

After retrieving the data stored under this key, let's say we got 0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb. This implies that the ERC725Y contract's address on LUKSO Mainnet is 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, and the corresponding address of this contract on the Ethereum Mainnet is 0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.

Example 2

There could be the case where a lookup is needed for a specific standardized wallet, for example a wallet standardized under the name of XYZ50:

  1. We start by identifying the bytes4 representation of the chain to lookup, let's say for instance, it's 0xffffffff.

  2. Next, we need the hash standardized for the wallet. In our example, it can be standardized as the keccak256 of XYZ50 equal to 0x1e647dad4813ed23203d95b2d3ab27ea25a4c1a2ed45c3002dc063fe9f4a14a4

  3. Using the above details, we can construct the data key as follows: 0x049b19b87a61ffffffff001e647dad4813ed23203d95b2d3ab27ea25a4c1a2.

After retrieving the data stored under this key, let's say we got 0xcccccccccccccccccccccccccccccccccccccccc. This implies that the wallet XYZ50 on the chain looked up is at the address 0xcccccccccccccccccccccccccccccccccccccccc.

Example 3

There could be the case where a lookup is needed for an address on a non EVM chain such as Bitocin. Here's how we would proceed:

  1. We start by identifying the bytes4 representation of the chain to lookup, let's say for instance, it's Bitcoin and its chain representation is 0xbbbbbbbb.

  2. Next, we need the address to lookup. In our example, let's consider it to be 0x2222222222222222222222222222222222222222.

  3. Using the above details, we can construct the data key as follows: 0x049b19b87a61bbbbbbbb002222222222222222222222222222222222222222.

After retrieving the data stored under this key, let's say we got 0x0062e907b15cbf27d5425399ebf6f0fb50ebb88f18. Given that the encoding of Bitcoin addresses is based on P2PKH (base58check), after decoding the address resolved will be 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa.

Verifying Address Resolution

While it's relatively simple to claim that a certain address on another chain is the corresponding address or under the same control, this can potentially lead to deceptive assertions, causing major problems. Therefore, it's essential to have a standardized mechanism for verifying such address resolution claims.

For verification purposes, the ERC725Y contract should exist on the chain to lookup. To verify that the resolution is correct, it is essential to have the same reverse lookup happen on the lookup chain. In this way, we have a resolution that could go in both ways, making it possible and sure that these 2 contracts are under the same control and point to each other.

This method represents an autonomous way for verifying the claim of address resolution, but other solutions such as verifying signature on the address looked up could also be used.

Example 4

Continuing with the example 1, the ERC725Y contract on the Ethereum chain at address 0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb should store a data key pointing back to the LUKSO network.

Supposing the bytes4 representation of LUKSO Mainnet is 0x42424242, the data key 0x049b19b87a614242424200bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb should exist in the ERC725Y contract on the Ethereum Mainnet , and the data value stored under the data key should be equal to 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.

Example 5

In case where the lookup is not intended for the ERC725Y contract itself, the verification process will require few more steps.

If the lookup in the ERC725Y contract deployed on LUKSO Mainnet is for a vault address to be checked on Ethereum Mainnet, then the lookup start with:

  1. We start by identifying the bytes4 representation of the Ethereum Mainnet chain, let's say for instance, it's 0xffffffff.

  2. Next, we need the address of the vault contract on LUKSO Mainnet. In our example, let's consider it to be 0xdddddddddddddddddddddddddddddddddddddddd.

  3. Using the above details, we can construct the data key as follows: 0x049b19b87a61ffffffff00dddddddddddddddddddddddddddddddddddddddd.

After retrieving the data stored under this key, let's say we got 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee. This implies that the vault contract's address on LUKSO Mainnet is 0xdddddddddddddddddddddddddddddddddddddddd, and the corresponding address of this contract on the Ethereum Mainnet is 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee.

The verification phase cannot go directly to 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee as this contract could be not implementing ERC725Y and just representing a vault. To have a verified resolution, we need a reverse lookup using the ERC725Y contract.

The ERC725Y should be available on the chain to lookup, in our case Ethereum Mainnet, and should be resolved from LUKSO Mainnet and should be pointing back to the LUKSO address on Ethereum Mainnet as shown in Example 4.

After verfying that the ERC725Y contracts on Ethereum and LUKSO point to each other, the verification to the vault happens as follows:

  1. We start by identifying the bytes4 representation of the LUKSO Mainnet chain, let's say for instance, it's 0x42424242.

  2. Next, we need the address of the vault contract on Ethereum Mainnet. In our example above, we got it as 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee.

  3. Using the above details, we can construct the data key as follows: 0x049b19b87a614242424200eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee.

The data stored under this data key should be equal to 0xdddddddddddddddddddddddddddddddddddddddd. This implies that the vault contracts on LUKSO Mainnet and Ethereum Mainnet are pointing and referencing each other through the ERC725Y contract existing on both chains.

In this way, a resolution that could go in both ways is established, making it possible to verify that these two contracts are under the same control and point to each other.

Rationale

The process of verification of address resolution autonomously may only be available for specific networks. Some networks do not have the capability to support contracts or storage, thus address resolution can be implemented, but not verification.

The standard does not enforce the process of creating the bytes4 representation of the chain. It is up to each chain to standardize their bytes4 representation. This approach can support a significant number of chains, up to 4,294,967,295.

The decision not to make the bytes4 as the chainId representation is because some networks have chainId that are larger than 4 bytes. Additionally, choosing not to use the hash of the network name or currency is due to the potential hash collisions.

Therefore, it's essential for each chain to add their representation to LSP24, while reviewing the already used bytes4 chain representations.

Implementation

ERC725Y JSON Schema LSP24MultichainAddressResolution:

[
    {
        "name": "LSP24MultichainAddressResolution:<bytes4>:<address|bytes32>",
        "key": "0x049b19b87a61<bytes4>00<address>",
        "keyType": "MappingWithGrouping",
        "valueType": "bytes",
        "valueContent": "Address|Bytes"
    }
]

List of Chains and Encoding

Chains can be added here:

Network Bytes4 representation Address Encoding
LUKSO TBD ChecksummedHex
Ethereum TBD ChecksummedHex
Bitcoin TBD P2PKH(0x00), P2SH(0x05), SegWit(‘bc’)
... ... ...
... ... ...

Copyright

Copyright and related rights waived via CC0.

@skimaharvey
Copy link
Member

skimaharvey commented Jun 24, 2023

lgtm. the only thing i was thinking of is

  • instead of using 0000 separator we could have a dedicated byte that will let the verifier know whether it is a "double" or "single" type verification but since the standard is made for offchain agents I guess it is not a big deal to verify directly.
  • when double verifying is possible maybe it could make sense to give the address where we verify and then append the bytes that enable that doubles verification. For example, on non-evm chain I would have no idea how to verify. Something like that (address + separator + calldataToVerify). Same applies for evm chains and addresses that dont implement ERC725Y
    Edit: I guess this comment can be discarded, just saw that the standard requires ERC725Y, LSP2 well may be we can make it generic 😆

@CJ42
Copy link
Member

CJ42 commented Jul 4, 2023

This sounds like a very interesting idea!

Maybe the first dynamic part of the data key can be chainId of the other chain to resolve to?

We could also use uint32 or uint64 for the type, but consider the max value allowed for a chainId based on EIP2294: https://eips.ethereum.org/EIPS/eip-2294#:~:text=Due%20to%20how%20the%20calculation,the%20highest%20value%20is%20used.

So the data key would look like:

     "name": "LSP24MultichainAddressResolution:<uint32>:<address|bytes32>",

Also for the second part of the data key, could the bytes32 correspond to the contract code hash?

https://docs.soliditylang.org/en/v0.8.20/cheatsheet.html#members-of-address

image

The data value stored under this data key is the address in the native format of the network of the address resolved. Each network could have a different representation of the address encoding, for example, bitcoin address encoding is different than EVM address encoding.

Great idea to store as bytes for this purpose! 👌

@YamenMerhi
Copy link
Member Author

After further research, a proposal could be to construct the chainId instead of the bytes4 representation for EVM chains. In this way, chains don't need to take a step to standardize a representation but it's already done with knowing the chainId of the EVM Network

@YamenMerhi
Copy link
Member Author

YamenMerhi commented Nov 16, 2023

To be reviewed to include a more generic address resolution while taking into consideration:
1-

{
     "name": "LSP24MultichainAddressResolution:<bytes4>:<address|bytes32>",
     "key": "0x049b19b87a61<bytes4>00<address>",
     "keyType": "MappingWithGrouping",
     "valueType": "bytes",
     "valueContent": "Address|Bytes"
}

Simplification to

{
     "name": "LSP24MultichainAddressResolution:<bytes8>:<address>",
     "key": "0x049b19b8<bytes8><address>",
     "keyType": "Custom",
     "valueType": "bytes",
     "valueContent": "Address|Bytes"
}

As the bytes32 lookup can happen by:

  • Looking up in another data key-value store
  • Retreive the address
  • Lookup the address with LSP24 data key

2 - No explicit bound for the type of chainId --> Probably Standardizing Registry for ChainIds,
Not All chainIds needs to be represented as there is a lot of Testnets that die eventually
3 - Address Resolution on Non-EVM chain
4 - Calldata or txFormat to resolve to the address on a specific chain according to the Sepcs of the Chain
5 - Have different type of dataValues, for example based on the first byte:
- When 0x00 --> Defines an Address to be resolved
- When 0x01 --> Defines a calldata to be executed on a specific chain
- When 0x02 --> Defines a txFormat to be simulated in the other Blockchain Network
- When 0x03 --> Defines a way to reference - and a way to reverse verify

The standard can continue to evolve
To be Tested with Bitcoin, Solana, Cardano, XRP ..

@Hugoo
Copy link
Contributor

Hugoo commented Apr 12, 2024

Is it stale?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

4 participants