Skip to content

Commit

Permalink
BCI-3898: fix multisig set config bug (#497)
Browse files Browse the repository at this point in the history
  • Loading branch information
augustbleeds committed Aug 1, 2024
1 parent 5f11cca commit ef54507
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 24 deletions.
1 change: 1 addition & 0 deletions packages-ts/starknet-gauntlet-cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ const registerExecuteCommand = <UI, CI>(
billingAccessController: process.env.BILLING_ACCESS_CONTROLLER,
link: process.env.LINK,
secret: flags.secret || process.env.SECRET,
randomSecret: flags.randomSecret || process.env.RANDOM_SECRET,
withLedger: !!flags.withLedger || !!process.env.WITH_LEDGER,
ledgerPath: (flags.ledgerPath as string) || process.env.LEDGER_PATH,
}
Expand Down
32 changes: 31 additions & 1 deletion packages-ts/starknet-gauntlet-multisig/src/wrapper/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
Input,
IStarknetProvider,
IStarknetWallet,
tryToWriteLastConfigDigestToRDD,
} from '@chainlink/starknet-gauntlet'
import { TransactionResponse } from '@chainlink/starknet-gauntlet/dist/transaction'
import {
Expand Down Expand Up @@ -242,11 +243,40 @@ export const wrapCommand = <UI, CI>(
const messages = {
[Action.EXECUTE]: `The multisig proposal reached the threshold and can be executed. Run the same command with the flag --multisigProposal=${state.proposal.id}`,
[Action.APPROVE]: `The multisig proposal needs ${approvalsLeft} more approvals. Run the same command with the flag --multisigProposal=${state.proposal.id}`,
[Action.NONE]: `The multisig proposal has been executed. No more actions needed`,
[Action.NONE]: `The multisig proposal has been executed. No more actions needed on-chain`,
}
deps.logger.line()
deps.logger.info(`${messages[state.proposal.nextAction]}`)
deps.logger.line()

if (state.proposal.nextAction === Action.NONE) {
// check if the proposal has the config set event

const txHash = result.responses[0].tx.hash
const txInfo = await this.executionContext.provider.provider.getTransactionReceipt(txHash)

if (txInfo.isSuccess()) {
const contractEvents = this.command.executionContext.contract.parseEvents(txInfo)
const event = contractEvents[contractEvents.length - 1]['ConfigSet']

// this was a set config multisig command
if (event) {
// write lastConfigDigest back to RDD
const hexLastConfigDigest = `${(event.latest_config_digest as bigint).toString(16)}`
// config digest string must be exactly 32 bytes
const paddedHexLastConfigDigest = hexLastConfigDigest.padStart(64, '0')
const configDigest = `0x${paddedHexLastConfigDigest}`

await tryToWriteLastConfigDigestToRDD(
deps,
this.executionContext.flags.rdd,
this.contractAddress,
configDigest,
)
}
}
}

return { proposalId }
}

Expand Down
4 changes: 3 additions & 1 deletion packages-ts/starknet-gauntlet-ocr2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,11 @@ This Should set the billing details for this feed on contract address
Run the following command substituting <OCR_CONTRACT_ADDRESS> with the OCR2 contract address you received in the deploy step:

```
yarn gauntlet ocr2:set_config --network=<NETWORK> --address=<ADDRESS> --f=<NUMBER> --signers=[<ACCOUNTS>] --transmitters=[<ACCOUNTS>] --onchainConfig=<CONFIG> --offchainConfig=<CONFIG> --offchainConfigVersion=<NUMBER> <OCR_CONTRACT_ADDRESS>
yarn gauntlet ocr2:set_config --network=<NETWORK> --address=<ADDRESS> --secret=<SECRET> --f=<NUMBER> --signers=[<ACCOUNTS>] --transmitters=[<ACCOUNTS>] --onchainConfig=<CONFIG> --offchainConfig=<CONFIG> --offchainConfigVersion=<NUMBER> <OCR_CONTRACT_ADDRESS>
```

Note: You must include the same random secret to deterministically run the set config multiple times (ex: for multisig proposals among different signers signing the same transaction). This can be achieved by setting a flag or environment variable ``--randomSecret`` or ``RANDOM_SECRET`` respectiviely.

This Should set the config for this feed on contract address.


Expand Down
37 changes: 20 additions & 17 deletions packages-ts/starknet-gauntlet-ocr2/src/commands/ocr2/setConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
bytesToFelts,
BeforeExecute,
getRDD,
tryToWriteLastConfigDigestToRDD,
} from '@chainlink/starknet-gauntlet'
import { time, diff } from '@chainlink/gauntlet-core/dist/utils'
import { ocr2ContractLoader } from '../../lib/contracts'
Expand Down Expand Up @@ -80,7 +81,7 @@ const makeUserInput = async (flags, args, env): Promise<SetConfigInput> => {
offchainConfig,
offchainConfigVersion: 2,
secret: flags.secret || env.secret,
randomSecret: flags.randomSecret || undefined,
randomSecret: flags.randomSecret || env.randomSecret,
}
}

