Skip to main content

RootGaugeFactory

The RootGaugeFactory contract is used to deploy liquidity gauges on the Ethereum mainnet. These gauges can then be voted on to be added to the GaugeController. If successful, the gauges will be able to receive CRV emissions, which then can be bridged via a Bridger contract to the child chains ChildGauge.

RootGaugeFactory.vy

The source code for the RootGaugeFactory.vy contract can be found on GitHub. The contract is written using Vyper version 0.3.10.

The contract is deployed on Ethereum at 0x306A45a1478A000dC701A6e1f7a569afb8D9DCD6.


Deploying Gauges

The RootGaugeFactory allows the deployment of root gauges on Ethereum and child gauges on the child chains. Root gauges can only be deployed if there is a bridger contract set for the given chain ID, otherwise the chain is not supported.

Supported Chains

If get_bridger(chain_id) returns a non-zero address, the chain is supported and a RootGauge can be deployed.

>>> RootGaugeFactory.get_bridger(252)           # fraxtal
'0x0199429171bcE183048dccf1d5546Ca519EA9717' # supported

>>> RootGaugeFactory.get_bridger(7700) # canto
'0x0000000000000000000000000000000000000000' # not supported

deploy_gauge

RootGaugeFactory.deploy_gauge(_chain_id: uint256, _salt: bytes32) -> RootGauge

Function to deploy and initialize a new root gauge for a given chain ID. This function is @payable to allow for bridging costs. This function call reverts if there is no bridger contract set for the given _chain_id.

Returns: newly deployed gauge (RootGauge).

Emits: DeployedGauge event.

InputTypeDescription
_chain_iduint256Chain ID of the child gauge
_saltbytes32Salt for the child gauge
<>Source code
event DeployedGauge:
_implementation: indexed(address)
_chain_id: indexed(uint256)
_deployer: indexed(address)
_salt: bytes32
_gauge: RootGauge

interface RootGauge:
def bridger() -> Bridger: view
def initialize(_bridger: Bridger, _chain_id: uint256, _child: address): nonpayable
def transmit_emissions(): nonpayable

call_proxy: public(CallProxy)
get_bridger: public(HashMap[uint256, Bridger])
get_child_factory: public(HashMap[uint256, address])
get_child_implementation: public(HashMap[uint256, address])
get_implementation: public(address)

get_gauge: public(HashMap[uint256, RootGauge[max_value(uint256)]])
get_gauge_count: public(HashMap[uint256, uint256])
is_valid_gauge: public(HashMap[RootGauge, bool])

@payable
@external
def deploy_gauge(_chain_id: uint256, _salt: bytes32) -> RootGauge:
"""
@notice Deploy a root liquidity gauge
@param _chain_id The chain identifier of the counterpart child gauge
@param _salt A value to deterministically deploy a gauge
"""
bridger: Bridger = self.get_bridger[_chain_id]
assert bridger != empty(Bridger) # dev: chain id not supported

implementation: address = self.get_implementation
salt: bytes32 = keccak256(_abi_encode(_chain_id, _salt))
gauge: RootGauge = RootGauge(create_minimal_proxy_to(
implementation,
value=msg.value,
salt=salt,
))
child: address = self._get_child(_chain_id, salt)

idx: uint256 = self.get_gauge_count[_chain_id]
self.get_gauge[_chain_id][idx] = gauge
self.get_gauge_count[_chain_id] = idx + 1
self.is_valid_gauge[gauge] = True

gauge.initialize(bridger, _chain_id, child)

log DeployedGauge(implementation, _chain_id, msg.sender, _salt, gauge)
return gauge

@internal
def _get_child(_chain_id: uint256, salt: bytes32) -> address:
"""
@dev zkSync address derivation is ignored, so need to set child address through a vote manually
"""
child_factory: address = self.get_child_factory[_chain_id]
child_impl: bytes20 = convert(self.get_child_implementation[_chain_id], bytes20)

assert child_factory != empty(address) # dev: child factory not set
assert child_impl != empty(bytes20) # dev: child implementation not set

