/uxd-evm

Primary LanguageTypeScriptOtherNOASSERTION

UXD ETHEREUM

This repository contains the smart contracts that implement the UXD protocol on Ethereum and EVM compatible chains. Contracts are written in Solidity and deployed using the Hardhat development environment.

Coding Conventions

The coding style should follow the official solidity style guide.

Setup

To set up the project, you must first install the dependencies using npm.

npm i

Compile the contracts

To compile the contracts, run:

npx hardhat compile

Environment Variables

Private keys, Etherscan and Alchemy API keys are needed to run the scripts to interact with the contracts. These are defined in environment variables in the .env file. An example of this file can be found in .env.example. Copy this file then replace the values with your own:

cp ./.env.example .env

Scripts

The hardhat scripts under the ./scripts folder can be used to deploy the contracts to a test or live network. Check the hardhat.config.ts file for the list and names of available networks. End to end workflows and tests can only be run on one of the live networks as they integrate with external contracts deployed to those networks.

Note: The scripts under the ./scripts/optimism/ folder are only intended to be run on Optimism (mainnet or goerli). Likewise scripts under ./scripts/arbitrum are used to deploy the contracts to Arbitrum (mainnet and testnet).

Deployment and Contract Configuration

To deploy the core contracts:

npx hardhat run ./scripts/optimism/1_deploy_core.ts --network optimismgoerli
npx hardhat run ./scripts/optimism/2_deploy_perp_depository.ts --network optimismgoerli

These scripts also initialize the contracts to a state where they are ready for interaction by users.

Note: The default owner of the contracts is the deployer address. This account is used to call restricted functions to set up the contracts for use. After initialization, ownership must be transferred to the governance contracts.

Minting and redeeming UXD

There are additional scripts which can be used to mint and redeem UXD. For example, to mint UXD on optimism goerli network with WETH as collateral, run:

npx hardhat run ./scripts/optimism/4_mint.ts --network optimismgoerli

The caller's account must have enough collateral (WETH or USDC) to mint.

To redeem UXD for USDC on the Arbitrum Goerli testnet:

npx hardhat run ./scripts/arbitrum/4_redeem.ts --network arbitrumgoerli

The caller's account must have enough UXD to redeem.

Governance

Scripts relating to governance functions are found under the Governance folder.

Deploying Governance Contracts

The default contract owner, which is the deployer addrss is used to set up the contracts in development and testing environments. For DevNet and Live environments, governance contracts must be deployed and ownership of UXDController, PerpDepository, UXPToken and UXDCouncilToken contracts transferred to the UXDTimelockController instance.

There are two models for governance:

  1. Governance Council: Voting power is through the UXDCouncilToken.
  2. Public Governance: This is intended to be later in the product lifecycle, where public votes determine the protocol direction. Voting power here is through the UXPToken.

Both models use the same governance structure. The only differnce being the governance token.

To deploy the UXD Council token governance, run:

npx hardhat run ./scripts/governance/1_deploy_governance_council.ts --network optimismgoerli

To deploy the public UXP token governance, run:

npx hardhat run ./scripts/governance/1_deploy_governance_public.ts --network optimismgoerli

In DevNet and MainNet, contract ownership must be transferred to the appropriate governance contracts.

To transfer ownership to the governance council contracts:

npx hardhat run ./scripts/governance/2_transfer_ownership.ts --network optimismgoerli

Once ownership is transferred to the council token, further changes including transferring ownership to public governance can only be executed by passing governance proposals.

Creating Governance Proposals

Governance proposals can be created by running the scripts in the proposal scripts in the Governance folder.

Executing Governance Proposals

Once governance proposals pass, a frontend such as Tally can be used to execute proposals. Alternatively, the script 20_execute_proposal.ts can be used.

Note: This script will have to be edited to match the parameters of the proposal to be executed.

Cross chain token transfers

UXD and UXP tokens are omnichain fungible tokens (OFTs) which can be transferred from/to any of the chains the protocol is deployed to. After deployment of the token contracts, cross-chain functionality must be enabled to support cross chain transfers.

To send tokens from chain A to chain B, chain A the core contracts must be deployed to both chains. Secondly, chain A must be set as a trusted remote of chain B and vice versa. This can be done using the hardhat tasks setUxdTrustedRemote and setUxpTrustedRemote.

npx hardhat setUxdTrustedRemote --network optimismgoerli --dstchain arbitrumgoerli
npx hardhat setUxdTrustedRemote --network arbitrumgoerli --dstchain optimismgoerli

Cross chain UXD token transfers should now be enabled on the specified networks.

To send 1 UXD from optimism to arbitrum for example:

npx hardhat sendUxdCrossChain --network optimismgoerli --dstchain arbitrumgoerli --amount 1.0

Upgrading Contracts

The UXDController, PerpDepository and RageDnDepository contracts are UUPS upgradeable contracts, thus, are self upgradeable. To upgrade the contracts, the new instance must first be deployed, then the call the upgradeTo(address) function to upgrade to the new instance.

Deploy the new contract instances using deploy scripts in scripts/upgrades folder. In DevNet and MainNet, installing the new instance must be done through creating a governance proposal.

Testing

Tests are written using the Mocha testing framework and Chai assertion library.

To run tests:

npx hardhat test

For a test coverage report:

npx hardhat coverage