Skip to content

Commit

Permalink
Feat/web3 upgrade (#181)
Browse files Browse the repository at this point in the history
* update some deps

* hadrhat config/smaller default baseFee

* NFT tests/workaround edge case

* update web3 dep

* update Web3 types

* update web3/constructContractCaller

* legacy/update types

* hardhat config/fixed accounts

* LOrder tests/reenable sign with web3

* NFT Order tests/reenable sign with web3

* getBalance tests workaround

* cleanup

* update some deps

* update snapshots

* update perrDeps

* update required Node v

* NFT tests/account for dust

* hadrhat config/lower initialBaseFeePerGas

* Feat/ether v6 support (#182)

* install ethersV6 as alias

* providers/ethersV6

* distinct ethersV5 exports

* legacy/support ethersV6

* simple SDK/support ethersV6

* simpleSDK.tests/add ethersV6

* partialSDK.tests/add ethersV6

* LOrders.tests/add ethersV6

* NFT_Orders.tests/add ethersV6

* update snapshots

* examples/ add ethersV6

* perrDeps/update ethers versions

* update snapshots

* cleanup

* move ethers types to provider/ethers

* move web3 types to provider/web3

* untie FetchError type from AxiosError

* ethers -> ethersV5, ethersV6 -> ethers to fix types when used as lib

* cleanup

* README/update version

* less dependency on ethers types

* update README

* rremove temp tests

* tests/ethersV6/fix derivation path arg position
  • Loading branch information
Velenir authored Nov 12, 2024
1 parent 570622f commit 84b0c60
Show file tree
Hide file tree
Showing 32 changed files with 1,287 additions and 1,898 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Refer to the documentation of the ParaSwap API: https://developers.paraswap.netw

**Canonical**: bring only the functions you actually need

**Lightweight**: 400B Gzipped for the minimal variant
**Lightweight**: 10KB Gzipped for the minimal variant

## Installing ParaSwap SDK

Expand All @@ -29,7 +29,7 @@ You can see some examples in [/src/examples](src/examples) directory.

### Simple SDK

Can be created by providing `chainId` and either `axios` or `window.fetch` (or alternative `fetch` implementation), and an optional `version` (`'5'` or `'6.1'`) parameter that corresponds to the API version SDK will be making requests to. The resulting SDK will be able to use all methods that query the API.
Can be created by providing `chainId` and either `axios` or `window.fetch` (or alternative `fetch` implementation), and an optional `version` (`'5'` or `'6.2'`) parameter that corresponds to the API version SDK will be making requests to. The resulting SDK will be able to use all methods that query the API.

```ts
import { constructSimpleSDK } from '@paraswap/sdk';
Expand Down
17 changes: 16 additions & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import 'hardhat-switch-network';

dotenv.config();

const TEST_MNEMONIC =
'radar blur cabbage chef fix engine embark joy scheme fiction master release';

const config: HardhatUserConfig = {
solidity: '0.8.24',
networks: {
Expand All @@ -14,10 +17,22 @@ const config: HardhatUserConfig = {
// blockNumber: 12345678,
},
chainId: 1,
// have to config hardhat with fixed accounts unlocked, otherwise signTx and signTyped data fail when used in RPC calls to Node
// which breaks web3.js
// ethers signs data and txs locally off-chain as long as it has provate key
// web3 is a bit harder to init wallets for locally.
// impersonateAccounts doesn't work, even though it should logically fully unlock accounts,
// but only remore accounts are unlocked, fixed are not,
// so we always need to only use accounts generated from this mnemonic

// refs:
// https://github.com/NomicFoundation/hardhat/issues/3059
// https://github.com/NomicFoundation/hardhat/issues/1226
accounts: { mnemonic: TEST_MNEMONIC }, // and with fixed
// dynamically switch between networks configured here
// by calling `hre.switchNetwork(networkName)` thanks to hardhat-switch-network plugin
gasPrice: 8e9,
initialBaseFeePerGas: 1e10, // will break if used with a chain without eip1559
initialBaseFeePerGas: 1e8, // will break if used with a chain without eip1559
},
},
};
Expand Down
25 changes: 15 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"testEnvironment": "node"
},
"engines": {
"node": ">=12"
"node": ">=18"
},
"size-limit": [
{
Expand All @@ -54,26 +54,28 @@
"bignumber.js": "^9.1.2",
"dotenv": "^16.4.5",
"dts-cli": "^2.0.5",
"ethers": "^5.7.2",
"ethers": "^6.13.4",
"ethersV5": "npm:ethers@5",
"hardhat": "^2.22.15",
"hardhat-switch-network": "^1.1.1",
"husky": "^9.1.6",
"isomorphic-unfetch": "^4.0.2",
"size-limit": "^11.1.6",
"tslib": "^2.8.0",
"typedoc": "^0.26.10",
"typedoc-plugin-markdown": "^4.2.9",
"tslib": "^2.8.1",
"typedoc": "^0.26.11",
"typedoc-plugin-markdown": "^4.2.10",
"typedoc-plugin-missing-exports": "^3.0.0",
"typedoc-plugin-replace-text": "^4.0.0",
"typescript": "^5.6.3",
"viem": "^2.21.37",
"viem": "^2.21.39",
"wagmi": "^2.12.25",
"web3": "^1.10.4"
"web3": "^4.14.0"
},
"peerDependencies": {
"axios": ">=0.25.0 <2.0.0",
"ethers": "^5.5.0",
"web3": "^1.7.1"
"ethers": "^5.5.0 || ^6.0.0",
"viem": "^2.21.0",
"web3": "^4.14.0"
},
"peerDependenciesMeta": {
"axios": {
Expand All @@ -84,11 +86,14 @@
},
"web3": {
"optional": true
},
"viem": {
"optional": true
}
},
"dependencies": {
"@paraswap/core": "2.4.0",
"ts-essentials": "^10.0.2"
"ts-essentials": "^10.0.3"
},
"author": "ParaSwap",
"description": "ParaSwap SDK",
Expand Down
38 changes: 38 additions & 0 deletions src/examples/ethersV6.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import axios from 'axios';
import { ethers } from 'ethers';
import {
constructPartialSDK,
constructFullSDK,
constructGetAdapters,
constructEthersV6ContractCaller,
constructAxiosFetcher,
} from '..';

const fetcher = constructAxiosFetcher(axios);

const provider = ethers.getDefaultProvider(1);
const contractCaller = constructEthersV6ContractCaller({
ethersV6ProviderOrSigner: provider,
EthersV6Contract: ethers.Contract,
});

const paraswap = constructFullSDK({
chainId: 1,
fetcher,
contractCaller,
});

const res = paraswap.swap.getAdapters();

// type Promise<ContractTransaction>
const txResponse = paraswap.swap.approveToken('1', '0x...');
// type Promise<ContractTransaction[]>
const txResponses = paraswap.swap.approveTokenBulk('1', ['0x...']);

const partial = constructPartialSDK(
{ apiURL: '', chainId: 1, fetcher },
constructGetAdapters
);

const res1 = partial.getAdapters();
2 changes: 1 addition & 1 deletion src/examples/limitOrders_all.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import axios from 'axios';
import BigNumber from 'bignumber.js';
import { ethers } from 'ethers';
import { ethers } from 'ethersV5';
import { assert } from 'ts-essentials';
import {
// swap methods
Expand Down
2 changes: 1 addition & 1 deletion src/examples/limitOrders_partial.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import axios from 'axios';
import BigNumber from 'bignumber.js';
import { ethers } from 'ethers';
import { ethers } from 'ethersV5';
import { assert } from 'ts-essentials';
import {
// swap methods
Expand Down
2 changes: 1 addition & 1 deletion src/examples/limitOrders_postOrder.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import axios from 'axios';
import { ethers } from 'ethers';
import { ethers } from 'ethersV5';

import {
// swap methods
Expand Down
2 changes: 1 addition & 1 deletion src/examples/partial.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import axios from 'axios';
import { ethers } from 'ethers';
import { ethers } from 'ethersV5';
import {
constructPartialSDK,
constructGetAdapters,
Expand Down
6 changes: 3 additions & 3 deletions src/examples/sdk.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import axios from 'axios';
import { ethers } from 'ethers';
import { ethers } from 'ethersV5';
import {
constructPartialSDK,
constructFullSDK,
constructGetAdapters,
constructEthersContractCaller,
constructEthersV5ContractCaller,
constructAxiosFetcher,
} from '..';

const fetcher = constructAxiosFetcher(axios);

const provider = ethers.getDefaultProvider(1);
const contractCaller = constructEthersContractCaller({
const contractCaller = constructEthersV5ContractCaller({
ethersProviderOrSigner: provider,
EthersContract: ethers.Contract,
});
Expand Down
2 changes: 1 addition & 1 deletion src/examples/simple.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import axios from 'axios';
import { ethers, Wallet } from 'ethers';
import { ethers, Wallet } from 'ethersV5';
import {
constructSimpleSDK,
ContractMethod,
Expand Down
13 changes: 11 additions & 2 deletions src/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import { EthersV5ProviderDeps } from './providers/ethers';
import { EthersV6ProviderDeps } from './providers/ethersV6';
export { constructFetcher as constructAxiosFetcher } from './fetchers/axios';
export { constructFetcher as constructFetchFetcher } from './fetchers/fetch';
export {
constructContractCaller as constructEthersContractCaller,
EthersProviderDeps,
constructEthersV5ContractCaller as constructEthersContractCaller,
constructEthersV5ContractCaller,
EthersV5ProviderDeps,
} from './providers/ethers';
export {
constructContractCaller as constructEthersV6ContractCaller,
EthersV6ProviderDeps,
} from './providers/ethersV6';
export type EthersProviderDeps = EthersV5ProviderDeps | EthersV6ProviderDeps;

export {
constructContractCaller as constructWeb3ContractCaller,
Web3UnpromiEvent,
Expand Down
95 changes: 18 additions & 77 deletions src/helpers/misc.ts
Original file line number Diff line number Diff line change
@@ -1,70 +1,4 @@
import type {
Contract as EthersContract,
ContractFunction as EthersContractFunction,
PopulatedTransaction as EthersPopulatedTransaction,
BigNumber as EthersBigNumber,
} from 'ethers';
import type {
ContractSendMethod as Web3ContractSendMethod,
Contract as Web3Contract,
} from 'web3-eth-contract';
import { assert, Primitive } from 'ts-essentials';

import type { AxiosError, AxiosResponse } from 'axios';

export type EthersContractWithMethod<T extends string> = EthersContract & {
readonly [method in T]: EthersContractFunction;
} & {
readonly functions: { [method in T]: EthersContractFunction };

readonly callStatic: { [method in T]: EthersContractFunction };
readonly estimateGas: {
[method in T]: EthersContractFunction<EthersBigNumber>;
};
readonly populateTransaction: {
[method in T]: EthersContractFunction<EthersPopulatedTransaction>;
};
};

export function ethersContractHasMethods<T extends string>(
contract: EthersContract,
...methods: T[]
): contract is EthersContractWithMethod<T> {
return methods.every((method) => typeof contract[method] === 'function');
}

export function assertEthersContractHasMethods<T extends string>(
contract: EthersContract,
...methods: T[]
): asserts contract is EthersContractWithMethod<T> {
assert(
ethersContractHasMethods(contract, ...methods),
`Contract must have methods: ${methods.join(', ')}`
);
}

export type Web3ContractWithMethod<T extends string> = Web3Contract & {
methods: { [method in T]: Web3ContractSendMethod };
};

export function web3ContractHasMethods<T extends string>(
contract: Web3Contract,
...methods: T[]
): contract is Web3ContractWithMethod<T> {
return methods.every(
(method) => typeof contract.methods[method] === 'function'
);
}

export function assertWeb3ContractHasMethods<T extends string>(
contract: Web3Contract,
...methods: T[]
): asserts contract is Web3ContractWithMethod<T> {
assert(
web3ContractHasMethods(contract, ...methods),
`Contract must have methods: ${methods.join(', ')}`
);
}
import type { Primitive } from 'ts-essentials';

export const objectToFilledEntries = <T extends Record<string, unknown>>(
object: T
Expand All @@ -91,16 +25,23 @@ export const constructSearchString = <
return queryString && `?${queryString}`;
};

type FetcherErrorConstructorInput = Pick<
AxiosError,
'code' | 'request' | 'isAxiosError' | 'message'
> & {
response?: Pick<
AxiosResponse,
'data' | 'status' | 'statusText' | 'headers'
> & {
config: { url?: string; method?: string };
};
type MinAxiosError = {
code?: string;
request?: any;
isAxiosError: boolean;
message: string;
};

type MinAxiosResponse = {
data: any;
status: number;
statusText: string;
headers: Record<string, any>;
config: { url?: string; method?: string };
};

type FetcherErrorConstructorInput = MinAxiosError & {
response?: MinAxiosResponse;
};

export interface FetcherErrorInterface extends FetcherErrorConstructorInput {
Expand Down
Loading

0 comments on commit 84b0c60

Please sign in to comment.