gauge_codehash: bytes32 = keccak256(
concat(0x602d3d8160093d39f3363d3d373d3d3d363d73, child_impl, 0x5af43d82803e903d91602b57fd5bf3))
digest: bytes32 = keccak256(concat(0xFF, convert(child_factory, bytes20), salt, gauge_codehash))
return convert(convert(digest, uint256) & convert(max_value(uint160), uint256), address)
Example

This example deploys a RootGauge for Fraxtal.

>>> RootGaugeFactory.deploy_gauge(252, '0x0000000000000000000000000000000000000000000000000000000000000000')

deploy_child_gauge

RootGaugeFactory.deploy_child_gauge(_chain_id: uint256, _lp_token: address, _salt: bytes32, _manager: address = msg.sender)
Important

This function will only work if a call_proxy is set. Otherwise, the function will revert.

Function to deploy a new child gauge on the child chain.

InputTypeDescription
_chain_iduint256Chain ID of the child gauge
_lp_tokenaddressAddress of the LP token
_saltbytes32Salt for the child gauge
_manageraddressAddress of the manager
<>Source code
call_proxy: public(CallProxy)
get_bridger: public(HashMap[uint256, Bridger])

@external
def deploy_child_gauge(_chain_id: uint256, _lp_token: address, _salt: bytes32, _manager: address = msg.sender):
bridger: Bridger = self.get_bridger[_chain_id]
assert bridger != empty(Bridger) # dev: chain id not supported

self.call_proxy.anyCall(
self,
_abi_encode(
_lp_token,
_salt,
_manager,
method_id=method_id("deploy_gauge(address,bytes32,address)")
),
empty(address),
_chain_id
)
Example

This example deploys a ChildGauge on Optimism for the 0xb757fc30bb2d96782188c45b6ebf20defe165ac7 LP token. 0x1234567890123456789012345678901234567890 is specified as the manager.

>>> RootGaugeFactory.deploy_child_gauge(10, '0xb757fc30bb2d96782188c45b6ebf20defe165ac7', '0x0000000000000000000000000000000000000000000000000000000000000000', '0x1234567890123456789012345678901234567890')

Transmitting Emissions

Once a root gauge has received emissions, they can be transmitted to the child gauge. This is done by calling the transmit_emissions function. Emissions can only be transmitted from the RootGaugeFactory.

Transmitting emissions is permissionless. Anyone can do it.

transmit_emissions

RootGaugeFactory.transmit_emissions(_gauge: RootGauge)

Function to mint and transmit emissions to the ChildGauge on the destination chain. This function is permissionless and can be called by anyone.

InputTypeDescription
_gaugeRootGaugeRoot gauge to transmit emissions for
<>Source code
interface Bridger:
def check(_addr: address) -> bool: view

interface RootGauge:
def transmit_emissions(): nonpayable

@external
def transmit_emissions(_gauge: RootGauge):
"""
@notice Call `transmit_emissions` on a root gauge
@dev Entrypoint to request emissions for a child gauge.
The way that gauges work, this can also be called on the root
chain without a request.
"""
# in most cases this will return True
# for special bridges *cough cough Multichain, we can only do
# one bridge per tx, therefore this will verify msg.sender in [tx.origin, self.call_proxy]
assert _gauge.bridger().check(msg.sender)
_gauge.transmit_emissions()
Example

This example transmits CRV emissions for the RootGauge at 0x6233394c3C466A45A505EFA4857489743168E9Fa to the ChildGauge on Fraxtal.

>>> RootGaugeFactory.transmit_emissions('0x6233394c3C466A45A505EFA4857489743168E9Fa')

get_bridger

RootGaugeFactory.get_bridger(_chain_id: uint256) -> Bridger: view

Getter for the bridger for a given chain ID. This contract is used to bridge CRV emissions to the ChildGauge.

Returns: bridger (Bridger).

InputTypeDescription
_chain_iduint256Chain ID of the child gauge
<>Source code
interface Bridger:
def check(_addr: address) -> bool: view

get_bridger: public(HashMap[uint256, Bridger])
Example
>>> RootGaugeFactory.get_bridger(252)
'0x0199429171bcE183048dccf1d5546Ca519EA9717'

Gauge Information

The RootGaugeFactory contract also provides a few getters to retrieve information about the deployed RootGauges.

get_gauge

RootGaugeFactory.get_gauge(_chain_id: uint256, _idx: uint256) -> RootGauge: view

