Smart Contracts

ContractAddressNetworks

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