Smart Contracts
Contract | Address | Networks |
---|---|---|
Account.sol | 0x00000000AfCbce78c080F96032a5C1cB1b832D7B | |
AccountFactory.sol | 0xe925f84cA9Dd5b3844fC424861D7bDf9485761B6 | |
DeployAndCall.sol | 0x452C31d60883F0CB51744Ab9fd01685d7443CA6f | |
SaltedDeployer.sol | 0x6b24634B517a63Ed0fa2a39977286e13e7E35E25 | |
LimitSwapVerifier.sol | 0x53D468E719694f3e542Dda96a237Af08eb394f2C | |
CancelVerifier.sol | 0xE0670a90E67eda0126D54843267b27Ca6343B2d8 |
brink-core
The brink-core repo contains core contracts for Brink accounts.
Account
The Account.sol contract is meant to be a canonical instance, deployed once, and used by many instances of Proxy.sol via delegatecall
proxied function calls. It contains all logic for proxy account interactions.
The Account contract exposes 4 functions that allow state changes to proxy account instances:
externalCall()
Makes a function call from the account proxy to an external contract using the call
opcode. Can only be called directly by the proxy account owner. This function can be used to execute account actions that require calls to external contracts, such as an ERC20 transfer.
delegateCall()
Makes a delegated function call from the account proxy to an external contract using the delegatecall
opcode. Can only be called directly by the proxy account owner. This function can be used to execute any call directly on the proxy account instance. It can be used to modify any state on the account. Practical examples of use include sstore
execution, outgoing ETH transfers, or direct execution of complex logic such as a swap on an AMM.
metaDelegateCall()
Allows execution of a delegatecall
permitted by an EIP-712 message signed by the proxy account owner. Can be called by any address as long as a valid signed message is provided.
The to
address of a metaDelegateCall()
should be the address of a secure verifier contract (see brink-verifiers for examples). The data
parameter contains the function call data to execute on the verifier contract. Both to
and data
must be included in the signed message.
metaPartialSignedDelegateCall()
Allows execution of a delegatecall
permitted by an EIP-712 message signed by the proxy account owner, with additional unsigned call data provided by the transaction executor. Can be called by any address as long as a valid signed message is provided.
The to
address and data
parameter behave the same way as they do in metaDelegateCall()
. The unsignedData
parameter is provided by the transaction executor, and is not included as part of the signed message. It is appended to data
and executed on the verifier contract at the to
address. The verifier must be set up to securely handle arbitrary execution of the unsigned portion of the call data it receives.
See the LimitSwapVerifier.tokenToToken() as an example of a verifier function that is designed to securely handle a partially signed delegate call. This function requires that the signed output, input, and expiry conditions are met, while allowing the executor to provide its own call data to source the limit swap.
Proxy
The Proxy.sol contract is a gas-optimized proxy instance deployed for each Brink account owner. This contract contains no specific logic for accounts. It uses delegatecall
in a fallback()
function to execute logic from the implementation
address, which should be the canonical Account.sol address.
Brink proxies can be upgraded by owner by modifying the implementation
address at the storage location set by the IMPLEMENTATION_PTR
constant. We recommend that you do not modify the implementation address! Your account will no longer be supported by any of the Brink open source tools such as brink-sdk.
See https://docs.openzeppelin.com/upgrades-plugins/1.x/proxies for general info on the proxy upgrade pattern.
DeployAndCall
The DeployAndCall.sol
contract allows for contract deployment and execution of call data on the newly deployed contract in the same transaction. It is not Brink specific, but can be used by executors to conveniently execute meta transactions on undeployed Brink proxy accounts by batching deployment and call into a single transaction.
CallExecutor
The CallExecutor.sol contract can be used by verifier functions to securely execute arbitrary call data without exposing the proxy account as msg.sender
.
See an example of use in LimitSwapVerifier.tokenToToken(). If the arbitrary call data execution here was not proxied through CallExecutor, this verifier would unsafely allow execution of any external contract call directly from the account proxy instance. A malicious executor could use this to initiate a 3rd ERC20 transfer to their own address, after satisfying the verified swap conditions.
Goerli Address: 0x79ee9ab99beb577ee852089588513192d63cbd14
brink-verifiers
The brink-verifiers repo contains contracts for Brink account signed messages. Verifiers are used to verify valid conditions for order execution, and to execute state changes that fulfill the conditions of an order.
LimitSwapVerifier
The LimitSwapVerifier.sol contract contains verifier functions for Brink limit swap orders. These are designed to be executed with metaPartialDelegateCall()
signed messages. The input, output, and expiry parameters are signed by account owners. Additional unsigned data is provided by the transaction executor to source the swap output.
Limit swap verifier functions are un-opinionated about how swaps are sourced. They will succeed as long as the required swap output is provided, and allow no more than the specified swap input to be transferred out of the account.
Note that the execution profit incentive for limit swaps is arbitrage based. The transaction executor can take a portion of input or output, as long as the verifier's requirements are met. There is a competitive incentive to source the swap efficiently, because a signed swap can only be executed once.
tokenToToken()
Supports ERC20 to ERC20 signed swaps.
ethToToken()
Supports ETH to ERC20 signed swaps.
tokenToEth()
Supports ERC20 to ETH signed swaps.
CancelVerifier
The CancelVerifier.sol contract contains a verifier function that invalidates an existing signed message, effectively cancelling the order associated with it. It writes to a bit
and bitmapIndex
which will invalidated any message that requires this bit
and bitmapIndex
to be empty. This can be used to cancel LimitSwapVerifier signed swaps, or any signed message type for a verifier that shares the same replay protection storage location.
Note that there is no profit incentive for executors to cancel on an owner's behalf. CancelVerifier.cancel() is designed to be called directly by account owners using Account.delegateCall().
Last updated