diff --git a/README.md b/README.md index 58b45fb6..ce05be9d 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,34 @@ export interface CloneUniswapContractDetails { v3Override?: CloneUniswapContractDetailsV3 | undefined; } +export interface Token { + chainId: ChainId; + contractAddress: string; + decimals: number; + symbol: string; + name: string; +} + +export interface NativeCurrencyInfo { + name: string; + symbol: string; +} + +export interface CustomNetwork { + nameNetwork: string; + multicallContractAddress: string; + nativeCurrency: NativeCurrencyInfo; + nativeWrappedTokenInfo: Token; + // defined your base tokens here! + baseTokens?: { + usdt?: Token | undefined; + dai?: Token | undefined; + comp?: Token | undefined; + usdc?: Token | undefined; + wbtc?: Token | undefined; + }; +} + export class UniswapPairSettings { slippage: number; deadlineMinutes: number; @@ -137,6 +165,8 @@ export class UniswapPairSettings { gasSettings?: GasSettings = undefined; // can be used to pass in a fork of uniswap contract details cloneUniswapContractDetails?: CloneUniswapContractDetails = undefined; + // can be used to define unsupported networks + customNetwork?: CustomNetwork = undefined; constructor(settings?: { slippage?: number | undefined; @@ -145,12 +175,14 @@ export class UniswapPairSettings { uniswapVersions?: UniswapVersion[] | undefined; gasSettings?: GasSettings | undefined; cloneUniswapContractDetails?: CloneUniswapContractDetails | undefined; + customNetwork?: CustomNetwork | undefined; }) { this.slippage = settings?.slippage || 0.005; this.deadlineMinutes = settings?.deadlineMinutes || 20; this.disableMultihops = settings?.disableMultihops || false; this.gasSettings = settings?.gasSettings; this.cloneUniswapContractDetails = settings?.cloneUniswapContractDetails; + this.customNetwork = settings?.customNetwork; if ( Array.isArray(settings?.uniswapVersions) && @@ -173,9 +205,9 @@ export class UniswapPairSettings { } ``` -### Ethereum provider +### With only the chainId -This will use your ethereum provider you pass in. This will work with any web3 provider, ethers provider or custom provider. For example when using MetaMask you can pass in the window.ethereum and it work. You must supply the ethereum address and the wallet be approved to use for the dApp and unlocked before passing it in. The uniswap sdk makes those assumptions without them it will not work as MetaMask is not allowed access to your dApp. Any change of network or ethereum address change you will need to handle in your dApp and regenerate the uniswap pair context. Most the time the contract addresses for your tokens are different anyway. +This will use a infura endpoint without you having to pass in a node ```ts import { UniswapPair, ChainId, UniswapVersion, ETH } from 'simple-uniswap-sdk'; @@ -187,7 +219,7 @@ const uniswapPair = new UniswapPair({ toTokenContractAddress: '0x1985365e9f78359a9B6AD760e32412f4a445E862', // the ethereum address of the user using this part of the dApp ethereumAddress: '0xB1E6079212888f0bE0cf55874B2EB9d7a5e02cD9', - ethereumProvider: YOUR_WEB3_ETHERS_OR_CUSTOM_ETHEREUM_PROVIDER, + chainId: ChainId.MAINNET, settings: new UniswapPairSettings({ // if not supplied it will use `0.005` which is 0.5% // please pass it in as a full number decimal so 0.7% @@ -210,9 +242,9 @@ const uniswapPair = new UniswapPair({ const uniswapPairFactory = await uniswapPair.createFactory(); ``` -### With only the chainId +### With your own provider url -This will use a infura endpoint without you having to pass in a node +This will use your node you pass in you must pass us the chainId as well, this stops the ethers instance calling pointless `JSONRPC` calls to get the chain id before every `JSONRPC` call. ```ts import { UniswapPair, ChainId, UniswapVersion, ETH } from 'simple-uniswap-sdk'; @@ -225,6 +257,7 @@ const uniswapPair = new UniswapPair({ // the ethereum address of the user using this part of the dApp ethereumAddress: '0xB1E6079212888f0bE0cf55874B2EB9d7a5e02cD9', chainId: ChainId.MAINNET, + providerUrl: YOUR_PROVIDER_URL, settings: new UniswapPairSettings({ // if not supplied it will use `0.005` which is 0.5% // please pass it in as a full number decimal so 0.7% @@ -247,9 +280,9 @@ const uniswapPair = new UniswapPair({ const uniswapPairFactory = await uniswapPair.createFactory(); ``` -### With your own provider url +### Custom Ethereum provider -This will use your node you pass in you must pass us the chainId as well, this stops the ethers instance calling pointless `JSONRPC` calls to get the chain id before every `JSONRPC` call. +This will use your ethereum provider you pass in. This will work with any web3 provider, ethers provider or custom provider. For example when using MetaMask you can pass in the window.ethereum and it work. You must supply the ethereum address and the wallet be approved to use for the dApp and unlocked before passing it in. The uniswap sdk makes those assumptions without them it will not work as MetaMask is not allowed access to your dApp. Any change of network or ethereum address change you will need to handle in your dApp and regenerate the uniswap pair context. Most the time the contract addresses for your tokens are different anyway. ```ts import { UniswapPair, ChainId, UniswapVersion, ETH } from 'simple-uniswap-sdk'; @@ -261,8 +294,7 @@ const uniswapPair = new UniswapPair({ toTokenContractAddress: '0x1985365e9f78359a9B6AD760e32412f4a445E862', // the ethereum address of the user using this part of the dApp ethereumAddress: '0xB1E6079212888f0bE0cf55874B2EB9d7a5e02cD9', - chainId: ChainId.MAINNET, - providerUrl: YOUR_PROVIDER_URL, + ethereumProvider: YOUR_WEB3_ETHERS_OR_CUSTOM_ETHEREUM_PROVIDER, settings: new UniswapPairSettings({ // if not supplied it will use `0.005` which is 0.5% // please pass it in as a full number decimal so 0.7% diff --git a/package.json b/package.json index 4b2affe8..c08cd070 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "simple-uniswap-sdk", - "version": "3.5.0", + "version": "3.6.0", "description": "Simple easy to understand SDK for uniswap which looks over best v2 and v3 to find you the best swap quote", "main": "dist/cjs/index.js", "module": "./dist/esm/index.js", diff --git a/src/common/tokens/eth.ts b/src/common/tokens/eth.ts index 10495fa5..4c5baac8 100644 --- a/src/common/tokens/eth.ts +++ b/src/common/tokens/eth.ts @@ -1,4 +1,5 @@ import { ChainId } from '../../enums/chain-id'; +import { NativeCurrencyInfo } from '../../factories/pair/models/custom-network'; import { Token } from '../../factories/token/models/token'; import { ErrorCodes } from '../errors/error-codes'; import { UniswapError } from '../errors/uniswap-error'; @@ -24,12 +25,20 @@ export const isNativeEth = (contractAddress: string): boolean => { return contractAddress.includes(ETH_PREFIX); }; -export const turnTokenIntoEthForResponse = (token: Token): Token => { +export const turnTokenIntoEthForResponse = ( + token: Token, + nativeCurrencyInfo: NativeCurrencyInfo | undefined +): Token => { const clone = deepClone(token); // clear down contract address clone.contractAddress = 'NO_CONTRACT_ADDRESS'; - clone.symbol = ETH_SYMBOL; - clone.name = ETH_NAME; + if (nativeCurrencyInfo) { + clone.symbol = nativeCurrencyInfo.symbol; + clone.name = nativeCurrencyInfo.name; + } else { + clone.symbol = ETH_SYMBOL; + clone.name = ETH_NAME; + } return clone; }; @@ -102,7 +111,18 @@ export class ETH { * Get ETH token info by chain id * @param chainId The chain id */ - public static info(chainId: ChainId | number): Token { + public static info( + chainId: ChainId | number, + customNetworkNativeWrappedTokenInfo: Token | undefined = undefined + ): Token { + if (customNetworkNativeWrappedTokenInfo) { + return { + ...customNetworkNativeWrappedTokenInfo, + contractAddress: appendEthToContractAddress( + customNetworkNativeWrappedTokenInfo.contractAddress + ), + }; + } switch (chainId) { case ChainId.MAINNET: return this.MAINNET(); diff --git a/src/common/utils/trade-path.ts b/src/common/utils/trade-path.ts index 346ddbdf..ca401b41 100644 --- a/src/common/utils/trade-path.ts +++ b/src/common/utils/trade-path.ts @@ -6,13 +6,20 @@ import { ETH } from '../tokens/eth'; export function getTradePath( chainId: ChainId, fromToken: Token, - toToken: Token + toToken: Token, + customNetworkNativeWrappedTokenInfo: Token | undefined ): TradePath { - if (fromToken.contractAddress === ETH.info(chainId).contractAddress) { + if ( + fromToken.contractAddress === + ETH.info(chainId, customNetworkNativeWrappedTokenInfo).contractAddress + ) { return TradePath.ethToErc20; } - if (toToken.contractAddress === ETH.info(chainId).contractAddress) { + if ( + toToken.contractAddress === + ETH.info(chainId, customNetworkNativeWrappedTokenInfo).contractAddress + ) { return TradePath.erc20ToEth; } diff --git a/src/custom-multicall.ts b/src/custom-multicall.ts new file mode 100644 index 00000000..286d524b --- /dev/null +++ b/src/custom-multicall.ts @@ -0,0 +1,15 @@ +import { Provider } from '@ethersproject/providers'; +import { Multicall } from 'ethereum-multicall'; + +export class CustomMulticall extends Multicall { + constructor( + ethersProvider: Provider, + multicallCustomContractAddress?: string | undefined + ) { + super({ + ethersProvider, + tryAggregate: true, + multicallCustomContractAddress, + }); + } +} diff --git a/src/ethers-provider.spec.ts b/src/ethers-provider.spec.ts index fa3eec7f..d1d7aba3 100644 --- a/src/ethers-provider.spec.ts +++ b/src/ethers-provider.spec.ts @@ -51,7 +51,7 @@ describe('EthersProvider', () => { }); }).toThrowError( new UniswapError( - 'Can not find chain name for 10293. This lib only supports mainnet(1), ropsten(4), kovan(42), rinkeby(4), görli(5) and ropsten(3)', + 'Can not find chain name for 10293. This lib only supports mainnet(1), ropsten(4), kovan(42), rinkeby(4) and görli(5)', ErrorCodes.canNotFindChainId ) ); diff --git a/src/ethers-provider.ts b/src/ethers-provider.ts index 22819f35..e952331f 100644 --- a/src/ethers-provider.ts +++ b/src/ethers-provider.ts @@ -3,14 +3,17 @@ import { Contract, ContractInterface, providers } from 'ethers'; import { ErrorCodes } from './common/errors/error-codes'; import { UniswapError } from './common/errors/uniswap-error'; import { ChainId, ChainNames } from './enums/chain-id'; +import { CustomNetwork } from './factories/pair/models/custom-network'; export interface ChainIdAndProvider { chainId: ChainId; providerUrl?: string | undefined; + customNetwork?: CustomNetwork | undefined; } export interface EthereumProvider { ethereumProvider: any; + customNetwork?: CustomNetwork | undefined; } export class EthersProvider { @@ -22,14 +25,7 @@ export class EthersProvider { constructor(private _providerContext: ChainIdAndProvider | EthereumProvider) { const chainId = (this._providerContext).chainId; if (chainId) { - const chainName = ChainNames.get(chainId); - if (!chainName) { - throw new UniswapError( - `Can not find chain name for ${chainId}. This lib only supports mainnet(1), ropsten(4), kovan(42), rinkeby(4), görli(5) and ropsten(3)`, - ErrorCodes.canNotFindChainId - ); - } - + const chainName = this.getChainName(chainId); const providerUrl = (this._providerContext) .providerUrl; if (providerUrl) { @@ -64,6 +60,27 @@ export class EthersProvider { } } + /** + * Get the chain name + * @param chainId The chain id + * @returns + */ + private getChainName(chainId: number): string { + if (this._providerContext.customNetwork) { + return this._providerContext.customNetwork.nameNetwork; + } + + const chainName = ChainNames.get(chainId); + if (!chainName) { + throw new UniswapError( + `Can not find chain name for ${chainId}. This lib only supports mainnet(1), ropsten(4), kovan(42), rinkeby(4) and görli(5)`, + ErrorCodes.canNotFindChainId + ); + } + + return chainName; + } + /** * Creates a contract instance * @param abi The ABI diff --git a/src/factories/pair/models/custom-network.ts b/src/factories/pair/models/custom-network.ts new file mode 100644 index 00000000..cdc70980 --- /dev/null +++ b/src/factories/pair/models/custom-network.ts @@ -0,0 +1,21 @@ +import { Token } from '../../token/models/token'; + +export interface NativeCurrencyInfo { + name: string; + symbol: string; +} + +export interface CustomNetwork { + nameNetwork: string; + multicallContractAddress: string; + nativeCurrency: NativeCurrencyInfo; + nativeWrappedTokenInfo: Token; + // defined your base tokens here! + baseTokens?: { + usdt?: Token | undefined; + dai?: Token | undefined; + comp?: Token | undefined; + usdc?: Token | undefined; + wbtc?: Token | undefined; + }; +} diff --git a/src/factories/pair/models/uniswap-pair-settings.ts b/src/factories/pair/models/uniswap-pair-settings.ts index 2f271d48..ba4a27f2 100644 --- a/src/factories/pair/models/uniswap-pair-settings.ts +++ b/src/factories/pair/models/uniswap-pair-settings.ts @@ -2,6 +2,7 @@ import { ErrorCodes } from '../../../common/errors/error-codes'; import { UniswapError } from '../../../common/errors/uniswap-error'; import { UniswapVersion } from '../../../enums/uniswap-version'; import { CloneUniswapContractDetails } from './clone-uniswap-contract-details'; +import { CustomNetwork } from './custom-network'; import { GasSettings } from './gas-settings'; export class UniswapPairSettings { @@ -11,6 +12,7 @@ export class UniswapPairSettings { uniswapVersions: UniswapVersion[] = [UniswapVersion.v2, UniswapVersion.v3]; gasSettings?: GasSettings = undefined; cloneUniswapContractDetails?: CloneUniswapContractDetails = undefined; + customNetwork?: CustomNetwork = undefined; constructor(settings?: { slippage?: number | undefined; @@ -19,12 +21,14 @@ export class UniswapPairSettings { uniswapVersions?: UniswapVersion[] | undefined; gasSettings?: GasSettings | undefined; cloneUniswapContractDetails?: CloneUniswapContractDetails | undefined; + customNetwork?: CustomNetwork | undefined; }) { this.slippage = settings?.slippage || 0.005; this.deadlineMinutes = settings?.deadlineMinutes || 20; this.disableMultihops = settings?.disableMultihops || false; this.gasSettings = settings?.gasSettings; this.cloneUniswapContractDetails = settings?.cloneUniswapContractDetails; + this.customNetwork = settings?.customNetwork; if ( Array.isArray(settings?.uniswapVersions) && diff --git a/src/factories/pair/uniswap-pair.factory.ts b/src/factories/pair/uniswap-pair.factory.ts index c7194a62..ab8f32e4 100644 --- a/src/factories/pair/uniswap-pair.factory.ts +++ b/src/factories/pair/uniswap-pair.factory.ts @@ -30,12 +30,14 @@ export class UniswapPairFactory { private _fromTokenFactory = new TokenFactory( this._uniswapPairFactoryContext.fromToken.contractAddress, this._uniswapPairFactoryContext.ethersProvider, + this._uniswapPairFactoryContext.settings.customNetwork, this._uniswapPairFactoryContext.settings.cloneUniswapContractDetails ); private _toTokenFactory = new TokenFactory( this._uniswapPairFactoryContext.toToken.contractAddress, - this._uniswapPairFactoryContext.ethersProvider + this._uniswapPairFactoryContext.ethersProvider, + this._uniswapPairFactoryContext.settings.customNetwork ); private _uniswapRouterFactory = new UniswapRouterFactory( @@ -352,7 +354,10 @@ export class UniswapPairFactory { bestRouteQuote.uniswapVersion ) : undefined, - toToken: turnTokenIntoEthForResponse(this.toToken), + toToken: turnTokenIntoEthForResponse( + this.toToken, + this._uniswapPairFactoryContext.settings?.customNetwork?.nativeCurrency + ), toBalance: new BigNumber(bestRouteQuotes.toBalance) .shiftedBy(this.toToken.decimals * -1) .toFixed(), @@ -485,7 +490,10 @@ export class UniswapPairFactory { toBalance: new BigNumber(bestRouteQuotes.toBalance) .shiftedBy(this.toToken.decimals * -1) .toFixed(), - fromToken: turnTokenIntoEthForResponse(this.fromToken), + fromToken: turnTokenIntoEthForResponse( + this.fromToken, + this._uniswapPairFactoryContext.settings?.customNetwork?.nativeCurrency + ), fromBalance: { hasEnough: bestRouteQuotes.hasEnoughBalance, balance: bestRouteQuotes.fromBalance, @@ -505,7 +513,13 @@ export class UniswapPairFactory { */ private tradePath(): TradePath { const network = this._uniswapPairFactoryContext.ethersProvider.network(); - return getTradePath(network.chainId, this.fromToken, this.toToken); + return getTradePath( + network.chainId, + this.fromToken, + this.toToken, + this._uniswapPairFactoryContext.settings.customNetwork + ?.nativeWrappedTokenInfo + ); } /** diff --git a/src/factories/pair/uniswap-pair.ts b/src/factories/pair/uniswap-pair.ts index d30ca042..7c68d2e2 100644 --- a/src/factories/pair/uniswap-pair.ts +++ b/src/factories/pair/uniswap-pair.ts @@ -88,7 +88,11 @@ export class UniswapPair { )).providerUrl; if (providerUrl && chainId) { - this._ethersProvider = new EthersProvider({ chainId, providerUrl }); + this._ethersProvider = new EthersProvider({ + chainId, + providerUrl, + customNetwork: this._uniswapPairContext.settings?.customNetwork, + }); return; } @@ -102,7 +106,10 @@ export class UniswapPair { )).ethereumProvider; if (ethereumProvider) { - this._ethersProvider = new EthersProvider({ ethereumProvider }); + this._ethersProvider = new EthersProvider({ + ethereumProvider, + customNetwork: this._uniswapPairContext.settings?.customNetwork, + }); return; } @@ -116,21 +123,26 @@ export class UniswapPair { * Create factory to be able to call methods on the 2 tokens */ public async createFactory(): Promise { - const chainId = this._ethersProvider.network().chainId; - if ( - chainId !== ChainId.MAINNET && - chainId !== ChainId.ROPSTEN && - chainId !== ChainId.RINKEBY && - chainId !== ChainId.GÖRLI && - chainId !== ChainId.KOVAN - ) { - throw new UniswapError( - `ChainId - ${chainId} is not supported. This lib only supports mainnet(1), ropsten(4), kovan(42), rinkeby(4), görli(5) and ropsten(3)`, - ErrorCodes.chainIdNotSupported - ); + if (this._uniswapPairContext.settings?.customNetwork === undefined) { + const chainId = this._ethersProvider.network().chainId; + if ( + chainId !== ChainId.MAINNET && + chainId !== ChainId.ROPSTEN && + chainId !== ChainId.RINKEBY && + chainId !== ChainId.GÖRLI && + chainId !== ChainId.KOVAN + ) { + throw new UniswapError( + `ChainId - ${chainId} is not supported. This lib only supports mainnet(1), ropsten(4), kovan(42), rinkeby(4), and görli(5)`, + ErrorCodes.chainIdNotSupported + ); + } } - const tokensFactory = new TokensFactory(this._ethersProvider); + const tokensFactory = new TokensFactory( + this._ethersProvider, + this._uniswapPairContext.settings?.customNetwork + ); const tokens = await tokensFactory.getTokens([ this._uniswapPairContext.fromTokenContractAddress, this._uniswapPairContext.toTokenContractAddress, diff --git a/src/factories/router/uniswap-router.factory.ts b/src/factories/router/uniswap-router.factory.ts index c7a0fa3c..21b9e3bd 100644 --- a/src/factories/router/uniswap-router.factory.ts +++ b/src/factories/router/uniswap-router.factory.ts @@ -3,7 +3,6 @@ import { CallReturnContext, ContractCallContext, ContractCallResults, - Multicall, } from 'ethereum-multicall'; import { ExactInputSingleRequest, @@ -32,6 +31,7 @@ import { onlyUnique } from '../../common/utils/only-unique'; import { parseEther } from '../../common/utils/parse-ether'; import { toEthersBigNumber } from '../../common/utils/to-ethers-big-number'; import { getTradePath } from '../../common/utils/trade-path'; +import { CustomMulticall } from '../../custom-multicall'; import { ChainId } from '../../enums/chain-id'; import { TradePath } from '../../enums/trade-path'; import { UniswapVersion } from '../../enums/uniswap-version'; @@ -61,10 +61,10 @@ import { import { UniswapRouterContractFactoryV3 } from './v3/uniswap-router-contract.factory.v3'; export class UniswapRouterFactory { - private _multicall = new Multicall({ - ethersProvider: this._ethersProvider.provider, - tryAggregate: true, - }); + private _multicall = new CustomMulticall( + this._ethersProvider.provider, + this._settings?.customNetwork?.multicallContractAddress + ); private _uniswapRouterContractFactoryV2 = new UniswapRouterContractFactoryV2( this._ethersProvider, @@ -82,6 +82,7 @@ export class UniswapRouterFactory { private _tokensFactory = new TokensFactory( this._ethersProvider, + this._settings.customNetwork, this._settings.cloneUniswapContractDetails ); @@ -1702,7 +1703,10 @@ export class UniswapRouterFactory { this.allTokens.find((t) => t.contractAddress === c)! ); if (index === 0) { - return turnTokenIntoEthForResponse(token); + return turnTokenIntoEthForResponse( + token, + this._settings?.customNetwork?.nativeCurrency + ); } return token; @@ -1730,11 +1734,17 @@ export class UniswapRouterFactory { transaction, tradeExpires, routePathArrayTokenMap: [ - turnTokenIntoEthForResponse(this._fromToken), + turnTokenIntoEthForResponse( + this._fromToken, + this._settings?.customNetwork?.nativeCurrency + ), this._toToken, ], routeText: `${ - turnTokenIntoEthForResponse(this._fromToken).symbol + turnTokenIntoEthForResponse( + this._fromToken, + this._settings?.customNetwork?.nativeCurrency + ).symbol } > ${this._toToken.symbol}`, routePathArray: [ this._fromToken.contractAddress, @@ -1821,7 +1831,10 @@ export class UniswapRouterFactory { this.allTokens.find((t) => t.contractAddress === c)! ); if (index === callReturnContext.methodParameters[1].length - 1) { - return turnTokenIntoEthForResponse(token); + return turnTokenIntoEthForResponse( + token, + this._settings?.customNetwork?.nativeCurrency + ); } return token; @@ -1850,10 +1863,16 @@ export class UniswapRouterFactory { tradeExpires, routePathArrayTokenMap: [ this._fromToken, - turnTokenIntoEthForResponse(this._toToken), + turnTokenIntoEthForResponse( + this._toToken, + this._settings?.customNetwork?.nativeCurrency + ), ], routeText: `${this._fromToken.symbol} > ${ - turnTokenIntoEthForResponse(this._toToken).symbol + turnTokenIntoEthForResponse( + this._toToken, + this._settings?.customNetwork?.nativeCurrency + ).symbol }`, routePathArray: [ this._fromToken.contractAddress, @@ -1976,7 +1995,12 @@ export class UniswapRouterFactory { */ private tradePath(): TradePath { const network = this._ethersProvider.network(); - return getTradePath(network.chainId, this._fromToken, this._toToken); + return getTradePath( + network.chainId, + this._fromToken, + this._toToken, + this._settings.customNetwork?.nativeWrappedTokenInfo + ); } private get allTokens(): Token[] { @@ -1985,7 +2009,7 @@ export class UniswapRouterFactory { private get allMainTokens(): Token[] { if (this._ethersProvider.provider.network.chainId === ChainId.MAINNET) { - return [ + const tokens: (Token | undefined)[] = [ this.USDTTokenForConnectedNetwork, this.COMPTokenForConnectedNetwork, this.USDCTokenForConnectedNetwork, @@ -1993,6 +2017,8 @@ export class UniswapRouterFactory { this.WETHTokenForConnectedNetwork, this.WBTCTokenForConnectedNetwork, ]; + + return tokens.filter((t) => t !== undefined) as Token[]; } return [this.WETHTokenForConnectedNetwork]; @@ -2015,7 +2041,9 @@ export class UniswapRouterFactory { pairs.push([this._fromToken, this.WETHTokenForConnectedNetwork]); } - return pairs.filter((t) => t[0].contractAddress !== t[1].contractAddress); + return this.filterUndefinedTokens(pairs).filter( + (t) => t[0].contractAddress !== t[1].contractAddress + ); } const pairs = [[this._fromToken, this.WETHTokenForConnectedNetwork]]; @@ -2024,7 +2052,7 @@ export class UniswapRouterFactory { private get mainCurrenciesPairsForToToken(): Token[][] { if (this._ethersProvider.provider.network.chainId === ChainId.MAINNET) { - const pairs: Token[][] = [ + const pairs: (Token | undefined)[][] = [ [this.USDTTokenForConnectedNetwork, this._toToken], [this.COMPTokenForConnectedNetwork, this._toToken], [this.USDCTokenForConnectedNetwork, this._toToken], @@ -2039,7 +2067,9 @@ export class UniswapRouterFactory { pairs.push([this.WETHTokenForConnectedNetwork, this._toToken]); } - return pairs.filter((t) => t[0].contractAddress !== t[1].contractAddress); + return this.filterUndefinedTokens(pairs).filter( + (t) => t[0].contractAddress !== t[1].contractAddress + ); } const pairs: Token[][] = [ @@ -2051,7 +2081,7 @@ export class UniswapRouterFactory { private get mainCurrenciesPairsForUSDT(): Token[][] { if (this._ethersProvider.provider.network.chainId === ChainId.MAINNET) { - const pairs: Token[][] = [ + const pairs: (Token | undefined)[][] = [ [this.USDTTokenForConnectedNetwork, this.COMPTokenForConnectedNetwork], [this.USDTTokenForConnectedNetwork, this.DAITokenForConnectedNetwork], [this.USDTTokenForConnectedNetwork, this.USDCTokenForConnectedNetwork], @@ -2068,7 +2098,7 @@ export class UniswapRouterFactory { ]); } - return pairs; + return this.filterUndefinedTokens(pairs); } return []; @@ -2076,7 +2106,7 @@ export class UniswapRouterFactory { private get mainCurrenciesPairsForCOMP(): Token[][] { if (this._ethersProvider.provider.network.chainId === ChainId.MAINNET) { - const pairs: Token[][] = [ + const pairs: (Token | undefined)[][] = [ [this.COMPTokenForConnectedNetwork, this.USDTTokenForConnectedNetwork], [this.COMPTokenForConnectedNetwork, this.DAITokenForConnectedNetwork], [this.COMPTokenForConnectedNetwork, this.USDCTokenForConnectedNetwork], @@ -2092,7 +2122,7 @@ export class UniswapRouterFactory { ]); } - return pairs; + return this.filterUndefinedTokens(pairs); } return []; @@ -2100,7 +2130,7 @@ export class UniswapRouterFactory { private get mainCurrenciesPairsForDAI(): Token[][] { if (this._ethersProvider.provider.network.chainId === ChainId.MAINNET) { - const pairs: Token[][] = [ + const pairs: (Token | undefined)[][] = [ [this.DAITokenForConnectedNetwork, this.COMPTokenForConnectedNetwork], [this.DAITokenForConnectedNetwork, this.WBTCTokenForConnectedNetwork], [this.DAITokenForConnectedNetwork, this.USDTTokenForConnectedNetwork], @@ -2117,7 +2147,7 @@ export class UniswapRouterFactory { ]); } - return pairs; + return this.filterUndefinedTokens(pairs); } return []; @@ -2125,7 +2155,7 @@ export class UniswapRouterFactory { private get mainCurrenciesPairsForUSDC(): Token[][] { if (this._ethersProvider.provider.network.chainId === ChainId.MAINNET) { - const pairs: Token[][] = [ + const pairs: (Token | undefined)[][] = [ [this.USDCTokenForConnectedNetwork, this.USDTTokenForConnectedNetwork], [this.USDCTokenForConnectedNetwork, this.COMPTokenForConnectedNetwork], [this.USDCTokenForConnectedNetwork, this.DAITokenForConnectedNetwork], @@ -2142,7 +2172,7 @@ export class UniswapRouterFactory { ]); } - return pairs; + return this.filterUndefinedTokens(pairs); } return []; @@ -2150,12 +2180,14 @@ export class UniswapRouterFactory { private get mainCurrenciesPairsForWBTC(): Token[][] { if (this._ethersProvider.provider.network.chainId === ChainId.MAINNET) { - return [ + const tokens: (Token | undefined)[][] = [ [this.WBTCTokenForConnectedNetwork, this.USDTTokenForConnectedNetwork], [this.WBTCTokenForConnectedNetwork, this.DAITokenForConnectedNetwork], [this.WBTCTokenForConnectedNetwork, this.USDCTokenForConnectedNetwork], [this.WBTCTokenForConnectedNetwork, this.WETHTokenForConnectedNetwork], ]; + + return this.filterUndefinedTokens(tokens); } return []; @@ -2163,39 +2195,71 @@ export class UniswapRouterFactory { private get mainCurrenciesPairsForWETH(): Token[][] { if (this._ethersProvider.provider.network.chainId === ChainId.MAINNET) { - return [ + const tokens: (Token | undefined)[][] = [ [this.WETHTokenForConnectedNetwork, this.USDTTokenForConnectedNetwork], [this.WETHTokenForConnectedNetwork, this.COMPTokenForConnectedNetwork], [this.WETHTokenForConnectedNetwork, this.DAITokenForConnectedNetwork], [this.WETHTokenForConnectedNetwork, this.USDCTokenForConnectedNetwork], [this.WETHTokenForConnectedNetwork, this.WBTCTokenForConnectedNetwork], ]; + + return this.filterUndefinedTokens(tokens); } return []; } + private filterUndefinedTokens(tokens: (Token | undefined)[][]): Token[][] { + return tokens.filter( + (t) => t[0] !== undefined && t[1] !== undefined + ) as Token[][]; + } + private get USDTTokenForConnectedNetwork() { + if (this._settings.customNetwork) { + return this._settings.customNetwork.baseTokens?.usdt; + } + return USDT.token(this._ethersProvider.provider.network.chainId); } private get COMPTokenForConnectedNetwork() { + if (this._settings.customNetwork) { + return this._settings.customNetwork.baseTokens?.comp; + } + return COMP.token(this._ethersProvider.provider.network.chainId); } private get DAITokenForConnectedNetwork() { + if (this._settings.customNetwork) { + return this._settings.customNetwork.baseTokens?.dai; + } + return DAI.token(this._ethersProvider.provider.network.chainId); } private get USDCTokenForConnectedNetwork() { + if (this._settings.customNetwork) { + return this._settings.customNetwork.baseTokens?.usdc; + } + return USDC.token(this._ethersProvider.provider.network.chainId); } private get WETHTokenForConnectedNetwork() { + if (this._settings.customNetwork) { + return this._settings.customNetwork.nativeWrappedTokenInfo; + } + return WETHContract.token(this._ethersProvider.provider.network.chainId); } private get WBTCTokenForConnectedNetwork() { + if (this._settings.customNetwork) { + return this._settings.customNetwork.baseTokens?.wbtc; + } + return WBTC.token(this._ethersProvider.provider.network.chainId); } } diff --git a/src/factories/token/token.factory.ts b/src/factories/token/token.factory.ts index 79229d03..6032a2cf 100644 --- a/src/factories/token/token.factory.ts +++ b/src/factories/token/token.factory.ts @@ -1,22 +1,24 @@ -import { ContractCallContext, Multicall } from 'ethereum-multicall'; +import { ContractCallContext } from 'ethereum-multicall'; import { BigNumber } from 'ethers'; import { ContractContext as ERC20ContractContext } from '../../ABI/types/erc20-contract'; import { ContractContext } from '../../common/contract-context'; import { ETH, isNativeEth } from '../../common/tokens/eth'; import { isTokenOverrideInfo } from '../../common/tokens/overrides'; import { getAddress } from '../../common/utils/get-address'; +import { CustomMulticall } from '../../custom-multicall'; import { UniswapVersion } from '../../enums/uniswap-version'; import { EthersProvider } from '../../ethers-provider'; import { uniswapContracts } from '../../uniswap-contract-context/get-uniswap-contracts'; import { CloneUniswapContractDetails } from '../pair/models/clone-uniswap-contract-details'; +import { CustomNetwork } from '../pair/models/custom-network'; import { AllowanceAndBalanceOf } from './models/allowance-balance-of'; import { Token } from './models/token'; export class TokenFactory { - private _multicall = new Multicall({ - ethersProvider: this._ethersProvider.provider, - tryAggregate: true, - }); + private _multicall = new CustomMulticall( + this._ethersProvider.provider, + this._customNetwork?.multicallContractAddress + ); private _erc20TokenContract = this._ethersProvider.getContract( @@ -27,6 +29,7 @@ export class TokenFactory { constructor( private _tokenContractAddress: string, private _ethersProvider: EthersProvider, + private _customNetwork?: CustomNetwork | undefined, private _cloneUniswapContractDetails?: | CloneUniswapContractDetails | undefined @@ -37,7 +40,10 @@ export class TokenFactory { */ public async getToken(): Promise { if (isNativeEth(this._tokenContractAddress)) { - return ETH.info(this._ethersProvider.network().chainId); + return ETH.info( + this._ethersProvider.network().chainId, + this._customNetwork?.nativeWrappedTokenInfo + ); } else { const overridenToken = isTokenOverrideInfo(this._tokenContractAddress); if (overridenToken) { diff --git a/src/factories/token/tokens.factory.ts b/src/factories/token/tokens.factory.ts index bf8f199f..ddbf3bfb 100644 --- a/src/factories/token/tokens.factory.ts +++ b/src/factories/token/tokens.factory.ts @@ -1,5 +1,5 @@ import BigNumber from 'bignumber.js'; -import { ContractCallContext, Multicall } from 'ethereum-multicall'; +import { ContractCallContext } from 'ethereum-multicall'; import { BigNumber as EthersBigNumber } from 'ethers'; import { ContractContext } from '../../common/contract-context'; import { ErrorCodes } from '../../common/errors/error-codes'; @@ -7,21 +7,24 @@ import { UniswapError } from '../../common/errors/uniswap-error'; import { ETH, isNativeEth } from '../../common/tokens/eth'; import { isTokenOverrideInfo } from '../../common/tokens/overrides'; import { getAddress } from '../../common/utils/get-address'; +import { CustomMulticall } from '../../custom-multicall'; import { UniswapVersion } from '../../enums/uniswap-version'; import { EthersProvider } from '../../ethers-provider'; import { uniswapContracts } from '../../uniswap-contract-context/get-uniswap-contracts'; import { CloneUniswapContractDetails } from '../pair/models/clone-uniswap-contract-details'; +import { CustomNetwork } from '../pair/models/custom-network'; import { Token } from './models/token'; import { TokenWithAllowanceInfo } from './models/token-with-allowance-info'; export class TokensFactory { - private _multicall = new Multicall({ - ethersProvider: this._ethersProvider.provider, - tryAggregate: true, - }); + private _multicall = new CustomMulticall( + this._ethersProvider.provider, + this._customNetwork?.multicallContractAddress + ); constructor( private _ethersProvider: EthersProvider, + private _customNetwork?: CustomNetwork | undefined, private _cloneUniswapContractDetails?: | CloneUniswapContractDetails | undefined @@ -72,7 +75,12 @@ export class TokensFactory { contractCallContexts.push(contractCallContext); } else { - tokens.push(ETH.info(this._ethersProvider.network().chainId)); + tokens.push( + ETH.info( + this._ethersProvider.network().chainId, + this._customNetwork?.nativeWrappedTokenInfo + ) + ); } } @@ -140,7 +148,11 @@ export class TokensFactory { ) ); } else { - const token = ETH.info(this._ethersProvider.network().chainId); + const token = ETH.info( + this._ethersProvider.network().chainId, + this._customNetwork?.nativeWrappedTokenInfo + ); + if (format) { results.push({ allowanceAndBalanceOf: { @@ -171,7 +183,10 @@ export class TokensFactory { '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', balanceOf: await this._ethersProvider.balanceOf(ethereumAddress), }, - token: ETH.info(this._ethersProvider.network().chainId), + token: ETH.info( + this._ethersProvider.network().chainId, + this._customNetwork?.nativeWrappedTokenInfo + ), }); } }