2

The openzeppelin minimal proxy contract here has this function predictDeterministicAddress() that hashes values like the sender's address, a salt... to generate a contract address that the create2 function will also generate, when it's passed the same values as dictated in this EIP.

This EIP states that an arbitrary value 0xff when hashed with a salt, sender's address and the contract bytecode will always generate the same address.

I'm trying to implement the predictDeterministicAddress() function on TRON blockchain but the TRON docs specify a different arbitrary value, 0x41 for implementing this same feature.

I tried to just replace the values but I can't see where the openzeppelin team used the value 0xff in their function.

Below is the openzeppelin hashing function:

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, implementation))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
            mstore(add(ptr, 0x38), shl(0x60, deployer))
            mstore(add(ptr, 0x4c), salt)
            mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
            predicted := keccak256(add(ptr, 0x37), 0x55)
        }
    }

Also due to my limited knowledge of assembly I can't fully grasp how their hashing function works exactly.

Can anyone explain to me, or help me understand how that function can be implemented on the TRON blockchain to the desired effect?

Basically I want to be able to pass the same values to create2 and also to this function on the TRON blockchain, and generate the same contract address.

Jasperan
  • 2,154
  • 1
  • 16
  • 40
KelvinIOT
  • 325
  • 1
  • 2
  • 14

1 Answers1

3

According to solidity's official documentation (https://docs.soliditylang.org/en/latest/control-structures.html?highlight=create2#salted-contract-creations-create2), the algorithm for calculating create2 addresses should be as follows:

keccak256(bytes1(0xff) ++ address(factory_contract) 
    ++ bytes32(salt) ++ keccak256(bytes(creation_code) ++ bytes(arg...)))

But on TRON, the algorithm should be as follows:

keccak256(bytes1(0x41) ++ address(factory_contract) 
    ++ bytes32(salt) ++ keccak256(bytes(creation_code) ++ bytes(arg...)))

The difference is that the first byte given to the outer keccak256 function. EVM in ethereum is 0xff, TVM in TRON is 0x41.

Before calculating the predicted address( predicted := keccak256(add(ptr, 0x37), 0x55) ), starting from (ptr), memory data:

0x00 ~ 0x13 3d602d80600a3d3981f3363d3d373d3d3d363d73 
0x14 ~ 0x27 (implementation address)
0x28 ~ 0x37 5af43d82803e903d91602b57fd5bf3 ff (This byte is the key, should be replaced by 0x41 on TRON)
0x38 ~ 0x4b (deployer address)
0x4c ~ 0x6b (salt bytes32)
0x6c ~ 0x8b (keccak256(0x00 ~ 0x37)) (This part hash is keccak256(bytes(creation_code) ++ bytes(arg...)))

This means that creation code for proxy contract will be 0x3d602d80600a3d3981f3363d3d373d3d3d363d73(impl)5af43d82803e903d91602b57fd5bf3. We can decompile this code on (https://ethervm.io/decompile), the results are as follows:

(implementation address is replaced by 0xea674fdde714fd979de3edf0f56aa9716b898ec8)

label_0000:
    // Inputs[3]
    // {
    //     @0000  returndata.length
    //     @0006  returndata.length
    //     @0009  memory[returndata.length:returndata.length + 0x2d]
    // }
    0000    3D  RETURNDATASIZE
    0001    60  PUSH1 0x2d
    0003    80  DUP1
    0004    60  PUSH1 0x0a
    0006    3D  RETURNDATASIZE
    0007    39  CODECOPY
    0008    81  DUP2
    0009    F3  *RETURN
    // Stack delta = +1
    // Outputs[3]
    // {
    //     @0000  stack[0] = returndata.length
    //     @0007  memory[returndata.length:returndata.length + 0x2d] = code[0x0a:0x37]
    //     @0009  return memory[returndata.length:returndata.length + 0x2d];
    // }
    // Block terminates

    000A    36    CALLDATASIZE
    000B    3D    RETURNDATASIZE
    000C    3D    RETURNDATASIZE
    000D    37    CALLDATACOPY
    000E    3D    RETURNDATASIZE
    000F    3D    RETURNDATASIZE
    0010    3D    RETURNDATASIZE
    0011    36    CALLDATASIZE
    0012    3D    RETURNDATASIZE
    0013    73    PUSH20 0xea674fdde714fd979de3edf0f56aa9716b898ec8
    0028    5A    GAS
    0029    F4    DELEGATECALL
    002A    3D    RETURNDATASIZE
    002B    82    DUP3
    002C    80    DUP1
    002D    3E    RETURNDATACOPY
    002E    90    SWAP1
    002F    3D    RETURNDATASIZE
    0030    91    SWAP2
    0031    60    PUSH1 0x2b
    0033    57    *JUMPI
    0034    FD    *REVERT
    0035    5B    JUMPDEST
    0036    F3    *RETURN

The openzeppelin hashing function should be adjusted on TRON as follows:

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, implementation))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf34100000000000000000000000000000000)
            mstore(add(ptr, 0x38), shl(0x60, deployer))
            mstore(add(ptr, 0x4c), salt)
            mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
            predicted := keccak256(add(ptr, 0x37), 0x55)
        }
    }
user72088
  • 46
  • 1
  • Hello, this works. Thanks alot, really. I tried reaching out to you, but couldnt find a contact detail, or something. Pls send me a dm if you dont mind. Also if you can suggest a way for me to learn about this stuff, i'd really appreciate. Thanks again. – KelvinIOT Mar 23 '22 at 04:37
  • I suggest you go to github or discord of TRON and make a issue. ^ _^ – user72088 Mar 23 '22 at 06:23
  • I dont think there is need for that, you already solved my issue. Thanks. I meant, how i could learn about handling bytes and writing assembly. – KelvinIOT Mar 23 '22 at 19:11
  • Get more info at (https://ethervm.io/) and (https://docs.soliditylang.org/en/latest/assembly.html) – user72088 Mar 24 '22 at 06:09