Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🌊 Setup contracts-watr deployment #1251

Merged
merged 28 commits into from
Apr 14, 2023
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3bbb11f
Create `contracts-watr` package
abam-iksde Apr 7, 2023
e40c0b5
Add initialize method to contracts
abam-iksde Mar 1, 2023
6e30c4f
Deployment script
abam-iksde Mar 1, 2023
3935f93
Make test showOwner script
abam-iksde Mar 1, 2023
c28994b
Add network parameter and prompt for PRIVATE_KEY in script
abam-iksde Mar 2, 2023
c35a211
Add canary generation to build
abam-iksde Mar 2, 2023
21d9030
Change `pnpm` to `yarn`
abam-iksde Mar 2, 2023
2749876
Don't pass `args`
abam-iksde Mar 2, 2023
736abf8
Add `Registry` to deployment
abam-iksde Mar 2, 2023
c7e674d
Create `IClaimableOwnable` interface
abam-iksde Mar 2, 2023
cb8fc57
Remove constructor from interface
abam-iksde Mar 2, 2023
12f66a0
Implement `IClaimableOwnable` interface
abam-iksde Mar 2, 2023
f6500f9
Lint
abam-iksde Mar 2, 2023
c1a0894
Verify ownership with tests
abam-iksde Mar 2, 2023
d20ba3d
Verify registry with test
abam-iksde Mar 2, 2023
1cd84e2
Use `transferProxyOwnership`
abam-iksde Mar 2, 2023
720db28
Handle proxy ownership
abam-iksde Mar 2, 2023
80953f0
Add `upgradeTo`
abam-iksde Mar 2, 2023
4c12812
Use deployed implementation address
abam-iksde Mar 2, 2023
7dc8927
Add ownership transfer
abam-iksde Mar 2, 2023
c620a98
Refactor deployment
abam-iksde Mar 2, 2023
e80ab8c
Verify proxy ownership with test
abam-iksde Mar 2, 2023
b56a3b1
Match `TrueCurrencyWithProofOfReserve` to contracts-por
abam-iksde Apr 12, 2023
c48ce32
Match `TrueUSD.test.ts` to contracts-por
abam-iksde Apr 12, 2023
dc65658
Merge branch 'watr-package' into watr-deployment
abam-iksde Apr 12, 2023
b8e695d
Merge branch 'main' into watr-deployment
abam-iksde Apr 12, 2023
ea45bec
Extract `ClaimableOwnable` interface
abam-iksde Apr 13, 2023
ebf48c5
Merge branch 'main' into watr-deployment
tt-krzysztof Apr 14, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions packages/contracts-watr/contracts/TokenControllerV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ import {IProofOfReserveToken} from "./interface/IProofOfReserveToken.sol";
* which can only be refilled by the owner.
*/

interface HasOwner {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is handled better in #1245 : extracting the interface from ClaimableOwnable.

function claimOwnership() external;

function transferOwnership(address newOwner) external;
}

