Skip to content

Commit

Permalink
Merge pull request #24 from uniswap-integration/feature/custom-network
Browse files Browse the repository at this point in the history
Feature/custom network
  • Loading branch information
joshstevens19 authored Oct 25, 2021
2 parents 8bebd9a + e737fa7 commit 75c2bcf
Show file tree
Hide file tree
Showing 14 changed files with 312 additions and 85 deletions.
50 changes: 41 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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) &&
Expand All @@ -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';
Expand All @@ -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%
Expand All @@ -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';
Expand All @@ -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%
Expand All @@ -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';
Expand All @@ -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%
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
28 changes: 24 additions & 4 deletions src/common/tokens/eth.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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;
};
Expand Down Expand Up @@ -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();
Expand Down
13 changes: 10 additions & 3 deletions src/common/utils/trade-path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
15 changes: 15 additions & 0 deletions src/custom-multicall.ts
Original file line number Diff line number Diff line change
@@ -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,
});
}
}
2 changes: 1 addition & 1 deletion src/ethers-provider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
);
Expand Down
33 changes: 25 additions & 8 deletions src/ethers-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -22,14 +25,7 @@ export class EthersProvider {
constructor(private _providerContext: ChainIdAndProvider | EthereumProvider) {
const chainId = (<ChainIdAndProvider>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 = (<ChainIdAndProvider>this._providerContext)
.providerUrl;
if (providerUrl) {
Expand Down Expand Up @@ -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
Expand Down
21 changes: 21 additions & 0 deletions src/factories/pair/models/custom-network.ts
Original file line number Diff line number Diff line change
@@ -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;
};
}
4 changes: 4 additions & 0 deletions src/factories/pair/models/uniswap-pair-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
Expand All @@ -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) &&
Expand Down
22 changes: 18 additions & 4 deletions src/factories/pair/uniswap-pair.factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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,
Expand All @@ -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
);
}

/**
Expand Down
Loading

0 comments on commit 75c2bcf

Please sign in to comment.