Skip to content

Commit

Permalink
some refactors and adding README
Browse files Browse the repository at this point in the history
  • Loading branch information
MohammadChavosh committed Dec 18, 2024
1 parent 0de9432 commit 04fb410
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 90 deletions.
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,28 @@ Response: {

```

## Getting signatures to change DVN onchain configs

### Setup

Depending on the environment (i.e testnet/mainnet), fill in the appropriate information regarding DVN addresses and KMS key ids in the `scripts/data` folder. The file names should be `dvn-addresses-<environment>.json` and `kms-keyids-<environment>.json` respectively. Take a look at existing testnet examples in the `scripts/data` folder to see how they need to be filled.

### Signatures for changing quorum

```
ts-node scripts/configChangePayloads/createSetQuorumSignatures.ts -e <environment> -c <comma-separated-chain-names> --oldQuorum <number> --newQuorum <number>
# e.g. ts-node scripts/configChangePayloads/createSetQuorumSignatures.ts -e testnet -c bsc,avalanche --oldQuorum 2 --newQuorum 1
```

### Signatures for adding/removing a signer

When adding a signer, you need to set `--shouldRevoke` arg as 0, when removing, you need to set it as 1.

```
ts-node scripts/configChangePayloads/createSetQuorumSignatures.ts -e <environment> -c <comma-separated-chain-names> --q <quorum> --signerAddress <string> --shouldRevoke <0 or 1>
# e.g. ts-node scripts/configChangePayloads/createAddOrRemoveSignerSignatures.ts -e testnet -c bsc,avalanche -q 1 --signerAddress 0x85e4857b7f15bbbbbc72d933a6357d3c22a0bbc7 --shouldRevoke 1
```

## Troubleshooting

### 1. Error creating KeyRing
Expand Down
67 changes: 22 additions & 45 deletions scripts/configChangePayloads/createAddOrRemoveSignerSignatures.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import { ethers } from 'ethers'
import { GcpKmsSigner } from 'ethers-gcp-kms-signer'
import fs from 'fs'
import path from 'path'
import { parse } from 'ts-command-line-args'

import { getChainIdForNetwork } from '@layerzerolabs/lz-definitions'

import { GcpKmsKey } from './kms'
import { getGcpKmsSigners } from './kms'
import {
getSignatures,
getSignaturesPayload,
getVId,
hashCallData,
} from './utils'

const PATH = path.join(__dirname)
const FILE_PATH = `${PATH}/signer-change-payloads.json`
const EXPIRATION = Date.now() + 7 * 24 * 60 * 60 * 1000 // 1 week expiration from now

/**
* This script creates signature payloads to be submitted by an Admin of the DVN contract
Expand Down Expand Up @@ -45,76 +49,49 @@ const args = parse({
})

const setSignerFunctionSig = 'function setSigner(address _signer, bool _active)'
const EXPIRATION = Date.now() + 7 * 24 * 60 * 60 * 1000 // 1 week expiration from now

const iface = new ethers.utils.Interface([setSignerFunctionSig])

const getCallData = (signerAddress: string, active: boolean) => {
return iface.encodeFunctionData('setSigner', [signerAddress, active])
}

const hashCallData = (target: string, callData: string, vId: string) => {
return ethers.utils.keccak256(
ethers.utils.solidityPack(
['uint32', 'address', 'uint', 'bytes'],
[vId, target, EXPIRATION, callData],
),
)
}

interface Signature {
signature: string
address: string
}

const main = async () => {
const { environment, chainNames, quorum, signerAddress, shouldRevoke } =
args
if (shouldRevoke !== 0 && shouldRevoke !== 1) {
throw new Error('shouldRevoke must be 0 or 1')
}

const dvnAddresses = require(`./data/dvn-addresses-${environment}.json`)

const keyIds = require(`./data/kms-keyids-${environment}.json`)
const signers = await Promise.all(
keyIds.map(async (credentials: GcpKmsKey) => {
return new GcpKmsSigner(credentials)
}),
)
const signers = await getGcpKmsSigners(keyIds)

const availableChainNames = chainNames.split(',')

const results: { [chainName: string]: any } = {}
await Promise.all(
availableChainNames.map(async (chainName) => {
results[chainName] = results[chainName] || {}
const vId = getChainIdForNetwork(chainName, environment, '2')
const vId = getVId(chainName, environment)
const callData = getCallData(
signerAddress,
shouldRevoke === 1 ? false : true,
)
const hash = hashCallData(dvnAddresses[chainName], callData, vId)
// sign
const signatures = await Promise.all(
signers.map(async (signer) => ({
signature: await signer.signMessage(
ethers.utils.arrayify(hash),
),
address: await signer.getAddress(),
})),
)

signatures.sort((a: Signature, b: Signature) =>
a.address.localeCompare(b.address),
)
const signaturesForQuorum = signatures.slice(0, quorum)
const signaturePayload = ethers.utils.solidityPack(
signaturesForQuorum.map(() => 'bytes'),
signaturesForQuorum.map((s: Signature) => s.signature),
const hash = hashCallData(
dvnAddresses[chainName],
vId,
EXPIRATION,
callData,
)

const signatures = await getSignatures(signers, hash)
const signaturesPayload = getSignaturesPayload(signatures, quorum)

results[chainName] = {
args: {
target: dvnAddresses[chainName],
signatures: signaturePayload,
signatures: signaturesPayload,
callData,
expiration: EXPIRATION,
vid: vId,
Expand Down
70 changes: 25 additions & 45 deletions scripts/configChangePayloads/createSetQuorumSignatures.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import { ethers } from 'ethers'
import { GcpKmsSigner } from 'ethers-gcp-kms-signer'
import fs from 'fs'
import path from 'path'
import { parse } from 'ts-command-line-args'

import { getChainIdForNetwork } from '@layerzerolabs/lz-definitions'

import { GcpKmsKey } from './kms'
import { GcpKmsKey, getGcpKmsSigners } from './kms'
import {
getSignatures,
getSignaturesPayload,
getVId,
hashCallData,
} from './utils'

const PATH = path.join(__dirname)
const FILE_PATH = `${PATH}/quorum-change-payloads.json`
const EXPIRATION = Date.now() + 7 * 24 * 60 * 60 * 1000 // 1 week expiration from now

/**
* This script creates signature payloads to be submitted by an Admin of the DVN contract
Expand Down Expand Up @@ -40,69 +44,45 @@ const args = parse({
})

const setQuorumFunctionSig = 'function setQuorum(uint64 _quorum)'
const EXPIRATION = Date.now() + 7 * 24 * 60 * 60 * 1000 // 1 week expiration from now

const iface = new ethers.utils.Interface([setQuorumFunctionSig])

const getCallData = (newQuorum: number) => {
return iface.encodeFunctionData('setQuorum', [newQuorum])
}

const hashCallData = (target: string, callData: string, vId: string) => {
return ethers.utils.keccak256(
ethers.utils.solidityPack(
['uint32', 'address', 'uint', 'bytes'],
[vId, target, EXPIRATION, callData],
),
)
}

interface Signature {
signature: string
address: string
}

const main = async () => {
const { environment, chainNames, oldQuorum, newQuorum } = args

const dvnAddresses = require(`./data/dvn-addresses-${environment}.json`)
const keyIds = require(`./data/kms-keyids-${environment}.json`)
const signers = await Promise.all(
keyIds.map(async (credentials: GcpKmsKey) => {
return new GcpKmsSigner(credentials)
}),
)

const keyIds: GcpKmsKey[] = require(`./data/kms-keyids-${environment}.json`)
const signers = await getGcpKmsSigners(keyIds)

const availableChainNames = chainNames.split(',')

const results: { [chainName: string]: any } = {}
await Promise.all(
availableChainNames.map(async (chainName) => {
results[chainName] = results[chainName] || {}
const vId = getChainIdForNetwork(chainName, environment, '2')
const vId = getVId(chainName, environment)
const callData = getCallData(newQuorum)
const hash = hashCallData(dvnAddresses[chainName], callData, vId)
// sign
const signatures = await Promise.all(
signers.map(async (signer) => ({
signature: await signer.signMessage(
ethers.utils.arrayify(hash),
),
address: await signer.getAddress(),
})),
)

signatures.sort((a: Signature, b: Signature) =>
a.address.localeCompare(b.address),
const hash = hashCallData(
dvnAddresses[chainName],
vId,
EXPIRATION,
callData,
)
const signaturesForQuorum = signatures.slice(0, oldQuorum)
const signaturePayload = ethers.utils.solidityPack(
signaturesForQuorum.map(() => 'bytes'),
signaturesForQuorum.map((s: Signature) => s.signature),

const signatures = await getSignatures(signers, hash)
const signaturesPayload = getSignaturesPayload(
signatures,
oldQuorum,
)

results[chainName] = {
args: {
target: dvnAddresses[chainName],
signatures: signaturePayload,
signatures: signaturesPayload,
callData,
expiration: EXPIRATION,
vid: vId,
Expand Down
12 changes: 12 additions & 0 deletions scripts/configChangePayloads/kms.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { GcpKmsSigner } from 'ethers-gcp-kms-signer'

/**
* Defines a GCP KMS Key.
*/
Expand All @@ -8,3 +10,13 @@ export interface GcpKmsKey {
keyId: string
keyVersion: string
}

export async function getGcpKmsSigners(
keyIds: GcpKmsKey[],
): Promise<GcpKmsSigner[]> {
return await Promise.all(
keyIds.map(async (credentials: GcpKmsKey) => {
return new GcpKmsSigner(credentials)
}),
)
}
58 changes: 58 additions & 0 deletions scripts/configChangePayloads/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { ethers } from 'ethers'
import { GcpKmsSigner } from 'ethers-gcp-kms-signer'

import { getChainIdForNetwork } from '@layerzerolabs/lz-definitions'

export interface Signature {
signature: string
address: string
}

export function getVId(chainName: string, environment: string): string {
// By convention the vid is always the endpointV1 chainId
if (['solana', 'ton', 'initia', 'movement'].includes(chainName)) {
const eid = getChainIdForNetwork(chainName, environment, '302')
return (parseInt(eid) % 30000).toString()
}
return getChainIdForNetwork(chainName, environment, '2')
}

export function hashCallData(
target: string,
vId: string,
expiration: number,
callData: string,
): string {
return ethers.utils.keccak256(
ethers.utils.solidityPack(
['uint32', 'address', 'uint', 'bytes'],
[vId, target, expiration, callData],
),
)
}

export async function getSignatures(
signers: GcpKmsSigner[],
hash: string,
): Promise<Signature[]> {
return await Promise.all(
signers.map(async (signer) => ({
signature: await signer.signMessage(ethers.utils.arrayify(hash)),
address: await signer.getAddress(),
})),
)
}

export function getSignaturesPayload(
signatures: Signature[],
quorum: number,
): string {
signatures.sort((a: Signature, b: Signature) =>
a.address.localeCompare(b.address),
)
const signaturesForQuorum = signatures.slice(0, quorum)
return ethers.utils.solidityPack(
signaturesForQuorum.map(() => 'bytes'),
signaturesForQuorum.map((s: Signature) => s.signature),
)
}

0 comments on commit 04fb410

Please sign in to comment.