'I'm trying to implement openzeppelin's minimal proxy clone contract on TRON blockchain
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.
Solution 1:[1]
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)
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | user72088 |
