Skip to content

Commit

Permalink
CeloProvider EIP-1193 support
Browse files Browse the repository at this point in the history
  • Loading branch information
shazarre committed Nov 7, 2024
1 parent caf2387 commit f0e04e3
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 25 deletions.
33 changes: 17 additions & 16 deletions packages/cli/src/commands/governance/approve-l2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { hexToBuffer, StrongAddress } from '@celo/base'
import { newKitFromWeb3 } from '@celo/contractkit'
import {
DEFAULT_OWNER_ADDRESS,
setBalance,
setCode,
testWithAnvilL2,
withImpersonatedAccount,
Expand Down Expand Up @@ -552,22 +553,18 @@ testWithAnvilL2('governance:approve cmd', (web3: Web3) => {
await setCode(web3, FALLBACK_HANDLER_ADDRESS, FALLBACK_HANDLER_CODE)

const kit = newKitFromWeb3(web3)
const [
approver,
securityCouncilSafeSignatory1,
securityCouncilSafeSignatory2,
securityCouncilSafeSignatory3,
] = (await web3.eth.getAccounts()) as StrongAddress[]
const [approver, securityCouncilSafeSignatory1] =
(await web3.eth.getAccounts()) as StrongAddress[]
const securityCouncilSafeSignatory2: StrongAddress =
'0x6C666E57A5E8715cFE93f92790f98c4dFf7b69e2'
const securityCouncilSafeSignatory2PrivateKey =
'0xe99303048756f2eac145377ebffdeec6747b8de31c1d34e004e1ee62f2b3d7a5'
const governance = await kit.contracts.getGovernance()
const writeMock = jest.spyOn(ux.write, 'stdout')
const logMock = jest.spyOn(console, 'log')

const safeAccountConfig: SafeAccountConfig = {
owners: [
securityCouncilSafeSignatory1,
securityCouncilSafeSignatory2,
securityCouncilSafeSignatory3,
],
owners: [securityCouncilSafeSignatory1, securityCouncilSafeSignatory2],
threshold: 2,
}

Expand Down Expand Up @@ -625,7 +622,6 @@ testWithAnvilL2('governance:approve cmd', (web3: Web3) => {
expect(await protocolKit.getOwners()).toEqual([
securityCouncilSafeSignatory1,
securityCouncilSafeSignatory2,
securityCouncilSafeSignatory3,
])

expect(await governance.getHotfixRecord(HOTFIX_BUFFER)).toMatchInlineSnapshot(`
Expand All @@ -637,11 +633,12 @@ testWithAnvilL2('governance:approve cmd', (web3: Web3) => {
}
`)

// We want to test if integration works for accounts that are not added to the node
await testLocallyWithWeb3Node(
Approve,
[
'--from',
securityCouncilSafeSignatory2,
securityCouncilSafeSignatory1,
'--hotfix',
HOTFIX_HASH,
'--useSafe',
Expand All @@ -651,16 +648,20 @@ testWithAnvilL2('governance:approve cmd', (web3: Web3) => {
web3
)

// Make sure the account has enough balance to pay for the transaction
await setBalance(web3, securityCouncilSafeSignatory2, BigInt(web3.utils.toWei('1', 'ether')))
await testLocallyWithWeb3Node(
Approve,
[
'--from',
securityCouncilSafeSignatory3,
securityCouncilSafeSignatory2,
'--hotfix',
HOTFIX_HASH,
'--useSafe',
'--type',
'securityCouncil',
'--privateKey',
securityCouncilSafeSignatory2PrivateKey,
],
web3
)
Expand All @@ -682,7 +683,7 @@ testWithAnvilL2('governance:approve cmd', (web3: Web3) => {
"Running Checks:",
],
[
" ✔ 0xE36Ea790bc9d7AB70C55260C66D52b1eca985f84 is security council safe signatory ",
" ✔ 0x6Ecbe1DB9EF729CBe972C83Fb886247691Fb6beb is security council safe signatory ",
],
[
" ✔ Hotfix 0xbf670baa773b342120e1af45433a465bbd6fa289a5cf72763d63d95e4e22482d is not already approved by security council ",
Expand All @@ -697,7 +698,7 @@ testWithAnvilL2('governance:approve cmd', (web3: Web3) => {
"Running Checks:",
],
[
" ✔ 0xE834EC434DABA538cd1b9Fe1582052B880BD7e63 is security council safe signatory ",
" ✔ 0x6C666E57A5E8715cFE93f92790f98c4dFf7b69e2 is security council safe signatory ",
],
[
" ✔ Hotfix 0xbf670baa773b342120e1af45433a465bbd6fa289a5cf72763d63d95e4e22482d is not already approved by security council ",
Expand Down
29 changes: 20 additions & 9 deletions packages/cli/src/commands/governance/approve.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { StrongAddress } from '@celo/base'
import { CeloTransactionObject } from '@celo/connect'
import { CeloProvider } from '@celo/connect/lib/celo-provider'
import { GovernanceWrapper } from '@celo/contractkit/lib/wrappers/Governance'
import { MultiSigWrapper } from '@celo/contractkit/lib/wrappers/MultiSig'
import { toBuffer } from '@ethereumjs/util'
Expand Down Expand Up @@ -123,13 +124,14 @@ export default class Approve extends BaseCommand {

// TODO find out if we need to use api-kit so that Safe UI can be used
if (isCel2 && approvalType === 'securityCouncil' && useSafe) {
const web3 = await this.getWeb3()

if (!(web3.currentProvider instanceof CeloProvider)) {
throw new Error('Unexpected web3 provider')
}

const protocolKit = await Safe.init({
// TODO cannot use existingProvider, we need to pass the web3 instance here somehow
// maybe a wrapper/exposing additional methods to be EIP-1193 compatible?
// @ts-expect-error
provider: governance.connection.web3.currentProvider.existingProvider.host,
// TODO this works only for accounts that are added directly to the node
// which won't work in real life
provider: web3.currentProvider.toEip1193Provider(),
signer: account,
safeAddress: await governance.getSecurityCouncil(),
})
Expand All @@ -145,7 +147,6 @@ export default class Approve extends BaseCommand {
})

const txHash = await protocolKit.getTransactionHash(safeTransaction)

if (!(await protocolKit.getOwnersWhoApprovedTx(txHash)).includes(account)) {
await protocolKit.approveTransactionHash(txHash)
}
Expand All @@ -155,8 +156,18 @@ export default class Approve extends BaseCommand {
(await protocolKit.getThreshold())
) {
const executeTxResponse = await protocolKit.executeTransaction(safeTransaction)
// @ts-expect-error
const receipt = await executeTxResponse.transactionResponse?.wait()

if (!executeTxResponse.transactionResponse) {
throw new Error('Transaction failed')
}

if (
'wait' in (executeTxResponse.transactionResponse as any) &&
typeof (executeTxResponse.transactionResponse as any).wait === 'function'
) {
// @ts-expect-error
const receipt = await executeTxResponse.transactionResponse?.wait()
}
}

// TODO: displaySendTx
Expand Down
26 changes: 26 additions & 0 deletions packages/sdk/connect/src/celo-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import debugFactory from 'debug'
import { Connection } from './connection'
import {
Callback,
Eip1193Provider,
Eip1193RequestArguments,
EncodedTransaction,
Error,
JsonRpcPayload,
Expand Down Expand Up @@ -168,6 +170,30 @@ export class CeloProvider implements Provider {
}
}

toEip1193Provider(): Eip1193Provider {
return {
request: async (args: Eip1193RequestArguments) => {
return new Promise((resolve, reject) => {
this.send(
{
id: 0,
jsonrpc: '2.0',
method: args.method,
params: args.params as any[],
},
(error: Error | null, result: unknown) => {
if (error) {
reject(error)
} else {
resolve((result as any).result)
}
}
)
})
},
}
}

private async handleAccounts(_payload: JsonRpcPayload): Promise<any> {
return this.connection.getAccounts()
}
Expand Down
10 changes: 10 additions & 0 deletions packages/sdk/connect/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,13 @@ export interface RLPEncodedTx {
rlpEncode: Hex
type: TransactionTypes
}

// Based on https://eips.ethereum.org/EIPS/eip-1193
export interface Eip1193RequestArguments {
readonly method: string
readonly params?: readonly unknown[] | object
}

export interface Eip1193Provider {
request(args: Eip1193RequestArguments): Promise<unknown>
}

0 comments on commit f0e04e3

Please sign in to comment.