Skip to content

Commit

Permalink
Fix check for unregistered contracts (#7319)
Browse files Browse the repository at this point in the history
### Description

Make decoding proposals with new contracts account for atomic registrations

### Tested

`celocli governance:show --proposalID 13 --node https://baklava-forno.celo-testnet.org`
  • Loading branch information
yorhodes authored Mar 8, 2021
1 parent 7ab5fc3 commit c77edc9
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 19 deletions.
5 changes: 2 additions & 3 deletions packages/sdk/contractkit/src/address-registry.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Address, NULL_ADDRESS } from '@celo/base/lib/address'
import { zip } from '@celo/base/lib/collections'
import debugFactory from 'debug'
import { CeloContract, RegisteredContracts } from './base'
import { CeloContract, RegisteredContracts, stripProxy } from './base'
import { newRegistry, Registry } from './generated/Registry'
import { ContractKit } from './kit'

Expand All @@ -27,9 +27,8 @@ export class AddressRegistry {
*/
async addressFor(contract: CeloContract): Promise<Address> {
if (!this.cache.has(contract)) {
const proxyStrippedContract = contract.replace('Proxy', '') as CeloContract
debug('Fetching address from Registry for %s', contract)
const address = await this.registry.methods.getAddressForString(proxyStrippedContract).call()
const address = await this.registry.methods.getAddressForString(stripProxy(contract)).call()

debug('Fetched address %s', address)
if (!address || address === NULL_ADDRESS) {
Expand Down
9 changes: 7 additions & 2 deletions packages/sdk/contractkit/src/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ export enum CeloContract {
Validators = 'Validators',
}

export const ProxyContracts = Object.keys(CeloContract).map((c) => `${c}Proxy`)

export type StableTokenContract = CeloContract.StableToken | CeloContract.StableTokenEUR

export type ExchangeContract = CeloContract.Exchange | CeloContract.ExchangeEUR
Expand All @@ -48,3 +46,10 @@ const AuxiliaryContracts = [
CeloContract.MetaTransactionWallet,
]
export const RegisteredContracts = AllContracts.filter((v) => !AuxiliaryContracts.includes(v))

export const stripProxy = (contract: CeloContract) => contract.replace('Proxy', '') as CeloContract

export const suffixProxy = (contract: CeloContract) =>
contract.endsWith('Proxy') ? contract : (`${contract}Proxy` as CeloContract)

export const ProxyContracts = AllContracts.map((c) => suffixProxy(c))
4 changes: 2 additions & 2 deletions packages/sdk/explorer/src/block-explorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ export class BlockExplorer {
)
}

async updateContractDetailsMapping(name: string, address: string) {
const cd = await getContractDetailsFromContract(this.kit, name as CeloContract, address)
async updateContractDetailsMapping(name: CeloContract, address: string) {
const cd = await getContractDetailsFromContract(this.kit, name, address)
this.addressMapping.set(cd.address, getContractMappingFromDetails(cd))
}

Expand Down
42 changes: 30 additions & 12 deletions packages/sdk/governance/src/proposals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
parseDecodedParams,
} from '@celo/connect'
import { CeloContract, ContractKit, RegisteredContracts } from '@celo/contractkit'
import { stripProxy, suffixProxy } from '@celo/contractkit/lib/base'
import { ABI as GovernanceABI } from '@celo/contractkit/lib/generated/Governance'
// tslint:disable: ordered-imports
import {
Expand Down Expand Up @@ -67,6 +68,16 @@ export interface ProposalTransactionJSON {
const isRegistryRepoint = (tx: ProposalTransactionJSON) =>
tx.contract === 'Registry' && tx.function === 'setAddressFor'

const registryRepointArgs = (tx: ProposalTransactionJSON) => {
if (!isRegistryRepoint(tx)) {
throw new Error(`Proposal transaction not a registry repoint:\n${JSON.stringify(tx, null, 2)}`)
}
return {
name: tx.args[0] as CeloContract,
address: tx.args[1] as string,
}
}

const isProxySetAndInitFunction = (tx: ProposalTransactionJSON) =>
tx.function === SET_AND_INITIALIZE_IMPLEMENTATION_ABI.name!

Expand Down Expand Up @@ -100,12 +111,12 @@ export const proposalToJSON = async (kit: ContractKit, proposal: Proposal) => {
}

if (isRegistryRepoint(jsonTx)) {
const [name, address] = jsonTx.args
await blockExplorer.updateContractDetailsMapping(name, address)
const args = registryRepointArgs(jsonTx)
await blockExplorer.updateContractDetailsMapping(stripProxy(args.name), args.address)
} else if (isProxySetFunction(jsonTx)) {
jsonTx.contract = `${jsonTx.contract}Proxy` as CeloContract
jsonTx.contract = suffixProxy(jsonTx.contract)
} else if (isProxySetAndInitFunction(jsonTx)) {
jsonTx.contract = `${jsonTx.contract}Proxy` as CeloContract
jsonTx.contract = suffixProxy(jsonTx.contract)

// Transform delegate call initialize args into a readable params map
const initAbi = getInitializeAbiOfImplementation(jsonTx.contract as any)
Expand Down Expand Up @@ -204,9 +215,19 @@ export class ProposalBuilder {
this.addWeb3Tx(tx.txo, { to, value: valueToString(value.toString()) })
}

setRegistryAddition = (contract: CeloContract, address: string) =>
(this.registryAdditions[stripProxy(contract)] = address)

getRegistryAddition = (contract: CeloContract): string | undefined =>
this.registryAdditions[stripProxy(contract)]

isRegistered = (contract: CeloContract) =>
RegisteredContracts.includes(stripProxy(contract)) ||
this.getRegistryAddition(contract) !== undefined

fromJsonTx = async (tx: ProposalTransactionJSON): Promise<ProposalTransaction> => {
// handle sending value to unregistered contracts
if (!RegisteredContracts.includes(tx.contract)) {
if (!this.isRegistered(tx.contract)) {
if (!isValidAddress(tx.contract)) {
throw new Error(
`Transaction to unregistered contract ${tx.contract} only supported by address`
Expand All @@ -220,16 +241,13 @@ export class ProposalBuilder {
}

// Account for canonical registry addresses from current proposal
let address = this.registryAdditions[tx.contract]

if (!address) {
address = await this.kit.registry.addressFor(tx.contract)
}
const address =
this.getRegistryAddition(tx.contract) ?? (await this.kit.registry.addressFor(tx.contract))

if (isRegistryRepoint(tx)) {
// Update canonical registry addresses
this.registryAdditions[tx.args[0]] = tx.args[1]
this.registryAdditions[tx.args[0] + 'Proxy'] = tx.args[1]
const args = registryRepointArgs(tx)
this.setRegistryAddition(args.name, args.address)
} else if (
tx.function === SET_AND_INITIALIZE_IMPLEMENTATION_ABI.name &&
Array.isArray(tx.args[1])
Expand Down

0 comments on commit c77edc9

Please sign in to comment.