Smart Contracts
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
Was this helpful?