Add terra ust for quoting
This commit is contained in:
parent
29704b701d
commit
0c50e93dc0
|
@ -1,41 +1,92 @@
|
||||||
import { ethers } from "ethers";
|
import { ethers } from "ethers";
|
||||||
import { UniEvmToken } from "./uniswap-core";
|
|
||||||
import { QuickswapRouter } from "./quickswap";
|
import { QuickswapRouter as MaticRouter } from "./quickswap";
|
||||||
import { SingleAmmSwapRouter as UniswapV3Router } from "./uniswap-v3";
|
import { UniswapV3Router as EthRouter } from "./uniswap-v3";
|
||||||
|
import { TerraUstTransfer as UstRouter } from "./terra-ust-transfer";
|
||||||
import {
|
import {
|
||||||
ETH_NETWORK_CHAIN_ID,
|
WETH_TOKEN_INFO,
|
||||||
POLYGON_NETWORK_CHAIN_ID,
|
WMATIC_TOKEN_INFO,
|
||||||
|
UST_TOKEN_INFO,
|
||||||
|
WORMHOLE_CHAIN_ID_ETHEREUM,
|
||||||
|
WORMHOLE_CHAIN_ID_POLYGON,
|
||||||
|
WORMHOLE_CHAIN_ID_TERRA,
|
||||||
} from "../utils/consts";
|
} from "../utils/consts";
|
||||||
|
import { addFixedAmounts, subtractFixedAmounts } from "../utils/math";
|
||||||
|
import { UstLocation } from "./generic";
|
||||||
|
import {
|
||||||
|
ExactInParameters,
|
||||||
|
ExactOutParameters,
|
||||||
|
makeExactInParameters,
|
||||||
|
makeExactOutParameters,
|
||||||
|
} from "./uniswap-core";
|
||||||
|
import { ChainId } from "@certusone/wormhole-sdk";
|
||||||
|
|
||||||
export { PROTOCOL as PROTOCOL_UNISWAP_V2 } from "./uniswap-v2";
|
export { PROTOCOL as PROTOCOL_UNISWAP_V2 } from "./uniswap-v2";
|
||||||
export { PROTOCOL as PROTOCOL_UNISWAP_V3 } from "./uniswap-v3";
|
export { PROTOCOL as PROTOCOL_UNISWAP_V3 } from "./uniswap-v3";
|
||||||
|
export { PROTOCOL as PROTOCOL_TERRA_UST_TRANSFER } from "./terra-ust-transfer";
|
||||||
|
|
||||||
|
export const TERRA_UST = UST_TOKEN_INFO.address;
|
||||||
|
|
||||||
export enum QuoteType {
|
export enum QuoteType {
|
||||||
ExactIn = 1,
|
ExactIn = 1,
|
||||||
ExactOut,
|
ExactOut,
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeRouter(provider: ethers.providers.Provider, id: number) {
|
export function makeEvmProviderFromAddress(tokenAddress: string) {
|
||||||
switch (id) {
|
switch (tokenAddress) {
|
||||||
case ETH_NETWORK_CHAIN_ID: {
|
case WETH_TOKEN_INFO.address: {
|
||||||
return new UniswapV3Router(provider);
|
const url = process.env.REACT_APP_GOERLI_PROVIDER;
|
||||||
|
if (!url) {
|
||||||
|
throw new Error("Could not find REACT_APP_GOERLI_PROVIDER");
|
||||||
}
|
}
|
||||||
case POLYGON_NETWORK_CHAIN_ID: {
|
return new ethers.providers.StaticJsonRpcProvider(url);
|
||||||
return new QuickswapRouter(provider);
|
}
|
||||||
|
case WMATIC_TOKEN_INFO.address: {
|
||||||
|
const url = process.env.REACT_APP_MUMBAI_PROVIDER;
|
||||||
|
if (!url) {
|
||||||
|
throw new Error("Could not find REACT_APP_MUMBAI_PROVIDER");
|
||||||
|
}
|
||||||
|
return new ethers.providers.StaticJsonRpcProvider(url);
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
throw Error("unrecognized chain id");
|
throw Error("unrecognized evm token address");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getUstAddress(id: number): string {
|
export function getChainIdFromAddress(tokenAddress: string) {
|
||||||
switch (id) {
|
switch (tokenAddress) {
|
||||||
case ETH_NETWORK_CHAIN_ID: {
|
case WETH_TOKEN_INFO.address: {
|
||||||
return "0x36Ed51Afc79619b299b238898E72ce482600568a";
|
return WORMHOLE_CHAIN_ID_ETHEREUM;
|
||||||
}
|
}
|
||||||
case POLYGON_NETWORK_CHAIN_ID: {
|
case WMATIC_TOKEN_INFO.address: {
|
||||||
return "0xe3a1c77e952b57b5883f6c906fc706fcc7d4392c";
|
return WORMHOLE_CHAIN_ID_POLYGON;
|
||||||
|
}
|
||||||
|
case UST_TOKEN_INFO.address: {
|
||||||
|
return WORMHOLE_CHAIN_ID_TERRA;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
throw Error("unrecognized evm token address");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function makeRouter(tokenAddress: string, loc: UstLocation) {
|
||||||
|
switch (tokenAddress) {
|
||||||
|
case WETH_TOKEN_INFO.address: {
|
||||||
|
const provider = makeEvmProviderFromAddress(tokenAddress);
|
||||||
|
const router = new EthRouter(provider);
|
||||||
|
await router.initialize(loc);
|
||||||
|
return router;
|
||||||
|
}
|
||||||
|
case WMATIC_TOKEN_INFO.address: {
|
||||||
|
const provider = makeEvmProviderFromAddress(tokenAddress);
|
||||||
|
const router = new MaticRouter(provider);
|
||||||
|
await router.initialize(loc);
|
||||||
|
return router;
|
||||||
|
}
|
||||||
|
case UST_TOKEN_INFO.address: {
|
||||||
|
return new UstRouter();
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
throw Error("unrecognized chain id");
|
throw Error("unrecognized chain id");
|
||||||
|
@ -51,123 +102,105 @@ function splitSlippageInHalf(totalSlippage: string): string {
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RelayerFee {
|
export interface RelayerFee {
|
||||||
amount: ethers.BigNumber;
|
amount: string;
|
||||||
tokenAddress: string;
|
tokenAddress: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExactInParameters {
|
|
||||||
protocol: string;
|
|
||||||
amountIn: ethers.BigNumber;
|
|
||||||
minAmountOut: ethers.BigNumber;
|
|
||||||
deadline: ethers.BigNumber;
|
|
||||||
poolFee: string;
|
|
||||||
path: [string, string];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ExactInCrossParameters {
|
export interface ExactInCrossParameters {
|
||||||
|
amountIn: string;
|
||||||
|
minAmountOut: string;
|
||||||
src: ExactInParameters;
|
src: ExactInParameters;
|
||||||
dst: ExactInParameters;
|
dst: ExactInParameters;
|
||||||
relayerFee: RelayerFee;
|
relayerFee: RelayerFee;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExactOutParameters {
|
|
||||||
protocol: string;
|
|
||||||
amountOut: ethers.BigNumber;
|
|
||||||
maxAmountIn: ethers.BigNumber;
|
|
||||||
deadline: ethers.BigNumber;
|
|
||||||
poolFee: string;
|
|
||||||
path: [string, string];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ExactOutCrossParameters {
|
export interface ExactOutCrossParameters {
|
||||||
|
amountOut: string;
|
||||||
|
maxAmountIn: string;
|
||||||
src: ExactOutParameters;
|
src: ExactOutParameters;
|
||||||
dst: ExactOutParameters;
|
dst: ExactOutParameters;
|
||||||
relayerFee: RelayerFee;
|
relayerFee: RelayerFee;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UniswapToUniswapQuoter {
|
export class UniswapToUniswapQuoter {
|
||||||
// providers
|
// tokens
|
||||||
srcProvider: ethers.providers.Provider;
|
tokenInAddress: string;
|
||||||
dstProvider: ethers.providers.Provider;
|
tokenOutAddress: string;
|
||||||
|
|
||||||
// networks
|
|
||||||
srcNetwork: ethers.providers.Network;
|
|
||||||
dstNetwork: ethers.providers.Network;
|
|
||||||
|
|
||||||
// routers
|
// routers
|
||||||
srcRouter: UniswapV3Router | QuickswapRouter;
|
srcRouter: UstRouter | EthRouter | MaticRouter;
|
||||||
dstRouter: UniswapV3Router | QuickswapRouter;
|
dstRouter: UstRouter | EthRouter | MaticRouter;
|
||||||
|
|
||||||
// tokens
|
constructor() {}
|
||||||
srcTokenIn: UniEvmToken;
|
|
||||||
srcTokenOut: UniEvmToken;
|
|
||||||
dstTokenIn: UniEvmToken;
|
|
||||||
dstTokenOut: UniEvmToken;
|
|
||||||
|
|
||||||
constructor(
|
async initialize(
|
||||||
srcProvider: ethers.providers.Provider,
|
tokenInAddress: string,
|
||||||
dstProvider: ethers.providers.Provider
|
tokenOutAddress: string
|
||||||
) {
|
): Promise<void> {
|
||||||
this.srcProvider = srcProvider;
|
if (tokenInAddress !== this.tokenInAddress) {
|
||||||
this.dstProvider = dstProvider;
|
this.tokenInAddress = tokenInAddress;
|
||||||
|
this.srcRouter = await makeRouter(tokenInAddress, UstLocation.Out);
|
||||||
}
|
}
|
||||||
|
|
||||||
async initialize(): Promise<void> {
|
if (tokenOutAddress != this.tokenOutAddress) {
|
||||||
[this.srcNetwork, this.dstNetwork] = await Promise.all([
|
this.tokenOutAddress = tokenOutAddress;
|
||||||
this.srcProvider.getNetwork(),
|
this.dstRouter = await makeRouter(tokenOutAddress, UstLocation.In);
|
||||||
this.dstProvider.getNetwork(),
|
}
|
||||||
]);
|
|
||||||
|
|
||||||
this.srcRouter = makeRouter(this.srcProvider, this.srcNetwork.chainId);
|
|
||||||
this.dstRouter = makeRouter(this.dstProvider, this.dstNetwork.chainId);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sameChain(): boolean {
|
|
||||||
return this.srcNetwork.chainId === this.dstNetwork.chainId;
|
|
||||||
}
|
|
||||||
|
|
||||||
async makeSrcTokens(
|
|
||||||
tokenInAddress: string
|
|
||||||
): Promise<[UniEvmToken, UniEvmToken]> {
|
|
||||||
const ustOutAddress = getUstAddress(this.srcNetwork.chainId);
|
|
||||||
|
|
||||||
const router = this.srcRouter;
|
|
||||||
|
|
||||||
[this.srcTokenIn, this.srcTokenOut] = await Promise.all([
|
|
||||||
router.makeToken(tokenInAddress),
|
|
||||||
router.makeToken(ustOutAddress),
|
|
||||||
]);
|
|
||||||
return [this.srcTokenIn, this.srcTokenOut];
|
|
||||||
}
|
|
||||||
|
|
||||||
async makeDstTokens(
|
|
||||||
tokenOutAddress: string
|
|
||||||
): Promise<[UniEvmToken, UniEvmToken]> {
|
|
||||||
const ustInAddress = getUstAddress(this.dstNetwork.chainId);
|
|
||||||
|
|
||||||
const router = this.dstRouter;
|
|
||||||
|
|
||||||
[this.dstTokenIn, this.dstTokenOut] = await Promise.all([
|
|
||||||
router.makeToken(ustInAddress),
|
|
||||||
router.makeToken(tokenOutAddress),
|
|
||||||
]);
|
|
||||||
return [this.dstTokenIn, this.dstTokenOut];
|
|
||||||
}
|
|
||||||
|
|
||||||
async computeAndVerifySrcPoolAddress(): Promise<string> {
|
async computeAndVerifySrcPoolAddress(): Promise<string> {
|
||||||
return this.srcRouter.computeAndVerifyPoolAddress(
|
return this.srcRouter.computeAndVerifyPoolAddress();
|
||||||
this.srcTokenIn,
|
|
||||||
this.srcTokenOut
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async computeAndVerifyDstPoolAddress(): Promise<string> {
|
async computeAndVerifyDstPoolAddress(): Promise<string> {
|
||||||
return this.dstRouter.computeAndVerifyPoolAddress(
|
return this.dstRouter.computeAndVerifyPoolAddress();
|
||||||
this.dstTokenIn,
|
}
|
||||||
this.dstTokenOut
|
|
||||||
);
|
computeSwapSlippage(slippage): string {
|
||||||
|
if (this.isSrcUst() || this.isDstUst()) {
|
||||||
|
return slippage;
|
||||||
|
}
|
||||||
|
|
||||||
|
return splitSlippageInHalf(slippage);
|
||||||
|
}
|
||||||
|
|
||||||
|
getRelayerFee(amount: string): RelayerFee {
|
||||||
|
if (this.isSrcUst()) {
|
||||||
|
return {
|
||||||
|
amount: this.srcRouter.computeUnitAmountOut(amount),
|
||||||
|
tokenAddress: TERRA_UST, // TODO: make sure this is the right address for bridge transfer?
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const relayerFee: RelayerFee = {
|
||||||
|
amount: this.srcRouter.computeUnitAmountOut(amount),
|
||||||
|
tokenAddress: this.srcRouter.getTokenOutAddress(),
|
||||||
|
};
|
||||||
|
return relayerFee;
|
||||||
|
}
|
||||||
|
|
||||||
|
makeSrcExactInParameters(
|
||||||
|
amountIn: string,
|
||||||
|
minAmountOut: string
|
||||||
|
): ExactInParameters {
|
||||||
|
if (this.isSrcUst()) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
return makeExactInParameters(this.srcRouter, amountIn, minAmountOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
makeDstExactInParameters(
|
||||||
|
amountIn: string,
|
||||||
|
minAmountOut: string
|
||||||
|
): ExactInParameters {
|
||||||
|
if (this.isDstUst()) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
return makeExactInParameters(this.dstRouter, amountIn, minAmountOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
async computeExactInParameters(
|
async computeExactInParameters(
|
||||||
|
@ -175,71 +208,68 @@ export class UniswapToUniswapQuoter {
|
||||||
slippage: string,
|
slippage: string,
|
||||||
relayerFeeUst: string
|
relayerFeeUst: string
|
||||||
): Promise<ExactInCrossParameters> {
|
): Promise<ExactInCrossParameters> {
|
||||||
const singleSlippage = splitSlippageInHalf(slippage);
|
const singleSlippage = this.computeSwapSlippage(slippage);
|
||||||
|
|
||||||
// src quote
|
// src quote
|
||||||
const srcRouter = this.srcRouter;
|
const srcRouter = this.srcRouter;
|
||||||
const srcTokenIn = this.srcTokenIn;
|
const srcMinAmountOut = await srcRouter.fetchExactInQuote(
|
||||||
const srcTokenOut = this.srcTokenOut;
|
|
||||||
const srcMinAmountOut = await srcRouter.fetchQuoteAmountOut(
|
|
||||||
srcTokenIn,
|
|
||||||
srcTokenOut,
|
|
||||||
amountIn,
|
amountIn,
|
||||||
singleSlippage
|
singleSlippage
|
||||||
);
|
);
|
||||||
|
|
||||||
// dst quote
|
// dst quote
|
||||||
const dstRouter = this.dstRouter;
|
const dstRouter = this.dstRouter;
|
||||||
const dstAmountIn = this.srcTokenOut.formatAmount(srcMinAmountOut);
|
const dstAmountIn = srcMinAmountOut; //srcRouter.formatAmountOut(srcMinAmountOut);
|
||||||
if (Number(dstAmountIn) < Number(relayerFeeUst)) {
|
if (Number(dstAmountIn) < Number(relayerFeeUst)) {
|
||||||
throw Error(
|
throw Error(
|
||||||
`srcAmountOut <= relayerFeeUst. ${dstAmountIn} vs ${relayerFeeUst}`
|
`srcAmountOut <= relayerFeeUst. ${dstAmountIn} vs ${relayerFeeUst}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dstTokenIn = this.dstTokenIn;
|
const dstAmountInAfterFee = subtractFixedAmounts(
|
||||||
const dstTokenOut = this.dstTokenOut;
|
|
||||||
const dstAmountInAfterFee = dstTokenIn.subtractAmounts(
|
|
||||||
dstAmountIn,
|
dstAmountIn,
|
||||||
relayerFeeUst
|
relayerFeeUst,
|
||||||
|
dstRouter.getTokenInDecimals()
|
||||||
);
|
);
|
||||||
|
|
||||||
const dstMinAmountOut = await dstRouter.fetchQuoteAmountOut(
|
const dstMinAmountOut = await dstRouter.fetchExactInQuote(
|
||||||
dstTokenIn,
|
|
||||||
dstTokenOut,
|
|
||||||
dstAmountInAfterFee,
|
dstAmountInAfterFee,
|
||||||
singleSlippage
|
singleSlippage
|
||||||
);
|
);
|
||||||
|
|
||||||
const srcParameters: ExactInParameters = {
|
// organize parameters
|
||||||
protocol: srcRouter.getProtocol(),
|
|
||||||
amountIn: srcTokenIn.computeUnitAmount(amountIn),
|
|
||||||
minAmountOut: srcMinAmountOut,
|
|
||||||
poolFee: srcRouter.getPoolFee(),
|
|
||||||
deadline: srcRouter.getTradeDeadline(),
|
|
||||||
path: [srcTokenIn.getAddress(), srcTokenOut.getAddress()],
|
|
||||||
};
|
|
||||||
|
|
||||||
const dstParameters: ExactInParameters = {
|
|
||||||
protocol: dstRouter.getProtocol(),
|
|
||||||
amountIn: dstTokenIn.computeUnitAmount(dstAmountInAfterFee),
|
|
||||||
minAmountOut: dstMinAmountOut,
|
|
||||||
poolFee: dstRouter.getPoolFee(),
|
|
||||||
deadline: dstRouter.getTradeDeadline(),
|
|
||||||
path: [dstTokenIn.getAddress(), dstTokenOut.getAddress()],
|
|
||||||
};
|
|
||||||
|
|
||||||
const params: ExactInCrossParameters = {
|
const params: ExactInCrossParameters = {
|
||||||
src: srcParameters,
|
amountIn: amountIn,
|
||||||
dst: dstParameters,
|
minAmountOut: dstMinAmountOut,
|
||||||
relayerFee: {
|
src: this.makeSrcExactInParameters(amountIn, srcMinAmountOut),
|
||||||
amount: dstTokenIn.computeUnitAmount(relayerFeeUst),
|
dst: this.makeDstExactInParameters(dstAmountInAfterFee, dstMinAmountOut),
|
||||||
tokenAddress: this.dstTokenIn.getAddress(),
|
relayerFee: this.getRelayerFee(relayerFeeUst),
|
||||||
},
|
|
||||||
};
|
};
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
makeSrcExactOutParameters(
|
||||||
|
amountOut: string,
|
||||||
|
maxAmountIn: string
|
||||||
|
): ExactOutParameters {
|
||||||
|
if (this.isSrcUst()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
return makeExactOutParameters(this.srcRouter, amountOut, maxAmountIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
makeDstExactOutParameters(
|
||||||
|
amountOut: string,
|
||||||
|
maxAmountIn: string
|
||||||
|
): ExactOutParameters {
|
||||||
|
if (this.isDstUst()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
return makeExactOutParameters(this.dstRouter, amountOut, maxAmountIn);
|
||||||
|
}
|
||||||
|
|
||||||
async computeExactOutParameters(
|
async computeExactOutParameters(
|
||||||
amountOut: string,
|
amountOut: string,
|
||||||
slippage: string,
|
slippage: string,
|
||||||
|
@ -249,69 +279,85 @@ export class UniswapToUniswapQuoter {
|
||||||
|
|
||||||
// dst quote first
|
// dst quote first
|
||||||
const dstRouter = this.dstRouter;
|
const dstRouter = this.dstRouter;
|
||||||
const dstTokenIn = this.dstTokenIn;
|
const dstMaxAmountIn = await dstRouter.fetchExactOutQuote(
|
||||||
const dstTokenOut = this.dstTokenOut;
|
|
||||||
const dstMaxAmountIn = await dstRouter.fetchQuoteAmountIn(
|
|
||||||
dstTokenIn,
|
|
||||||
dstTokenOut,
|
|
||||||
amountOut,
|
amountOut,
|
||||||
singleSlippage
|
singleSlippage
|
||||||
);
|
);
|
||||||
|
|
||||||
// src quote
|
// src quote
|
||||||
const srcRouter = this.srcRouter;
|
const srcRouter = this.srcRouter;
|
||||||
const srcAmountOut = this.dstTokenIn.formatAmount(dstMaxAmountIn);
|
const srcAmountOut = dstMaxAmountIn;
|
||||||
if (Number(srcAmountOut) < Number(relayerFeeUst)) {
|
if (Number(srcAmountOut) < Number(relayerFeeUst)) {
|
||||||
throw Error(
|
throw Error(
|
||||||
`dstAmountIn <= relayerFeeUst. ${srcAmountOut} vs ${relayerFeeUst}`
|
`dstAmountIn <= relayerFeeUst. ${srcAmountOut} vs ${relayerFeeUst}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const srcTokenIn = this.srcTokenIn;
|
const srcAmountOutBeforeFee = addFixedAmounts(
|
||||||
const srcTokenOut = this.srcTokenOut;
|
|
||||||
const srcAmountOutBeforeFee = srcTokenOut.addAmounts(
|
|
||||||
srcAmountOut,
|
srcAmountOut,
|
||||||
relayerFeeUst
|
relayerFeeUst,
|
||||||
|
srcRouter.getTokenOutDecimals()
|
||||||
);
|
);
|
||||||
|
|
||||||
const srcMaxAmountIn = await srcRouter.fetchQuoteAmountIn(
|
const srcMaxAmountIn = await srcRouter.fetchExactOutQuote(
|
||||||
srcTokenIn,
|
|
||||||
srcTokenOut,
|
|
||||||
srcAmountOutBeforeFee,
|
srcAmountOutBeforeFee,
|
||||||
singleSlippage
|
singleSlippage
|
||||||
);
|
);
|
||||||
|
|
||||||
const srcParameters: ExactOutParameters = {
|
// organize parameters
|
||||||
protocol: srcRouter.getProtocol(),
|
|
||||||
amountOut: srcTokenOut.computeUnitAmount(srcAmountOutBeforeFee),
|
|
||||||
maxAmountIn: srcMaxAmountIn,
|
|
||||||
poolFee: srcRouter.getPoolFee(),
|
|
||||||
deadline: srcRouter.getTradeDeadline(),
|
|
||||||
path: [srcTokenIn.getAddress(), srcTokenOut.getAddress()],
|
|
||||||
};
|
|
||||||
|
|
||||||
const dstParameters: ExactOutParameters = {
|
|
||||||
protocol: dstRouter.getProtocol(),
|
|
||||||
amountOut: dstTokenOut.computeUnitAmount(amountOut),
|
|
||||||
maxAmountIn: dstMaxAmountIn,
|
|
||||||
poolFee: dstRouter.getPoolFee(),
|
|
||||||
deadline: dstRouter.getTradeDeadline(),
|
|
||||||
path: [dstTokenIn.getAddress(), dstTokenOut.getAddress()],
|
|
||||||
};
|
|
||||||
|
|
||||||
const params: ExactOutCrossParameters = {
|
const params: ExactOutCrossParameters = {
|
||||||
src: srcParameters,
|
amountOut: amountOut,
|
||||||
dst: dstParameters,
|
maxAmountIn: srcMaxAmountIn,
|
||||||
relayerFee: {
|
src: this.makeSrcExactOutParameters(
|
||||||
amount: dstTokenIn.computeUnitAmount(relayerFeeUst),
|
srcAmountOutBeforeFee,
|
||||||
tokenAddress: this.dstTokenIn.getAddress(),
|
srcMaxAmountIn
|
||||||
},
|
),
|
||||||
|
dst: this.makeDstExactOutParameters(amountOut, dstMaxAmountIn),
|
||||||
|
relayerFee: this.getRelayerFee(relayerFeeUst),
|
||||||
};
|
};
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
setDeadlines(deadline: string): void {
|
setDeadlines(deadline: string): void {
|
||||||
|
if (!this.isSrcUst()) {
|
||||||
|
// @ts-ignore
|
||||||
this.srcRouter.setDeadline(deadline);
|
this.srcRouter.setDeadline(deadline);
|
||||||
|
}
|
||||||
|
if (!this.isDstUst()) {
|
||||||
|
// @ts-ignore
|
||||||
this.dstRouter.setDeadline(deadline);
|
this.dstRouter.setDeadline(deadline);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isSrcUst(): boolean {
|
||||||
|
return this.tokenInAddress === TERRA_UST;
|
||||||
|
}
|
||||||
|
|
||||||
|
isDstUst(): boolean {
|
||||||
|
return this.tokenOutAddress === TERRA_UST;
|
||||||
|
}
|
||||||
|
|
||||||
|
getSrcEvmProvider(): ethers.providers.Provider {
|
||||||
|
if (this.isSrcUst()) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
return this.srcRouter.getProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
getDstEvmProvider(): ethers.providers.Provider {
|
||||||
|
if (this.isDstUst()) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
return this.dstRouter.getProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
getSrcChainId(): ChainId {
|
||||||
|
return getChainIdFromAddress(this.tokenInAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
getDstChainId(): ChainId {
|
||||||
|
return getChainIdFromAddress(this.tokenOutAddress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { ethers } from "ethers";
|
||||||
import { GenericToken } from "./generic";
|
import { GenericToken } from "./generic";
|
||||||
|
|
||||||
// erc20 spec
|
// erc20 spec
|
||||||
import { abi as Erc20Abi } from "../abi/erc20.json";
|
import { abi as Erc20Abi } from "../../abi/erc20.json";
|
||||||
import {
|
import {
|
||||||
TransactionReceipt,
|
TransactionReceipt,
|
||||||
TransactionRequest,
|
TransactionRequest,
|
||||||
|
|
|
@ -1,7 +1,40 @@
|
||||||
export abstract class DexRouter {
|
import { FixedNumber } from "ethers";
|
||||||
abstract makeToken(tokenAddress: string): any;
|
|
||||||
abstract quoteLot(tokenA: any, tokenB: any, amount: string): Promise<any>;
|
export enum UstLocation {
|
||||||
abstract setSlippage(slippage: string): void;
|
In = 1,
|
||||||
|
Out,
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class RouterCore {
|
||||||
|
abstract computeAndVerifyPoolAddress(): Promise<string>;
|
||||||
|
|
||||||
|
abstract computePoolAddress(): string;
|
||||||
|
|
||||||
|
//abstract computeUnitAmountIn(amount: string): string;
|
||||||
|
|
||||||
|
abstract computeUnitAmountOut(amount: string): string;
|
||||||
|
|
||||||
|
abstract fetchExactInQuote(
|
||||||
|
amountOut: string,
|
||||||
|
slippage: string
|
||||||
|
): Promise<string>;
|
||||||
|
|
||||||
|
abstract fetchExactOutQuote(
|
||||||
|
amountOut: string,
|
||||||
|
slippage: string
|
||||||
|
): Promise<string>;
|
||||||
|
|
||||||
|
abstract formatAmountIn(amount: string): string;
|
||||||
|
|
||||||
|
abstract formatAmountOut(amount: string): string;
|
||||||
|
|
||||||
|
abstract getProtocol(): string;
|
||||||
|
|
||||||
|
abstract getTokenInDecimals(): number;
|
||||||
|
|
||||||
|
abstract getTokenOutDecimals(): number;
|
||||||
|
|
||||||
|
abstract getTokenOutAddress(): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class GenericToken {
|
export abstract class GenericToken {
|
||||||
|
@ -9,16 +42,3 @@ export abstract class GenericToken {
|
||||||
|
|
||||||
abstract getDecimals(): number;
|
abstract getDecimals(): number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: wrap SwapRoute and other routes
|
|
||||||
export class GenericRoute {
|
|
||||||
route: any;
|
|
||||||
|
|
||||||
constructor(route: any) {
|
|
||||||
this.route = route;
|
|
||||||
}
|
|
||||||
|
|
||||||
getRoute(): any {
|
|
||||||
return this.route;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
import { ethers } from "ethers";
|
import { ethers } from "ethers";
|
||||||
import { QUICKSWAP_FACTORY_ADDRESS } from "../utils/consts";
|
import { QUICKSWAP_FACTORY_ADDRESS, WMATIC_TOKEN_INFO } from "../utils/consts";
|
||||||
import { SingleAmmSwapRouter } from "./uniswap-v2";
|
import { UstLocation } from "./generic";
|
||||||
|
import { UniswapV2Router } from "./uniswap-v2";
|
||||||
|
|
||||||
export { PROTOCOL } from "./uniswap-v2";
|
export { PROTOCOL } from "./uniswap-v2";
|
||||||
|
|
||||||
export class QuickswapRouter extends SingleAmmSwapRouter {
|
export class QuickswapRouter extends UniswapV2Router {
|
||||||
constructor(provider: ethers.providers.Provider) {
|
constructor(provider: ethers.providers.Provider) {
|
||||||
super(provider);
|
super(provider);
|
||||||
super.setFactoryAddress(QUICKSWAP_FACTORY_ADDRESS);
|
super.setFactoryAddress(QUICKSWAP_FACTORY_ADDRESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async initialize(ustLocation: UstLocation): Promise<void> {
|
||||||
|
await super.initializeTokens(WMATIC_TOKEN_INFO, ustLocation);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
import { Dec, Int } from "@terra-money/terra.js";
|
||||||
|
|
||||||
|
import { UST_TOKEN_INFO } from "../utils/consts";
|
||||||
|
import { RouterCore } from "./generic";
|
||||||
|
|
||||||
|
export const PROTOCOL = "TerraUstTransfer";
|
||||||
|
|
||||||
|
const UST_DECIMALS = 6;
|
||||||
|
|
||||||
|
const UST_AMOUNT_MULTIPLIER = "1000000";
|
||||||
|
|
||||||
|
export class TerraUstTransfer extends RouterCore {
|
||||||
|
computePoolAddress(): string {
|
||||||
|
return UST_TOKEN_INFO.address;
|
||||||
|
}
|
||||||
|
|
||||||
|
computeAndVerifyPoolAddress(): Promise<string> {
|
||||||
|
return new Promise<string>((resolve) => {
|
||||||
|
return resolve(this.computePoolAddress());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
formatAmountIn(amount: string): string {
|
||||||
|
const formatted = new Dec(amount).div(UST_AMOUNT_MULTIPLIER);
|
||||||
|
return formatted.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
formatAmountOut(amount: string): string {
|
||||||
|
return this.formatAmountIn(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
computeUnitAmountIn(amount: string): string {
|
||||||
|
const unitified = new Dec(amount).mul(UST_AMOUNT_MULTIPLIER);
|
||||||
|
return new Int(unitified.toString()).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
computeUnitAmountOut(amount: string): string {
|
||||||
|
return this.computeUnitAmountIn(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
getProtocol(): string {
|
||||||
|
return PROTOCOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchExactInQuote(amountIn: string, slippage: string): Promise<string> {
|
||||||
|
return amountIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchExactOutQuote(
|
||||||
|
amountOut: string,
|
||||||
|
slippage: string
|
||||||
|
): Promise<string> {
|
||||||
|
return amountOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTokenInDecimals(): number {
|
||||||
|
return UST_DECIMALS;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTokenOutDecimals(): number {
|
||||||
|
return UST_DECIMALS;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTokenOutAddress(): string {
|
||||||
|
return this.computePoolAddress();
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,8 @@ import { ethers } from "ethers";
|
||||||
import { CurrencyAmount, Token } from "@uniswap/sdk-core";
|
import { CurrencyAmount, Token } from "@uniswap/sdk-core";
|
||||||
|
|
||||||
import { EvmToken } from "./evm";
|
import { EvmToken } from "./evm";
|
||||||
|
import { RouterCore, UstLocation } from "./generic";
|
||||||
|
import { TokenInfo } from "../utils/consts";
|
||||||
|
|
||||||
export function computeTradeDeadline(deadline: string): ethers.BigNumber {
|
export function computeTradeDeadline(deadline: string): ethers.BigNumber {
|
||||||
return ethers.BigNumber.from(Math.floor(Date.now() / 1000)).add(deadline);
|
return ethers.BigNumber.from(Math.floor(Date.now() / 1000)).add(deadline);
|
||||||
|
@ -78,46 +80,112 @@ export async function makeUniEvmToken(
|
||||||
return new UniEvmToken(chainId, erc20);
|
return new UniEvmToken(chainId, erc20);
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class UniswapRouterCore {
|
function stringToBigNumber(value: string): ethers.BigNumber {
|
||||||
|
return ethers.BigNumber.from(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExactInParameters {
|
||||||
|
protocol: string;
|
||||||
|
amountIn: ethers.BigNumber;
|
||||||
|
minAmountOut: ethers.BigNumber;
|
||||||
|
deadline: ethers.BigNumber;
|
||||||
|
poolFee: string;
|
||||||
|
path: [string, string];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExactOutParameters {
|
||||||
|
protocol: string;
|
||||||
|
amountOut: ethers.BigNumber;
|
||||||
|
maxAmountIn: ethers.BigNumber;
|
||||||
|
deadline: ethers.BigNumber;
|
||||||
|
poolFee: string;
|
||||||
|
path: [string, string];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function makeExactInParameters(
|
||||||
|
router: UniswapRouterCore,
|
||||||
|
amountIn: string,
|
||||||
|
minAmountOut: string
|
||||||
|
): ExactInParameters {
|
||||||
|
const params: ExactInParameters = {
|
||||||
|
protocol: router.getProtocol(),
|
||||||
|
amountIn: router.tokenIn.computeUnitAmount(amountIn),
|
||||||
|
minAmountOut: router.tokenOut.computeUnitAmount(minAmountOut),
|
||||||
|
poolFee: router.getPoolFee(),
|
||||||
|
deadline: router.getTradeDeadline(),
|
||||||
|
path: [router.tokenIn.getAddress(), router.tokenOut.getAddress()],
|
||||||
|
};
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function makeExactOutParameters(
|
||||||
|
router: UniswapRouterCore,
|
||||||
|
amountOut: string,
|
||||||
|
maxAmountIn: string
|
||||||
|
): ExactOutParameters {
|
||||||
|
const params: ExactOutParameters = {
|
||||||
|
protocol: router.getProtocol(),
|
||||||
|
amountOut: router.tokenOut.computeUnitAmount(amountOut),
|
||||||
|
maxAmountIn: router.tokenIn.computeUnitAmount(maxAmountIn),
|
||||||
|
poolFee: router.getPoolFee(),
|
||||||
|
deadline: router.getTradeDeadline(),
|
||||||
|
path: [router.tokenIn.getAddress(), router.tokenOut.getAddress()],
|
||||||
|
};
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class UniswapRouterCore extends RouterCore {
|
||||||
provider: ethers.providers.Provider;
|
provider: ethers.providers.Provider;
|
||||||
|
network: ethers.providers.Network;
|
||||||
|
|
||||||
|
// wormhole
|
||||||
|
chainId: number;
|
||||||
|
|
||||||
|
// tokens
|
||||||
|
tokenIn: UniEvmToken;
|
||||||
|
tokenOut: UniEvmToken;
|
||||||
|
|
||||||
// params
|
// params
|
||||||
deadline: string = "";
|
deadline: string = "";
|
||||||
|
|
||||||
constructor(provider: ethers.providers.Provider) {
|
constructor(provider: ethers.providers.Provider) {
|
||||||
|
super();
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async makeToken(tokenAddress: string): Promise<UniEvmToken> {
|
public getProvider(): ethers.providers.Provider {
|
||||||
const network = await this.provider.getNetwork();
|
return this.provider;
|
||||||
return makeUniEvmToken(this.provider, network.chainId, tokenAddress);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract computePoolAddress(
|
public async initializeTokens(
|
||||||
tokenIn: UniEvmToken,
|
tokenInfo: TokenInfo,
|
||||||
tokenOut: UniEvmToken
|
ustLocation: UstLocation
|
||||||
): string;
|
): Promise<void> {
|
||||||
|
this.network = await this.provider.getNetwork();
|
||||||
|
|
||||||
abstract computeAndVerifyPoolAddress(
|
const network = this.network;
|
||||||
tokenIn: UniEvmToken,
|
|
||||||
tokenOut: UniEvmToken
|
|
||||||
): Promise<string>;
|
|
||||||
|
|
||||||
abstract fetchQuoteAmountOut(
|
if (ustLocation == UstLocation.Out) {
|
||||||
tokenIn: UniEvmToken,
|
[this.tokenIn, this.tokenOut] = await Promise.all([
|
||||||
tokenOut: UniEvmToken,
|
makeUniEvmToken(this.provider, network.chainId, tokenInfo.address),
|
||||||
amountOut: string,
|
makeUniEvmToken(
|
||||||
slippage: string
|
this.provider,
|
||||||
): Promise<ethers.BigNumber>;
|
network.chainId,
|
||||||
|
tokenInfo.ustPairedAddress
|
||||||
abstract fetchQuoteAmountIn(
|
),
|
||||||
tokenIn: UniEvmToken,
|
]);
|
||||||
tokenOut: UniEvmToken,
|
} else {
|
||||||
amountOut: string,
|
[this.tokenIn, this.tokenOut] = await Promise.all([
|
||||||
slippage: string
|
makeUniEvmToken(
|
||||||
): Promise<ethers.BigNumber>;
|
this.provider,
|
||||||
|
network.chainId,
|
||||||
abstract getProtocol(): string;
|
tokenInfo.ustPairedAddress
|
||||||
|
),
|
||||||
|
makeUniEvmToken(this.provider, network.chainId, tokenInfo.address),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
public getPoolFee(): string {
|
public getPoolFee(): string {
|
||||||
return "";
|
return "";
|
||||||
|
@ -130,4 +198,36 @@ export abstract class UniswapRouterCore {
|
||||||
public getTradeDeadline(): ethers.BigNumber {
|
public getTradeDeadline(): ethers.BigNumber {
|
||||||
return computeTradeDeadline(this.deadline);
|
return computeTradeDeadline(this.deadline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public computeUnitAmountIn(amount: string): string {
|
||||||
|
return this.tokenIn.computeUnitAmount(amount).toString();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
public computeUnitAmountOut(amount: string): string {
|
||||||
|
return this.tokenOut.computeUnitAmount(amount).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public formatAmountIn(amount: string): string {
|
||||||
|
return this.tokenIn.formatAmount(stringToBigNumber(amount));
|
||||||
|
}
|
||||||
|
|
||||||
|
public formatAmountOut(amount: string): string {
|
||||||
|
return this.tokenOut.formatAmount(stringToBigNumber(amount));
|
||||||
|
}
|
||||||
|
|
||||||
|
public getTokenInDecimals(): number {
|
||||||
|
return this.tokenIn.getDecimals();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getTokenOutDecimals(): number {
|
||||||
|
return this.tokenOut.getDecimals();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getTokenOutAddress(): string {
|
||||||
|
return this.tokenOut.getAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract getProtocol(): string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,19 @@ import { CurrencyAmount, TradeType } from "@uniswap/sdk-core";
|
||||||
import { abi as IUniswapV2PairABI } from "@uniswap/v2-core/build/UniswapV2Pair.json";
|
import { abi as IUniswapV2PairABI } from "@uniswap/v2-core/build/UniswapV2Pair.json";
|
||||||
import { computePairAddress, Pair, Route, Trade } from "@uniswap/v2-sdk";
|
import { computePairAddress, Pair, Route, Trade } from "@uniswap/v2-sdk";
|
||||||
|
|
||||||
import { UniEvmToken, UniswapRouterCore } from "./uniswap-core";
|
import { UniswapRouterCore } from "./uniswap-core";
|
||||||
|
|
||||||
export const PROTOCOL = "UniswapV2";
|
export const PROTOCOL = "UniswapV2";
|
||||||
|
|
||||||
export class SingleAmmSwapRouter extends UniswapRouterCore {
|
// uniswap v3 (ethereum)
|
||||||
|
//export const UNISWAP_V3_FACTORY_ADDRESS = '0x1F98431c8aD98523631AE4a59f267346ea31F984';
|
||||||
|
//export const UNISWAP_V3_ROUTER_ADDRESS = '0xE592427A0AEce92De3Edee1F18E0157C05861564';
|
||||||
|
|
||||||
|
// quickswap (polygon)
|
||||||
|
export const QUICKSWAP_V2_ROUTER_ADDRESS =
|
||||||
|
"0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff";
|
||||||
|
|
||||||
|
export class UniswapV2Router extends UniswapRouterCore {
|
||||||
factoryAddress: string;
|
factoryAddress: string;
|
||||||
pairContract: ethers.Contract;
|
pairContract: ethers.Contract;
|
||||||
pair: Pair;
|
pair: Pair;
|
||||||
|
@ -17,23 +25,20 @@ export class SingleAmmSwapRouter extends UniswapRouterCore {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
computePoolAddress(tokenIn: UniEvmToken, tokenOut: UniEvmToken): string {
|
computePoolAddress(): string {
|
||||||
if (this.factoryAddress === undefined) {
|
if (this.factoryAddress === undefined) {
|
||||||
throw Error("factoryAddress is undefined. use setFactoryAddress");
|
throw Error("factoryAddress is undefined. use setFactoryAddress");
|
||||||
}
|
}
|
||||||
|
|
||||||
return computePairAddress({
|
return computePairAddress({
|
||||||
factoryAddress: this.factoryAddress,
|
factoryAddress: this.factoryAddress,
|
||||||
tokenA: tokenIn.getUniToken(),
|
tokenA: this.tokenIn.getUniToken(),
|
||||||
tokenB: tokenOut.getUniToken(),
|
tokenB: this.tokenOut.getUniToken(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async computeAndVerifyPoolAddress(
|
async computeAndVerifyPoolAddress(): Promise<string> {
|
||||||
tokenIn: UniEvmToken,
|
const pairAddress = this.computePoolAddress();
|
||||||
tokenOut: UniEvmToken
|
|
||||||
): Promise<string> {
|
|
||||||
const pairAddress = this.computePoolAddress(tokenIn, tokenOut);
|
|
||||||
|
|
||||||
// verify by attempting to call factory()
|
// verify by attempting to call factory()
|
||||||
const poolContract = new ethers.Contract(
|
const poolContract = new ethers.Contract(
|
||||||
|
@ -46,8 +51,8 @@ export class SingleAmmSwapRouter extends UniswapRouterCore {
|
||||||
return pairAddress;
|
return pairAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
async createPool(tokenIn: UniEvmToken, tokenOut: UniEvmToken): Promise<Pair> {
|
async createPool(): Promise<Pair> {
|
||||||
const pairAddress = this.computePoolAddress(tokenIn, tokenOut);
|
const pairAddress = this.computePoolAddress();
|
||||||
|
|
||||||
const pairContract = new ethers.Contract(
|
const pairContract = new ethers.Contract(
|
||||||
pairAddress,
|
pairAddress,
|
||||||
|
@ -63,6 +68,9 @@ export class SingleAmmSwapRouter extends UniswapRouterCore {
|
||||||
const reserve0 = reserves._reserve0.toString();
|
const reserve0 = reserves._reserve0.toString();
|
||||||
const reserve1 = reserves._reserve1.toString();
|
const reserve1 = reserves._reserve1.toString();
|
||||||
|
|
||||||
|
const tokenIn = this.tokenIn;
|
||||||
|
const tokenOut = this.tokenOut;
|
||||||
|
|
||||||
if (token0.toLowerCase() === tokenIn.getAddress().toLowerCase()) {
|
if (token0.toLowerCase() === tokenIn.getAddress().toLowerCase()) {
|
||||||
return new Pair(
|
return new Pair(
|
||||||
CurrencyAmount.fromRawAmount(tokenIn.getUniToken(), reserve0),
|
CurrencyAmount.fromRawAmount(tokenIn.getUniToken(), reserve0),
|
||||||
|
@ -76,15 +84,13 @@ export class SingleAmmSwapRouter extends UniswapRouterCore {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchQuoteAmountOut(
|
async fetchExactInQuote(amountIn: string, slippage: string): Promise<string> {
|
||||||
tokenIn: UniEvmToken,
|
|
||||||
tokenOut: UniEvmToken,
|
|
||||||
amountIn: string,
|
|
||||||
slippage: string
|
|
||||||
): Promise<ethers.BigNumber> {
|
|
||||||
// create pool
|
// create pool
|
||||||
const pair = await this.createPool(tokenIn, tokenOut);
|
const pair = await this.createPool();
|
||||||
|
|
||||||
// let's get that quote
|
// let's get that quote
|
||||||
|
const tokenIn = this.tokenIn;
|
||||||
|
const tokenOut = this.tokenOut;
|
||||||
|
|
||||||
const route = new Route(
|
const route = new Route(
|
||||||
[pair],
|
[pair],
|
||||||
|
@ -108,18 +114,24 @@ export class SingleAmmSwapRouter extends UniswapRouterCore {
|
||||||
.mulUnsafe(slippageMultiplier)
|
.mulUnsafe(slippageMultiplier)
|
||||||
.round(decimals);
|
.round(decimals);
|
||||||
|
|
||||||
return tokenOut.computeUnitAmount(minAmountOutWithSlippage.toString());
|
/*
|
||||||
|
return tokenOut
|
||||||
|
.computeUnitAmount(minAmountOutWithSlippage.toString())
|
||||||
|
.toString();
|
||||||
|
*/
|
||||||
|
return minAmountOutWithSlippage.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchQuoteAmountIn(
|
async fetchExactOutQuote(
|
||||||
tokenIn: UniEvmToken,
|
|
||||||
tokenOut: UniEvmToken,
|
|
||||||
amountOut: string,
|
amountOut: string,
|
||||||
slippage: string
|
slippage: string
|
||||||
): Promise<ethers.BigNumber> {
|
): Promise<string> {
|
||||||
// create pool
|
// create pool
|
||||||
const pair = await this.createPool(tokenIn, tokenOut);
|
const pair = await this.createPool();
|
||||||
|
|
||||||
// let's get that quote
|
// let's get that quote
|
||||||
|
const tokenIn = this.tokenIn;
|
||||||
|
const tokenOut = this.tokenOut;
|
||||||
|
|
||||||
const route = new Route(
|
const route = new Route(
|
||||||
[pair],
|
[pair],
|
||||||
|
@ -142,7 +154,12 @@ export class SingleAmmSwapRouter extends UniswapRouterCore {
|
||||||
.divUnsafe(slippageDivisor)
|
.divUnsafe(slippageDivisor)
|
||||||
.round(decimals);
|
.round(decimals);
|
||||||
|
|
||||||
return tokenIn.computeUnitAmount(maxAmountInWithSlippage.toString());
|
/*
|
||||||
|
return tokenIn
|
||||||
|
.computeUnitAmount(maxAmountInWithSlippage.toString())
|
||||||
|
.toString();
|
||||||
|
*/
|
||||||
|
return maxAmountInWithSlippage.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
getProtocol(): string {
|
getProtocol(): string {
|
||||||
|
|
|
@ -14,11 +14,12 @@ import {
|
||||||
} from "@uniswap/v3-sdk";
|
} from "@uniswap/v3-sdk";
|
||||||
|
|
||||||
import { UniEvmToken, UniswapRouterCore } from "./uniswap-core";
|
import { UniEvmToken, UniswapRouterCore } from "./uniswap-core";
|
||||||
import { UNISWAP_V3_FACTORY_ADDRESS } from "../utils/consts";
|
import { WETH_TOKEN_INFO, UNISWAP_V3_FACTORY_ADDRESS } from "../utils/consts";
|
||||||
|
import { UstLocation } from "./generic";
|
||||||
|
|
||||||
export const PROTOCOL = "UniswapV3";
|
export const PROTOCOL = "UniswapV3";
|
||||||
|
|
||||||
export class SingleAmmSwapRouter extends UniswapRouterCore {
|
export class UniswapV3Router extends UniswapRouterCore {
|
||||||
poolContract: ethers.Contract;
|
poolContract: ethers.Contract;
|
||||||
pool: Pool;
|
pool: Pool;
|
||||||
poolFee: FeeAmount;
|
poolFee: FeeAmount;
|
||||||
|
@ -30,24 +31,26 @@ export class SingleAmmSwapRouter extends UniswapRouterCore {
|
||||||
this.poolFee = FeeAmount.MEDIUM;
|
this.poolFee = FeeAmount.MEDIUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async initialize(ustLocation: UstLocation): Promise<void> {
|
||||||
|
await this.initializeTokens(WETH_TOKEN_INFO, ustLocation);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
getPoolFee(): string {
|
getPoolFee(): string {
|
||||||
return this.poolFee.toString();
|
return this.poolFee.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
computePoolAddress(tokenIn: UniEvmToken, tokenOut: UniEvmToken): string {
|
computePoolAddress(): string {
|
||||||
return computePoolAddress({
|
return computePoolAddress({
|
||||||
factoryAddress: UNISWAP_V3_FACTORY_ADDRESS,
|
factoryAddress: UNISWAP_V3_FACTORY_ADDRESS,
|
||||||
fee: this.poolFee,
|
fee: this.poolFee,
|
||||||
tokenA: tokenIn.getUniToken(),
|
tokenA: this.tokenIn.getUniToken(),
|
||||||
tokenB: tokenOut.getUniToken(),
|
tokenB: this.tokenOut.getUniToken(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async computeAndVerifyPoolAddress(
|
async computeAndVerifyPoolAddress(): Promise<string> {
|
||||||
tokenIn: UniEvmToken,
|
const pairAddress = this.computePoolAddress();
|
||||||
tokenOut: UniEvmToken
|
|
||||||
): Promise<string> {
|
|
||||||
const pairAddress = this.computePoolAddress(tokenIn, tokenOut);
|
|
||||||
|
|
||||||
// verify by attempting to call factory()
|
// verify by attempting to call factory()
|
||||||
const poolContract = new ethers.Contract(
|
const poolContract = new ethers.Contract(
|
||||||
|
@ -60,8 +63,8 @@ export class SingleAmmSwapRouter extends UniswapRouterCore {
|
||||||
return pairAddress;
|
return pairAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
async createPool(tokenIn: UniEvmToken, tokenOut: UniEvmToken): Promise<Pool> {
|
async createPool(): Promise<Pool> {
|
||||||
const poolAddress = this.computePoolAddress(tokenIn, tokenOut);
|
const poolAddress = this.computePoolAddress();
|
||||||
|
|
||||||
const poolContract = new ethers.Contract(
|
const poolContract = new ethers.Contract(
|
||||||
poolAddress,
|
poolAddress,
|
||||||
|
@ -103,8 +106,8 @@ export class SingleAmmSwapRouter extends UniswapRouterCore {
|
||||||
];
|
];
|
||||||
|
|
||||||
return new Pool(
|
return new Pool(
|
||||||
tokenIn.getUniToken(),
|
this.tokenIn.getUniToken(),
|
||||||
tokenOut.getUniToken(),
|
this.tokenOut.getUniToken(),
|
||||||
this.poolFee,
|
this.poolFee,
|
||||||
sqrtPriceX96.toString(), //note the description discrepancy - sqrtPriceX96 and sqrtRatioX96 are interchangable values
|
sqrtPriceX96.toString(), //note the description discrepancy - sqrtPriceX96 and sqrtRatioX96 are interchangable values
|
||||||
liquidity,
|
liquidity,
|
||||||
|
@ -114,13 +117,15 @@ export class SingleAmmSwapRouter extends UniswapRouterCore {
|
||||||
}
|
}
|
||||||
|
|
||||||
async computeTradeExactIn(
|
async computeTradeExactIn(
|
||||||
tokenIn: UniEvmToken,
|
|
||||||
tokenOut: UniEvmToken,
|
|
||||||
amount: string
|
amount: string
|
||||||
): Promise<Trade<Token, Token, TradeType.EXACT_INPUT>> {
|
): Promise<Trade<Token, Token, TradeType.EXACT_INPUT>> {
|
||||||
// create pool
|
// create pool
|
||||||
const pool = await this.createPool(tokenIn, tokenOut);
|
const pool = await this.createPool();
|
||||||
|
|
||||||
// let's get that quote
|
// let's get that quote
|
||||||
|
const tokenIn = this.tokenIn;
|
||||||
|
const tokenOut = this.tokenOut;
|
||||||
|
|
||||||
const amountIn = tokenIn.computeUnitAmount(amount);
|
const amountIn = tokenIn.computeUnitAmount(amount);
|
||||||
|
|
||||||
const route = new Route(
|
const route = new Route(
|
||||||
|
@ -136,13 +141,15 @@ export class SingleAmmSwapRouter extends UniswapRouterCore {
|
||||||
}
|
}
|
||||||
|
|
||||||
async computeTradeExactOut(
|
async computeTradeExactOut(
|
||||||
tokenIn: UniEvmToken,
|
|
||||||
tokenOut: UniEvmToken,
|
|
||||||
amount: string
|
amount: string
|
||||||
): Promise<Trade<Token, Token, TradeType.EXACT_OUTPUT>> {
|
): Promise<Trade<Token, Token, TradeType.EXACT_OUTPUT>> {
|
||||||
// create pool
|
// create pool
|
||||||
const pool = await this.createPool(tokenIn, tokenOut);
|
const pool = await this.createPool();
|
||||||
|
|
||||||
// let's get that quote
|
// let's get that quote
|
||||||
|
const tokenIn = this.tokenIn;
|
||||||
|
const tokenOut = this.tokenOut;
|
||||||
|
|
||||||
const amountOut = tokenOut.computeUnitAmount(amount);
|
const amountOut = tokenOut.computeUnitAmount(amount);
|
||||||
|
|
||||||
const route = new Route(
|
const route = new Route(
|
||||||
|
@ -160,15 +167,11 @@ export class SingleAmmSwapRouter extends UniswapRouterCore {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchQuoteAmountOut(
|
async fetchExactInQuote(amountIn: string, slippage: string): Promise<string> {
|
||||||
tokenIn: UniEvmToken,
|
|
||||||
tokenOut: UniEvmToken,
|
|
||||||
amountIn: string,
|
|
||||||
slippage: string
|
|
||||||
): Promise<ethers.BigNumber> {
|
|
||||||
// get the quote
|
// get the quote
|
||||||
const trade = await this.computeTradeExactIn(tokenIn, tokenOut, amountIn);
|
const trade = await this.computeTradeExactIn(amountIn);
|
||||||
|
|
||||||
|
const tokenOut = this.tokenOut;
|
||||||
const decimals = tokenOut.getDecimals();
|
const decimals = tokenOut.getDecimals();
|
||||||
|
|
||||||
// calculate output amount with slippage
|
// calculate output amount with slippage
|
||||||
|
@ -183,18 +186,22 @@ export class SingleAmmSwapRouter extends UniswapRouterCore {
|
||||||
.mulUnsafe(slippageMultiplier)
|
.mulUnsafe(slippageMultiplier)
|
||||||
.round(decimals);
|
.round(decimals);
|
||||||
|
|
||||||
return tokenOut.computeUnitAmount(minAmountOutWithSlippage.toString());
|
/*
|
||||||
|
return tokenOut
|
||||||
|
.computeUnitAmount(minAmountOutWithSlippage.toString())
|
||||||
|
.toString();
|
||||||
|
*/
|
||||||
|
return minAmountOutWithSlippage.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchQuoteAmountIn(
|
async fetchExactOutQuote(
|
||||||
tokenIn: UniEvmToken,
|
|
||||||
tokenOut: UniEvmToken,
|
|
||||||
amountOut: string,
|
amountOut: string,
|
||||||
slippage: string
|
slippage: string
|
||||||
): Promise<ethers.BigNumber> {
|
): Promise<string> {
|
||||||
// get the quote
|
// get the quote
|
||||||
const trade = await this.computeTradeExactOut(tokenIn, tokenOut, amountOut);
|
const trade = await this.computeTradeExactOut(amountOut);
|
||||||
|
|
||||||
|
const tokenIn = this.tokenIn;
|
||||||
const decimals = tokenIn.getDecimals();
|
const decimals = tokenIn.getDecimals();
|
||||||
|
|
||||||
// calculate output amount with slippage
|
// calculate output amount with slippage
|
||||||
|
@ -209,7 +216,12 @@ export class SingleAmmSwapRouter extends UniswapRouterCore {
|
||||||
.divUnsafe(slippageDivisor)
|
.divUnsafe(slippageDivisor)
|
||||||
.round(decimals);
|
.round(decimals);
|
||||||
|
|
||||||
return tokenIn.computeUnitAmount(maxAmountInWithSlippage.toString());
|
/*
|
||||||
|
return tokenIn
|
||||||
|
.computeUnitAmount(maxAmountInWithSlippage.toString())
|
||||||
|
.toString();
|
||||||
|
*/
|
||||||
|
return maxAmountInWithSlippage.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
getProtocol(): string {
|
getProtocol(): string {
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
import { ethers } from "ethers";
|
import { ethers } from "ethers";
|
||||||
import { TransactionReceipt } from "@ethersproject/abstract-provider";
|
import { TransactionReceipt } from "@ethersproject/abstract-provider";
|
||||||
import {
|
import {
|
||||||
CHAIN_ID_POLYGON as WORMHOLE_CHAIN_ID_POLYGON,
|
|
||||||
CHAIN_ID_ETH as WORMHOLE_CHAIN_ID_ETHEREUM,
|
|
||||||
ChainId,
|
ChainId,
|
||||||
getEmitterAddressEth,
|
getEmitterAddressEth,
|
||||||
hexToUint8Array,
|
hexToUint8Array,
|
||||||
nativeToHexString,
|
nativeToHexString,
|
||||||
parseSequenceFromLogEth,
|
parseSequenceFromLogEth,
|
||||||
getSignedVAAWithRetry,
|
//getSignedVAAWithRetry,
|
||||||
} from "@certusone/wormhole-sdk";
|
} from "@certusone/wormhole-sdk";
|
||||||
|
import getSignedVAAWithRetry from "@certusone/wormhole-sdk/lib/cjs/rpc/getSignedVAAWithRetry";
|
||||||
import { grpc } from "@improbable-eng/grpc-web";
|
import { grpc } from "@improbable-eng/grpc-web";
|
||||||
import { UniEvmToken } from "../route/uniswap-core";
|
import { UniEvmToken } from "../route/uniswap-core";
|
||||||
import {
|
import {
|
||||||
|
@ -21,15 +20,22 @@ import {
|
||||||
UniswapToUniswapQuoter,
|
UniswapToUniswapQuoter,
|
||||||
} from "../route/cross-quote";
|
} from "../route/cross-quote";
|
||||||
import {
|
import {
|
||||||
|
TOKEN_BRIDGE_ADDRESS_ETHEREUM,
|
||||||
TOKEN_BRIDGE_ADDRESS_POLYGON,
|
TOKEN_BRIDGE_ADDRESS_POLYGON,
|
||||||
|
TOKEN_BRIDGE_ADDRESS_TERRA,
|
||||||
CORE_BRIDGE_ADDRESS_ETHEREUM,
|
CORE_BRIDGE_ADDRESS_ETHEREUM,
|
||||||
CORE_BRIDGE_ADDRESS_POLYGON,
|
CORE_BRIDGE_ADDRESS_POLYGON,
|
||||||
TOKEN_BRIDGE_ADDRESS_ETHEREUM,
|
CORE_BRIDGE_ADDRESS_TERRA,
|
||||||
|
WORMHOLE_CHAIN_ID_ETHEREUM,
|
||||||
|
WORMHOLE_CHAIN_ID_POLYGON,
|
||||||
|
WORMHOLE_CHAIN_ID_TERRA,
|
||||||
WORMHOLE_RPC_HOSTS,
|
WORMHOLE_RPC_HOSTS,
|
||||||
POLYGON_NETWORK_CHAIN_ID,
|
//ETH_NETWORK_CHAIN_ID,
|
||||||
ETH_NETWORK_CHAIN_ID,
|
//POLYGON_NETWORK_CHAIN_ID,
|
||||||
|
//TERRA_NETWORK_CHAIN_ID,
|
||||||
WETH_TOKEN_INFO,
|
WETH_TOKEN_INFO,
|
||||||
WMATIC_TOKEN_INFO,
|
WMATIC_TOKEN_INFO,
|
||||||
|
UST_TOKEN_INFO,
|
||||||
} from "../utils/consts";
|
} from "../utils/consts";
|
||||||
import {
|
import {
|
||||||
CROSSCHAINSWAP_GAS_PARAMETERS,
|
CROSSCHAINSWAP_GAS_PARAMETERS,
|
||||||
|
@ -38,10 +44,13 @@ import {
|
||||||
swapExactOutFromVaaNative,
|
swapExactOutFromVaaNative,
|
||||||
swapExactOutFromVaaToken,
|
swapExactOutFromVaaToken,
|
||||||
} from "./util";
|
} from "./util";
|
||||||
import { abi as SWAP_CONTRACT_V2_ABI } from "../abi/contracts/CrossChainSwapV2.json";
|
import { abi as SWAP_CONTRACT_V2_ABI } from "../../abi/contracts/CrossChainSwapV2.json";
|
||||||
import { abi as SWAP_CONTRACT_V3_ABI } from "../abi/contracts/CrossChainSwapV3.json";
|
import { abi as SWAP_CONTRACT_V3_ABI } from "../../abi/contracts/CrossChainSwapV3.json";
|
||||||
import { SWAP_CONTRACT_ADDRESS as CROSSCHAINSWAP_CONTRACT_ADDRESS_ETHEREUM } from "../addresses/goerli";
|
import { SWAP_CONTRACT_ADDRESS as CROSSCHAINSWAP_CONTRACT_ADDRESS_ETHEREUM } from "../../scripts/contract-addresses/goerli";
|
||||||
import { SWAP_CONTRACT_ADDRESS as CROSSCHAINSWAP_CONTRACT_ADDRESS_POLYGON } from "../addresses/mumbai";
|
import { SWAP_CONTRACT_ADDRESS as CROSSCHAINSWAP_CONTRACT_ADDRESS_POLYGON } from "../../scripts/contract-addresses/mumbai";
|
||||||
|
|
||||||
|
// placeholders
|
||||||
|
const CROSSCHAINSWAP_CONTRACT_ADDRESS_TERRA = "";
|
||||||
|
|
||||||
interface SwapContractParameters {
|
interface SwapContractParameters {
|
||||||
address: string;
|
address: string;
|
||||||
|
@ -80,21 +89,35 @@ const EXECUTION_PARAMETERS_POLYGON: ExecutionParameters = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function makeExecutionParameters(id: number): ExecutionParameters {
|
const EXECUTION_PARAMETERS_TERRA: ExecutionParameters = {
|
||||||
switch (id) {
|
crossChainSwap: {
|
||||||
case ETH_NETWORK_CHAIN_ID: {
|
address: CROSSCHAINSWAP_CONTRACT_ADDRESS_TERRA,
|
||||||
|
},
|
||||||
|
wormhole: {
|
||||||
|
chainId: WORMHOLE_CHAIN_ID_TERRA,
|
||||||
|
coreBridgeAddress: CORE_BRIDGE_ADDRESS_TERRA,
|
||||||
|
tokenBridgeAddress: TOKEN_BRIDGE_ADDRESS_TERRA,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function makeExecutionParameters(chainId: ChainId): ExecutionParameters {
|
||||||
|
switch (chainId) {
|
||||||
|
case WORMHOLE_CHAIN_ID_ETHEREUM: {
|
||||||
return EXECUTION_PARAMETERS_ETHEREUM;
|
return EXECUTION_PARAMETERS_ETHEREUM;
|
||||||
}
|
}
|
||||||
case POLYGON_NETWORK_CHAIN_ID: {
|
case WORMHOLE_CHAIN_ID_POLYGON: {
|
||||||
return EXECUTION_PARAMETERS_POLYGON;
|
return EXECUTION_PARAMETERS_POLYGON;
|
||||||
}
|
}
|
||||||
|
case WORMHOLE_CHAIN_ID_TERRA: {
|
||||||
|
return EXECUTION_PARAMETERS_TERRA;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
throw Error("unrecognized chain id");
|
throw Error("unrecognized chain id");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function approveContractTokenSpend(
|
async function evmApproveContractTokenSpend(
|
||||||
provider: ethers.providers.Provider,
|
provider: ethers.providers.Provider,
|
||||||
signer: ethers.Signer,
|
signer: ethers.Signer,
|
||||||
tokenContract: ethers.Contract,
|
tokenContract: ethers.Contract,
|
||||||
|
@ -140,7 +163,7 @@ function makeCrossChainSwapV2Contract(
|
||||||
return new ethers.Contract(contractAddress, SWAP_CONTRACT_V2_ABI, provider);
|
return new ethers.Contract(contractAddress, SWAP_CONTRACT_V2_ABI, provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeCrossChainSwapContract(
|
function makeCrossChainSwapEvmContract(
|
||||||
provider: ethers.providers.Provider,
|
provider: ethers.providers.Provider,
|
||||||
protocol: string,
|
protocol: string,
|
||||||
contractAddress: string
|
contractAddress: string
|
||||||
|
@ -163,7 +186,7 @@ function addressToBytes32(
|
||||||
return hexToUint8Array(hexString);
|
return hexToUint8Array(hexString);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function approveAndSwapExactIn(
|
async function evmApproveAndSwapExactIn(
|
||||||
srcProvider: ethers.providers.Provider,
|
srcProvider: ethers.providers.Provider,
|
||||||
srcWallet: ethers.Signer,
|
srcWallet: ethers.Signer,
|
||||||
srcTokenIn: UniEvmToken,
|
srcTokenIn: UniEvmToken,
|
||||||
|
@ -175,7 +198,7 @@ async function approveAndSwapExactIn(
|
||||||
const swapContractParams = srcExecutionParams.crossChainSwap;
|
const swapContractParams = srcExecutionParams.crossChainSwap;
|
||||||
|
|
||||||
const protocol = quoteParams.src.protocol;
|
const protocol = quoteParams.src.protocol;
|
||||||
const swapContract = makeCrossChainSwapContract(
|
const swapContract = makeCrossChainSwapEvmContract(
|
||||||
srcProvider,
|
srcProvider,
|
||||||
protocol,
|
protocol,
|
||||||
swapContractParams.address
|
swapContractParams.address
|
||||||
|
@ -187,18 +210,19 @@ async function approveAndSwapExactIn(
|
||||||
|
|
||||||
const address = await srcWallet.getAddress();
|
const address = await srcWallet.getAddress();
|
||||||
|
|
||||||
|
const dstWormholeChainId = dstExecutionParams.wormhole.chainId;
|
||||||
|
|
||||||
const swapParams = [
|
const swapParams = [
|
||||||
amountIn,
|
amountIn,
|
||||||
quoteParams.src.minAmountOut,
|
quoteParams.src.minAmountOut,
|
||||||
quoteParams.dst.minAmountOut,
|
quoteParams.dst.minAmountOut,
|
||||||
address,
|
addressToBytes32(address, dstWormholeChainId),
|
||||||
quoteParams.src.deadline,
|
quoteParams.src.deadline,
|
||||||
quoteParams.dst.poolFee || quoteParams.src.poolFee,
|
quoteParams.dst.poolFee || quoteParams.src.poolFee,
|
||||||
];
|
];
|
||||||
|
|
||||||
const pathArray = quoteParams.src.path.concat(quoteParams.dst.path);
|
const pathArray = quoteParams.src.path.concat(quoteParams.dst.path);
|
||||||
|
|
||||||
const dstWormholeChainId = dstExecutionParams.wormhole.chainId;
|
|
||||||
const dstContractAddress = addressToBytes32(
|
const dstContractAddress = addressToBytes32(
|
||||||
dstExecutionParams.crossChainSwap.address,
|
dstExecutionParams.crossChainSwap.address,
|
||||||
dstWormholeChainId
|
dstWormholeChainId
|
||||||
|
@ -227,7 +251,7 @@ async function approveAndSwapExactIn(
|
||||||
return tx.wait();
|
return tx.wait();
|
||||||
} else {
|
} else {
|
||||||
console.info("approving contract to spend token in");
|
console.info("approving contract to spend token in");
|
||||||
await approveContractTokenSpend(
|
await evmApproveContractTokenSpend(
|
||||||
srcProvider,
|
srcProvider,
|
||||||
srcWallet,
|
srcWallet,
|
||||||
srcTokenIn.getContract(),
|
srcTokenIn.getContract(),
|
||||||
|
@ -249,7 +273,7 @@ async function approveAndSwapExactIn(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function approveAndSwapExactOut(
|
async function evmApproveAndSwapExactOut(
|
||||||
srcProvider: ethers.providers.Provider,
|
srcProvider: ethers.providers.Provider,
|
||||||
srcWallet: ethers.Signer,
|
srcWallet: ethers.Signer,
|
||||||
srcTokenIn: UniEvmToken,
|
srcTokenIn: UniEvmToken,
|
||||||
|
@ -261,7 +285,7 @@ async function approveAndSwapExactOut(
|
||||||
const swapContractParams = srcExecutionParams.crossChainSwap;
|
const swapContractParams = srcExecutionParams.crossChainSwap;
|
||||||
|
|
||||||
const protocol = quoteParams.src.protocol;
|
const protocol = quoteParams.src.protocol;
|
||||||
const swapContract = makeCrossChainSwapContract(
|
const swapContract = makeCrossChainSwapEvmContract(
|
||||||
srcProvider,
|
srcProvider,
|
||||||
protocol,
|
protocol,
|
||||||
swapContractParams.address
|
swapContractParams.address
|
||||||
|
@ -274,17 +298,18 @@ async function approveAndSwapExactOut(
|
||||||
|
|
||||||
const address = await srcWallet.getAddress();
|
const address = await srcWallet.getAddress();
|
||||||
|
|
||||||
|
const dstWormholeChainId = dstExecutionParams.wormhole.chainId;
|
||||||
|
|
||||||
const swapParams = [
|
const swapParams = [
|
||||||
amountOut,
|
amountOut,
|
||||||
maxAmountIn,
|
maxAmountIn,
|
||||||
quoteParams.dst.amountOut,
|
quoteParams.dst.amountOut,
|
||||||
address,
|
addressToBytes32(address, dstWormholeChainId),
|
||||||
quoteParams.src.deadline,
|
quoteParams.src.deadline,
|
||||||
quoteParams.dst.poolFee || quoteParams.src.poolFee,
|
quoteParams.dst.poolFee || quoteParams.src.poolFee,
|
||||||
];
|
];
|
||||||
const pathArray = quoteParams.src.path.concat(quoteParams.dst.path);
|
const pathArray = quoteParams.src.path.concat(quoteParams.dst.path);
|
||||||
|
|
||||||
const dstWormholeChainId = dstExecutionParams.wormhole.chainId;
|
|
||||||
const dstContractAddress = addressToBytes32(
|
const dstContractAddress = addressToBytes32(
|
||||||
dstExecutionParams.crossChainSwap.address,
|
dstExecutionParams.crossChainSwap.address,
|
||||||
dstWormholeChainId
|
dstWormholeChainId
|
||||||
|
@ -313,7 +338,7 @@ async function approveAndSwapExactOut(
|
||||||
return tx.wait();
|
return tx.wait();
|
||||||
} else {
|
} else {
|
||||||
console.info("approving contract to spend token in");
|
console.info("approving contract to spend token in");
|
||||||
await approveContractTokenSpend(
|
await evmApproveContractTokenSpend(
|
||||||
srcProvider,
|
srcProvider,
|
||||||
srcWallet,
|
srcWallet,
|
||||||
srcTokenIn.getContract(),
|
srcTokenIn.getContract(),
|
||||||
|
@ -345,7 +370,7 @@ async function swapExactInFromVaa(
|
||||||
): Promise<TransactionReceipt> {
|
): Promise<TransactionReceipt> {
|
||||||
const swapContractParams = dstExecutionParams.crossChainSwap;
|
const swapContractParams = dstExecutionParams.crossChainSwap;
|
||||||
|
|
||||||
const swapContract = makeCrossChainSwapContract(
|
const swapContract = makeCrossChainSwapEvmContract(
|
||||||
dstProvider,
|
dstProvider,
|
||||||
dstProtocol,
|
dstProtocol,
|
||||||
swapContractParams.address
|
swapContractParams.address
|
||||||
|
@ -371,7 +396,7 @@ async function swapExactOutFromVaa(
|
||||||
): Promise<TransactionReceipt> {
|
): Promise<TransactionReceipt> {
|
||||||
const swapContractParams = dstExecutionParams.crossChainSwap;
|
const swapContractParams = dstExecutionParams.crossChainSwap;
|
||||||
|
|
||||||
const swapContract = makeCrossChainSwapContract(
|
const swapContract = makeCrossChainSwapEvmContract(
|
||||||
dstProvider,
|
dstProvider,
|
||||||
dstProtocol,
|
dstProtocol,
|
||||||
swapContractParams.address
|
swapContractParams.address
|
||||||
|
@ -399,7 +424,7 @@ interface VaaSearchParams {
|
||||||
emitterAddress: string;
|
emitterAddress: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeProvider(tokenAddress: string) {
|
export function makeEvmProvider(tokenAddress: string) {
|
||||||
switch (tokenAddress) {
|
switch (tokenAddress) {
|
||||||
case WETH_TOKEN_INFO.address: {
|
case WETH_TOKEN_INFO.address: {
|
||||||
const url = process.env.REACT_APP_GOERLI_PROVIDER;
|
const url = process.env.REACT_APP_GOERLI_PROVIDER;
|
||||||
|
@ -416,6 +441,7 @@ export function makeProvider(tokenAddress: string) {
|
||||||
return new ethers.providers.StaticJsonRpcProvider(url);
|
return new ethers.providers.StaticJsonRpcProvider(url);
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
console.log("huh?", tokenAddress);
|
||||||
throw Error("unrecognized token address");
|
throw Error("unrecognized token address");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -440,8 +466,16 @@ export class UniswapToUniswapExecutor {
|
||||||
transportFactory: grpc.TransportFactory;
|
transportFactory: grpc.TransportFactory;
|
||||||
vaaSearchParams: VaaSearchParams;
|
vaaSearchParams: VaaSearchParams;
|
||||||
vaaBytes: Uint8Array;
|
vaaBytes: Uint8Array;
|
||||||
srcReceipt: TransactionReceipt;
|
|
||||||
dstReceipt: TransactionReceipt;
|
// receipts
|
||||||
|
srcEvmReceipt: TransactionReceipt;
|
||||||
|
dstEvmReceipt: TransactionReceipt;
|
||||||
|
srcTerraReceipt: any;
|
||||||
|
dstTerraReceipt: any;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.quoter = new UniswapToUniswapQuoter();
|
||||||
|
}
|
||||||
|
|
||||||
async initialize(
|
async initialize(
|
||||||
tokenInAddress: string,
|
tokenInAddress: string,
|
||||||
|
@ -450,20 +484,14 @@ export class UniswapToUniswapExecutor {
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
this.isNative = isNative;
|
this.isNative = isNative;
|
||||||
|
|
||||||
const srcProvider = makeProvider(tokenInAddress);
|
await this.quoter.initialize(tokenInAddress, tokenOutAddress);
|
||||||
const dstProvider = makeProvider(tokenOutAddress);
|
|
||||||
|
|
||||||
this.quoter = new UniswapToUniswapQuoter(srcProvider, dstProvider);
|
|
||||||
await this.quoter.initialize();
|
|
||||||
|
|
||||||
await this.makeTokens(tokenInAddress, tokenOutAddress);
|
|
||||||
|
|
||||||
// now that we have a chain id for each network, get contract info for each chain
|
// now that we have a chain id for each network, get contract info for each chain
|
||||||
this.srcExecutionParams = makeExecutionParameters(
|
this.srcExecutionParams = makeExecutionParameters(
|
||||||
this.quoter.srcNetwork.chainId
|
this.quoter.getSrcChainId()
|
||||||
);
|
);
|
||||||
this.dstExecutionParams = makeExecutionParameters(
|
this.dstExecutionParams = makeExecutionParameters(
|
||||||
this.quoter.dstNetwork.chainId
|
this.quoter.getDstChainId()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,6 +511,7 @@ export class UniswapToUniswapExecutor {
|
||||||
this.quoter.setDeadlines(deadline);
|
this.quoter.setDeadlines(deadline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
async makeTokens(
|
async makeTokens(
|
||||||
tokenInAddress: string,
|
tokenInAddress: string,
|
||||||
tokenOutAddress: string
|
tokenOutAddress: string
|
||||||
|
@ -507,7 +536,7 @@ export class UniswapToUniswapExecutor {
|
||||||
getTokens(): CrossChainSwapTokens {
|
getTokens(): CrossChainSwapTokens {
|
||||||
return this.tokens;
|
return this.tokens;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
async computeAndVerifySrcPoolAddress(): Promise<string> {
|
async computeAndVerifySrcPoolAddress(): Promise<string> {
|
||||||
return this.quoter.computeAndVerifySrcPoolAddress();
|
return this.quoter.computeAndVerifySrcPoolAddress();
|
||||||
}
|
}
|
||||||
|
@ -546,19 +575,19 @@ export class UniswapToUniswapExecutor {
|
||||||
return this.cachedExactOutParams;
|
return this.cachedExactOutParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
getSrcProvider(): ethers.providers.Provider {
|
getSrcEvmProvider(): ethers.providers.Provider {
|
||||||
return this.quoter.srcProvider;
|
return this.quoter.getSrcEvmProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
getDstProvider(): ethers.providers.Provider {
|
getDstEvmProvider(): ethers.providers.Provider {
|
||||||
return this.quoter.dstProvider;
|
return this.quoter.getDstEvmProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
async approveAndSwapExactIn(
|
async evmApproveAndSwapExactIn(
|
||||||
wallet: ethers.Signer
|
wallet: ethers.Signer
|
||||||
): Promise<TransactionReceipt> {
|
): Promise<TransactionReceipt> {
|
||||||
return approveAndSwapExactIn(
|
return evmApproveAndSwapExactIn(
|
||||||
this.getSrcProvider(),
|
this.getSrcEvmProvider(),
|
||||||
wallet,
|
wallet,
|
||||||
this.tokens.srcIn,
|
this.tokens.srcIn,
|
||||||
this.cachedExactInParams,
|
this.cachedExactInParams,
|
||||||
|
@ -568,11 +597,11 @@ export class UniswapToUniswapExecutor {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async approveAndSwapExactOut(
|
async evmApproveAndSwapExactOut(
|
||||||
wallet: ethers.Signer
|
wallet: ethers.Signer
|
||||||
): Promise<TransactionReceipt> {
|
): Promise<TransactionReceipt> {
|
||||||
return approveAndSwapExactOut(
|
return evmApproveAndSwapExactOut(
|
||||||
this.getSrcProvider(),
|
this.getSrcEvmProvider(),
|
||||||
wallet,
|
wallet,
|
||||||
this.tokens.srcIn,
|
this.tokens.srcIn,
|
||||||
this.cachedExactOutParams,
|
this.cachedExactOutParams,
|
||||||
|
@ -582,23 +611,40 @@ export class UniswapToUniswapExecutor {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async approveAndSwap(wallet: ethers.Signer): Promise<TransactionReceipt> {
|
srcIsUst(): boolean {
|
||||||
|
return (
|
||||||
|
this.quoter.tokenInAddress === UST_TOKEN_INFO.address &&
|
||||||
|
this.cachedExactInParams.src === undefined
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async evmApproveAndSwap(wallet: ethers.Signer): Promise<TransactionReceipt> {
|
||||||
const quoteType = this.quoteType;
|
const quoteType = this.quoteType;
|
||||||
|
|
||||||
if (quoteType === QuoteType.ExactIn) {
|
if (quoteType === QuoteType.ExactIn) {
|
||||||
this.srcReceipt = await this.approveAndSwapExactIn(wallet);
|
this.srcEvmReceipt = await this.evmApproveAndSwapExactIn(wallet);
|
||||||
} else if (quoteType === QuoteType.ExactOut) {
|
} else if (quoteType === QuoteType.ExactOut) {
|
||||||
this.srcReceipt = await this.approveAndSwapExactOut(wallet);
|
this.srcEvmReceipt = await this.evmApproveAndSwapExactOut(wallet);
|
||||||
} else {
|
} else {
|
||||||
throw Error("no quote found");
|
throw Error("no quote found");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fetchAndSetEmitterAndSequence();
|
this.fetchAndSetEmitterAndSequence();
|
||||||
return this.srcReceipt;
|
return this.srcEvmReceipt;
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchAndSetEmitterAndSequence(): void {
|
fetchAndSetEmitterAndSequence(): void {
|
||||||
const receipt = this.srcReceipt;
|
// TODO
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchAndSetTerraEmitterAndSequence(): void {
|
||||||
|
// TODO
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchAndSetEvmEmitterAndSequence(): void {
|
||||||
|
const receipt = this.srcEvmReceipt;
|
||||||
if (receipt === undefined) {
|
if (receipt === undefined) {
|
||||||
throw Error("no swap receipt found");
|
throw Error("no swap receipt found");
|
||||||
}
|
}
|
||||||
|
@ -623,11 +669,15 @@ export class UniswapToUniswapExecutor {
|
||||||
const emitterAddress = vaaSearchParams.emitterAddress;
|
const emitterAddress = vaaSearchParams.emitterAddress;
|
||||||
console.info(`sequence: ${sequence}, emitterAddress: ${emitterAddress}`);
|
console.info(`sequence: ${sequence}, emitterAddress: ${emitterAddress}`);
|
||||||
// wait for VAA to be signed
|
// wait for VAA to be signed
|
||||||
|
|
||||||
const vaaResponse = await getSignedVAAWithRetry(
|
const vaaResponse = await getSignedVAAWithRetry(
|
||||||
WORMHOLE_RPC_HOSTS,
|
WORMHOLE_RPC_HOSTS,
|
||||||
this.srcExecutionParams.wormhole.chainId,
|
this.srcExecutionParams.wormhole.chainId,
|
||||||
vaaSearchParams.emitterAddress,
|
vaaSearchParams.emitterAddress,
|
||||||
vaaSearchParams.sequence
|
vaaSearchParams.sequence,
|
||||||
|
{
|
||||||
|
transport: this.transportFactory,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
// grab vaaBytes
|
// grab vaaBytes
|
||||||
this.vaaBytes = vaaResponse.vaaBytes;
|
this.vaaBytes = vaaResponse.vaaBytes;
|
||||||
|
@ -636,22 +686,27 @@ export class UniswapToUniswapExecutor {
|
||||||
async fetchVaaAndSwap(wallet: ethers.Signer): Promise<TransactionReceipt> {
|
async fetchVaaAndSwap(wallet: ethers.Signer): Promise<TransactionReceipt> {
|
||||||
await this.fetchSignedVaaFromSwap();
|
await this.fetchSignedVaaFromSwap();
|
||||||
|
|
||||||
|
// check if Terra transaction
|
||||||
|
// TODO: change return as something else (not evm TransactionReceipt)
|
||||||
|
|
||||||
const quoteType = this.quoteType;
|
const quoteType = this.quoteType;
|
||||||
|
|
||||||
if (quoteType === QuoteType.ExactIn) {
|
if (quoteType === QuoteType.ExactIn) {
|
||||||
this.dstReceipt = await this.swapExactInFromVaa(wallet);
|
this.dstEvmReceipt = await this.evmSwapExactInFromVaa(wallet);
|
||||||
} else if (quoteType === QuoteType.ExactOut) {
|
} else if (quoteType === QuoteType.ExactOut) {
|
||||||
this.dstReceipt = await this.swapExactOutFromVaa(wallet);
|
this.dstEvmReceipt = await this.evmSwapExactOutFromVaa(wallet);
|
||||||
} else {
|
} else {
|
||||||
throw Error("no quote found");
|
throw Error("no quote found");
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.dstReceipt;
|
return this.dstEvmReceipt;
|
||||||
}
|
}
|
||||||
|
|
||||||
async swapExactInFromVaa(wallet: ethers.Signer): Promise<TransactionReceipt> {
|
async evmSwapExactInFromVaa(
|
||||||
|
wallet: ethers.Signer
|
||||||
|
): Promise<TransactionReceipt> {
|
||||||
return swapExactInFromVaa(
|
return swapExactInFromVaa(
|
||||||
this.getDstProvider(),
|
this.getDstEvmProvider(),
|
||||||
wallet,
|
wallet,
|
||||||
this.dstExecutionParams,
|
this.dstExecutionParams,
|
||||||
this.cachedExactInParams.dst.protocol,
|
this.cachedExactInParams.dst.protocol,
|
||||||
|
@ -660,11 +715,11 @@ export class UniswapToUniswapExecutor {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async swapExactOutFromVaa(
|
async evmSwapExactOutFromVaa(
|
||||||
wallet: ethers.Signer
|
wallet: ethers.Signer
|
||||||
): Promise<TransactionReceipt> {
|
): Promise<TransactionReceipt> {
|
||||||
return swapExactOutFromVaa(
|
return swapExactOutFromVaa(
|
||||||
this.getDstProvider(),
|
this.getDstEvmProvider(),
|
||||||
wallet,
|
wallet,
|
||||||
this.dstExecutionParams,
|
this.dstExecutionParams,
|
||||||
this.cachedExactOutParams.dst.protocol,
|
this.cachedExactOutParams.dst.protocol,
|
||||||
|
@ -673,6 +728,10 @@ export class UniswapToUniswapExecutor {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setTransport(transportFactory: grpc.TransportFactory) {
|
||||||
|
this.transportFactory = transportFactory;
|
||||||
|
}
|
||||||
|
|
||||||
//getSwapResult(
|
//getSwapResult(
|
||||||
// walletAddress: string,
|
// walletAddress: string,
|
||||||
// onSwapResult: (result: boolean) => void
|
// onSwapResult: (result: boolean) => void
|
||||||
|
@ -680,7 +739,7 @@ export class UniswapToUniswapExecutor {
|
||||||
// console.log(this.cachedExactInParams.dst.protocol);
|
// console.log(this.cachedExactInParams.dst.protocol);
|
||||||
// console.log(this.dstExecutionParams.crossChainSwap.address);
|
// console.log(this.dstExecutionParams.crossChainSwap.address);
|
||||||
// const contract = makeCrossChainSwapContract(
|
// const contract = makeCrossChainSwapContract(
|
||||||
// this.getDstProvider(),
|
// this.getDstEvmProvider(),
|
||||||
// this.quoteType === QuoteType.ExactIn
|
// this.quoteType === QuoteType.ExactIn
|
||||||
// ? this.cachedExactInParams.dst.protocol
|
// ? this.cachedExactInParams.dst.protocol
|
||||||
// : this.cachedExactOutParams.dst.protocol,
|
// : this.cachedExactOutParams.dst.protocol,
|
||||||
|
|
|
@ -1,10 +1,21 @@
|
||||||
import {
|
import {
|
||||||
ChainId,
|
ChainId,
|
||||||
CHAIN_ID_ETH,
|
CHAIN_ID_ETH as WORMHOLE_CHAIN_ID_ETHEREUM,
|
||||||
CHAIN_ID_POLYGON,
|
CHAIN_ID_POLYGON as WORMHOLE_CHAIN_ID_POLYGON,
|
||||||
|
CHAIN_ID_TERRA as WORMHOLE_CHAIN_ID_TERRA,
|
||||||
} from "@certusone/wormhole-sdk";
|
} from "@certusone/wormhole-sdk";
|
||||||
import ethIcon from "../icons/eth.svg";
|
//import ethIcon from "../icons/eth.svg";
|
||||||
import polygonIcon from "../icons/polygon.svg";
|
//import polygonIcon from "../icons/polygon.svg";
|
||||||
|
|
||||||
|
const ethIcon = undefined;
|
||||||
|
const polygonIcon = undefined;
|
||||||
|
const ustIcon = undefined;
|
||||||
|
|
||||||
|
export {
|
||||||
|
WORMHOLE_CHAIN_ID_ETHEREUM,
|
||||||
|
WORMHOLE_CHAIN_ID_POLYGON,
|
||||||
|
WORMHOLE_CHAIN_ID_TERRA,
|
||||||
|
};
|
||||||
|
|
||||||
export interface TokenInfo {
|
export interface TokenInfo {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -13,42 +24,57 @@ export interface TokenInfo {
|
||||||
logo: string;
|
logo: string;
|
||||||
isNative: boolean;
|
isNative: boolean;
|
||||||
maxAmount: number;
|
maxAmount: number;
|
||||||
|
ustPairedAddress: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MATIC_TOKEN_INFO: TokenInfo = {
|
export const MATIC_TOKEN_INFO: TokenInfo = {
|
||||||
name: "MATIC",
|
name: "MATIC",
|
||||||
address: "0x9c3c9283d3e44854697cd22d3faa240cfb032889", // used to compute quote
|
address: "0x9c3c9283d3e44854697cd22d3faa240cfb032889", // used to compute quote
|
||||||
chainId: CHAIN_ID_POLYGON,
|
chainId: WORMHOLE_CHAIN_ID_POLYGON,
|
||||||
logo: polygonIcon,
|
logo: polygonIcon,
|
||||||
isNative: true,
|
isNative: true,
|
||||||
maxAmount: 0.1,
|
maxAmount: 0.1,
|
||||||
|
ustPairedAddress: "0xe3a1c77e952b57b5883f6c906fc706fcc7d4392c",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WMATIC_TOKEN_INFO: TokenInfo = {
|
export const WMATIC_TOKEN_INFO: TokenInfo = {
|
||||||
name: "WMATIC",
|
name: "WMATIC",
|
||||||
address: "0x9c3c9283d3e44854697cd22d3faa240cfb032889",
|
address: "0x9c3c9283d3e44854697cd22d3faa240cfb032889",
|
||||||
chainId: CHAIN_ID_POLYGON,
|
chainId: WORMHOLE_CHAIN_ID_POLYGON,
|
||||||
logo: polygonIcon,
|
logo: polygonIcon,
|
||||||
isNative: false,
|
isNative: false,
|
||||||
maxAmount: 0.1,
|
maxAmount: 0.1,
|
||||||
|
ustPairedAddress: "0xe3a1c77e952b57b5883f6c906fc706fcc7d4392c",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ETH_TOKEN_INFO: TokenInfo = {
|
export const ETH_TOKEN_INFO: TokenInfo = {
|
||||||
name: "ETH",
|
name: "ETH",
|
||||||
address: "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6", // used to compute quote
|
address: "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6", // used to compute quote
|
||||||
chainId: CHAIN_ID_ETH,
|
chainId: WORMHOLE_CHAIN_ID_ETHEREUM,
|
||||||
logo: ethIcon,
|
logo: ethIcon,
|
||||||
isNative: true,
|
isNative: true,
|
||||||
maxAmount: 0.01,
|
maxAmount: 0.01,
|
||||||
|
ustPairedAddress: "0x36Ed51Afc79619b299b238898E72ce482600568a",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WETH_TOKEN_INFO: TokenInfo = {
|
export const WETH_TOKEN_INFO: TokenInfo = {
|
||||||
name: "WETH",
|
name: "WETH",
|
||||||
address: "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6",
|
address: "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6",
|
||||||
chainId: CHAIN_ID_ETH,
|
chainId: WORMHOLE_CHAIN_ID_ETHEREUM,
|
||||||
logo: ethIcon,
|
logo: ethIcon,
|
||||||
isNative: false,
|
isNative: false,
|
||||||
maxAmount: 0.01,
|
maxAmount: 0.01,
|
||||||
|
ustPairedAddress: "0x36Ed51Afc79619b299b238898E72ce482600568a",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const UST_TOKEN_INFO: TokenInfo = {
|
||||||
|
name: "UST",
|
||||||
|
address: "uusd",
|
||||||
|
chainId: WORMHOLE_CHAIN_ID_TERRA,
|
||||||
|
logo: ustIcon,
|
||||||
|
isNative: false,
|
||||||
|
maxAmount: 10.0,
|
||||||
|
ustPairedAddress: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TOKEN_INFOS = [
|
export const TOKEN_INFOS = [
|
||||||
|
@ -56,19 +82,21 @@ export const TOKEN_INFOS = [
|
||||||
WMATIC_TOKEN_INFO,
|
WMATIC_TOKEN_INFO,
|
||||||
ETH_TOKEN_INFO,
|
ETH_TOKEN_INFO,
|
||||||
WETH_TOKEN_INFO,
|
WETH_TOKEN_INFO,
|
||||||
|
UST_TOKEN_INFO,
|
||||||
];
|
];
|
||||||
|
|
||||||
export const ETH_NETWORK_CHAIN_ID = 5;
|
// evm handling
|
||||||
|
export const EVM_ETH_NETWORK_CHAIN_ID = 5;
|
||||||
export const POLYGON_NETWORK_CHAIN_ID = 80001;
|
export const EVM_POLYGON_NETWORK_CHAIN_ID = 80001;
|
||||||
|
|
||||||
export const getEvmChainId = (chainId: ChainId) =>
|
export const getEvmChainId = (chainId: ChainId) =>
|
||||||
chainId === CHAIN_ID_ETH
|
chainId === WORMHOLE_CHAIN_ID_ETHEREUM
|
||||||
? ETH_NETWORK_CHAIN_ID
|
? EVM_ETH_NETWORK_CHAIN_ID
|
||||||
: chainId === CHAIN_ID_POLYGON
|
: chainId === WORMHOLE_CHAIN_ID_POLYGON
|
||||||
? POLYGON_NETWORK_CHAIN_ID
|
? EVM_POLYGON_NETWORK_CHAIN_ID
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
// misc
|
||||||
export const RELAYER_FEE_UST = "0.25";
|
export const RELAYER_FEE_UST = "0.25";
|
||||||
|
|
||||||
export const WORMHOLE_RPC_HOSTS = [
|
export const WORMHOLE_RPC_HOSTS = [
|
||||||
|
@ -81,12 +109,16 @@ export const CORE_BRIDGE_ADDRESS_ETHEREUM =
|
||||||
export const CORE_BRIDGE_ADDRESS_POLYGON =
|
export const CORE_BRIDGE_ADDRESS_POLYGON =
|
||||||
"0x0CBE91CF822c73C2315FB05100C2F714765d5c20";
|
"0x0CBE91CF822c73C2315FB05100C2F714765d5c20";
|
||||||
|
|
||||||
|
export const CORE_BRIDGE_ADDRESS_TERRA = undefined;
|
||||||
|
|
||||||
export const TOKEN_BRIDGE_ADDRESS_ETHEREUM =
|
export const TOKEN_BRIDGE_ADDRESS_ETHEREUM =
|
||||||
"0xF890982f9310df57d00f659cf4fd87e65adEd8d7";
|
"0xF890982f9310df57d00f659cf4fd87e65adEd8d7";
|
||||||
|
|
||||||
export const TOKEN_BRIDGE_ADDRESS_POLYGON =
|
export const TOKEN_BRIDGE_ADDRESS_POLYGON =
|
||||||
"0x377D55a7928c046E18eEbb61977e714d2a76472a";
|
"0x377D55a7928c046E18eEbb61977e714d2a76472a";
|
||||||
|
|
||||||
|
export const TOKEN_BRIDGE_ADDRESS_TERRA = undefined;
|
||||||
|
|
||||||
export const QUICKSWAP_FACTORY_ADDRESS =
|
export const QUICKSWAP_FACTORY_ADDRESS =
|
||||||
"0x5757371414417b8C6CAad45bAeF941aBc7d3Ab32";
|
"0x5757371414417b8C6CAad45bAeF941aBc7d3Ab32";
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { FixedNumber } from "ethers";
|
||||||
|
|
||||||
|
export function addFixedAmounts(
|
||||||
|
left: string,
|
||||||
|
right: string,
|
||||||
|
decimals: number
|
||||||
|
): string {
|
||||||
|
const sum = FixedNumber.from(left).addUnsafe(FixedNumber.from(right));
|
||||||
|
return sum.round(this.getDecimals()).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function subtractFixedAmounts(
|
||||||
|
left: string,
|
||||||
|
right: string,
|
||||||
|
decimals: number
|
||||||
|
): string {
|
||||||
|
const diff = FixedNumber.from(left).subUnsafe(FixedNumber.from(right));
|
||||||
|
return diff.round(decimals).toString();
|
||||||
|
}
|
Loading…
Reference in New Issue