/
okuswap-on-chain-trade.ts
156 lines (130 loc) · 5.97 KB
/
okuswap-on-chain-trade.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import BigNumber from 'bignumber.js';
import { RubicSdkError, UnnecessaryApproveError } from 'src/common/errors';
import { EvmBasicTransactionOptions } from 'src/core/blockchain/web3-private-service/web3-private/evm-web3-private/models/evm-basic-transaction-options';
import { EvmWeb3Pure } from 'src/core/blockchain/web3-pure/typed-web3-pure/evm-web3-pure/evm-web3-pure';
import { Web3Pure } from 'src/core/blockchain/web3-pure/web3-pure';
import { EncodeTransactionOptions } from 'src/features/common/models/encode-transaction-options';
import { rubicProxyContractAddress } from 'src/features/cross-chain/calculation-manager/providers/common/constants/rubic-proxy-contract-address';
import { getOnChainGasData } from 'src/features/on-chain/calculation-manager/utils/get-on-chain-gas-data';
import { TransactionReceipt } from 'web3-eth';
import { ON_CHAIN_TRADE_TYPE, OnChainTradeType } from '../../common/models/on-chain-trade-type';
import { AggregatorEvmOnChainTrade } from '../../common/on-chain-aggregator/aggregator-evm-on-chain-trade-abstract';
import { GetToAmountAndTxDataResponse } from '../../common/on-chain-aggregator/models/aggregator-on-chain-types';
import { OkuQuoteRequestBody, OkuSwapRequestBody } from './models/okuswap-api-types';
import { OkuSwapSupportedBlockchain } from './models/okuswap-on-chain-supported-chains';
import { OkuSwapOnChainTradeStruct } from './models/okuswap-trade-types';
import { OkuSwapApiService } from './services/okuswap-api-service';
export class OkuSwapOnChainTrade extends AggregatorEvmOnChainTrade {
/* @internal */
public static async getGasLimit(
tradeStruct: OkuSwapOnChainTradeStruct,
providerGateway: string
): Promise<BigNumber | null> {
const okuswapTrade = new OkuSwapOnChainTrade(
tradeStruct,
EvmWeb3Pure.EMPTY_ADDRESS,
providerGateway
);
return getOnChainGasData(okuswapTrade);
}
public readonly type: OnChainTradeType = ON_CHAIN_TRADE_TYPE.OKU_SWAP;
private readonly okuSubProvider: string;
private readonly quoteReqBody: OkuQuoteRequestBody;
private readonly swapReqBody: OkuSwapRequestBody;
protected readonly providerGateway: string;
protected get spenderAddress(): string {
return this.useProxy
? rubicProxyContractAddress[this.from.blockchain].gateway
: this.providerGateway;
}
protected get fromBlockchain(): OkuSwapSupportedBlockchain {
return this.from.blockchain as OkuSwapSupportedBlockchain;
}
public get dexContractAddress(): string {
throw new RubicSdkError('Dex address is unknown before swap is started');
}
constructor(
tradeStruct: OkuSwapOnChainTradeStruct,
providerAddress: string,
providerGateway: string
) {
super(tradeStruct, providerAddress);
this.providerGateway = providerGateway;
this.okuSubProvider = tradeStruct.subProvider;
this.quoteReqBody = tradeStruct.quoteReqBody;
this.swapReqBody = tradeStruct.swapReqBody;
}
/**
* Sends approve and if needed permit2Approve on UniswapV3Like-contract
*/
public async approve(
options: EvmBasicTransactionOptions,
checkNeedApprove = true,
amount: BigNumber | 'infinity' = 'infinity'
): Promise<TransactionReceipt> {
const permit2Address =
this.permit2ApproveConfig.permit2Address ||
'0xFcf5986450E4A014fFE7ad4Ae24921B589D039b5';
if (this.permit2ApproveConfig.usePermit2Approve) {
const needPermit2Approve = await this.needPermit2Approve();
if (needPermit2Approve) {
await this.web3Private.approveOnPermit2(
this.from.address,
permit2Address,
this.spenderAddress,
amount,
new BigNumber(1_000_000),
options
);
}
}
if (checkNeedApprove) {
const needApprove = await this.needApprove(this.walletAddress);
if (!needApprove) {
throw new UnnecessaryApproveError();
}
}
this.checkWalletConnected();
await this.checkBlockchainCorrect();
return this.web3Private.approveTokens(this.from.address, permit2Address, amount, options);
}
public async needApprove(fromAddress?: string): Promise<boolean> {
if (!fromAddress) {
this.checkWalletConnected();
}
const permit2Address =
this.permit2ApproveConfig.permit2Address ||
'0xFcf5986450E4A014fFE7ad4Ae24921B589D039b5';
const needPermit2Approve = await this.needPermit2Approve();
const allowance = await this.web3Public.getAllowance(
this.from.address,
this.walletAddress,
permit2Address
);
return allowance.lt(this.from.weiAmount) || needPermit2Approve;
}
private async needPermit2Approve(): Promise<boolean> {
const permit2Address =
this.permit2ApproveConfig.permit2Address ||
'0xFcf5986450E4A014fFE7ad4Ae24921B589D039b5';
const [allowance, expiration] = await this.web3Public.getAllowanceAndExpirationOnPermit2(
this.from.address,
this.walletAddress,
this.spenderAddress,
permit2Address
);
return this.from.weiAmount.gt(allowance) || new BigNumber(Date.now()).gt(expiration);
}
protected async getTransactionConfigAndAmount(
_options: EncodeTransactionOptions
): Promise<GetToAmountAndTxDataResponse> {
const [{ outAmount, estimatedGas }, evmConfig] = await Promise.all([
OkuSwapApiService.makeQuoteRequest(this.okuSubProvider, this.quoteReqBody),
OkuSwapApiService.makeSwapRequest(this.okuSubProvider, this.swapReqBody)
]);
return {
toAmount: Web3Pure.toWei(outAmount, this.to.decimals),
tx: { ...evmConfig, gas: estimatedGas }
};
}
}