Getter for gauges on a given chain ID and index.

Returns: gauge (address).

InputTypeDescription
_chain_iduint256Chain ID of the child gauge
_idxuint256Index of the gauge
<>Source code
get_gauge: public(HashMap[uint256, RootGauge[max_value(uint256)]])
Example
>>> RootGaugeFactory.get_gauge(252, 0)
'0x6233394c3C466A45A505EFA4857489743168E9Fa'

get_gauge_count

RootGaugeFactory.get_gauge_count(_chain_id: uint256) -> uint256: view

Getter to get the number of gauges for a given chain ID. This value is incremented by one for each new gauge deployed.

Returns: number of gauges (uint256).

InputTypeDescription
_chain_iduint256Chain ID of the child gauge
<>Source code
get_gauge_count: public(HashMap[uint256, uint256])
Example
>>> RootGaugeFactory.get_gauge_count(252)
3

is_valid_gauge

RootGaugeFactory.is_valid_gauge(_gauge: RootGauge) -> bool: view

Getter to check if a gauge is valid.

Returns: True if the gauge is valid, False otherwise (bool).

InputTypeDescription
_gaugeRootGaugeRoot gauge to check validity for
<>Source code
is_valid_gauge: public(HashMap[RootGauge, bool])
Example
>>> RootGaugeFactory.is_valid_gauge('0x6233394c3C466A45A505EFA4857489743168E9Fa')
True

Child and Root Implementations and Factories

The RootGaugeFactory contract also provides a few getters to retrieve information about the deployed ChildGauge implementations and factories.

get_implementation

RootGaugeFactory.get_implementation() -> address: view

Getter for the RootGauge implementation contract. This implementation contract is used to deploy new RootGauge contracts using Vyper's built-in create_minimal_proxy_to function.

Returns: implementation address (address).

<>Source code
get_implementation: public(address)
Example
>>> RootGaugeFactory.get_implementation()
'0x96720942F9fF22eFd8611F696E5333Fe3671717a'

set_implementation

RootGaugeFactory.set_implementation(_implementation: address)
Guarded Method

This function is only callable by the owner of the contract.

warning

Changing the implementation contract requires a change on all child factories.

Function to set the implementation contract of the RootGauge.

Emits: UpdateImplementation event.

InputTypeDescription
_implementationaddressAddress of the new implementation
<>Source code
event UpdateImplementation:
_old_implementation: address
_new_implementation: address

get_implementation: public(address)

owner: public(address)

@external
def set_implementation(_implementation: address):
"""
@notice Set the implementation
@dev Changing implementation require change on all child factories
@param _implementation The address of the implementation to use
"""
assert msg.sender == self.owner # dev: only owner

log UpdateImplementation(self.get_implementation, _implementation)
self.get_implementation = _implementation
Example

This example sets the RootGauge implementation to the address 0x6233394c3C466A45A505EFA4857489743168E9Fa.

>>> RootGaugeFactory.get_implementation()
'0x0000000000000000000000000000000000000000'

>>> RootGaugeFactory.set_implementation('0x6233394c3C466A45A505EFA4857489743168E9Fa')

>>> RootGaugeFactory.get_implementation()
'0x6233394c3C466A45A505EFA4857489743168E9Fa'

get_child_factory

RootGaugeFactory.get_child_factory(_chain_id: uint256) -> address: view

Getter for the child factory for a given chain ID.

Returns: child factory address (address).

InputTypeDescription
_chain_iduint256Chain ID of the child gauge
<>Source code
get_child_factory: public(HashMap[uint256, address])
Example
>>> RootGaugeFactory.get_child_factory(252)
'0x0B8D6B6CeFC7Aa1C2852442e518443B1b22e1C52'

get_child_implementation

RootGaugeFactory.get_child_implementation(_chain_id: uint256) -> address: view

Getter for the child implementation for a given chain ID.

Returns: child implementation address (address).

InputTypeDescription
_chain_iduint256Chain ID of the child gauge
<>Source code
get_child_implementation: public(HashMap[uint256, address])
Example
>>> RootGaugeFactory.get_child_implementation(252)
'0x6A611215540555A7feBCB64CB0Ed11Ac90F165Af'

set_child