Expand All @@ -92,10 +93,18 @@ const makeUserInput = async (flags, args, env): Promise<SetConfigInput> => {
offchainConfig: flags.offchainConfig,
offchainConfigVersion: parseInt(flags.offchainConfigVersion),
secret: flags.secret || env.secret,
randomSecret: flags.randomSecret || undefined,
randomSecret: flags.randomSecret || env.randomSecret,
}
}

export const validateSecretsNotEmpty = async (input) => {
if (input.secret === undefined) {
throw new Error(`A secret must be provided (--secret flag or SECRET environment variable)`)
}

return true
}

const makeContractInput = async (
input: SetConfigInput,
ctx: ExecutionContext,
Expand All @@ -122,6 +131,7 @@ const makeContractInput = async (
const { offchainConfig } = await encoding.serializeOffchainConfig(
input.offchainConfig,
input.secret,
input.randomSecret,
)
const onchainConfig = [] // onchain config should be empty array for input (generate onchain)
return [oracles, input.f, onchainConfig, 2, bytesToFelts(offchainConfig)]
Expand Down Expand Up @@ -188,21 +198,13 @@ const afterExecute: AfterExecute<SetConfigInput, ContractInput> = (context, inpu
// config digest string must be exactly 32 bytes
const paddedHexLastConfigDigest = hexLastConfigDigest.padStart(64, '0')
const configDigest = `0x${paddedHexLastConfigDigest}`
deps.logger.info(`lastConfigDigest to save in RDD: ${configDigest}`)
if (context.flags.rdd) {
const rdd = getRDD(context.flags.rdd)
const contractAddr = context.contract.address
// set updated lastConfigDigest
rdd[CONTRACT_TYPES.AGGREGATOR][contractAddr]['config']['lastConfigDigest'] = configDigest
fs.writeFileSync(context.flags.rdd, JSON.stringify(rdd, null, 2))
deps.logger.success(
`RDD file ${context.flags.rdd} has been updated! You must reformat RDD by running ./bin/degenerate and ./bin/generate in that exact order`,
)
} else {
deps.logger.warn(
`No RDD file was inputted, you must manually update lastConfigDigest in RDD yourself`,
)
}

await tryToWriteLastConfigDigestToRDD(
deps,
context.flags.rdd,
context.contract.address,
configDigest,
)

return { successfulConfiguration: true }
} catch (e) {
Expand All @@ -214,6 +216,7 @@ const afterExecute: AfterExecute<SetConfigInput, ContractInput> = (context, inpu

const commandConfig: ExecuteCommandConfig<SetConfigInput, ContractInput> = {
...SetConfig,
validations: [...SetConfig.validations, validateSecretsNotEmpty],
makeUserInput: makeUserInput,
makeContractInput: makeContractInput,
loadContract: ocr2ContractLoader,
Expand Down
6 changes: 1 addition & 5 deletions packages-ts/starknet-gauntlet-ocr2/src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import {
ExecuteCommandConfig,
makeExecuteCommand,
isValidAddress,
} from '@chainlink/starknet-gauntlet'
import { isValidAddress } from '@chainlink/starknet-gauntlet'

export const validateClassHash = async (input) => {
if (isValidAddress(input.classHash) || input.classHash === undefined) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ const validInput = {
},
offchainConfigVersion: 2,
secret: 'awe accuse polygon tonic depart acuity onyx inform bound gilbert expire',
randomSecret: 'awe accuse polygon tonic depart acuity onyx inform bound gilbert expire',
}

const getNumCallsPerAddress = (txReceipt: InvokeTransactionReceiptResponse) => {
Expand Down
25 changes: 25 additions & 0 deletions packages-ts/starknet-gauntlet/src/utils/configDigest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import fs from 'fs'
import { CONTRACT_TYPES, getRDD } from '../rdd'
import { Dependencies } from '../dependencies'

export const tryToWriteLastConfigDigestToRDD = async (
deps: Pick<Dependencies, 'logger' | 'prompt'>,
rddPath: string,
contractAddr: string,
configDigest: string,
) => {
deps.logger.info(`lastConfigDigest to save in RDD: ${configDigest}`)
if (rddPath) {
const rdd = getRDD(rddPath)
// set updated lastConfigDigest
rdd[CONTRACT_TYPES.AGGREGATOR][contractAddr]['config']['lastConfigDigest'] = configDigest
fs.writeFileSync(rddPath, JSON.stringify(rdd, null, 2))
deps.logger.success(
`RDD file ${rddPath} has been updated! You must reformat RDD by running ./bin/degenerate and ./bin/generate in that exact order`,
)
} else {
deps.logger.warn(
`No RDD file was inputted, you must manually update lastConfigDigest in RDD yourself`,
)
}
}
1 change: 1 addition & 0 deletions packages-ts/starknet-gauntlet/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './address'
export * from './configDigest'

0 comments on commit ef54507

Please sign in to comment.