Skip to content

Commit

Permalink
🎡 Multisig leveraging dry-runs (#85)
Browse files Browse the repository at this point in the history
* Dry-run like multisig - config and signer

* Simplify multisig

Leverage 1) dry-run 2) tx batch replication to safe

* Log text cleanup, colors

Removing unnecessary code

* Updating addresses of deployed contracts

* Fix logging tests

* Fix example project - logic

* Fix checking for if contract code changed

* Remove code not needed after simplification

* Fix linting

* Add changeset

* Rename fn after vanruch remark
  • Loading branch information
marcin-trust authored Jan 26, 2022
1 parent e3fbe04 commit 3d3797d
Show file tree
Hide file tree
Showing 28 changed files with 260 additions and 649 deletions.
5 changes: 5 additions & 0 deletions .changeset/gorgeous-moons-deny.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'ethereum-mars': patch
---

Rework multisig on dry-run foundation
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ docs/source/_build
.vscode
cache
.nyc_output
tsconfig.tsbuildinfo
81 changes: 18 additions & 63 deletions packages/example/deployments.json
Original file line number Diff line number Diff line change
@@ -1,84 +1,39 @@
{
"kovan": {
"dai": {
"txHash": "0x7c058a68e08739b173f5acace0e6fa29dd95aafc5601733fef46bfe4de37ca6f",
"address": "0x0a3BDD55AbA03BE21365A164bac541845f2412AF"
},
"btc": {
"multisig": true,
"txHash": "0x1234abcd....",
"address": "0x28562C8c670BdA5AA186156Fff49F07C2Ff0124F"
},
"market": {
"multisig": true,
"txHash": "0x1234abcd....",
"address": "0x51Ef1C90C02bE44d8609EAc9A3Fe30b7B907fB9c"
},
"dai_proxy": {
"txHash": "0xe2b80e23d3a90278e0f0e623d74802c00084872e15ad5950480d2f0004c4f6fc",
"address": "0xD6c9fb590c15EA0B8FF016934488459E1578C66c"
},
"btc_proxy": {
"txHash": "0x28e6d21a3e8f224967ba3a7d09c9a1298f81f8cad450085949530826399727a9",
"address": "0x92146cB5fCC0fCA0d1A0E24f28Ebc447D73983E1"
}
},
"rinkeby": {
"preProxied": {
"address": "0x4e2A5FBcc6F4D9084078DD22572F68508db58cde",
"multisig": true
},
"preProxied_proxy": {
"address": "0x6477449B2DEe45061A07f50D1ADf4F14745250e2",
"multisig": true
},
"firstImpl": {
"address": "0x1f9b25e82411d6833258E12299D415E30070349b",
"multisig": true
},
"secondImpl": {
"address": "0x2dAF1283F1fec9430c7B2BE3aC6de91316e2c13F",
"multisig": true
},
"firstImpl_proxy": {
"address": "0xD16e947D18aa823891c364Ca6C3859dcB810F94f",
"txHash": "0x1ea5d560f381f1e01dff325155a890028f3e78cc03eb8e17809abf924d9873ea",
"address": "0xf303e0312e5bC76B88CC4128768F0c7CdA9854c2",
"multisig": true
},
"secondImpl_proxy": {
"address": "0xd5BfA8d7aE023c7a400c75F438C44CD0298E1B66",
"txHash": "0x719616a5ecbc1e25b1b9daaab17aaf888790d341125136fdd48e9c82e960b47b",
"address": "0x4D800bd33970537c6BE38267FAc39b30a49b3098",
"multisig": true
},
"firstBare": {
"address": "0x7d78C83E8D44282644443585DF17777a897a1eCc",
"txHash": "0xb5280556a3364f0e0522684e090c5ce5df46f58547a907804df748ca39a47ece",
"address": "0x606726A56294a0f3b6dFDDaCA45F1bb2a0769449",
"multisig": true
},
"secondBare": {
"address": "0xd08E76c8bE999577af1a51DA63D7c5be1407038f",
"txHash": "0xba6dfc4447d35eb2190aab14c0467609230bc61b32893d6cef760e98bccfe301",
"address": "0x5bE964d739e9934b7BdF76D00f6A28d491d8BEb1",
"multisig": true
},
"firstMarket": {
"address": "0x2AD49DfB0F0F2Eb12722cc9F4De662bDE1720fA7",
"market": {
"txHash": "0x43742bc4f33a033ef409bb498d83c4b6410f93dc4f62fc64acaf8d26019fbb3d",
"address": "0x2B39d9F9173A0BD90f4b91895140788d5789995F",
"multisig": true
},
"secondMarket": {
"address": "0x1D68D6dBf3e1905c5e60cFe75EEb372349425ca2",
"firstImpl": {
"txHash": "0x2ab7fe540a49d0fca122b80ad1243b8eae907e5b6e4aef2343cc1bc5f48b2471",
"address": "0x7E080543BBCBB2549CA9D8C3A7f8cec82D635D86",
"multisig": true
},
"_multisig": {
"Contract creation, proxying and initialization": {
"id": "0xa3347af848a3ba5824a3b22fd9d57c64787999091c77a4b7b7cf2e0fc933a2dd",
"state": "EXECUTED",
"txHash": "0xde1973d64ea04fd7047c9801cc18e19fd97bf7e6f05e49251878053eacdd88b8"
},
"Conditional initialization": {
"id": "0x99f9ab9fe81f6e1d2a2ac124597dce3a2feed808a78d00e945af8a5a8181c522",
"state": "EXECUTED",
"txHash": "0x8abc9b1742e9315965bbde886a9e6920dea9fd1026b17a0efac2ca65a70bdd23"
},
"Cross-dependant initialization multisig": {
"id": "0xca09e75db41176d9e5795c1b3a85b5e848ccfbc9294d93a8495ef72270d6f9cf",
"state": "PROPOSED"
}
"secondImpl": {
"txHash": "0xe6d469862e639df2e5d81546f86b3444a5a5e7f032c531ffa73adceaf134618a",
"address": "0x676DE87a94113a956bf4F08CCa1F430969B49e64",
"multisig": true
}
}
}
6 changes: 3 additions & 3 deletions packages/example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
"lint:fix": "yarn lint:prettier --write && yarn lint:eslint --fix",
"lint:eslint": "eslint './{src,test}/**/*.ts'",
"lint:prettier": "prettier './{src,test}/**/*.ts'",
"build": "yarn waffle && mars",
"build": "yarn waffle && mars && tsc",
"deploy": "ts-node src/index.ts",
"deploy:multisig": "ts-node src/multisig.ts",
"test": "echo tests",
"cover": "echo tests"
"test": "echo no tests here",
"cover": "echo no tests here"
},
"dependencies": {
"ethereum-mars": "0.x"
Expand Down
78 changes: 22 additions & 56 deletions packages/example/src/multisig.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,24 @@
import { contract, createProxy, debug, deploy, Options, runIf } from 'ethereum-mars'
import { Market, Token, UpgradeabilityProxy } from '../build/artifacts'
import ganache from 'ganache-core'
import { Wallet } from 'ethers'
import { multisig } from 'ethereum-mars/build/src/syntax/multisig'
import { logConfig } from 'ethereum-mars/build/src/logging'

const inMemoryRunOptions = ((): Options => {
const wallet = Wallet.createRandom()
const provider = ganache.provider({
locked: true,
gasPrice: '0',
accounts: [{ secretKey: wallet.privateKey, balance: '100000000000000000000' }],
})
return {
dryRun: true,
network: provider,
fromAddress: wallet.address,
}
})()

const options = process.argv.indexOf('--network') < 0 ? inMemoryRunOptions : {}
options.multisigGnosisSafe = '0x8772CD484C059EC5c61459a0abb5A45ece16701f'
options.multisigGnosisServiceUri = 'https://safe-transaction.rinkeby.gnosis.io'
logConfig.mode.console = true
const options = {
network: 'rinkeby',
logFile: 'tx.log',
noConfirm: true,
multisig: true,
multisigGnosisSafe: '0x8772CD484C059EC5c61459a0abb5A45ece16701f',
multisigGnosisServiceUri: 'https://safe-transaction.rinkeby.gnosis.io',
} as Options
logConfig.mode.console = false

// based upon https://github.com/trusttoken/smart-contracts/blob/main/deploy/truefi2.ts
// to reproduce complexity level of the standard deployment script
deploy(options, (deployer, config) => {
deploy(options, (deployer) => {
debug(`Deployer is ${deployer}`)

const isRinkeby = config.networkName === 'rinkeby'
const useMultisig = isRinkeby
const proxyCreationPhase = true

const creationMultisig = useMultisig ? multisig('Contract creation, proxying and initialization') : undefined

const proxy = createProxy(UpgradeabilityProxy)

// existing contracts, already deployed
const wellKnown = isRinkeby ? '0x124BCA8F86a1eC3b84d68BEDB0Cc640D301C3eEF' : contract('wellKnown', Token)
const preProxied = proxy(contract('preProxied', Token), { noImplUpgrade: proxyCreationPhase })

// new contract implementations
const firstImpl = contract('firstImpl', Token)
const secondImpl = contract('secondImpl', Token)
Expand All @@ -49,20 +27,15 @@ deploy(options, (deployer, config) => {
const firstProxied = proxy(firstImpl, {
onInitialize: 'initialize',
params: [112233],
noImplUpgrade: proxyCreationPhase,
})
const secondProxied = proxy(secondImpl, { noImplUpgrade: proxyCreationPhase })
const secondProxied = proxy(secondImpl)

// new bare contracts
const firstBare = contract('firstBare', Token)
const secondBare = contract('secondBare', Token)

// contracts that depend on previous deployments in order to construct
const firstMarket = contract('firstMarket', Market, [wellKnown, preProxied])
const secondMarket = contract('secondMarket', Market, [firstProxied, secondBare])

creationMultisig?.propose()
const conditionalInitMultisig = useMultisig ? multisig('Conditional initialization') : undefined
const market = contract('market', Market, [firstProxied, secondBare])

// contract initialization
runIf(firstProxied.isInitialized().not(), () => {
Expand All @@ -77,24 +50,17 @@ deploy(options, (deployer, config) => {
runIf(secondBare.val().equals(0), () => {
secondBare.initialize(222)
})
// the following one is to show initialization has not happened in the multisig yet
// we need to move the below to a separate multisig group
runIf(secondBare.val().equals(222), () => {
secondBare.initialize(333)
})

conditionalInitMultisig?.propose()
const crossDependantInitializationMultisig = useMultisig
? multisig('Cross-dependant initialization multisig')
: undefined

// to show dependencies on initialization of other contracts
firstProxied.approve(secondMarket, 50000)
secondBare.approve(secondMarket, 50000)
secondMarket.supply(11111, 22222)
runIf(firstMarket.xToken().equals(0).not().and(secondBare.val().equals(0).not()), () => {
secondMarket.supply(33333, 22222)
})

crossDependantInitializationMultisig?.propose()
debug('Balance in firstProxied', firstProxied.balanceOf(deployer))
debug('Balance in secondBare', secondBare.balanceOf(deployer))
firstProxied.approve(market, 11111)
secondBare.approve(market, 22222)
runIf(
firstProxied.allowance(deployer, market).gte(11111).and(secondBare.allowance(deployer, market).gte(22222)),
() => {
market.supply(11111, 22222)
}
)
}).then()
10 changes: 10 additions & 0 deletions packages/mars/deployments.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
{
"rinkeby": {
"impl_proxy": {
"txHash": "0xccdb5085057d2c66c42d5c48ebe011149eeee1ed7ca06c4202fd9d58d88d01ee",
"address": "0xCBF89991D0FF2b4CfB971a1F2604143225068072",
"multisig": true
},
"impl": {
"txHash": "0xd394543f4e0cb585ec7a0571b08ee87a2d331598565aeb3ed01b56f4b36a8e62",
"address": "0x030dA9f941AfB71646F25B3768DB3527cF1fCc9C",
"multisig": true
}
}
}
13 changes: 0 additions & 13 deletions packages/mars/src/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { AbiConstructorEntry, AbiFunctionEntry } from './abi'
import { ArtifactFrom } from './syntax/artifact'
import { BooleanLike, Future } from './values'
import { TransactionOptions } from './execute/sendTransaction'
import { MultisigBuilder } from './multisig'

export type Action =
| DeployAction
Expand All @@ -12,8 +11,6 @@ export type Action =
| StartConditionalAction
| EndConditionalAction
| DebugAction
| MultisigActionStart
| MultisigActionEnd
| GetStorageAction

export interface DeployAction {
Expand All @@ -25,7 +22,6 @@ export interface DeployAction {
options: Partial<TransactionOptions>
resolve: (address: string) => void
skipUpgrade: boolean
multisig?: MultisigBuilder
}

export interface StartConditionalAction {
Expand Down Expand Up @@ -53,7 +49,6 @@ export interface TransactionAction {
params: any[]
options: Partial<TransactionOptions>
resolve: (value: any) => void
multisig?: MultisigBuilder
}

export interface EncodeAction {
Expand All @@ -68,14 +63,6 @@ export interface DebugAction {
messages: any[]
}

export interface MultisigActionStart {
type: 'MULTISIG_START'
}

export interface MultisigActionEnd {
type: 'MULTISIG_END'
}

export interface GetStorageAction {
type: 'GET_STORAGE_AT'
address: Future<string>
Expand Down
5 changes: 2 additions & 3 deletions packages/mars/src/context.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Action } from './actions'
import { MultisigContext } from './syntax/multisig'
import { MultisigTxDispatcher } from './multisig'

export const context = {
enabled: false,
Expand All @@ -11,6 +11,5 @@ export const context = {
actions: [] as Action[],
// Counts depth of conditional transactions after the failed one
conditionalDepth: 0,
// TODO extract GlobalContext class and remove undefined
multisig: undefined as MultisigContext | undefined,
multisig: undefined as MultisigTxDispatcher | undefined,
}
15 changes: 13 additions & 2 deletions packages/mars/src/deploy.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { context } from './context'
import { getConfig, Options } from './options'
import { execute, ExecuteOptions } from './execute/execute'
import { MultisigContext } from './syntax/multisig'
import { MultisigTxDispatcher } from './multisig'
import { log } from './logging'

export async function deploy<T>(
options: Options,
Expand All @@ -11,9 +12,19 @@ export async function deploy<T>(

context.enabled = true
context.actions = []
context.multisig = config.multisig ? new MultisigContext(config.multisig) : undefined
context.multisig = config.multisig ? new MultisigTxDispatcher(config.multisig) : undefined
const result = callback(await config.signer.getAddress(), config)
context.enabled = false
await execute(context.actions, config)

// Refactor -> extract to multisig extension
if (config.multisig && context.multisig) {
if (context.multisig.txBatch.length > 0) {
const multisigId = await context.multisig.propose()
await context.multisig.approve(multisigId)
} else {
log('Multisig batch empty. Nothing to process.')
}
}
return { result, config }
}
3 changes: 3 additions & 0 deletions packages/mars/src/execute/bytecode.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export function isBytecodeEqual(a: string, b: string) {
if (a === undefined) throw new Error('left-side operand undefined')
if (b === undefined) throw new Error('right-side operand undefined')

return removeHashes(normalize(a)) === removeHashes(normalize(b))
}

Expand Down
Loading

0 comments on commit 3d3797d

Please sign in to comment.