Skip to content

Instantly share code, notes, and snippets.

@calebrate
Created July 21, 2022 20:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save calebrate/3756313e261d4eafafb6aad02bcfe8ef to your computer and use it in GitHub Desktop.
Save calebrate/3756313e261d4eafafb6aad02bcfe8ef to your computer and use it in GitHub Desktop.
Uniswap Governance Messaging over Wormhole

Uniswap Governance Messaging over Wormhole

Architecture Diagram

image

Description

We are proposing a lightweight protocol for messaging Uniswap governance decisions from Ethereum to other chains.

The goal of this architecture is to use existing tools and battle-tested infrastructure wherever possible.

Governance still happens using the existing GovernerBeta contract and Uniswap’s UI.

The GovernerBeta feeds into the GovernanceMessenger contract on Ethereum, which serialises the requests as defined in the types below and passes them into the Ethereum Wormhole endpoint.

Wormhole produces a VAA (verifiable action approval) for this message, which can now be submitted to the GovernanceMessageReceiver contract on the target chain. The GovernanceMessageReceiver contract verifies the authenticity of the VAA using the local wormhole endpoint and passes the instruction into a local Timelock contract, which owns the local Factory.

A Timelock contract is put on each individual chain to add an optional layer of control over the universal bridge into the system. As an extra signer, the chains native bridge can act as an escape hatch by which pending proposals in the Timelock can be canceled.

Detailed design

Types

interface IUniGovTypes {
	// Factory Governance Actions
	struct SetFactoryOwner {
		uint16 chainId;
		address factoryAddress;
		address newOwner;
	}
	
	struct EnableFeeAmount {
		uint16 chainId;
		address factoryAddress;
		uint24 fee;
		int24 tickSpacing;
	}
	
	// Pool Governance Actions
	struct setProtocolFee {
		uint16 chainId;
		address poolAddress;
		uint8 feeProtocol0;
		uint8 feeProtocol1;
	}
	
	struct collectProtocolFee {
		uint16 chainId;
		address poolAddress;

		address recipient;
		uint128 amount0Requested;
		uint128 amount1Requested;
	}
	
	// General Timelock Actions
	struct QueueTransaction {
		uint16 chainId;
		address target;
		uint256 value;
		bytes data;
	}
	
	struct CancelPendingTransaction {
		uint16 chainId;
		bytes32 id;
	}

}

Endpoints

GovernanceMessenger Contract

interface IGovernanceMessenger {

	/// @notice Change the ownership of a factory contract on a specific chain
	/// @param chainId The chainId this should get executed on
	/// @param factoryAddress The address of the factory on that chain
	/// @param newOwner The address of the new owner
	function setFactoryOwner(
		uint16 chainId;

		address factoryAddress;
		address newOwner;
	) external;
	
	/// @notice Enable a fee amount on a set of chains
	/// @param chainId The chainId this should get executed on
	/// @param factoryAddress The address of the factory on that chain
	/// @param fee The fee amount to enable, denominated in hundredths of a bip (i.e. 1e-6)
	/// @param tickSpacing The spacing between ticks to be enforced for all pools created with the given fee amount
	function enableFeeAmount(
		uint16 chainId;

		address factoryAddress;
		uint24 fee;
		int24 tickSpacing;
	) external;
	
	/// @notice Set the denominator of the protocol's % share of the fees
	/// @param chainId The chainId this should get executed on
	/// @param poolAddress The address of the pool to execute the governance action on
  /// @param feeProtocol0 new protocol fee for token0 of the pool
  /// @param feeProtocol1 new protocol fee for token1 of the pool
	struct setProtocolFee {
		uint16 chainId;

		address poolAddress;
		uint8 feeProtocol0;
		uint8 feeProtocol1;
	}
	
	/// @notice Collect the protocol fee accrued to the pool
	/// @param chainId The chainId this should get executed on
	/// @param poolAddress The address of the pool to execute the governance action on
	/// @param recipient The address to which collected protocol fees should be sent (on the target chain)
  /// @param amount0Requested The maximum amount of token0 to send, can be 0 to collect fees in only token1
  /// @param amount1Requested The maximum amount of token1 to send, can be 0 to collect fees in only token0
	struct collectProtocolFee {
		uint16 chainId;

		address poolAddress;
		address recipient;
		uint128 amount0Requested;
		uint128 amount1Requested;
	}
	
	/// @notice Queue a transaction on the timelock contract
	/// @param chainId The chainId this should get executed on
	/// @param target The address to call
	/// @param value to pass with the call
  /// @param data The data to pass with the call
  struct queueTransaction {
		uint16 chainId;

		address target;
		uint256 value;
		bytes data;
	}
	
	/// @notice Cancel a transaction on the timelock contract
	/// @param chainId The chainId this should get executed on
	/// @param id The id of the call to cancel
	struct cancelPendingTransaction {
		uint16 chainId;

		bytes32 id;
	}
}

GovernanceMessageReceiver Contract

interface IGovernanceMessenger {

	/// @notice Submit a VAA containing a serialised governance action to the Timelock contract
	/// @param vaa The VAA from the GovernanceMessenger contract
	function submitActionToTimelock(
		bytes vaa
	) external;
	
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment