Importing compiled bytecode, not just sources

Hi! :wave:

Is it technically possible to import compiled bytecode of a contract instead of its sources? Maybe not today but, theoretically, at some point in the future.

With the rapid development of Solidity, having contracts written for different versions of Solidity in one project is not uncommon. For example, a contract that uses UniswapV2 flash loans (UniswapV2 uses pragma solidity =0.5.16). Testing such contracts requires compiling and deploying all dependency contracts. There’s no issue in Hardhat since it allows to compile contracts with different Solidity compiler versions and then deploy them on the same local network (Hardhat tests are written in JS and it runs a local network). But it’s problematic in newer tools like dapp-tools and Foundry because they use Solidity to write tests, and Solidity doesn’t allow to import contracts that use an older Solidity compiler. Here’s an example of such test contract:

pragma solidity ^0.8.10;

import "ds-test/test.sol";
import "../Contract.sol";
import "v2-core/UniswapV2Pair.sol";

contract ContractTest is DSTest {
    function setUp() public {}

    function testExample() public {
        assertTrue(true);
    }
}

The compiler will fail because UniswapV2Pair.sol requires Solidity 0.5.16. Since Solidity is changing rapidly, it becomes more and more problematic updating older contract. And it’ll be more problematic in a year or two (chances are, UniswapV2 and other big DeFi projects will still be running). Also, updating older third-party contracts might result in bugs that might not be noticed in development/testing: as a result, a contract developed against a bugged mock or updated third-party contract will work incorrectly on mainnet.

It would be nice if we could compile older contracts with older Solidity compilers and then import their bytecode in contracts that are compiled by newer Solidity compilers. This will probably be needed only in test contracts but, with the improvement of developer tools and ecosystem, why not make testing easier and more secure?

What do you mean by “import their bytecode in contracts that are compiled by newer Solidity compilers”? If I understand you correctly, you do not really want that bytecode to be part of the new contract, you only want to call a contract with that bytecode, right? So what you usually do is extract an ABI-compatible interface (let’s call it MyInterface) of that contract and modify it so that it compiles with the current version of Solidity. I’m pretty sure there are tools out there that can do it. Then you deploy the contract you only have the bytecode of - let’s call the deployed address addr - and create a contract (pointer) of that interface type at that address: MyInterface interf = MyInterface(addr);.

You can now call functions on interf as you would if you had the source code of that contract.

That’s essentially what hardhat does taken to the Solidity world.

I would imagine that toolkits have options to help you automate that process somewhat.

I want exactly the opposite: to import bytecode and deploy it as a contract, i.e. instantiate a contract using that bytecode. Of course, I’ll need an interface to interact with the contract, but interface alone won’t work because there’s no contract deployed.

There’s actually a workaround for this problem:

This workaround also simplifies development of Yul+ contracts:
https://www.libevm.com/2021/12/18/yulp-smart-contract-dev/

It seems like Solidity can make bytecode loading native and, as a result, not hacky. With the evolution of smart contract development tools, there’s a demand for this feature.