contract TokenControllerV3 {
using SafeMath for uint256;

Expand Down Expand Up @@ -183,6 +189,12 @@ contract TokenControllerV3 {
_;
}

function initialize() external {
require(!initialized, "already initialized");
owner = msg.sender;
initialized = true;
}

/**
* @dev Modifier throws if called by any account other than proofOfReserveEnabler or owner.
*/
Expand All @@ -209,6 +221,19 @@ contract TokenControllerV3 {
pendingOwner = address(0);
}

/*
========================================
token ownership
========================================
*/
function transferTrueCurrencyOwnership(address _newOwner) external onlyOwner {
HasOwner(address(token)).transferOwnership(_newOwner);
}

function claimTrueCurrencyOwnership() public onlyOwner {
HasOwner(address(token)).claimOwnership();
}

/*
========================================
proxy functions
Expand Down
6 changes: 6 additions & 0 deletions packages/contracts-watr/contracts/TrueCurrency.sol
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ abstract contract TrueCurrency is BurnableTokenWithBounds {
*/
event Mint(address indexed to, uint256 value);

function initialize() external {
require(!initialized, "already initialized");
owner = msg.sender;
initialized = true;
}

/**
* @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
Expand Down
6 changes: 0 additions & 6 deletions packages/contracts-watr/contracts/mocks/MockTrueCurrency.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,6 @@ contract MockTrueCurrency is TrueCurrencyWithProofOfReserve {
uint8 constant DECIMALS = 18;
uint8 constant ROUNDING = 2;

function initialize() external {
require(!initialized);
owner = msg.sender;
initialized = true;
}

function decimals() public pure override returns (uint8) {
return DECIMALS;
}
Expand Down
6 changes: 0 additions & 6 deletions packages/contracts-watr/contracts/mocks/RegistryMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,4 @@ contract RegistryMock is Registry {
owner = msg.sender;
emit OwnershipTransferred(address(0), owner);
}

function initialize() public {
require(!initialized, "already initialized");
owner = msg.sender;
initialized = true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,6 @@ interface HasOwner {
contract TokenControllerMock is TokenControllerV3 {
event TransferChild(address indexed child, address indexed newOwner);

// initalize controller. useful for tests
function initialize() external {
require(!initialized, "already initialized");
owner = msg.sender;
initialized = true;
}

// initialize with paramaters. useful for tests
// sets initial paramaters on testnet
function initializeWithParams(TrueCurrency _token, Registry _registry) external {
Expand Down
6 changes: 6 additions & 0 deletions packages/contracts-watr/contracts/test/Registry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ contract Registry {
event StartSubscription(bytes32 indexed attribute, RegistryClone indexed subscriber);
event StopSubscription(bytes32 indexed attribute, RegistryClone indexed subscriber);

function initialize() external {
require(!initialized, "already initialized");
owner = msg.sender;
initialized = true;
}

// Allows a write if either a) the writer is that Registry's owner, or
// b) the writer is writing to attribute foo and that writer already has
// the canWriteTo-foo attribute set (in that same Registry)
Expand Down
5 changes: 3 additions & 2 deletions packages/contracts-watr/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@
"prebuild": "yarn clean",
"build:hardhat": "hardhat compile",
"build:typechain": "typechain --target ethers-v5 --out-dir build/types 'build/*.json'",
"build": "yarn build:hardhat && yarn build:typechain && mars",
"build:canary": "git log --pretty=format:'%H' -n 1 > ./build/canary.hash",
"build": "yarn build:hardhat && yarn build:typechain && mars && yarn build:canary",
"preflatten": "rm -rf custom_flatten",
"flatten": "waffle flatten .waffle.json",
"test": "mocha 'test/**/*.test.ts'",
"checks": "yarn lint && yarn test",
"deploy": "./utils/bash/marsDeploy.sh"
"deploy": "./utils/bash/marsDeploy.sh scripts/deployment/deploy.ts"
},
"dependencies": {
"ethereum-mars": "^0.2.6-dev.eb75a27",
Expand Down
27 changes: 21 additions & 6 deletions packages/contracts-watr/scripts/deployment/baseDeployment.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
import {contract, createProxy, ExecuteOptions} from "ethereum-mars";
import {OwnedUpgradeabilityProxy, TokenControllerV3} from "../../build/artifacts";
import { TrueUSD } from '../../build/artifacts'
import { deployToken } from './deployToken'
import { deployTokenController, setupTokenController } from './deployTokenController'
import { deployRegistry } from './deployRegistry'

export function baseDeployment(deployer: string, options: ExecuteOptions) {
const proxy = createProxy(OwnedUpgradeabilityProxy)
export function baseDeployment() {
const {
implementation: tokenControllerImplementation,
proxy: tokenControllerProxy,
} = deployTokenController()

const tokenControllerImplementation = contract(TokenControllerV3)
const tokenControllerProxy = proxy(tokenControllerImplementation)
const { implementation: trueUSDImplementation, proxy: trueUSDProxy } = deployToken(TrueUSD, tokenControllerProxy)

const {
implementation: registryImplementation,
proxy: registryProxy,
} = deployRegistry()

setupTokenController(tokenControllerProxy, trueUSDProxy, registryProxy)

return {
trueUSDImplementation,
trueUSDProxy,
tokenControllerImplementation,
tokenControllerProxy,
registryImplementation,
registryProxy,
}
}
6 changes: 3 additions & 3 deletions packages/contracts-watr/scripts/deployment/deploy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {deploy} from "ethereum-mars";
import {baseDeployment} from "./baseDeployment";
import { deploy } from 'ethereum-mars'
import { baseDeployment } from './baseDeployment'

deploy({ verify: true }, baseDeployment)
deploy({ verify: false }, baseDeployment)
16 changes: 16 additions & 0 deletions packages/contracts-watr/scripts/deployment/deployRegistry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { contract, createProxy } from 'ethereum-mars'
import { OwnedUpgradeabilityProxy, Registry } from '../../build/artifacts'

export function deployRegistry() {
const ownedUpgradabilityProxy = createProxy(OwnedUpgradeabilityProxy)

const implementation = contract(Registry)
const proxy = ownedUpgradabilityProxy(implementation, (registry) => {
registry.initialize()
})

return {
implementation,
proxy,
}
}
25 changes: 25 additions & 0 deletions packages/contracts-watr/scripts/deployment/deployToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { AddressLike, ArtifactFrom, contract, createProxy, Transaction, TransactionOverrides } from 'ethereum-mars'
import { OwnedUpgradeabilityProxy } from '../../build/artifacts'
import { NoParams } from 'ethereum-mars/build/src/syntax/contract'

type Token = NoParams & {
initialize(options?: TransactionOverrides): Transaction,
transferOwnership(newOwner: AddressLike, options?: TransactionOverrides): Transaction,
}

export function deployToken<T extends Token>(tokenArtifact: ArtifactFrom<T>, controller: AddressLike) {
const implementation = contract(tokenArtifact)
const tokenProxy = createProxy(OwnedUpgradeabilityProxy, (proxy) => {
proxy.upgradeTo(implementation)
proxy.transferProxyOwnership(controller)
})
const proxy = tokenProxy(implementation, (token) => {
token.initialize()
token.transferOwnership(controller)
})

return {
implementation,
proxy,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { AddressLike, contract, createProxy } from 'ethereum-mars'
import { OwnedUpgradeabilityProxy, TokenControllerV3 } from '../../build/artifacts'

export function deployTokenController() {
const ownedUpgradabilityProxy = createProxy(OwnedUpgradeabilityProxy)

const implementation = contract(TokenControllerV3)
const proxy = ownedUpgradabilityProxy(implementation, (controller) => {
controller.initialize()
})

return {
implementation,
proxy,
}
}

export function setupTokenController(controller: ReturnType<typeof deployTokenController>['proxy'], token: AddressLike, registry: AddressLike) {
controller.setRegistry(registry)
controller.setToken(token)
controller.claimTrueCurrencyProxyOwnership()
controller.claimTrueCurrencyOwnership()
}
55 changes: 55 additions & 0 deletions packages/contracts-watr/test/verifyDeployment.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Contract } from 'ethers'
import { JsonRpcProvider } from '@ethersproject/providers'
import { expect } from 'chai'
import { unknown as deployments } from '../deployments-watr_local.json'

describe('verify deployment', () => {
const provider = new JsonRpcProvider('http://127.0.0.1:8822', 688)
const ownableInterface = [
'function owner() view returns (address)',
'function proxyOwner() view returns (address)',
]
const controllerInterface = [
...ownableInterface,
'function token() view returns (address)',
'function registry() view returns (address)',
]

const ownableContract = (address: string) => new Contract(
address,
controllerInterface,
provider,
)

const controllerContract = (address: string) => new Contract(
address,
controllerInterface,
provider,
)

it('controller owns currency', async () => {
const contract = ownableContract(deployments.trueUSD_proxy.address)

const owner = await contract.owner()
const proxyOwner = await contract.proxyOwner()

expect(owner).to.eq(deployments.tokenControllerV3_proxy.address)
expect(proxyOwner).to.eq(deployments.tokenControllerV3_proxy.address)
})

it('controller has currency set as token', async () => {
const contract = controllerContract(deployments.tokenControllerV3_proxy.address)

const token = await contract.token()

expect(token).to.eq(deployments.trueUSD_proxy.address)
})

it('controller has registry set correctly', async () => {
const contract = controllerContract(deployments.tokenControllerV3_proxy.address)

const token = await contract.registry()

expect(token).to.eq(deployments.registry_proxy.address)
})
})
86 changes: 76 additions & 10 deletions packages/contracts-watr/utils/bash/marsDeploy.sh
Original file line number Diff line number Diff line change
@@ -1,16 +1,83 @@
PRIVATE_KEY=0xe1ad20aae239ccbb609aa537d515dc9d53c5936ea67d8acc9fe0618925279f7d
export PRIVATE_KEY
#!/bin/bash
set -eu

DEPLOY_SCRIPT="scripts/deployment/deploy.ts"
# Example usage:
# $ ./utils/bash/marsDeploy.sh scripts/deployment/deploy.ts --network optimism_goerli
# PRIVATE_KEY=0x123..64

# Consume the first argument as a path to the Mars deploy script.
# All other command line arguments get forwarded to Mars.
DEPLOY_SCRIPT="$1"
shift 1

network=''
network_name=''
args="$@"
dry_run='false'
force='false'

mkdir -p cache
while [[ "$@" ]]; do
case "$1" in
--network)
if [ "$2" ]; then
if [[ "$2" == 'local' ]]; then
network_name='watr_local'
network='http://127.0.0.1:8822'
else
echo "Error: invalid network parameter: '$2'"
exit 1
fi
shift 1
fi
;;
--dry-run)
dry_run='true'
;;
--force)
force='true'
;;
-?)
# ignore
;;
esac
shift 1
done

