@shapeshiftoss/swapper 8.5.3 → 8.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.d.ts +2 -1
- package/dist/api.js +1 -0
- package/dist/swappers/cow/CowSwapper.d.ts +4 -3
- package/dist/swappers/cow/CowSwapper.js +5 -4
- package/dist/swappers/cow/cowBuildTrade/cowBuildTrade.d.ts +3 -2
- package/dist/swappers/cow/cowBuildTrade/cowBuildTrade.js +11 -16
- package/dist/swappers/cow/cowExecuteTrade/cowExecuteTrade.d.ts +4 -0
- package/dist/swappers/cow/cowExecuteTrade/cowExecuteTrade.js +91 -0
- package/dist/swappers/cow/cowGetTradeTxs/cowGetTradeTxs.d.ts +3 -0
- package/dist/swappers/cow/cowGetTradeTxs/cowGetTradeTxs.js +31 -0
- package/dist/swappers/cow/getCowSwapTradeQuote/getCowSwapTradeQuote.js +8 -15
- package/dist/swappers/cow/types.d.ts +13 -0
- package/dist/swappers/cow/utils/constants.d.ts +4 -0
- package/dist/swappers/cow/utils/constants.js +5 -1
- package/dist/swappers/cow/utils/helpers/helpers.d.ts +37 -0
- package/dist/swappers/cow/utils/helpers/helpers.js +44 -1
- package/package.json +3 -3
package/dist/api.d.ts
CHANGED
|
@@ -164,7 +164,8 @@ export declare enum SwapErrorTypes {
|
|
|
164
164
|
VALIDATION_FAILED = "VALIDATION_FAILED",
|
|
165
165
|
MAKE_MEMO_FAILED = "MAKE_MEMO_FAILED",
|
|
166
166
|
PRICE_RATIO_FAILED = "PRICE_RATIO_FAILED",
|
|
167
|
-
POOL_NOT_FOUND = "POOL_NOT_FOUND"
|
|
167
|
+
POOL_NOT_FOUND = "POOL_NOT_FOUND",
|
|
168
|
+
GET_TRADE_TXS_FAILED = "GET_TRADE_TXS_FAILED"
|
|
168
169
|
}
|
|
169
170
|
export interface Swapper<T extends ChainId> {
|
|
170
171
|
/** Human readable swapper name */
|
package/dist/api.js
CHANGED
|
@@ -36,4 +36,5 @@ var SwapErrorTypes;
|
|
|
36
36
|
SwapErrorTypes["MAKE_MEMO_FAILED"] = "MAKE_MEMO_FAILED";
|
|
37
37
|
SwapErrorTypes["PRICE_RATIO_FAILED"] = "PRICE_RATIO_FAILED";
|
|
38
38
|
SwapErrorTypes["POOL_NOT_FOUND"] = "POOL_NOT_FOUND";
|
|
39
|
+
SwapErrorTypes["GET_TRADE_TXS_FAILED"] = "GET_TRADE_TXS_FAILED";
|
|
39
40
|
})(SwapErrorTypes = exports.SwapErrorTypes || (exports.SwapErrorTypes = {}));
|
|
@@ -2,7 +2,8 @@ import { AssetId } from '@shapeshiftoss/caip';
|
|
|
2
2
|
import { ethereum } from '@shapeshiftoss/chain-adapters';
|
|
3
3
|
import { Asset, KnownChainIds } from '@shapeshiftoss/types';
|
|
4
4
|
import Web3 from 'web3';
|
|
5
|
-
import { ApprovalNeededInput, ApprovalNeededOutput, ApproveInfiniteInput, BuildTradeInput, BuyAssetBySellIdInput, ExecuteTradeInput, GetTradeQuoteInput, Swapper, SwapperType,
|
|
5
|
+
import { ApprovalNeededInput, ApprovalNeededOutput, ApproveInfiniteInput, BuildTradeInput, BuyAssetBySellIdInput, ExecuteTradeInput, GetTradeQuoteInput, Swapper, SwapperType, TradeQuote, TradeResult, TradeTxs } from '../../api';
|
|
6
|
+
import { CowTrade } from './types';
|
|
6
7
|
/**
|
|
7
8
|
* CowSwap only supports ERC-20 swaps, hence ETH is not supported
|
|
8
9
|
* In order to get rates correctly, we need WETH asset to be passed as feeAsset
|
|
@@ -18,7 +19,7 @@ export declare class CowSwapper implements Swapper<KnownChainIds.EthereumMainnet
|
|
|
18
19
|
deps: CowSwapperDeps;
|
|
19
20
|
constructor(deps: CowSwapperDeps);
|
|
20
21
|
getType(): SwapperType;
|
|
21
|
-
buildTrade(args: BuildTradeInput): Promise<
|
|
22
|
+
buildTrade(args: BuildTradeInput): Promise<CowTrade<KnownChainIds.EthereumMainnet>>;
|
|
22
23
|
getTradeQuote(input: GetTradeQuoteInput): Promise<TradeQuote<KnownChainIds.EthereumMainnet>>;
|
|
23
24
|
getUsdRate(input: Asset): Promise<string>;
|
|
24
25
|
executeTrade(args: ExecuteTradeInput<KnownChainIds.EthereumMainnet>): Promise<TradeResult>;
|
|
@@ -26,5 +27,5 @@ export declare class CowSwapper implements Swapper<KnownChainIds.EthereumMainnet
|
|
|
26
27
|
approveInfinite(args: ApproveInfiniteInput<KnownChainIds.EthereumMainnet>): Promise<string>;
|
|
27
28
|
filterBuyAssetsBySellAssetId(args: BuyAssetBySellIdInput): AssetId[];
|
|
28
29
|
filterAssetIdsBySellable(assetIds: AssetId[]): AssetId[];
|
|
29
|
-
getTradeTxs(): Promise<TradeTxs>;
|
|
30
|
+
getTradeTxs(args: TradeResult): Promise<TradeTxs>;
|
|
30
31
|
}
|
|
@@ -5,6 +5,8 @@ const api_1 = require("../../api");
|
|
|
5
5
|
const cowApprovalNeeded_1 = require("./cowApprovalNeeded/cowApprovalNeeded");
|
|
6
6
|
const cowApproveInfinite_1 = require("./cowApproveInfinite/cowApproveInfinite");
|
|
7
7
|
const cowBuildTrade_1 = require("./cowBuildTrade/cowBuildTrade");
|
|
8
|
+
const cowExecuteTrade_1 = require("./cowExecuteTrade/cowExecuteTrade");
|
|
9
|
+
const cowGetTradeTxs_1 = require("./cowGetTradeTxs/cowGetTradeTxs");
|
|
8
10
|
const getCowSwapTradeQuote_1 = require("./getCowSwapTradeQuote/getCowSwapTradeQuote");
|
|
9
11
|
const blacklist_1 = require("./utils/blacklist");
|
|
10
12
|
const helpers_1 = require("./utils/helpers/helpers");
|
|
@@ -26,8 +28,7 @@ class CowSwapper {
|
|
|
26
28
|
return (0, helpers_1.getUsdRate)(this.deps, input);
|
|
27
29
|
}
|
|
28
30
|
async executeTrade(args) {
|
|
29
|
-
|
|
30
|
-
throw new Error('CowSwapper: executeTrade unimplemented');
|
|
31
|
+
return (0, cowExecuteTrade_1.cowExecuteTrade)(this.deps, args);
|
|
31
32
|
}
|
|
32
33
|
async approvalNeeded(args) {
|
|
33
34
|
return (0, cowApprovalNeeded_1.cowApprovalNeeded)(this.deps, args);
|
|
@@ -47,8 +48,8 @@ class CowSwapper {
|
|
|
47
48
|
filterAssetIdsBySellable(assetIds) {
|
|
48
49
|
return assetIds.filter((id) => id.startsWith('eip155:1/erc20') && !blacklist_1.COWSWAP_UNSUPPORTED_ASSETS.includes(id));
|
|
49
50
|
}
|
|
50
|
-
async getTradeTxs() {
|
|
51
|
-
|
|
51
|
+
async getTradeTxs(args) {
|
|
52
|
+
return (0, cowGetTradeTxs_1.cowGetTradeTxs)(this.deps, args);
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
55
|
exports.CowSwapper = CowSwapper;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { KnownChainIds } from '@shapeshiftoss/types';
|
|
2
|
-
import { BuildTradeInput
|
|
2
|
+
import { BuildTradeInput } from '../../../api';
|
|
3
3
|
import { CowSwapperDeps } from '../CowSwapper';
|
|
4
|
-
|
|
4
|
+
import { CowTrade } from '../types';
|
|
5
|
+
export declare function cowBuildTrade(deps: CowSwapperDeps, input: BuildTradeInput): Promise<CowTrade<KnownChainIds.EthereumMainnet>>;
|
|
@@ -12,7 +12,7 @@ const helpers_2 = require("../utils/helpers/helpers");
|
|
|
12
12
|
async function cowBuildTrade(deps, input) {
|
|
13
13
|
try {
|
|
14
14
|
const { sellAsset, buyAsset, sellAmount, sellAssetAccountNumber, wallet } = input;
|
|
15
|
-
const { adapter,
|
|
15
|
+
const { adapter, web3 } = deps;
|
|
16
16
|
const { assetReference: sellAssetErc20Address, assetNamespace: sellAssetNamespace } = (0, caip_1.fromAssetId)(sellAsset.assetId);
|
|
17
17
|
const { assetReference: buyAssetErc20Address, assetNamespace: buyAssetNamespace } = (0, caip_1.fromAssetId)(buyAsset.assetId);
|
|
18
18
|
if (buyAssetNamespace !== 'erc20' || sellAssetNamespace !== 'erc20') {
|
|
@@ -57,36 +57,29 @@ async function cowBuildTrade(deps, input) {
|
|
|
57
57
|
spenderAddress: constants_1.COW_SWAP_VAULT_RELAYER_ADDRESS,
|
|
58
58
|
contractAddress: sellAssetErc20Address
|
|
59
59
|
});
|
|
60
|
-
const [feeDataOptions,
|
|
60
|
+
const [feeDataOptions, sellAssetUsdRate] = await Promise.all([
|
|
61
61
|
adapter.getFeeData({
|
|
62
62
|
to: sellAssetErc20Address,
|
|
63
63
|
value: '0',
|
|
64
64
|
chainSpecific: { from: receiveAddress, contractData: data }
|
|
65
65
|
}),
|
|
66
|
-
(0, helpers_2.getUsdRate)(deps, feeAsset),
|
|
67
66
|
(0, helpers_2.getUsdRate)(deps, sellAsset)
|
|
68
67
|
]);
|
|
69
68
|
const feeData = feeDataOptions['fast'];
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// hence feeInFeeAsset = feeInSellAsset * sellAssetUsdRate / feeAssetUsdRate
|
|
74
|
-
const feeInSellAsset = (0, bignumber_1.bnOrZero)(quote.feeAmount).div((0, bignumber_1.bn)(10).exponentiatedBy(sellAsset.precision));
|
|
75
|
-
// feeInFeeAsset = feeInSellAsset * sellAssetUsdRate / feeAssetUsdRate
|
|
76
|
-
const feeInFeeAsset = feeInSellAsset
|
|
69
|
+
// calculating trade fee in USD
|
|
70
|
+
const tradeFeeFiat = (0, bignumber_1.bnOrZero)(quote.feeAmount)
|
|
71
|
+
.div((0, bignumber_1.bn)(10).exponentiatedBy(sellAsset.precision))
|
|
77
72
|
.multipliedBy((0, bignumber_1.bnOrZero)(sellAssetUsdRate))
|
|
78
|
-
.
|
|
79
|
-
// taking precision into account
|
|
80
|
-
const fee = feeInFeeAsset.multipliedBy((0, bignumber_1.bn)(10).exponentiatedBy(feeAsset.precision)).toString();
|
|
73
|
+
.toString();
|
|
81
74
|
const trade = {
|
|
82
75
|
rate,
|
|
83
76
|
feeData: {
|
|
84
|
-
fee,
|
|
77
|
+
fee: '0',
|
|
85
78
|
chainSpecific: {
|
|
86
79
|
estimatedGas: feeData.chainSpecific.gasLimit,
|
|
87
80
|
gasPrice: feeData.chainSpecific.gasPrice
|
|
88
81
|
},
|
|
89
|
-
tradeFee:
|
|
82
|
+
tradeFee: tradeFeeFiat
|
|
90
83
|
},
|
|
91
84
|
sellAmount: normalizedSellAmount,
|
|
92
85
|
buyAmount: quote.buyAmount,
|
|
@@ -94,7 +87,9 @@ async function cowBuildTrade(deps, input) {
|
|
|
94
87
|
buyAsset,
|
|
95
88
|
sellAsset,
|
|
96
89
|
sellAssetAccountNumber,
|
|
97
|
-
receiveAddress
|
|
90
|
+
receiveAddress,
|
|
91
|
+
feeAmountInSellToken: quote.feeAmount,
|
|
92
|
+
sellAmountWithoutFee: quote.sellAmount
|
|
98
93
|
};
|
|
99
94
|
const allowanceRequired = await (0, helpers_1.getAllowanceRequired)({
|
|
100
95
|
adapter,
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { KnownChainIds } from '@shapeshiftoss/types';
|
|
2
|
+
import { ExecuteTradeInput, TradeResult } from '../../../api';
|
|
3
|
+
import { CowSwapperDeps } from '../CowSwapper';
|
|
4
|
+
export declare function cowExecuteTrade({ apiUrl, adapter }: CowSwapperDeps, { trade, wallet }: ExecuteTradeInput<KnownChainIds.EthereumMainnet>): Promise<TradeResult>;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cowExecuteTrade = void 0;
|
|
4
|
+
const caip_1 = require("@shapeshiftoss/caip");
|
|
5
|
+
const chain_adapters_1 = require("@shapeshiftoss/chain-adapters");
|
|
6
|
+
const hdwallet_core_1 = require("@shapeshiftoss/hdwallet-core");
|
|
7
|
+
const ethers_1 = require("ethers");
|
|
8
|
+
const api_1 = require("../../../api");
|
|
9
|
+
const constants_1 = require("../utils/constants");
|
|
10
|
+
const cowService_1 = require("../utils/cowService");
|
|
11
|
+
const helpers_1 = require("../utils/helpers/helpers");
|
|
12
|
+
async function cowExecuteTrade({ apiUrl, adapter }, { trade, wallet }) {
|
|
13
|
+
const cowTrade = trade;
|
|
14
|
+
const { sellAsset, buyAsset, feeAmountInSellToken, sellAmountWithoutFee } = cowTrade;
|
|
15
|
+
const { assetReference: sellAssetErc20Address, assetNamespace: sellAssetNamespace } = (0, caip_1.fromAssetId)(sellAsset.assetId);
|
|
16
|
+
const { assetReference: buyAssetErc20Address, assetNamespace: buyAssetNamespace } = (0, caip_1.fromAssetId)(buyAsset.assetId);
|
|
17
|
+
if (buyAssetNamespace !== 'erc20' || sellAssetNamespace !== 'erc20') {
|
|
18
|
+
throw new api_1.SwapError('[cowExecuteTrade] - Both assets need to be ERC-20 to use CowSwap', {
|
|
19
|
+
code: api_1.SwapErrorTypes.UNSUPPORTED_PAIR,
|
|
20
|
+
details: { buyAssetNamespace, sellAssetNamespace }
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const orderToSign = {
|
|
25
|
+
sellToken: sellAssetErc20Address,
|
|
26
|
+
buyToken: buyAssetErc20Address,
|
|
27
|
+
sellAmount: sellAmountWithoutFee,
|
|
28
|
+
buyAmount: trade.buyAmount,
|
|
29
|
+
validTo: (0, helpers_1.getNowPlusThirtyMinutesTimestamp)(),
|
|
30
|
+
appData: constants_1.DEFAULT_APP_DATA,
|
|
31
|
+
feeAmount: feeAmountInSellToken,
|
|
32
|
+
kind: constants_1.ORDER_KIND_SELL,
|
|
33
|
+
partiallyFillable: false,
|
|
34
|
+
receiver: trade.receiveAddress,
|
|
35
|
+
sellTokenBalance: constants_1.ERC20_TOKEN_BALANCE,
|
|
36
|
+
buyTokenBalance: constants_1.ERC20_TOKEN_BALANCE
|
|
37
|
+
};
|
|
38
|
+
// We need to construct orderDigest, sign it and send it to cowSwap API, in order to submit a trade
|
|
39
|
+
// Some context about this : https://docs.cow.fi/tutorials/how-to-submit-orders-via-the-api/4.-signing-the-order
|
|
40
|
+
// For more info, check hashOrder method implementation
|
|
41
|
+
const orderDigest = (0, helpers_1.hashOrder)((0, helpers_1.domain)(1, constants_1.COW_SWAP_SETTLEMENT_ADDRESS), orderToSign);
|
|
42
|
+
const bip44Params = chain_adapters_1.ethereum.ChainAdapter.defaultBIP44Params;
|
|
43
|
+
const message = {
|
|
44
|
+
messageToSign: {
|
|
45
|
+
addressNList: (0, hdwallet_core_1.bip32ToAddressNList)((0, chain_adapters_1.toRootDerivationPath)(bip44Params)),
|
|
46
|
+
message: ethers_1.ethers.utils.arrayify(orderDigest)
|
|
47
|
+
},
|
|
48
|
+
wallet
|
|
49
|
+
};
|
|
50
|
+
const signatureOrderDigest = await adapter.signMessage(message);
|
|
51
|
+
// Passing the signature through split/join to normalize the `v` byte.
|
|
52
|
+
// Some wallets do not pad it with `27`, which causes a signature failure
|
|
53
|
+
// `splitSignature` pads it if needed, and `joinSignature` simply puts it back together
|
|
54
|
+
const signature = ethers_1.ethers.utils.joinSignature(ethers_1.ethers.utils.splitSignature(signatureOrderDigest));
|
|
55
|
+
/**
|
|
56
|
+
* /v1/orders
|
|
57
|
+
* params: {
|
|
58
|
+
* sellToken: contract address of token to sell
|
|
59
|
+
* buyToken: contractAddress of token to buy
|
|
60
|
+
* receiver: receiver address
|
|
61
|
+
* validTo: time duration during which order is valid (putting current timestamp + 30 minutes for real order)
|
|
62
|
+
* appData: appData that can be used later, can be defaulted to "0x0000000000000000000000000000000000000000000000000000000000000000"
|
|
63
|
+
* partiallyFillable: false
|
|
64
|
+
* from: sender address
|
|
65
|
+
* kind: "sell" or "buy"
|
|
66
|
+
* feeAmount: amount of fee in sellToken base
|
|
67
|
+
* sellTokenBalance: "erc20" string,
|
|
68
|
+
* buyTokenBalance: "erc20" string,
|
|
69
|
+
* signingScheme: the signing scheme used for the signature
|
|
70
|
+
* signature: a signed message specific to cowswap for this order
|
|
71
|
+
* from: same as receiver address in our case
|
|
72
|
+
* }
|
|
73
|
+
*/
|
|
74
|
+
const ordersResponse = await cowService_1.cowService.post(`${apiUrl}/v1/orders/`, {
|
|
75
|
+
...orderToSign,
|
|
76
|
+
signingScheme: constants_1.SIGNING_SCHEME,
|
|
77
|
+
signature,
|
|
78
|
+
from: trade.receiveAddress
|
|
79
|
+
});
|
|
80
|
+
return { tradeId: ordersResponse.data };
|
|
81
|
+
}
|
|
82
|
+
catch (e) {
|
|
83
|
+
if (e instanceof api_1.SwapError)
|
|
84
|
+
throw e;
|
|
85
|
+
throw new api_1.SwapError('[cowExecuteTrade]', {
|
|
86
|
+
cause: e,
|
|
87
|
+
code: api_1.SwapErrorTypes.EXECUTE_TRADE_FAILED
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
exports.cowExecuteTrade = cowExecuteTrade;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cowGetTradeTxs = void 0;
|
|
4
|
+
const api_1 = require("../../../api");
|
|
5
|
+
const constants_1 = require("../utils/constants");
|
|
6
|
+
const cowService_1 = require("../utils/cowService");
|
|
7
|
+
async function cowGetTradeTxs(deps, input) {
|
|
8
|
+
try {
|
|
9
|
+
const getOrdersResponse = await cowService_1.cowService.get(`${deps.apiUrl}/v1/orders/${input.tradeId}`);
|
|
10
|
+
const { data: { status } } = getOrdersResponse;
|
|
11
|
+
if (status !== constants_1.ORDER_STATUS_FULFILLED) {
|
|
12
|
+
return {
|
|
13
|
+
sellTxid: ''
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
const getTradesResponse = await cowService_1.cowService.get(`${deps.apiUrl}/v1/trades/?orderUid=${input.tradeId}`);
|
|
17
|
+
return {
|
|
18
|
+
sellTxid: '',
|
|
19
|
+
buyTxid: getTradesResponse.data[0].txHash
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
if (e instanceof api_1.SwapError)
|
|
24
|
+
throw e;
|
|
25
|
+
throw new api_1.SwapError('[cowGetTradeTxs]', {
|
|
26
|
+
cause: e,
|
|
27
|
+
code: api_1.SwapErrorTypes.GET_TRADE_TXS_FAILED
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.cowGetTradeTxs = cowGetTradeTxs;
|
|
@@ -12,7 +12,7 @@ const helpers_2 = require("../utils/helpers/helpers");
|
|
|
12
12
|
async function getCowSwapTradeQuote(deps, input) {
|
|
13
13
|
try {
|
|
14
14
|
const { sellAsset, buyAsset, sellAmount, sellAssetAccountNumber, wallet } = input;
|
|
15
|
-
const { adapter,
|
|
15
|
+
const { adapter, web3 } = deps;
|
|
16
16
|
const { assetReference: sellAssetErc20Address, assetNamespace: sellAssetNamespace } = (0, caip_1.fromAssetId)(sellAsset.assetId);
|
|
17
17
|
const { assetReference: buyAssetErc20Address, assetNamespace: buyAssetNamespace } = (0, caip_1.fromAssetId)(buyAsset.assetId);
|
|
18
18
|
if (buyAssetNamespace !== 'erc20' || sellAssetNamespace !== 'erc20') {
|
|
@@ -61,33 +61,26 @@ async function getCowSwapTradeQuote(deps, input) {
|
|
|
61
61
|
spenderAddress: constants_1.COW_SWAP_VAULT_RELAYER_ADDRESS,
|
|
62
62
|
contractAddress: sellAssetErc20Address
|
|
63
63
|
});
|
|
64
|
-
const [feeDataOptions,
|
|
64
|
+
const [feeDataOptions, sellAssetUsdRate] = await Promise.all([
|
|
65
65
|
adapter.getFeeData({
|
|
66
66
|
to: sellAssetErc20Address,
|
|
67
67
|
value: '0',
|
|
68
68
|
chainSpecific: { from: receiveAddress, contractData: data }
|
|
69
69
|
}),
|
|
70
|
-
(0, helpers_2.getUsdRate)(deps, feeAsset),
|
|
71
70
|
(0, helpers_2.getUsdRate)(deps, sellAsset)
|
|
72
71
|
]);
|
|
73
72
|
const feeData = feeDataOptions['fast'];
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
// hence feeInFeeAsset = feeInSellAsset * sellAssetUsdRate / feeAssetUsdRate
|
|
78
|
-
const feeInSellAsset = (0, bignumber_1.bnOrZero)(quote.feeAmount).div((0, bignumber_1.bn)(10).exponentiatedBy(sellAsset.precision));
|
|
79
|
-
// feeInFeeAsset = feeInSellAsset * sellAssetUsdRate / feeAssetUsdRate
|
|
80
|
-
const feeInFeeAsset = feeInSellAsset
|
|
73
|
+
// calculating trade fee in USD
|
|
74
|
+
const tradeFeeFiat = (0, bignumber_1.bnOrZero)(quote.feeAmount)
|
|
75
|
+
.div((0, bignumber_1.bn)(10).exponentiatedBy(sellAsset.precision))
|
|
81
76
|
.multipliedBy((0, bignumber_1.bnOrZero)(sellAssetUsdRate))
|
|
82
|
-
.
|
|
83
|
-
// taking precision into account
|
|
84
|
-
const fee = feeInFeeAsset.multipliedBy((0, bignumber_1.bn)(10).exponentiatedBy(feeAsset.precision)).toString();
|
|
77
|
+
.toString();
|
|
85
78
|
return {
|
|
86
79
|
rate,
|
|
87
80
|
minimum,
|
|
88
81
|
maximum,
|
|
89
82
|
feeData: {
|
|
90
|
-
fee,
|
|
83
|
+
fee: '0',
|
|
91
84
|
chainSpecific: {
|
|
92
85
|
estimatedGas: feeData.chainSpecific.gasLimit,
|
|
93
86
|
gasPrice: feeData.chainSpecific.gasPrice,
|
|
@@ -95,7 +88,7 @@ async function getCowSwapTradeQuote(deps, input) {
|
|
|
95
88
|
.multipliedBy((0, bignumber_1.bnOrZero)(feeData.chainSpecific.gasPrice))
|
|
96
89
|
.toString()
|
|
97
90
|
},
|
|
98
|
-
tradeFee:
|
|
91
|
+
tradeFee: tradeFeeFiat
|
|
99
92
|
},
|
|
100
93
|
sellAmount: normalizedSellAmount,
|
|
101
94
|
buyAmount: quote.buyAmount,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ChainId } from '@shapeshiftoss/caip';
|
|
2
|
+
import { Trade } from '../../api';
|
|
1
3
|
export declare type CowSwapPriceResponse = {
|
|
2
4
|
amount: string;
|
|
3
5
|
token: string;
|
|
@@ -18,3 +20,14 @@ export declare type CowSwapQuoteResponse = {
|
|
|
18
20
|
from: string;
|
|
19
21
|
expiration: string;
|
|
20
22
|
};
|
|
23
|
+
export declare type CowSwapGetOrdersResponse = {
|
|
24
|
+
status: string;
|
|
25
|
+
};
|
|
26
|
+
export declare type CowSwapGetTradesElement = {
|
|
27
|
+
txHash: string;
|
|
28
|
+
};
|
|
29
|
+
export declare type CowSwapGetTradesResponse = Array<CowSwapGetTradesElement>;
|
|
30
|
+
export interface CowTrade<C extends ChainId> extends Trade<C> {
|
|
31
|
+
feeAmountInSellToken: string;
|
|
32
|
+
sellAmountWithoutFee: string;
|
|
33
|
+
}
|
|
@@ -8,4 +8,8 @@ export declare const DEFAULT_SOURCE: {
|
|
|
8
8
|
export declare const DEFAULT_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
9
9
|
export declare const DEFAULT_APP_DATA = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
|
10
10
|
export declare const COW_SWAP_VAULT_RELAYER_ADDRESS = "0xc92e8bdf79f0507f65a392b0ab4667716bfe0110";
|
|
11
|
+
export declare const COW_SWAP_SETTLEMENT_ADDRESS = "0x9008D19f58AAbD9eD0D60971565AA8510560ab41";
|
|
11
12
|
export declare const ORDER_KIND_SELL = "sell";
|
|
13
|
+
export declare const SIGNING_SCHEME = "ethsign";
|
|
14
|
+
export declare const ERC20_TOKEN_BALANCE = "erc20";
|
|
15
|
+
export declare const ORDER_STATUS_FULFILLED = "fulfilled";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ORDER_KIND_SELL = exports.COW_SWAP_VAULT_RELAYER_ADDRESS = exports.DEFAULT_APP_DATA = exports.DEFAULT_ADDRESS = exports.DEFAULT_SOURCE = exports.MIN_COWSWAP_VALUE_USD = exports.MAX_COWSWAP_TRADE = exports.MAX_ALLOWANCE = void 0;
|
|
3
|
+
exports.ORDER_STATUS_FULFILLED = exports.ERC20_TOKEN_BALANCE = exports.SIGNING_SCHEME = exports.ORDER_KIND_SELL = exports.COW_SWAP_SETTLEMENT_ADDRESS = exports.COW_SWAP_VAULT_RELAYER_ADDRESS = exports.DEFAULT_APP_DATA = exports.DEFAULT_ADDRESS = exports.DEFAULT_SOURCE = exports.MIN_COWSWAP_VALUE_USD = exports.MAX_COWSWAP_TRADE = exports.MAX_ALLOWANCE = void 0;
|
|
4
4
|
const constants_1 = require("@ethersproject/constants");
|
|
5
5
|
exports.MAX_ALLOWANCE = '100000000000000000000000000';
|
|
6
6
|
exports.MAX_COWSWAP_TRADE = '100000000000000000000000000';
|
|
@@ -9,4 +9,8 @@ exports.DEFAULT_SOURCE = [{ name: 'CowSwap', proportion: '1' }];
|
|
|
9
9
|
exports.DEFAULT_ADDRESS = constants_1.AddressZero;
|
|
10
10
|
exports.DEFAULT_APP_DATA = constants_1.HashZero;
|
|
11
11
|
exports.COW_SWAP_VAULT_RELAYER_ADDRESS = '0xc92e8bdf79f0507f65a392b0ab4667716bfe0110';
|
|
12
|
+
exports.COW_SWAP_SETTLEMENT_ADDRESS = '0x9008D19f58AAbD9eD0D60971565AA8510560ab41';
|
|
12
13
|
exports.ORDER_KIND_SELL = 'sell';
|
|
14
|
+
exports.SIGNING_SCHEME = 'ethsign';
|
|
15
|
+
exports.ERC20_TOKEN_BALANCE = 'erc20';
|
|
16
|
+
exports.ORDER_STATUS_FULFILLED = 'fulfilled';
|
|
@@ -1,5 +1,28 @@
|
|
|
1
|
+
import { TypedDataDomain, TypedDataField } from '@ethersproject/abstract-signer';
|
|
1
2
|
import { Asset } from '@shapeshiftoss/types';
|
|
2
3
|
import { CowSwapperDeps } from '../../CowSwapper';
|
|
4
|
+
export declare const ORDER_TYPE_FIELDS: {
|
|
5
|
+
name: string;
|
|
6
|
+
type: string;
|
|
7
|
+
}[];
|
|
8
|
+
/**
|
|
9
|
+
* EIP-712 typed data type definitions.
|
|
10
|
+
*/
|
|
11
|
+
export declare type TypedDataTypes = Record<string, Array<TypedDataField>>;
|
|
12
|
+
export declare type CowSwapOrder = {
|
|
13
|
+
sellToken: string;
|
|
14
|
+
buyToken: string;
|
|
15
|
+
sellAmount: string;
|
|
16
|
+
buyAmount: string;
|
|
17
|
+
validTo: number;
|
|
18
|
+
appData: string;
|
|
19
|
+
feeAmount: string;
|
|
20
|
+
kind: string;
|
|
21
|
+
partiallyFillable: boolean;
|
|
22
|
+
receiver: string;
|
|
23
|
+
sellTokenBalance: string;
|
|
24
|
+
buyTokenBalance: string;
|
|
25
|
+
};
|
|
3
26
|
export declare type CowSwapQuoteApiInput = {
|
|
4
27
|
appData: string;
|
|
5
28
|
buyToken: string;
|
|
@@ -13,3 +36,17 @@ export declare type CowSwapQuoteApiInput = {
|
|
|
13
36
|
};
|
|
14
37
|
export declare const getUsdRate: ({ apiUrl, feeAsset }: CowSwapperDeps, input: Asset) => Promise<string>;
|
|
15
38
|
export declare const getNowPlusThirtyMinutesTimestamp: () => number;
|
|
39
|
+
export declare const hashTypedData: (domain: TypedDataDomain, types: TypedDataTypes, data: Record<string, unknown>) => string;
|
|
40
|
+
/**
|
|
41
|
+
* Compute the 32-byte signing hash for the specified order.
|
|
42
|
+
* Implementation is following https://github.com/cowprotocol/contracts/blob/main/src/ts/order.ts
|
|
43
|
+
* Some more ressources that can be useful :
|
|
44
|
+
* https://docs.cow.fi/tutorials/how-to-submit-orders-via-the-api/4.-signing-the-order
|
|
45
|
+
* https://docs.cow.fi/smart-contracts/settlement-contract/signature-schemes
|
|
46
|
+
*
|
|
47
|
+
* @param domain The EIP-712 domain separator to compute the hash for.
|
|
48
|
+
* @param order The order to compute the digest for.
|
|
49
|
+
* @return Hex-encoded 32-byte order digest.
|
|
50
|
+
*/
|
|
51
|
+
export declare const hashOrder: (domain: TypedDataDomain, order: CowSwapOrder) => string;
|
|
52
|
+
export declare const domain: (chainId: number, verifyingContract: string) => TypedDataDomain;
|
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getNowPlusThirtyMinutesTimestamp = exports.getUsdRate = void 0;
|
|
3
|
+
exports.domain = exports.hashOrder = exports.hashTypedData = exports.getNowPlusThirtyMinutesTimestamp = exports.getUsdRate = exports.ORDER_TYPE_FIELDS = void 0;
|
|
4
4
|
const caip_1 = require("@shapeshiftoss/caip");
|
|
5
|
+
const ethers_1 = require("ethers");
|
|
5
6
|
const api_1 = require("../../../../api");
|
|
6
7
|
const bignumber_1 = require("../../../utils/bignumber");
|
|
7
8
|
const cowService_1 = require("../cowService");
|
|
8
9
|
const USDC_CONTRACT_ADDRESS = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48';
|
|
9
10
|
const USDC_ASSET_PRECISION = 6;
|
|
11
|
+
exports.ORDER_TYPE_FIELDS = [
|
|
12
|
+
{ name: 'sellToken', type: 'address' },
|
|
13
|
+
{ name: 'buyToken', type: 'address' },
|
|
14
|
+
{ name: 'receiver', type: 'address' },
|
|
15
|
+
{ name: 'sellAmount', type: 'uint256' },
|
|
16
|
+
{ name: 'buyAmount', type: 'uint256' },
|
|
17
|
+
{ name: 'validTo', type: 'uint32' },
|
|
18
|
+
{ name: 'appData', type: 'bytes32' },
|
|
19
|
+
{ name: 'feeAmount', type: 'uint256' },
|
|
20
|
+
{ name: 'kind', type: 'string' },
|
|
21
|
+
{ name: 'partiallyFillable', type: 'bool' },
|
|
22
|
+
{ name: 'sellTokenBalance', type: 'string' },
|
|
23
|
+
{ name: 'buyTokenBalance', type: 'string' }
|
|
24
|
+
];
|
|
10
25
|
const getUsdRate = async ({ apiUrl, feeAsset }, input) => {
|
|
11
26
|
// Replacing ETH by WETH specifically for CowSwap in order to get an usd rate when called with ETH as feeAsset
|
|
12
27
|
const asset = input.assetId !== caip_1.ethAssetId ? input : feeAsset;
|
|
@@ -51,3 +66,31 @@ const getNowPlusThirtyMinutesTimestamp = () => {
|
|
|
51
66
|
return Math.round(ts.getTime() / 1000);
|
|
52
67
|
};
|
|
53
68
|
exports.getNowPlusThirtyMinutesTimestamp = getNowPlusThirtyMinutesTimestamp;
|
|
69
|
+
const hashTypedData = (domain, types, data) => {
|
|
70
|
+
return ethers_1.ethers.utils._TypedDataEncoder.hash(domain, types, data);
|
|
71
|
+
};
|
|
72
|
+
exports.hashTypedData = hashTypedData;
|
|
73
|
+
/**
|
|
74
|
+
* Compute the 32-byte signing hash for the specified order.
|
|
75
|
+
* Implementation is following https://github.com/cowprotocol/contracts/blob/main/src/ts/order.ts
|
|
76
|
+
* Some more ressources that can be useful :
|
|
77
|
+
* https://docs.cow.fi/tutorials/how-to-submit-orders-via-the-api/4.-signing-the-order
|
|
78
|
+
* https://docs.cow.fi/smart-contracts/settlement-contract/signature-schemes
|
|
79
|
+
*
|
|
80
|
+
* @param domain The EIP-712 domain separator to compute the hash for.
|
|
81
|
+
* @param order The order to compute the digest for.
|
|
82
|
+
* @return Hex-encoded 32-byte order digest.
|
|
83
|
+
*/
|
|
84
|
+
const hashOrder = (domain, order) => {
|
|
85
|
+
return (0, exports.hashTypedData)(domain, { Order: exports.ORDER_TYPE_FIELDS }, order);
|
|
86
|
+
};
|
|
87
|
+
exports.hashOrder = hashOrder;
|
|
88
|
+
const domain = (chainId, verifyingContract) => {
|
|
89
|
+
return {
|
|
90
|
+
name: 'Gnosis Protocol',
|
|
91
|
+
version: 'v2',
|
|
92
|
+
chainId,
|
|
93
|
+
verifyingContract
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
exports.domain = domain;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shapeshiftoss/swapper",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.6.0",
|
|
4
4
|
"description": "An interface and implementations to trade coins via various protocols",
|
|
5
5
|
"repository": "https://github.com/shapeshift/lib",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@shapeshiftoss/caip": "^6.2.0",
|
|
35
35
|
"@shapeshiftoss/chain-adapters": "^7.2.0",
|
|
36
36
|
"@shapeshiftoss/errors": "^1.1.2",
|
|
37
|
-
"@shapeshiftoss/hdwallet-core": "^1.
|
|
37
|
+
"@shapeshiftoss/hdwallet-core": "^1.27.0",
|
|
38
38
|
"@shapeshiftoss/types": "^7.0.0"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"@shapeshiftoss/caip": "^6.2.0",
|
|
43
43
|
"@shapeshiftoss/chain-adapters": "^7.2.0",
|
|
44
44
|
"@shapeshiftoss/errors": "^1.1.2",
|
|
45
|
-
"@shapeshiftoss/hdwallet-core": "^1.
|
|
45
|
+
"@shapeshiftoss/hdwallet-core": "^1.27.0",
|
|
46
46
|
"@shapeshiftoss/types": "^7.0.0",
|
|
47
47
|
"@types/readline-sync": "^1.4.4",
|
|
48
48
|
"readline-sync": "^1.4.10",
|