Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 5 additions & 0 deletions .changeset/fix-ledger-console-noise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@celo/wallet-ledger': patch
---

Replace `console.info` with `debug` for derivation path logging to avoid noisy test output
5 changes: 5 additions & 0 deletions .changeset/remove-delegate-debug-logs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@celo/celocli': patch
---

Remove debug console.log statements from lockedcelo:delegate command that were leaking internal values to stdout
17 changes: 17 additions & 0 deletions .changeset/remove-rpc-contract-promievent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'@celo/connect': major
'@celo/contractkit': minor
'@celo/celocli': minor
'@celo/dev-utils': minor
---

**Remove rpc-contract.ts, PromiEvent, and legacy Contract interface from @celo/connect**

- Deleted `rpc-contract.ts`, `promi-event.ts`, and `viem-contract.ts` — replaced with native viem `getContract()` / `GetContractReturnType`
- `CeloTxObject.send()` now returns `Promise<string>` (tx hash) instead of `PromiEvent<CeloTxReceipt>`
- Removed `Connection.createContract()` — use `Connection.getCeloContract()` instead
- Removed `PromiEvent<T>` and `Contract` interfaces from types
- `Connection.getViemContract()` deprecated — delegates to `getCeloContract()`
- `ViemContract<TAbi>` deprecated — use `CeloContract<TAbi>` (viem's `GetContractReturnType`)
- Contract deployment rewritten to use viem's `encodeDeployData` + `connection.sendTransaction()`
- All contractkit wrappers, CLI commands, and test files updated
10 changes: 10 additions & 0 deletions .changeset/remove-web3-shim.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@celo/connect': major
'@celo/contractkit': major
'@celo/celocli': major
'@celo/explorer': patch
'@celo/governance': patch
'@celo/dev-utils': patch
---

Remove Web3 shim from Connection and migrate contractkit to use viem ABIs with Connection.createContract(). Add backward-compatible kit.web3 shim (deprecated). Add newKitFromProvider() factory function.
5 changes: 5 additions & 0 deletions .changeset/strong-typing-contractkit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@celo/contractkit': minor
---

**Improved type safety**: Added explicit type annotations to all wrapper methods that previously emitted `CeloTransactionObject<any>` or `Promise<any>` in their declaration files. All `proxySend` and `proxyCall` usages now have explicit return types, eliminating approximately 110 instances of `any` in the public API surface. This provides better IDE autocompletion and compile-time type checking for consumers of `@celo/contractkit`.
15 changes: 15 additions & 0 deletions .changeset/viem-native-migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
'@celo/connect': minor
'@celo/contractkit': minor
'@celo/explorer': patch
---

**Migrate internal contract interaction from web3-style RPC Contract to viem-native ViemContract**

- Added `ViemContract` type and `createViemTxObject()` function in `@celo/connect`
- Added `Connection.getViemContract()` factory method
- Updated all 36 ContractKit wrappers to use viem-native contract interaction
- Updated `proxyCall`/`proxySend` to accept `ViemContract` + function name strings
- Migrated CLI commands, dev-utils, and explorer to use new API
- Deprecated `Connection.createContract()` (kept for backward compatibility with `.deploy()`)
- Public API unchanged: `CeloTransactionObject`, wrapper method signatures remain the same
2 changes: 1 addition & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
attestations: write
id-token: write
repository-projects: write
uses: celo-org/reusable-workflows/.github/workflows/npm-publish.yaml@develop-npm-publishing-oidc
uses: celo-org/reusable-workflows/.github/workflows/npm-publish.yaml@develop
with:
node-version: 20
version-command: yarn version-then-update-files
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
diff --git a/index.js b/index.js
index 5462c1f830bdbe79bf2b1fcfd811cd9799b4dd11..e8fe7e61083d95714bba6f2d4544d0426749a64f 100644
--- a/index.js
+++ b/index.js
@@ -28,14 +28,19 @@ function bufferEq(a, b) {
}

bufferEq.install = function() {
- Buffer.prototype.equal = SlowBuffer.prototype.equal = function equal(that) {
+ Buffer.prototype.equal = function equal(that) {
return bufferEq(this, that);
};
+ if (SlowBuffer) {
+ SlowBuffer.prototype.equal = Buffer.prototype.equal;
+ }
};

var origBufEqual = Buffer.prototype.equal;
-var origSlowBufEqual = SlowBuffer.prototype.equal;
+var origSlowBufEqual = SlowBuffer ? SlowBuffer.prototype.equal : undefined;
bufferEq.restore = function() {
Buffer.prototype.equal = origBufEqual;
- SlowBuffer.prototype.equal = origSlowBufEqual;
+ if (SlowBuffer && origSlowBufEqual) {
+ SlowBuffer.prototype.equal = origSlowBufEqual;
+ }
};
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,10 @@
"typescript": "5.3.3"
},
"resolutions": {
"web3": "1.10.4",
"web3-utils": "1.10.4",
"blind-threshold-bls": "npm:@celo/blind-threshold-bls@1.0.0-beta",
"@types/bn.js": "4.11.6",
"bignumber.js": "9.0.0"
"bignumber.js": "9.0.0",
"buffer-equal-constant-time@npm:1.0.1": "patch:buffer-equal-constant-time@npm%3A1.0.1#~/.yarn/patches/buffer-equal-constant-time-npm-1.0.1-41826f3419.patch"
},
"dependencies": {
"@changesets/cli": "^2.29.5"
Expand Down
1 change: 1 addition & 0 deletions packages/actions/tsconfig-base.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"compilerOptions": {
"rootDir": "src",
"declaration": true,
"declarationMap": true,
"esModuleInterop": true,
"types": ["node"],
"lib": ["esnext"],
Expand Down
4 changes: 1 addition & 3 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
"@celo/wallet-hsm-azure": "^8.0.3",
"@celo/wallet-ledger": "^8.0.3",
"@celo/wallet-local": "^8.0.3",
"@ethereumjs/util": "8.0.5",
"@ledgerhq/hw-transport-node-hid": "^6.28.5",
"@oclif/core": "^3.27.0",
"@oclif/plugin-autocomplete": "^3.2.0",
Expand All @@ -74,8 +73,7 @@
"fs-extra": "^8.1.0",
"humanize-duration": "^3.32.1",
"prompts": "^2.0.1",
"viem": "^2.33.2",
"web3": "1.10.4"
"viem": "^2.33.2"
},
"devDependencies": {
"@celo/dev-utils": "workspace:^",
Expand Down
70 changes: 36 additions & 34 deletions packages/cli/src/base.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ import http from 'http'
import { tmpdir } from 'os'
import { MethodNotFoundRpcError } from 'viem'
import { privateKeyToAddress } from 'viem/accounts'
import Web3 from 'web3'
import { BaseCommand } from './base'
import Set from './commands/config/set'
import CustomHelp from './help'
import { stripAnsiCodesFromNestedArray, testLocallyWithWeb3Node } from './test-utils/cliUtils'
import { stripAnsiCodesFromNestedArray, testLocallyWithNode } from './test-utils/cliUtils'
import { mockRpcFetch } from './test-utils/mockRpc'
import { CustomFlags } from './utils/command'
import * as config from './utils/config'
Expand Down Expand Up @@ -62,17 +61,17 @@ describe('flags', () => {
describe('--node celo-sepolia', () => {
it('it connects to 11_142_220', async () => {
const command = new BasicCommand(['--node', 'celo-sepolia'], config)
const runnerWeb3 = await command.getWeb3()
const connectdChain = await runnerWeb3.eth.getChainId()
expect(connectdChain).toBe(11_142_220)
const runnerClient = await command.getPublicClient()
const connectdChain = runnerClient.chain
expect(connectdChain.id).toBe(11_142_220)
})
})
describe.each(['celo', 'mainnet'])('--node %s', (node) => {
it('it connects to 42220', async () => {
const command = new BasicCommand(['--node', node], config)
const runnerWeb3 = await command.getWeb3()
const connectdChain = await runnerWeb3.eth.getChainId()
expect(connectdChain).toBe(42220)
const runnerClient = await command.getPublicClient()
const connectdChain = runnerClient.chain
expect(connectdChain.id).toBe(42220)
})
})
describe('--node websockets', () => {
Expand Down Expand Up @@ -105,7 +104,7 @@ jest.mock('../package.json', () => ({
version: '5.2.3',
}))

testWithAnvilL2('BaseCommand', (web3: Web3) => {
testWithAnvilL2('BaseCommand', (provider) => {
const logSpy = jest.spyOn(console, 'log').mockImplementation()

beforeEach(() => {
Expand All @@ -118,7 +117,7 @@ testWithAnvilL2('BaseCommand', (web3: Web3) => {
const storedDerivationPath = readConfig(tmpdir()).derivationPath
console.info('storedDerivationPath', storedDerivationPath)
expect(storedDerivationPath).not.toBe(undefined)
await testLocallyWithWeb3Node(BasicCommand, ['--useLedger'], web3)
await testLocallyWithNode(BasicCommand, ['--useLedger'], provider)
expect(WalletLedgerExports.newLedgerWalletWithSetup).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({
Expand All @@ -134,8 +133,8 @@ testWithAnvilL2('BaseCommand', (web3: Web3) => {
it('uses custom derivationPath', async () => {
const storedDerivationPath = readConfig(tmpdir()).derivationPath
const customPath = "m/44'/9000'/0'"
await testLocallyWithWeb3Node(Set, ['--derivationPath', customPath], web3)
await testLocallyWithWeb3Node(BasicCommand, ['--useLedger'], web3)
await testLocallyWithNode(Set, ['--derivationPath', customPath], provider)
await testLocallyWithNode(BasicCommand, ['--useLedger'], provider)
expect(WalletLedgerExports.newLedgerWalletWithSetup).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({
Expand All @@ -147,12 +146,12 @@ testWithAnvilL2('BaseCommand', (web3: Web3) => {
baseDerivationPath: customPath,
})
)
await testLocallyWithWeb3Node(Set, ['--derivationPath', storedDerivationPath], web3)
await testLocallyWithNode(Set, ['--derivationPath', storedDerivationPath], provider)
})
})

it('--ledgerAddresses passes derivationPathIndexes to LedgerWallet', async () => {
await testLocallyWithWeb3Node(BasicCommand, ['--useLedger', '--ledgerAddresses', '5'], web3)
await testLocallyWithNode(BasicCommand, ['--useLedger', '--ledgerAddresses', '5'], provider)

expect(WalletLedgerExports.newLedgerWalletWithSetup).toHaveBeenCalledWith(
expect.anything(),
Expand Down Expand Up @@ -197,10 +196,10 @@ testWithAnvilL2('BaseCommand', (web3: Web3) => {

describe('with --ledgerLiveMode', () => {
it('--ledgerAddresses passes changeIndexes to LedgerWallet', async () => {
await testLocallyWithWeb3Node(
await testLocallyWithNode(
BasicCommand,
['--useLedger', '--ledgerLiveMode', '--ledgerAddresses', '5'],
web3
provider
)

expect(WalletLedgerExports.newLedgerWalletWithSetup).toHaveBeenCalledWith(
Expand Down Expand Up @@ -246,10 +245,10 @@ testWithAnvilL2('BaseCommand', (web3: Web3) => {
})
describe('with --ledgerCustomAddresses', () => {
it('passes custom changeIndexes to LedgerWallet', async () => {
await testLocallyWithWeb3Node(
await testLocallyWithNode(
BasicCommand,
['--useLedger', '--ledgerLiveMode', '--ledgerCustomAddresses', '[1,8,9]'],
web3
provider
)

expect(WalletLedgerExports.newLedgerWalletWithSetup).toHaveBeenCalledWith(
Expand Down Expand Up @@ -293,10 +292,10 @@ testWithAnvilL2('BaseCommand', (web3: Web3) => {
})
describe('with --ledgerCustomAddresses', () => {
it('passes custom derivationPathIndexes to LedgerWallet', async () => {
await testLocallyWithWeb3Node(
await testLocallyWithNode(
BasicCommand,
['--useLedger', '--ledgerCustomAddresses', '[1,8,9]'],
web3
provider
)

expect(WalletLedgerExports.newLedgerWalletWithSetup).toHaveBeenCalledWith(
Expand Down Expand Up @@ -341,7 +340,7 @@ testWithAnvilL2('BaseCommand', (web3: Web3) => {

describe('with --from', () => {
it('uses it as the default account', async () => {
await testLocallyWithWeb3Node(
await testLocallyWithNode(
BasicCommand,
[
'--useLedger',
Expand All @@ -350,7 +349,7 @@ testWithAnvilL2('BaseCommand', (web3: Web3) => {
'--from',
'0x1234567890123456789012345678901234567890',
],
web3
provider
)

expect(ViemAccountLedgerExports.ledgerToWalletClient).toHaveBeenCalledWith(
Expand Down Expand Up @@ -381,7 +380,7 @@ testWithAnvilL2('BaseCommand', (web3: Web3) => {
const errorSpy = jest.spyOn(console, 'error').mockImplementation()

await expect(
testLocallyWithWeb3Node(TestErrorCommand, [], web3)
testLocallyWithNode(TestErrorCommand, [], provider)
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Unable to create an RPC Wallet Client, the node is not unlocked. Did you forget to use \`--privateKey\` or \`--useLedger\`?"`
)
Expand All @@ -399,7 +398,7 @@ testWithAnvilL2('BaseCommand', (web3: Web3) => {
const errorSpy = jest.spyOn(console, 'error').mockImplementation()

await expect(
testLocallyWithWeb3Node(TestErrorCommand, [], web3)
testLocallyWithNode(TestErrorCommand, [], provider)
).rejects.toThrowErrorMatchingInlineSnapshot(`"test error"`)

expect(errorSpy.mock.calls).toMatchInlineSnapshot(`
Expand Down Expand Up @@ -432,7 +431,7 @@ testWithAnvilL2('BaseCommand', (web3: Web3) => {
const errorSpy = jest.spyOn(console, 'error').mockImplementation()

await expect(
testLocallyWithWeb3Node(TestErrorCommand, ['--output', 'csv'], web3)
testLocallyWithNode(TestErrorCommand, ['--output', 'csv'], provider)
).rejects.toThrowErrorMatchingInlineSnapshot(`"test error"`)

expect(errorSpy.mock.calls).toMatchInlineSnapshot(`[]`)
Expand All @@ -453,7 +452,7 @@ testWithAnvilL2('BaseCommand', (web3: Web3) => {
throw new Error('Mock connection stop error')
})

await testLocallyWithWeb3Node(TestConnectionStopErrorCommand, [], web3)
await testLocallyWithNode(TestConnectionStopErrorCommand, [], provider)

expect(logSpy.mock.calls).toMatchInlineSnapshot(`
[
Expand Down Expand Up @@ -489,10 +488,10 @@ testWithAnvilL2('BaseCommand', (web3: Web3) => {
}

await expect(
testLocallyWithWeb3Node(
testLocallyWithNode(
TestPrivateKeyCommand,
['--privateKey', privateKey, '--from', wrongFromAddress],
web3
provider
)
).rejects.toThrowErrorMatchingInlineSnapshot(
`"The --from address ${wrongFromAddress} does not match the address derived from the provided private key 0x1Be31A94361a391bBaFB2a4CCd704F57dc04d4bb."`
Expand All @@ -515,10 +514,10 @@ testWithAnvilL2('BaseCommand', (web3: Web3) => {
}

await expect(
testLocallyWithWeb3Node(
testLocallyWithNode(
TestPrivateKeyCommand,
['--privateKey', privateKey, '--from', correctFromAddress],
web3
provider
)
).resolves.not.toThrow()
})
Expand All @@ -538,7 +537,7 @@ testWithAnvilL2('BaseCommand', (web3: Web3) => {
}

await expect(
testLocallyWithWeb3Node(TestPrivateKeyCommand, ['--privateKey', privateKey], web3)
testLocallyWithNode(TestPrivateKeyCommand, ['--privateKey', privateKey], provider)
).resolves.not.toThrow()
})
})
Expand Down Expand Up @@ -687,7 +686,6 @@ testWithAnvilL2('BaseCommand', (web3: Web3) => {
})

delete process.env.TELEMETRY_ENABLED
process.env.TELEMETRY_URL = 'http://localhost:3000/'

const fetchSpy = jest.spyOn(global, 'fetch')

Expand All @@ -697,13 +695,17 @@ testWithAnvilL2('BaseCommand', (web3: Web3) => {
}, 5000) // Higher timeout than the telemetry logic uses
})

server.listen(3000, async () => {
server.listen(0, async () => {
const address = server.address() as { port: number }
const telemetryUrl = `http://localhost:${address.port}/`
process.env.TELEMETRY_URL = telemetryUrl

// Make sure the command actually returns
await expect(TestTelemetryCommand.run([])).resolves.toBe(EXPECTED_COMMAND_RESULT)

expect(fetchSpy.mock.calls.length).toEqual(1)

expect(fetchSpy.mock.calls[0][0]).toMatchInlineSnapshot(`"http://localhost:3000/"`)
expect(fetchSpy.mock.calls[0][0]).toEqual(telemetryUrl)
expect(fetchSpy.mock.calls[0][1]?.body).toMatchInlineSnapshot(`
"
celocli_invocation{success="true", version="5.2.3", command="test:telemetry-timeout"} 1
Expand Down
Loading
Loading