if [[ "${dry_run}" == 'false' ]]; then
if [[ "$(git status --porcelain)" ]]; then
echo "Error: git working directory must be empty to run deploy script."
exit 1
fi

if [[ "$(git log --pretty=format:'%H' -n 1)" != "$(cat ./build/canary.hash)" ]]; then
echo "Error: Build canary does not match current commit hash. Please run yarn run build."
exit 1
fi
fi

network='watr'
# Skip prompt if PRIVATE_KEY variable already exists
if [[ -z "${PRIVATE_KEY:-}" ]]; then
# Prompt the user for a PRIVATE_KEY without echoing to bash output.
# Then export PRIVATE_KEY to an environment variable that won't get
# leaked to bash history.
#
# WARNING: environment variables are still leaked to the process table
# while a process is running, and hence visible in a call to `ps -E`.
echo "Enter a private key (0x{64 hex chars}) for contract deployment,"
echo "or leave blank if performing a dry run without authorization."
read -s -p "PRIVATE_KEY=" PRIVATE_KEY
export PRIVATE_KEY
fi

if [[ "${network}" == '' ]]; then
echo "Error: No network provided"
exit 1
fi

mkdir -p cache

# Log file name
network_log="-${network}"
network_log="-${network_name}"
target_file_name="$(basename -- ${DEPLOY_SCRIPT})"
target_log="-${target_file_name%.*}"
dry_run_log=''
Expand All @@ -19,10 +86,9 @@ if [[ "${dry_run}" == 'true' ]]; then
fi
timestamp_log="-$(date +%s)"

pnpm mars
yarn mars
ts-node ${DEPLOY_SCRIPT} \
--waffle-config ./.waffle.json \
${args} \
--network "http://127.0.0.1:8822" \
--out-file "deployments-${network}.json" \
--network "$network" \
--out-file "deployments-${network_name}.json" \
--log "./cache/deploy${network_log}${target_log}${dry_run_log}${timestamp_log}.log"