Skip to content

Commit

Permalink
fix: upgrade web3 dependency to v4 in defender sdk (#601)
Browse files Browse the repository at this point in the history
* deps: bump web3 js

* fix: tests + provider API

* fix: leftovers
  • Loading branch information
MCarlomagno authored Oct 25, 2024
1 parent 717ae25 commit 1a78fad
Show file tree
Hide file tree
Showing 7 changed files with 381 additions and 2,207 deletions.
2 changes: 1 addition & 1 deletion examples/relayer-web3-provider/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@
"dependencies": {
"@openzeppelin/defender-sdk-relay-signer-client": "1.15.0",
"dotenv": "^16.3.1",
"web3": "^1.10.0"
"web3": "^4.14.0"
}
}
11 changes: 4 additions & 7 deletions packages/relay-signer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@
"@ethersproject/abstract-signer": "^5.7.0",
"@ethersproject/hash": "^5.7.0",
"@ethersproject/transactions": "^5.7.0",
"jest-mock-extended": "^3.0.5",
"web3-core": "^1.10.4",
"web3-core-helpers": "^1.10.0"
"jest-mock-extended": "^3.0.5"
},
"dependencies": {
"@ethersproject/providers": "^5.7.2",
Expand All @@ -43,10 +41,9 @@
"lodash": "^4.17.21"
},
"peerDependencies": {
"web3": "^1.10.0",
"web3-core": "^1.10.4",
"web3-core-helpers": "^1.10.0",
"web3-utils": "^1.10.0"
"web3": "^4.14.0",
"web3-core": "^4.7.0",
"web3-utils": "^4.3.2"
},
"publishConfig": {
"access": "public"
Expand Down
5 changes: 4 additions & 1 deletion packages/relay-signer/src/relayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ export class Relayer implements IRelayer {
const { ActionRelayer } = require('./action');
this.relayer = new ActionRelayer(credentials);
} else if (isApiCredentials(credentials)) {
this.relayer = new RelaySignerClient(credentials);
this.relayer = new RelaySignerClient({
...credentials,
authConfig: { ...credentials.authConfig, type: 'relay' },
});
} else {
throw new Error(
`Missing credentials for creating a Relayer instance. If you are running this code in an Action, make sure you pass the "credentials" parameter from the handler to the Relayer constructor. If you are running this on your own process, then pass an object with the "apiKey" and "apiSecret" generated by the relayer.`,
Expand Down
26 changes: 9 additions & 17 deletions packages/relay-signer/src/web3/query.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,23 @@
import { JsonRpcPayload, JsonRpcResponse } from 'web3-core-helpers';
import { JsonRpcRequest, JsonRpcResponseWithResult } from 'web3';
import { Relayer } from '../relayer';
import { RelayerParams } from '../models/relayer';
import { isRelayer } from '../ethers/utils';

type Web3Callback = (error: Error | null, result?: JsonRpcResponse) => void;

export class DefenderRelayQueryProvider {
protected relayer: Relayer;
protected id = 1;

constructor(relayerCredentials: RelayerParams | Relayer) {
this.relayer = isRelayer(relayerCredentials) ? relayerCredentials : new Relayer(relayerCredentials);
}
public sendAsync(payload: JsonRpcPayload, callback: Web3Callback): void {
return this.send(payload, callback);
}

public send(payload: JsonRpcPayload, callback: Web3Callback): void {
const payloadId = typeof payload.id === 'string' ? parseInt(payload.id) : payload.id;
this.relayer
.call({ method: payload.method, params: payload.params ?? [] })
.then((response) =>
callback(null, {
...response,
id: payloadId ?? response.id ?? this.id++,
}),
)
.catch((err) => callback(err, undefined));
private toJsonRpcResponse = <T>(payload: any): JsonRpcResponseWithResult<T> => ({
jsonrpc: '2.0',
id: payload.id ?? this.id++,
result: payload.result,
});

public async request<T>(payload: JsonRpcRequest<string[]>): Promise<JsonRpcResponseWithResult<T>> {
return this.relayer.call({ method: payload.method, params: payload.params ?? [] }).then(this.toJsonRpcResponse<T>);
}
}
75 changes: 37 additions & 38 deletions packages/relay-signer/src/web3/sender.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { Relayer } from '../relayer';
import { DefenderRelayQueryProvider } from './query';
import { DefenderRelaySenderOptions, DefenderRelaySenderProvider } from './sender';
import { RelayerTransaction } from '../models/transactions';
import Web3 from 'web3';
import { AbiItem } from 'web3-utils';
import { JsonRpcIdentifier, Web3 } from 'web3';
import { AbiItem, toHex } from 'web3-utils';

type DefenderRelaySenderProviderWithOptions = DefenderRelaySenderProvider & {
options: DefenderRelaySenderOptions;
Expand All @@ -31,7 +31,7 @@ describe('web3/sender', () => {
transactionId: '1',
validUntil: '2031-05-19T23:09:47.129Z',
data: '0x01',
value: '0x02',
value: '0x2',
createdAt: '2022-10-30T00:11:35.501Z',
};

Expand Down Expand Up @@ -66,11 +66,11 @@ describe('web3/sender', () => {
policies: {},
});

provider.sendAsync.mockImplementation((payload, callback) => {
provider.request.mockImplementation((payload) => {
const result = (value: any) =>
callback(null, {
Promise.resolve({
result: value,
jsonrpc: '2.0',
jsonrpc: '2.0' as JsonRpcIdentifier,
id: typeof payload.id === 'number' ? payload.id! : parseInt(payload.id!),
});

Expand All @@ -80,13 +80,15 @@ describe('web3/sender', () => {
case 'eth_estimateGas':
return result('0xea60');
case 'eth_getTransactionReceipt':
return result(null);
return result({ transactionHash: tx.hash });
case 'eth_subscribe':
return result('0x9cef478923ff08bf67fde6c64013158d');
case 'eth_getBlockByNumber':
return result('0x6b11e5');
return result({ baseFeePerGas: '0x0' });
case 'eth_blockNumber':
return result('0x69db6e');
default:
console.log(payload);
return result(null);
}
});

Expand All @@ -99,9 +101,9 @@ describe('web3/sender', () => {

sender.options.speed = 'safeLow';
const request = pick(tx, 'from', 'to', 'data', 'value');
const sent = await new Promise((resolve) => web3.eth.sendTransaction(request).on('transactionHash', resolve));
const sent = await web3.eth.sendTransaction(request);

expect(sent).toEqual(tx.hash);
expect(sent.transactionHash).toEqual(tx.hash);
expect(relayer.sendTransaction).toHaveBeenCalledWith({
...request,
gasLimit: '0xea60',
Expand All @@ -118,16 +120,15 @@ describe('web3/sender', () => {

sender.options.speed = undefined;
const request = { ...pick(tx, 'from', 'to', 'data', 'value', 'gasLimit'), gasPrice: 1e9 };
const sent = await new Promise((resolve) => web3.eth.sendTransaction(request).on('transactionHash', resolve));
const sent = await web3.eth.sendTransaction(request);

expect(sent).toEqual(tx.hash);
expect(sent.transactionHash).toEqual(tx.hash);
expect(relayer.sendTransaction).toHaveBeenCalledWith({
...request,
gasLimit: '0xea60',
speed: undefined,
gasPrice: '0x3b9aca00',
maxFeePerGas: undefined,
maxPriorityFeePerGas: undefined,
gas: '0xea60',
});
});

Expand All @@ -136,54 +137,56 @@ describe('web3/sender', () => {

sender.options.speed = undefined;
const request = pick(tx, 'from', 'to', 'data', 'value', 'gasLimit', 'maxFeePerGas', 'maxPriorityFeePerGas');
const sent = await new Promise((resolve) => web3.eth.sendTransaction(request).on('transactionHash', resolve));
const sent = await web3.eth.sendTransaction(request);

expect(sent).toEqual(tx.hash);
expect(sent.transactionHash).toEqual(tx.hash);
expect(relayer.sendTransaction).toHaveBeenCalledWith({
...request,
gasLimit: '0xea60',
gas: '0xea60',
speed: undefined,
gasPrice: undefined,
maxFeePerGas: '0x2540be400',
maxPriorityFeePerGas: '0x3b9aca00',
});
});

it('replaces a tx by nonce', async () => {
const replacedHash = tx.hash;
tx.hash = replacedHash;
relayer.replaceTransactionByNonce.mockResolvedValue({ ...tx, hash: replacedHash });

const request = pick(tx, 'from', 'to', 'data', 'value', 'gasLimit', 'nonce');
const sent = await new Promise((resolve) => web3.eth.sendTransaction(request).on('transactionHash', resolve));
const sent = await web3.eth.sendTransaction(request);

expect(sent).toEqual(replacedHash);
expect(sent.transactionHash).toEqual(replacedHash);
expect(relayer.replaceTransactionByNonce).toHaveBeenCalledWith(30, {
...request,
gasLimit: '0xea60',
speed: undefined,
gasPrice: '0x3b9aca00',
gas: '0xea60',
nonce: '0x1e',
gasPrice: undefined,
maxFeePerGas: '0x3b9aca00',
maxPriorityFeePerGas: '0x3b9aca00',
});

relayer.replaceTransactionByNonce.mockResolvedValue(tx);
tx.hash = replacedHash;
});

it('sends a contract tx', async () => {
relayer.sendTransaction.mockResolvedValue(tx);

sender.options.speed = 'safeLow';
const contract = new web3.eth.Contract(transferAbi, tx.to, { from });
const sent = await new Promise((resolve) =>
contract.methods.transfer(from, '0x02').send().on('transactionHash', resolve),
);
const sent = await contract.methods.transfer?.(from, '0x02').send();

expect(sent).toEqual(tx.hash);
expect(sent?.transactionHash).toEqual(tx.hash);
expect(relayer.sendTransaction).toHaveBeenCalledWith({
...pick(tx, 'from', 'gaslimit', 'speed'),
data: contract.methods.transfer(from, '0x02').encodeABI(),
to: tx.to.toLowerCase(),
data: contract.methods.transfer?.(from, '0x02').encodeABI(),
to: tx.to,
gasLimit: '0xea60',
speed: tx.speed,
gasPrice: undefined,
validUntil: undefined,
});
});

Expand All @@ -192,20 +195,16 @@ describe('web3/sender', () => {

sender.options.speed = 'safeLow';
const contract = new web3.eth.Contract(transferAbi, tx.to, { from });
const sent = await new Promise((resolve) =>
contract.methods.transfer(from, '0x02').send({ nonce: tx.nonce }).on('transactionHash', resolve),
);
const sent = await contract.methods.transfer?.(from, '0x02').send({ nonce: toHex(tx.nonce) });

expect(sent).toEqual(tx.hash);
expect(sent?.transactionHash).toEqual(tx.hash);
expect(relayer.replaceTransactionByNonce).toHaveBeenCalledWith(30, {
...pick(tx, 'from', 'gaslimit', 'speed'),
nonce: '0x1e',
data: contract.methods.transfer(from, '0x02').encodeABI(),
to: tx.to.toLowerCase(),
data: contract.methods.transfer?.(from, '0x02').encodeABI(),
to: tx.to,
gasLimit: '0xea60',
speed: tx.speed,
gasPrice: undefined,
validUntil: undefined,
});
});
});
Loading

0 comments on commit 1a78fad

Please sign in to comment.