Transformers need to be permissioned because they are executed in the context of the Flash Wallet. This means that a malicious Transformer could grief the protocol by destroying the Flash Wallet via
selfdestruct, so we need some way to authenticate that the Transformer is safe to use at runtime.
The Transformer Deployer
create’s all Transformers, and its deployment nonce is used to validate a Transformer at runtime. The deployer is owned by 0x Labs, so only we are able to deploy Transformers.
The deployer implements two functions:
kill(). The former is used to deploy new Transformers; it will emit a Deployed event (that includes the nonce) or reverts if it fails to
create the Transformer. The
kill() function is used to destroy deprecated Transformers; this emits a Killed event or reverts if the Transformer’s
die() function reverts. Note that we cannot verify a Transformer called
selfdestruct in the
kill function because this information is not available until after the transaction executes.
/// @dev Deploy a new contract. Only callable by an authority. /// Any attached ETH will also be forwarded. function deploy(bytes memory bytecode) public payable onlyAuthorized returns (address deployedAddress); /// @dev Call `die()` on a contract. Only callable by an authority. /// @param target The target contract to call `die()` on. /// @param ethRecipient The Recipient of any ETH locked in `target`. function kill(IKillable target, address payable ethRecipient) public onlyAuthorized;
View the code for the Transformer Deployer here.
Permissionless Transfomer Deployer
A permissionless deployer has been developed and can be seen here. This serves a similar function to the current delployer, only it is capable of validating the Transformer’s bytecode before deploying. It does this by tracing the bytecode in search of reachable opcodes that could post a threat to the Flash Wallet.
isDelegateCallSafe function performs this check. It will return
false if any of the following opcodes are reachable:
/// @dev Checks whether a given address is safe to be called via /// delegatecall. A contract is considered unsafe if it includes any /// of the following opcodes: CALLCODE, DELEGATECALL, SELFDESTRUCT, /// CREATE, CREATE2, SLOAD, and STORE. This code is adapted from /// https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/helpers/IndestructibleRegistry.sol /// @param target The address to check. /// @return True if the contract is considered safe for delegatecall. function isDelegateCallSafe(address target) public view returns (bool);
deploy function is similar to the existing Transformer Deployer, only it uses a user-provided nonce to deploy the Transformer.
/// @dev Deploy a new contract. Any attached ETH will be forwarded. function deploy(bytes memory bytecode, bytes32 salt) public payable returns (address deployedAddress);
Note that there is no
kill function in this deployer.
View the code for the Permissionless Transformer Deployer here.
There is some overhead to switching over to this deployer, as the Flash Wallet would need to be redeployed and some integrators would need to update their code. Therefore, this will be put into production once there is community-demand for permissionless transformers. Reach out to us on Discord if you’d like to deploy a Transformer!