RootGaugeFactory.set_child(_chain_id: uint256, _bridger: Bridger, _child_factory: address, _child_impl: address)
Guarded Method

This function is only callable by the owner of the contract.

Function to set different child properties for a given chain ID such as the bridger contract, ChildGaugeFactory and ChildGauge implementation.

Emits: ChildUpdated event.

InputTypeDescription
_chain_iduint256Chain ID of the child gauge
_bridgerBridgerBridger contract for the child gauge
_child_factoryaddressAddress of the new ChildGaugeFactory
_child_impladdressAddress of the new ChildGauge implementation
<>Source code
event ChildUpdated:
_chain_id: indexed(uint256)
_new_bridger: Bridger
_new_factory: address
_new_implementation: address

get_bridger: public(HashMap[uint256, Bridger])
get_child_factory: public(HashMap[uint256, address])
get_child_implementation: public(HashMap[uint256, address])

owner: public(address)

@external
def set_child(_chain_id: uint256, _bridger: Bridger, _child_factory: address, _child_impl: address):
"""
@notice Set the bridger for `_chain_id`
@param _chain_id The chain identifier to set the bridger for
@param _bridger The bridger contract to use
@param _child_factory Address of factory on L2 (needed in price derivation)
@param _child_impl Address of gauge implementation on L2 (needed in price derivation)
"""
assert msg.sender == self.owner # dev: only owner

log ChildUpdated(_chain_id, _bridger, _child_factory, _child_impl)
self.get_bridger[_chain_id] = _bridger
self.get_child_factory[_chain_id] = _child_factory
self.get_child_implementation[_chain_id] = _child_impl
Example

This example sets the following properties for chain ID 252:

  • Bridger: 0x0199429171bcE183048dccf1d5546Ca519EA9717
  • ChildGaugeFactory: 0x0B8D6B6CeFC7Aa1C2852442e518443B1b22e1C52
  • ChildGauge implementation: 0x6A611215540555A7feBCB64CB0Ed11Ac90F165Af
>>> RootGaugeFactory.set_child(252, '0x0199429171bcE183048dccf1d5546Ca519EA9717', '0x0B8D6B6CeFC7Aa1C2852442e518443B1b22e1C52', '0x6A611215540555A7feBCB64CB0Ed11Ac90F165Af')

Call Proxy

call_proxy

RootGaugeFactory.call_proxy() -> CallProxy: view

Getter to get the call proxy which is used for inter-chain communication. This variable is initially set at contract initialization and can be changed via the set_call_proxy function.

Returns: call proxy (CallProxy).

<>Source code
interface CallProxy:
def anyCall(
_to: address, _data: Bytes[1024], _fallback: address, _to_chain_id: uint256
): nonpayable

call_proxy: public(CallProxy)

@external
def __init__(_call_proxy: CallProxy, _owner: address):
self.call_proxy = _call_proxy
log UpdateCallProxy(empty(CallProxy), _call_proxy)

self.owner = _owner
log TransferOwnership(empty(address), _owner)
Example
>>> RootGaugeFactory.call_proxy()
'0x0000000000000000000000000000000000000000'

set_call_proxy

RootGaugeFactory.set_call_proxy(_call_proxy: CallProxy)
Guarded Method

This function is only callable by the owner of the contract.

Function to set the call proxy.

Emits: UpdateCallProxy event.

InputTypeDescription
_call_proxyCallProxyCall proxy to set
<>Source code
event UpdateCallProxy:
_old_call_proxy: CallProxy
_new_call_proxy: CallProxy

call_proxy: public(CallProxy)

@external
def set_call_proxy(_call_proxy: CallProxy):
"""
@notice Set CallProxy
@param _call_proxy Contract to use for inter-chain communication
"""
assert msg.sender == self.owner

self.call_proxy = _call_proxy
log UpdateCallProxy(empty(CallProxy), _call_proxy)
Example

This example sets the call proxy to 0x1234567890123456789012345678901234567890.

>>> RootGaugeFactory.call_proxy()
'0x0000000000000000000000000000000000000000'

>>> RootGaugeFactory.set_call_proxy('0x1234567890123456789012345678901234567890')

>>> RootGaugeFactory.call_proxy()
'0x1234567890123456789012345678901234567890'

Contract Ownership

For contract ownership details, see here.