# ASE with bridge-contracts [toc] ## Motivation This is an alternative proposal building on top of the [Address Space Extension with Translation Map](https://notes.ethereum.org/@ipsilon/address-space-extension-exploration) idea. See [this for open questions](https://notes.ethereum.org/@ipsilon/address-space-extension-issues). One of the major issues identified is the inability to distinguish short (legacy) addresses from compressed addresses, and the resulting complexity of automatic translation. In order to avoid this problem, we introduce a special contract type, called bridge contract, which announces itself being capable of interacting with the new address space, but is actually placed in the legacy address space (and has a short address). Other contracts in the legacy space can not interact with the new address space. ## Specification Assume the address format and execution logic (bar translation map) from the previous write ups: - address taking/returning instructions operate on 20-byte addresses in contracts in the legacy address space, while on 32-byte addresses in the new address space, - calling a legacy account from a new address results in an exceptional abort (like the `invalid` instruction), unless it is a bridge contract (see next). ### Bridge contract A bridge contract is a contract which has a legacy short address, but is marked as capable of understanding long addresses. Legacy accounts do not have such a marker and are unaffected. There are two options depending what marker do we want: #### Option 1: EOF / EIP-3540 This option is simple: any contract having a valid [EIP-3540](https://eips.ethereum.org/EIPS/eip-3540) prefix is considered valid as a bridge contract. *Should there be some risk, a special section/version requirement can be introduced to restrict the number of contracts.* #### Option 2: Special creation Introduce a new field in the account, `is_bridge`, which if true announces a contract to be a bridge contract. Such an account can be created via, either: a) A new transaction type specficially for this b) A new CREATE-instruction specifically for this ### Instructions The instructions for the bridge contract context operate like they do in the new address space: they take and return 32-byte addresses. When a bridge contract calls another contract, it will be visible with a legacy short address. This makes it possible for them to interact with legacy contracts without any workarounds. With this in place, various wrappers or bridges can be written to move (token) balances between the different address spaces, or to even proxy calls between them. ### Translation map There is no need for a translation map. ## Examples ### Simple token visible on both sides It is possible to deploy a new token as a bridge contract, allowing to hold balances for both legacy and new account, **and** taking transfers from legacy accounts. Since `address` and `address32` would be distinct types for both the ABI encoding and Solidity, it would be possible to write a single contract which has both ERC-20-like interfaces: ```solidity interface CompatibleToken { // Legacy interface function balanceOf(address recipient) external view returns (uint); function transfer(address recipient, uint amount) external; // Modern interface, accepting both address-types function balanceOf(address32 recipient) external view returns (uint); function transfer(address32 recipient, uint amount) external; // ... the rest of the functions ... } ``` We need two entry points, as the selectors for the dispatch table are generated based on function name and argument types. ### Simple token bridge This example is a contract which burns tokens on the legacy space, and mints new ones on the new space. The benefit is that the tokens are moved to the new address space. ```solidity contract Bridge { // The traditional ERC-20 standard with only address IERC20 oldToken; // ERC-NEWT is the new token standard supporting address32 IERCNEWT newToken; constructor(address _oldToken, address32 _newToken) { oldToken = IERC20(_oldToken); newToken = IERCNEWT(_newToken); } function swap(address32 to, uint amount) { // Ensure we are being called from within the legacy space require(uint256(msg.sender) <= 2**160-1); oldToken.transferFrom(msg.sender, address(this), amount); // Asuming oldToken allows for self burning oldToken.burn(amount); // Assuming the bridge is a minter newToken.mint(to, amount); } } ``` #### Use case: Moving legacy DAI to new space Execute two transactions in the legacy context: 1. Call `DAI.approve(bridge, 100)` 2. Call `Bridge.swap(recipient_long_address, 100)` ### Generic proxy A generic proxy forwarder contract (as available in OpenZeppelin) should just work out of the box. ## Questions - Could keep a translation map too, in order to inspect/use it within bridge contracts -- any usefulness? - ?