@cowprotocol/sdk-trading 0.1.0-monorepo.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/README.md +576 -0
- package/dist/index.d.mts +326 -0
- package/dist/index.d.ts +326 -0
- package/dist/index.js +1067 -0
- package/dist/index.mjs +1025 -0
- package/package.json +51 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,1025 @@
|
|
|
1
|
+
// src/postCoWProtocolTrade.ts
|
|
2
|
+
import { SigningScheme as SigningScheme3 } from "@cowprotocol/sdk-order-book";
|
|
3
|
+
|
|
4
|
+
// src/consts.ts
|
|
5
|
+
import { EcdsaSigningScheme, SigningScheme } from "@cowprotocol/sdk-order-book";
|
|
6
|
+
import { SupportedChainId } from "@cowprotocol/sdk-config";
|
|
7
|
+
var DEFAULT_QUOTE_VALIDITY = 60 * 30;
|
|
8
|
+
var DEFAULT_SLIPPAGE_BPS = 50;
|
|
9
|
+
var ETH_FLOW_DEFAULT_SLIPPAGE_BPS = {
|
|
10
|
+
[SupportedChainId.MAINNET]: 200,
|
|
11
|
+
// 2%,
|
|
12
|
+
[SupportedChainId.ARBITRUM_ONE]: 50,
|
|
13
|
+
// 0.5%,
|
|
14
|
+
[SupportedChainId.BASE]: 50,
|
|
15
|
+
// 0.5%,
|
|
16
|
+
[SupportedChainId.GNOSIS_CHAIN]: 50,
|
|
17
|
+
// 0.5%,
|
|
18
|
+
[SupportedChainId.SEPOLIA]: 50,
|
|
19
|
+
// 0.5%,
|
|
20
|
+
[SupportedChainId.POLYGON]: 50,
|
|
21
|
+
// 0.5%,
|
|
22
|
+
[SupportedChainId.AVALANCHE]: 50
|
|
23
|
+
// 0.5%,
|
|
24
|
+
};
|
|
25
|
+
var SIGN_SCHEME_MAP = {
|
|
26
|
+
[EcdsaSigningScheme.EIP712]: SigningScheme.EIP712,
|
|
27
|
+
[EcdsaSigningScheme.ETHSIGN]: SigningScheme.ETHSIGN
|
|
28
|
+
};
|
|
29
|
+
var GAS_LIMIT_DEFAULT = BigInt(15e4);
|
|
30
|
+
|
|
31
|
+
// src/postCoWProtocolTrade.ts
|
|
32
|
+
import { OrderSigningUtils as OrderSigningUtils2 } from "@cowprotocol/sdk-order-signing";
|
|
33
|
+
|
|
34
|
+
// src/getOrderToSign.ts
|
|
35
|
+
import { BuyTokenDestination, getQuoteAmountsAndCosts, SellTokenSource } from "@cowprotocol/sdk-order-book";
|
|
36
|
+
|
|
37
|
+
// src/utils/getPartnerFeeBps.ts
|
|
38
|
+
function getPartnerFeeBps(partnerFee) {
|
|
39
|
+
if (!partnerFee) {
|
|
40
|
+
return void 0;
|
|
41
|
+
}
|
|
42
|
+
if ("volumeBps" in partnerFee) {
|
|
43
|
+
return partnerFee.volumeBps;
|
|
44
|
+
}
|
|
45
|
+
if (Array.isArray(partnerFee)) {
|
|
46
|
+
for (const fee of partnerFee) {
|
|
47
|
+
if ("volumeBps" in fee) {
|
|
48
|
+
return fee.volumeBps;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return void 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/getOrderToSign.ts
|
|
56
|
+
function getOrderToSign({ from, networkCostsAmount = "0" }, limitOrderParams, appDataKeccak256) {
|
|
57
|
+
const {
|
|
58
|
+
sellAmount,
|
|
59
|
+
buyAmount,
|
|
60
|
+
sellToken,
|
|
61
|
+
sellTokenDecimals,
|
|
62
|
+
buyToken,
|
|
63
|
+
buyTokenDecimals,
|
|
64
|
+
kind,
|
|
65
|
+
partiallyFillable = false,
|
|
66
|
+
slippageBps = DEFAULT_SLIPPAGE_BPS,
|
|
67
|
+
partnerFee,
|
|
68
|
+
validFor
|
|
69
|
+
} = limitOrderParams;
|
|
70
|
+
const receiver = limitOrderParams.receiver || from;
|
|
71
|
+
const validTo = limitOrderParams.validTo || Math.floor(Date.now() / 1e3) + (validFor || DEFAULT_QUOTE_VALIDITY);
|
|
72
|
+
const orderParams = {
|
|
73
|
+
sellToken,
|
|
74
|
+
buyToken,
|
|
75
|
+
sellAmount,
|
|
76
|
+
buyAmount,
|
|
77
|
+
receiver,
|
|
78
|
+
validTo,
|
|
79
|
+
kind,
|
|
80
|
+
feeAmount: networkCostsAmount,
|
|
81
|
+
appData: appDataKeccak256,
|
|
82
|
+
partiallyFillable
|
|
83
|
+
};
|
|
84
|
+
const { afterSlippage } = getQuoteAmountsAndCosts({
|
|
85
|
+
orderParams,
|
|
86
|
+
slippagePercentBps: slippageBps,
|
|
87
|
+
partnerFeeBps: getPartnerFeeBps(partnerFee),
|
|
88
|
+
sellDecimals: sellTokenDecimals,
|
|
89
|
+
buyDecimals: buyTokenDecimals
|
|
90
|
+
});
|
|
91
|
+
return {
|
|
92
|
+
sellToken,
|
|
93
|
+
buyToken,
|
|
94
|
+
sellAmount: afterSlippage.sellAmount.toString(),
|
|
95
|
+
buyAmount: afterSlippage.buyAmount.toString(),
|
|
96
|
+
validTo,
|
|
97
|
+
kind,
|
|
98
|
+
partiallyFillable,
|
|
99
|
+
appData: appDataKeccak256,
|
|
100
|
+
receiver,
|
|
101
|
+
feeAmount: "0",
|
|
102
|
+
sellTokenBalance: SellTokenSource.ERC20,
|
|
103
|
+
buyTokenBalance: BuyTokenDestination.ERC20
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// src/postSellNativeCurrencyOrder.ts
|
|
108
|
+
import { getGlobalAdapter as getGlobalAdapter2 } from "@cowprotocol/sdk-common";
|
|
109
|
+
import { SigningScheme as SigningScheme2 } from "@cowprotocol/sdk-order-book";
|
|
110
|
+
|
|
111
|
+
// src/calculateUniqueOrderId.ts
|
|
112
|
+
import { OrderSigningUtils } from "@cowprotocol/sdk-order-signing";
|
|
113
|
+
import {
|
|
114
|
+
BARN_ETH_FLOW_ADDRESS,
|
|
115
|
+
ETH_FLOW_ADDRESS,
|
|
116
|
+
MAX_VALID_TO_EPOCH,
|
|
117
|
+
WRAPPED_NATIVE_CURRENCIES
|
|
118
|
+
} from "@cowprotocol/sdk-config";
|
|
119
|
+
async function calculateUniqueOrderId(chainId, order, checkEthFlowOrderExists, env) {
|
|
120
|
+
const { orderDigest, orderId } = await OrderSigningUtils.generateOrderId(
|
|
121
|
+
chainId,
|
|
122
|
+
{
|
|
123
|
+
...order,
|
|
124
|
+
sellTokenBalance: order.sellTokenBalance,
|
|
125
|
+
buyTokenBalance: order.buyTokenBalance,
|
|
126
|
+
validTo: MAX_VALID_TO_EPOCH,
|
|
127
|
+
sellToken: WRAPPED_NATIVE_CURRENCIES[chainId].address
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
owner: env === "staging" ? BARN_ETH_FLOW_ADDRESS : ETH_FLOW_ADDRESS
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
if (checkEthFlowOrderExists && await checkEthFlowOrderExists(orderId, orderDigest)) {
|
|
134
|
+
console.error("ETH FLOW", "[calculateUniqueOrderId] \u274C Collision detected: " + orderId, {
|
|
135
|
+
sellAmount: order.sellAmount,
|
|
136
|
+
fee: order.feeAmount
|
|
137
|
+
});
|
|
138
|
+
return calculateUniqueOrderId(chainId, adjustAmounts(order), checkEthFlowOrderExists);
|
|
139
|
+
}
|
|
140
|
+
return orderId;
|
|
141
|
+
}
|
|
142
|
+
function adjustAmounts(order) {
|
|
143
|
+
const buyAmount = BigInt(order.buyAmount);
|
|
144
|
+
return { ...order, buyAmount: (buyAmount - BigInt(1)).toString() };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// src/getEthFlowTransaction.ts
|
|
148
|
+
import { BARN_ETH_FLOW_ADDRESS as BARN_ETH_FLOW_ADDRESS2, ETH_FLOW_ADDRESS as ETH_FLOW_ADDRESS2 } from "@cowprotocol/sdk-config";
|
|
149
|
+
|
|
150
|
+
// src/utils/misc.ts
|
|
151
|
+
import { ETH_ADDRESS, WRAPPED_NATIVE_CURRENCIES as WRAPPED_NATIVE_CURRENCIES2 } from "@cowprotocol/sdk-config";
|
|
152
|
+
function swapParamsToLimitOrderParams(params, quoteResponse) {
|
|
153
|
+
return {
|
|
154
|
+
...params,
|
|
155
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
156
|
+
quoteId: quoteResponse.id,
|
|
157
|
+
sellAmount: quoteResponse.quote.sellAmount,
|
|
158
|
+
buyAmount: quoteResponse.quote.buyAmount
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function getIsEthFlowOrder(params) {
|
|
162
|
+
return params.sellToken.toLowerCase() === ETH_ADDRESS.toLowerCase();
|
|
163
|
+
}
|
|
164
|
+
function calculateGasMargin(value) {
|
|
165
|
+
return value + value * BigInt(20) / BigInt(100);
|
|
166
|
+
}
|
|
167
|
+
function mapQuoteAmountsAndCosts(value, mapper) {
|
|
168
|
+
const {
|
|
169
|
+
costs: { networkFee, partnerFee }
|
|
170
|
+
} = value;
|
|
171
|
+
function serializeAmounts(value2) {
|
|
172
|
+
return {
|
|
173
|
+
sellAmount: mapper(value2.sellAmount),
|
|
174
|
+
buyAmount: mapper(value2.buyAmount)
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
...value,
|
|
179
|
+
costs: {
|
|
180
|
+
...value.costs,
|
|
181
|
+
networkFee: {
|
|
182
|
+
...networkFee,
|
|
183
|
+
amountInSellCurrency: mapper(networkFee.amountInSellCurrency),
|
|
184
|
+
amountInBuyCurrency: mapper(networkFee.amountInBuyCurrency)
|
|
185
|
+
},
|
|
186
|
+
partnerFee: {
|
|
187
|
+
...partnerFee,
|
|
188
|
+
amount: mapper(partnerFee.amount)
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
beforeNetworkCosts: serializeAmounts(value.beforeNetworkCosts),
|
|
192
|
+
afterNetworkCosts: serializeAmounts(value.afterNetworkCosts),
|
|
193
|
+
afterPartnerFees: serializeAmounts(value.afterPartnerFees),
|
|
194
|
+
afterSlippage: serializeAmounts(value.afterSlippage)
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
function getTradeParametersAfterQuote({
|
|
198
|
+
quoteParameters,
|
|
199
|
+
sellToken
|
|
200
|
+
}) {
|
|
201
|
+
return { ...quoteParameters, sellToken };
|
|
202
|
+
}
|
|
203
|
+
function adjustEthFlowOrderParams(chainId, params) {
|
|
204
|
+
return {
|
|
205
|
+
...params,
|
|
206
|
+
sellToken: WRAPPED_NATIVE_CURRENCIES2[chainId].address,
|
|
207
|
+
slippageBps: typeof params.slippageBps === "number" ? params.slippageBps : ETH_FLOW_DEFAULT_SLIPPAGE_BPS[chainId]
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// src/getEthFlowTransaction.ts
|
|
212
|
+
import {
|
|
213
|
+
getGlobalAdapter,
|
|
214
|
+
ContractFactory
|
|
215
|
+
} from "@cowprotocol/sdk-common";
|
|
216
|
+
async function getEthFlowTransaction(appDataKeccak256, _params, chainId, additionalParams = {}, paramSigner) {
|
|
217
|
+
const signer = paramSigner ? getGlobalAdapter().createSigner(paramSigner) : getGlobalAdapter().signer;
|
|
218
|
+
const { networkCostsAmount = "0", checkEthFlowOrderExists } = additionalParams;
|
|
219
|
+
const from = await signer.getAddress();
|
|
220
|
+
const params = {
|
|
221
|
+
..._params,
|
|
222
|
+
...adjustEthFlowOrderParams(chainId, _params)
|
|
223
|
+
};
|
|
224
|
+
const { quoteId } = params;
|
|
225
|
+
const contract = getEthFlowContract(signer, params.env);
|
|
226
|
+
const orderToSign = getOrderToSign({ from, networkCostsAmount }, params, appDataKeccak256);
|
|
227
|
+
const orderId = await calculateUniqueOrderId(chainId, orderToSign, checkEthFlowOrderExists, params.env);
|
|
228
|
+
const ethOrderParams = {
|
|
229
|
+
buyToken: orderToSign.buyToken,
|
|
230
|
+
receiver: orderToSign.receiver,
|
|
231
|
+
sellAmount: orderToSign.sellAmount,
|
|
232
|
+
buyAmount: orderToSign.buyAmount,
|
|
233
|
+
feeAmount: orderToSign.feeAmount,
|
|
234
|
+
partiallyFillable: orderToSign.partiallyFillable,
|
|
235
|
+
quoteId,
|
|
236
|
+
appData: appDataKeccak256,
|
|
237
|
+
validTo: orderToSign.validTo.toString()
|
|
238
|
+
};
|
|
239
|
+
const estimatedGas = await contract.estimateGas.createOrder?.(ethOrderParams, { value: orderToSign.sellAmount }).catch((error) => {
|
|
240
|
+
console.error(error);
|
|
241
|
+
return GAS_LIMIT_DEFAULT;
|
|
242
|
+
}) || GAS_LIMIT_DEFAULT;
|
|
243
|
+
const data = contract.interface.encodeFunctionData("createOrder", [ethOrderParams]);
|
|
244
|
+
return {
|
|
245
|
+
orderId,
|
|
246
|
+
orderToSign,
|
|
247
|
+
transaction: {
|
|
248
|
+
data,
|
|
249
|
+
gasLimit: "0x" + calculateGasMargin(estimatedGas).toString(16),
|
|
250
|
+
to: contract.address,
|
|
251
|
+
value: "0x" + BigInt(orderToSign.sellAmount).toString(16)
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
function getEthFlowContract(signer, env) {
|
|
256
|
+
const address = env === "staging" ? BARN_ETH_FLOW_ADDRESS2 : ETH_FLOW_ADDRESS2;
|
|
257
|
+
return ContractFactory.createEthFlowContract(address, signer);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// src/postSellNativeCurrencyOrder.ts
|
|
261
|
+
import { log } from "@cowprotocol/sdk-common";
|
|
262
|
+
async function postSellNativeCurrencyOrder(orderBookApi, appData, _params, additionalParams = {}, paramSigner) {
|
|
263
|
+
const signer = paramSigner ? getGlobalAdapter2().createSigner(paramSigner) : getGlobalAdapter2().signer;
|
|
264
|
+
const { appDataKeccak256, fullAppData } = appData;
|
|
265
|
+
const { orderId, transaction, orderToSign } = await getEthFlowTransaction(
|
|
266
|
+
appDataKeccak256,
|
|
267
|
+
_params,
|
|
268
|
+
orderBookApi.context.chainId,
|
|
269
|
+
additionalParams,
|
|
270
|
+
signer
|
|
271
|
+
);
|
|
272
|
+
log("Uploading app-data");
|
|
273
|
+
await orderBookApi.uploadAppData(appDataKeccak256, fullAppData);
|
|
274
|
+
log("Sending on-chain order transaction");
|
|
275
|
+
const txReceipt = await signer.sendTransaction(transaction);
|
|
276
|
+
log(`On-chain order transaction sent, txHash: ${txReceipt.hash}, order: ${orderId}`);
|
|
277
|
+
return { txHash: txReceipt.hash, orderId, orderToSign, signature: "", signingScheme: SigningScheme2.EIP1271 };
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// src/postCoWProtocolTrade.ts
|
|
281
|
+
import { CowError, getGlobalAdapter as getGlobalAdapter4, log as log2 } from "@cowprotocol/sdk-common";
|
|
282
|
+
|
|
283
|
+
// src/appDataUtils.ts
|
|
284
|
+
import {
|
|
285
|
+
MetadataApi,
|
|
286
|
+
stringifyDeterministic
|
|
287
|
+
} from "@cowprotocol/sdk-app-data";
|
|
288
|
+
import { getGlobalAdapter as getGlobalAdapter3 } from "@cowprotocol/sdk-common";
|
|
289
|
+
import deepmerge from "deepmerge";
|
|
290
|
+
async function buildAppData({ slippageBps, appCode, orderClass: orderClassName, partnerFee }, advancedParams) {
|
|
291
|
+
const quoteParams = { slippageBips: slippageBps };
|
|
292
|
+
const orderClass = { orderClass: orderClassName };
|
|
293
|
+
const metadataApiSdk = new MetadataApi(getGlobalAdapter3());
|
|
294
|
+
const doc = await metadataApiSdk.generateAppDataDoc(
|
|
295
|
+
deepmerge(
|
|
296
|
+
{
|
|
297
|
+
appCode,
|
|
298
|
+
metadata: {
|
|
299
|
+
quote: quoteParams,
|
|
300
|
+
orderClass,
|
|
301
|
+
partnerFee
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
advancedParams || {}
|
|
305
|
+
)
|
|
306
|
+
);
|
|
307
|
+
const { fullAppData, appDataKeccak256 } = await generateAppDataFromDoc(doc);
|
|
308
|
+
return { doc, fullAppData, appDataKeccak256 };
|
|
309
|
+
}
|
|
310
|
+
async function generateAppDataFromDoc(doc) {
|
|
311
|
+
const adapter = getGlobalAdapter3();
|
|
312
|
+
const fullAppData = await stringifyDeterministic(doc);
|
|
313
|
+
const appDataKeccak256 = adapter.utils.keccak256(adapter.utils.toUtf8Bytes(fullAppData));
|
|
314
|
+
return { fullAppData, appDataKeccak256 };
|
|
315
|
+
}
|
|
316
|
+
async function mergeAppDataDoc(_doc, appDataOverride) {
|
|
317
|
+
const doc = appDataOverride.metadata?.hooks ? {
|
|
318
|
+
..._doc,
|
|
319
|
+
metadata: {
|
|
320
|
+
..._doc.metadata,
|
|
321
|
+
hooks: {}
|
|
322
|
+
}
|
|
323
|
+
} : _doc;
|
|
324
|
+
const appData = appDataOverride ? deepmerge(doc, appDataOverride) : doc;
|
|
325
|
+
const { fullAppData, appDataKeccak256 } = await generateAppDataFromDoc(appData);
|
|
326
|
+
return {
|
|
327
|
+
fullAppData,
|
|
328
|
+
appDataKeccak256,
|
|
329
|
+
doc: appData
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// ../sdk/package.json
|
|
334
|
+
var package_default = {
|
|
335
|
+
name: "@cowprotocol/cow-sdk",
|
|
336
|
+
version: "7.0.0-monorepo.0",
|
|
337
|
+
license: "(MIT OR Apache-2.0)",
|
|
338
|
+
description: "CowProtocol SDK - Complete umbrella package for CoW Protocol interactions",
|
|
339
|
+
main: "./dist/index.js",
|
|
340
|
+
module: "./dist/index.mjs",
|
|
341
|
+
types: "./dist/index.d.ts",
|
|
342
|
+
exports: {
|
|
343
|
+
".": {
|
|
344
|
+
types: "./dist/index.d.ts",
|
|
345
|
+
import: "./dist/index.mjs",
|
|
346
|
+
require: "./dist/index.js"
|
|
347
|
+
}
|
|
348
|
+
},
|
|
349
|
+
sideEffects: false,
|
|
350
|
+
files: [
|
|
351
|
+
"dist/**"
|
|
352
|
+
],
|
|
353
|
+
scripts: {
|
|
354
|
+
build: "tsup src/index.ts --format esm,cjs --dts --treeshake",
|
|
355
|
+
postbuild: "cp package.json dist && pnpm copy-md-files",
|
|
356
|
+
"copy-md-files": 'npx cpx "**/*.md" dist',
|
|
357
|
+
lint: "eslint src/**/*.ts",
|
|
358
|
+
typecheck: "tsc --noEmit",
|
|
359
|
+
clean: "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
|
|
360
|
+
},
|
|
361
|
+
devDependencies: {
|
|
362
|
+
"@cow-sdk/typescript-config": "workspace:*",
|
|
363
|
+
"@types/node": "^20.17.31",
|
|
364
|
+
jest: "^29.7.0",
|
|
365
|
+
"ts-node": "^10.8.2",
|
|
366
|
+
tsup: "^7.2.0",
|
|
367
|
+
typescript: "^5.2.2"
|
|
368
|
+
},
|
|
369
|
+
dependencies: {
|
|
370
|
+
"@cowprotocol/sdk-app-data": "workspace:*",
|
|
371
|
+
"@cowprotocol/sdk-bridging": "workspace:*",
|
|
372
|
+
"@cowprotocol/sdk-common": "workspace:*",
|
|
373
|
+
"@cowprotocol/sdk-composable": "workspace:*",
|
|
374
|
+
"@cowprotocol/sdk-config": "workspace:*",
|
|
375
|
+
"@cowprotocol/sdk-contracts-ts": "workspace:*",
|
|
376
|
+
"@cowprotocol/sdk-cow-shed": "workspace:*",
|
|
377
|
+
"@cowprotocol/sdk-order-book": "workspace:*",
|
|
378
|
+
"@cowprotocol/sdk-order-signing": "workspace:*",
|
|
379
|
+
"@cowprotocol/sdk-subgraph": "workspace:*",
|
|
380
|
+
"@cowprotocol/sdk-trading": "workspace:*",
|
|
381
|
+
"@cowprotocol/sdk-weiroll": "workspace:*"
|
|
382
|
+
},
|
|
383
|
+
peerDependencies: {
|
|
384
|
+
"@openzeppelin/merkle-tree": "^1.x",
|
|
385
|
+
"cross-fetch": "^3.x",
|
|
386
|
+
"ipfs-only-hash": "^4.x",
|
|
387
|
+
multiformats: "^9.x"
|
|
388
|
+
},
|
|
389
|
+
peerDependenciesMeta: {
|
|
390
|
+
"cross-fetch": {
|
|
391
|
+
optional: false
|
|
392
|
+
},
|
|
393
|
+
"ipfs-only-hash": {
|
|
394
|
+
optional: true
|
|
395
|
+
},
|
|
396
|
+
multiformats: {
|
|
397
|
+
optional: true
|
|
398
|
+
},
|
|
399
|
+
"@openzeppelin/merkle-tree": {
|
|
400
|
+
optional: true
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
keywords: [
|
|
404
|
+
"cow",
|
|
405
|
+
"cow-protocol",
|
|
406
|
+
"sdk",
|
|
407
|
+
"crypto",
|
|
408
|
+
"typescript",
|
|
409
|
+
"subgraph"
|
|
410
|
+
],
|
|
411
|
+
repository: {
|
|
412
|
+
type: "git",
|
|
413
|
+
url: "https://github.com/cowprotocol/cow-sdk.git",
|
|
414
|
+
directory: "packages/sdk"
|
|
415
|
+
},
|
|
416
|
+
bugs: {
|
|
417
|
+
url: "https://github.com/cowprotocol/cow-sdk/issues"
|
|
418
|
+
},
|
|
419
|
+
homepage: "https://github.com/cowprotocol/cow-sdk#readme"
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
// src/postCoWProtocolTrade.ts
|
|
423
|
+
async function postCoWProtocolTrade(orderBookApi, paramAppData, params, additionalParams = {}, paramSigner) {
|
|
424
|
+
const adapter = getGlobalAdapter4();
|
|
425
|
+
const appData = await createAppDataWithUTM(paramAppData);
|
|
426
|
+
const signer = paramSigner ? adapter.createSigner(paramSigner) : adapter.signer;
|
|
427
|
+
const { networkCostsAmount = "0", signingScheme: _signingScheme = SigningScheme3.EIP712 } = additionalParams;
|
|
428
|
+
if (getIsEthFlowOrder(params)) {
|
|
429
|
+
const quoteId2 = params.quoteId;
|
|
430
|
+
if (typeof quoteId2 === "number") {
|
|
431
|
+
return postSellNativeCurrencyOrder(orderBookApi, appData, { ...params, quoteId: quoteId2 }, additionalParams, paramSigner);
|
|
432
|
+
} else {
|
|
433
|
+
throw new Error("quoteId is required for EthFlow orders");
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
const { quoteId = null, owner } = params;
|
|
437
|
+
const { appDataKeccak256, fullAppData } = appData;
|
|
438
|
+
const chainId = orderBookApi.context.chainId;
|
|
439
|
+
const from = owner || await signer.getAddress();
|
|
440
|
+
const orderToSign = getOrderToSign({ from, networkCostsAmount }, params, appData.appDataKeccak256);
|
|
441
|
+
log2("Signing order...");
|
|
442
|
+
const { signature, signingScheme } = await (async () => {
|
|
443
|
+
if (_signingScheme === SigningScheme3.PRESIGN) {
|
|
444
|
+
return { signature: from, signingScheme: SigningScheme3.PRESIGN };
|
|
445
|
+
} else {
|
|
446
|
+
const signingResult = await OrderSigningUtils2.signOrder(orderToSign, chainId, signer);
|
|
447
|
+
return { signature: signingResult.signature, signingScheme: SIGN_SCHEME_MAP[signingResult.signingScheme] };
|
|
448
|
+
}
|
|
449
|
+
})();
|
|
450
|
+
const orderBody = {
|
|
451
|
+
...orderToSign,
|
|
452
|
+
from,
|
|
453
|
+
signature,
|
|
454
|
+
signingScheme,
|
|
455
|
+
quoteId,
|
|
456
|
+
appData: fullAppData,
|
|
457
|
+
appDataHash: appDataKeccak256
|
|
458
|
+
};
|
|
459
|
+
log2("Posting order...");
|
|
460
|
+
const orderId = await orderBookApi.sendOrder(orderBody);
|
|
461
|
+
log2(`Order created, id: ${orderId}`);
|
|
462
|
+
return { orderId, signature, signingScheme, orderToSign };
|
|
463
|
+
}
|
|
464
|
+
async function createAppDataWithUTM(originalAppData) {
|
|
465
|
+
if (disableUtm) {
|
|
466
|
+
return originalAppData;
|
|
467
|
+
}
|
|
468
|
+
let parsedData;
|
|
469
|
+
try {
|
|
470
|
+
parsedData = JSON.parse(originalAppData.fullAppData);
|
|
471
|
+
} catch {
|
|
472
|
+
try {
|
|
473
|
+
const unescapedData = originalAppData.fullAppData.replace(/\\"/g, '"');
|
|
474
|
+
parsedData = JSON.parse(unescapedData);
|
|
475
|
+
} catch (error) {
|
|
476
|
+
throw new CowError(`Failed to parse app data: ${originalAppData.fullAppData}: ${error}`);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
const orderSpecificUtmContent = parsedData.utm?.utmContent;
|
|
480
|
+
const defaultUtmContent = "\u{1F42E} moo-ving to defi \u{1F42E}";
|
|
481
|
+
const utmContent2 = orderSpecificUtmContent || utmContent || defaultUtmContent;
|
|
482
|
+
const defaultUtm = {
|
|
483
|
+
utmCampaign: "developer-cohort",
|
|
484
|
+
utmContent: utmContent2,
|
|
485
|
+
utmMedium: `cow-sdk@${package_default.version}`,
|
|
486
|
+
utmSource: "cowmunity",
|
|
487
|
+
utmTerm: "js"
|
|
488
|
+
};
|
|
489
|
+
parsedData.utm = defaultUtm;
|
|
490
|
+
const { fullAppData, appDataKeccak256 } = await generateAppDataFromDoc(parsedData);
|
|
491
|
+
return {
|
|
492
|
+
...originalAppData,
|
|
493
|
+
fullAppData,
|
|
494
|
+
appDataKeccak256
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// src/getQuote.ts
|
|
499
|
+
import { getGlobalAdapter as getGlobalAdapter5, log as log3 } from "@cowprotocol/sdk-common";
|
|
500
|
+
import {
|
|
501
|
+
getQuoteAmountsAndCosts as getQuoteAmountsAndCosts2,
|
|
502
|
+
OrderBookApi as OrderBookApi3,
|
|
503
|
+
OrderQuoteSideKindBuy,
|
|
504
|
+
OrderQuoteSideKindSell,
|
|
505
|
+
PriceQuality,
|
|
506
|
+
SigningScheme as SigningScheme4
|
|
507
|
+
} from "@cowprotocol/sdk-order-book";
|
|
508
|
+
|
|
509
|
+
// src/getOrderTypedData.ts
|
|
510
|
+
import { ORDER_TYPE_FIELDS } from "@cowprotocol/sdk-contracts-ts";
|
|
511
|
+
|
|
512
|
+
// src/types.ts
|
|
513
|
+
var ORDER_PRIMARY_TYPE = "Order";
|
|
514
|
+
|
|
515
|
+
// src/getOrderTypedData.ts
|
|
516
|
+
import { OrderSigningUtils as OrderSigningUtils3 } from "@cowprotocol/sdk-order-signing";
|
|
517
|
+
var EIP712DomainTypes = [
|
|
518
|
+
{ name: "name", type: "string" },
|
|
519
|
+
{ name: "version", type: "string" },
|
|
520
|
+
{ name: "chainId", type: "uint256" },
|
|
521
|
+
{ name: "verifyingContract", type: "address" }
|
|
522
|
+
];
|
|
523
|
+
async function getOrderTypedData(chainId, orderToSign) {
|
|
524
|
+
const domain = await OrderSigningUtils3.getDomain(chainId);
|
|
525
|
+
return {
|
|
526
|
+
domain,
|
|
527
|
+
primaryType: ORDER_PRIMARY_TYPE,
|
|
528
|
+
types: {
|
|
529
|
+
[ORDER_PRIMARY_TYPE]: ORDER_TYPE_FIELDS,
|
|
530
|
+
EIP712Domain: EIP712DomainTypes
|
|
531
|
+
},
|
|
532
|
+
message: orderToSign
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// src/suggestSlippageBps.ts
|
|
537
|
+
import { percentageToBps } from "@cowprotocol/sdk-common";
|
|
538
|
+
import { getQuoteAmountsWithCosts } from "@cowprotocol/sdk-order-book";
|
|
539
|
+
|
|
540
|
+
// src/utils/slippage.ts
|
|
541
|
+
var SCALE = 10n ** 6n;
|
|
542
|
+
function getSlippagePercent(params) {
|
|
543
|
+
const { sellAmountBeforeNetworkCosts, sellAmountAfterNetworkCosts, slippage, isSell } = params;
|
|
544
|
+
const sellAmount = isSell ? sellAmountAfterNetworkCosts : sellAmountBeforeNetworkCosts;
|
|
545
|
+
if (sellAmount <= 0n) {
|
|
546
|
+
throw new Error("sellAmount must be greater than 0: " + sellAmount);
|
|
547
|
+
}
|
|
548
|
+
if (slippage < 0n) {
|
|
549
|
+
throw new Error("slippage must be non-negative: " + slippage);
|
|
550
|
+
}
|
|
551
|
+
if (isSell) {
|
|
552
|
+
const percentageInScale = SCALE - SCALE * (sellAmount - slippage) / sellAmount;
|
|
553
|
+
return Number(percentageInScale) / Number(SCALE);
|
|
554
|
+
} else {
|
|
555
|
+
const percentageInScale = SCALE * (sellAmount + slippage) / sellAmount - SCALE;
|
|
556
|
+
return Number(percentageInScale) / Number(SCALE);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// src/suggestSlippageFromFee.ts
|
|
561
|
+
import { applyPercentage } from "@cowprotocol/sdk-common";
|
|
562
|
+
function suggestSlippageFromFee(params) {
|
|
563
|
+
const { feeAmount, multiplyingFactorPercent } = params;
|
|
564
|
+
if (feeAmount < 0n) {
|
|
565
|
+
throw new Error("Fee amount must be non-negative: " + feeAmount);
|
|
566
|
+
}
|
|
567
|
+
if (multiplyingFactorPercent < 0) {
|
|
568
|
+
throw new Error("multiplyingFactorPercent must be non-negative: " + multiplyingFactorPercent);
|
|
569
|
+
}
|
|
570
|
+
return applyPercentage(feeAmount, multiplyingFactorPercent);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// src/suggestSlippageFromVolume.ts
|
|
574
|
+
import { applyPercentage as applyPercentage2 } from "@cowprotocol/sdk-common";
|
|
575
|
+
function suggestSlippageFromVolume(params) {
|
|
576
|
+
const { sellAmountBeforeNetworkCosts, sellAmountAfterNetworkCosts, isSell, slippagePercent } = params;
|
|
577
|
+
const sellAmount = isSell ? sellAmountAfterNetworkCosts : sellAmountBeforeNetworkCosts;
|
|
578
|
+
if (sellAmount <= 0n) {
|
|
579
|
+
throw new Error("sellAmount must be greater than 0: " + sellAmount);
|
|
580
|
+
}
|
|
581
|
+
if (slippagePercent < 0) {
|
|
582
|
+
throw new Error("slippagePercent must be non-negative: " + slippagePercent);
|
|
583
|
+
}
|
|
584
|
+
return applyPercentage2(sellAmount, slippagePercent);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// src/suggestSlippageBps.ts
|
|
588
|
+
var MIN_SLIPPAGE_BPS = 50;
|
|
589
|
+
var MAX_SLIPPAGE_BPS = 1e4;
|
|
590
|
+
var SLIPPAGE_FEE_MULTIPLIER_PERCENT = 50;
|
|
591
|
+
var SLIPPAGE_VOLUME_MULTIPLIER_PERCENT = 0.5;
|
|
592
|
+
function suggestSlippageBps(params) {
|
|
593
|
+
const { quote, tradeParameters } = params;
|
|
594
|
+
const { sellTokenDecimals, buyTokenDecimals } = tradeParameters;
|
|
595
|
+
const { isSell, sellAmountBeforeNetworkCosts, sellAmountAfterNetworkCosts } = getQuoteAmountsWithCosts({
|
|
596
|
+
sellDecimals: sellTokenDecimals,
|
|
597
|
+
buyDecimals: buyTokenDecimals,
|
|
598
|
+
orderParams: quote.quote
|
|
599
|
+
});
|
|
600
|
+
const { feeAmount: feeAmountString } = quote.quote;
|
|
601
|
+
const feeAmount = BigInt(feeAmountString);
|
|
602
|
+
const slippageBpsFromFee = suggestSlippageFromFee({
|
|
603
|
+
feeAmount,
|
|
604
|
+
multiplyingFactorPercent: SLIPPAGE_FEE_MULTIPLIER_PERCENT
|
|
605
|
+
});
|
|
606
|
+
const slippageBpsFromVolume = suggestSlippageFromVolume({
|
|
607
|
+
isSell,
|
|
608
|
+
sellAmountBeforeNetworkCosts,
|
|
609
|
+
sellAmountAfterNetworkCosts,
|
|
610
|
+
slippagePercent: SLIPPAGE_VOLUME_MULTIPLIER_PERCENT
|
|
611
|
+
});
|
|
612
|
+
const totalSlippageBps = slippageBpsFromFee + slippageBpsFromVolume;
|
|
613
|
+
const slippagePercent = getSlippagePercent({
|
|
614
|
+
isSell,
|
|
615
|
+
sellAmountBeforeNetworkCosts,
|
|
616
|
+
sellAmountAfterNetworkCosts,
|
|
617
|
+
slippage: totalSlippageBps
|
|
618
|
+
});
|
|
619
|
+
const slippageBps = percentageToBps(slippagePercent);
|
|
620
|
+
return Math.max(Math.min(slippageBps, MAX_SLIPPAGE_BPS), MIN_SLIPPAGE_BPS);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// src/getQuote.ts
|
|
624
|
+
var ETH_FLOW_AUX_QUOTE_PARAMS = {
|
|
625
|
+
signingScheme: SigningScheme4.EIP1271,
|
|
626
|
+
onchainOrder: true,
|
|
627
|
+
// Ethflow orders are subsidized in the backend.
|
|
628
|
+
// This means we can assume the verification gas costs are zero for the quote/fee estimation
|
|
629
|
+
verificationGasLimit: 0
|
|
630
|
+
};
|
|
631
|
+
async function getQuoteRaw(_tradeParameters, trader, advancedSettings, _orderBookApi) {
|
|
632
|
+
const { appCode, chainId, account: from } = trader;
|
|
633
|
+
const isEthFlow = getIsEthFlowOrder(_tradeParameters);
|
|
634
|
+
const tradeParameters = isEthFlow ? {
|
|
635
|
+
..._tradeParameters,
|
|
636
|
+
...adjustEthFlowOrderParams(chainId, _tradeParameters)
|
|
637
|
+
} : _tradeParameters;
|
|
638
|
+
const {
|
|
639
|
+
sellToken,
|
|
640
|
+
buyToken,
|
|
641
|
+
amount,
|
|
642
|
+
kind,
|
|
643
|
+
partnerFee,
|
|
644
|
+
validFor = DEFAULT_QUOTE_VALIDITY,
|
|
645
|
+
slippageBps,
|
|
646
|
+
env = "prod"
|
|
647
|
+
} = tradeParameters;
|
|
648
|
+
log3(
|
|
649
|
+
`getQuote for: Swap ${amount} ${sellToken} for ${buyToken} on chain ${chainId} with ${slippageBps !== void 0 ? `${slippageBps} BPS` : "AUTO"} slippage`
|
|
650
|
+
);
|
|
651
|
+
const orderBookApi = _orderBookApi || new OrderBookApi3({ chainId, env });
|
|
652
|
+
const receiver = tradeParameters.receiver || from;
|
|
653
|
+
const isSell = kind === "sell";
|
|
654
|
+
log3("Building app data...");
|
|
655
|
+
const slippageBpsOrDefault = slippageBps ?? DEFAULT_SLIPPAGE_BPS;
|
|
656
|
+
const buildAppDataParams = {
|
|
657
|
+
slippageBps: slippageBpsOrDefault,
|
|
658
|
+
orderClass: "market",
|
|
659
|
+
appCode,
|
|
660
|
+
partnerFee
|
|
661
|
+
};
|
|
662
|
+
const appDataInfo = await buildAppData(buildAppDataParams, advancedSettings?.appData);
|
|
663
|
+
const { appDataKeccak256, fullAppData } = appDataInfo;
|
|
664
|
+
log3(`App data: appDataKeccak256=${appDataKeccak256} fullAppData=${fullAppData}`);
|
|
665
|
+
const quoteRequest = {
|
|
666
|
+
from,
|
|
667
|
+
sellToken,
|
|
668
|
+
buyToken,
|
|
669
|
+
receiver,
|
|
670
|
+
validFor,
|
|
671
|
+
appData: fullAppData,
|
|
672
|
+
appDataHash: appDataKeccak256,
|
|
673
|
+
priceQuality: PriceQuality.OPTIMAL,
|
|
674
|
+
// Do not change this parameter because we rely on the fact that quote has id
|
|
675
|
+
signingScheme: SigningScheme4.EIP712,
|
|
676
|
+
...isEthFlow ? ETH_FLOW_AUX_QUOTE_PARAMS : {},
|
|
677
|
+
...isSell ? { kind: OrderQuoteSideKindSell.SELL, sellAmountBeforeFee: amount } : { kind: OrderQuoteSideKindBuy.BUY, buyAmountAfterFee: amount },
|
|
678
|
+
...advancedSettings?.quoteRequest
|
|
679
|
+
};
|
|
680
|
+
log3("Getting quote...");
|
|
681
|
+
const quote = await orderBookApi.getQuote(quoteRequest);
|
|
682
|
+
const suggestedSlippageBps = suggestSlippageBps({ quote, tradeParameters, trader, advancedSettings });
|
|
683
|
+
if (slippageBps === void 0) {
|
|
684
|
+
if (suggestedSlippageBps > DEFAULT_SLIPPAGE_BPS) {
|
|
685
|
+
log3(
|
|
686
|
+
`Suggested slippage is greater than ${DEFAULT_SLIPPAGE_BPS} BPS (default), using the suggested slippage (${suggestedSlippageBps} BPS)`
|
|
687
|
+
);
|
|
688
|
+
const newAppDataInfo = await buildAppData(
|
|
689
|
+
{
|
|
690
|
+
...buildAppDataParams,
|
|
691
|
+
slippageBps: suggestedSlippageBps
|
|
692
|
+
},
|
|
693
|
+
advancedSettings?.appData
|
|
694
|
+
);
|
|
695
|
+
log3(
|
|
696
|
+
`App data with new suggested slippage: appDataKeccak256=${newAppDataInfo.appDataKeccak256} fullAppData=${newAppDataInfo.fullAppData}`
|
|
697
|
+
);
|
|
698
|
+
return {
|
|
699
|
+
slippageBps: suggestedSlippageBps,
|
|
700
|
+
suggestedSlippageBps,
|
|
701
|
+
tradeParameters: { ..._tradeParameters, slippageBps: suggestedSlippageBps },
|
|
702
|
+
appDataInfo: newAppDataInfo,
|
|
703
|
+
// We reuse the quote, because the slippage has no fundamental impact on the quote
|
|
704
|
+
quote,
|
|
705
|
+
orderBookApi
|
|
706
|
+
};
|
|
707
|
+
} else {
|
|
708
|
+
log3(
|
|
709
|
+
`Suggested slippage is only ${suggestedSlippageBps} BPS. Using the default slippage (${DEFAULT_SLIPPAGE_BPS} BPS)`
|
|
710
|
+
);
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
return {
|
|
714
|
+
quote,
|
|
715
|
+
appDataInfo,
|
|
716
|
+
orderBookApi,
|
|
717
|
+
tradeParameters,
|
|
718
|
+
slippageBps: slippageBpsOrDefault,
|
|
719
|
+
suggestedSlippageBps
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
async function getQuote(_tradeParameters, trader, advancedSettings, _orderBookApi) {
|
|
723
|
+
const { quote, orderBookApi, tradeParameters, slippageBps, suggestedSlippageBps, appDataInfo } = await getQuoteRaw(
|
|
724
|
+
_tradeParameters,
|
|
725
|
+
trader,
|
|
726
|
+
advancedSettings,
|
|
727
|
+
_orderBookApi
|
|
728
|
+
);
|
|
729
|
+
const { partnerFee, sellTokenDecimals, buyTokenDecimals } = tradeParameters;
|
|
730
|
+
const { chainId, account: from } = trader;
|
|
731
|
+
const amountsAndCosts = getQuoteAmountsAndCosts2({
|
|
732
|
+
orderParams: quote.quote,
|
|
733
|
+
slippagePercentBps: slippageBps,
|
|
734
|
+
partnerFeeBps: getPartnerFeeBps(partnerFee),
|
|
735
|
+
sellDecimals: sellTokenDecimals,
|
|
736
|
+
buyDecimals: buyTokenDecimals
|
|
737
|
+
});
|
|
738
|
+
const orderToSign = getOrderToSign(
|
|
739
|
+
{ from, networkCostsAmount: quote.quote.feeAmount },
|
|
740
|
+
swapParamsToLimitOrderParams(tradeParameters, quote),
|
|
741
|
+
appDataInfo.appDataKeccak256
|
|
742
|
+
);
|
|
743
|
+
const orderTypedData = await getOrderTypedData(chainId, orderToSign);
|
|
744
|
+
return {
|
|
745
|
+
result: {
|
|
746
|
+
tradeParameters,
|
|
747
|
+
suggestedSlippageBps,
|
|
748
|
+
amountsAndCosts,
|
|
749
|
+
orderToSign,
|
|
750
|
+
quoteResponse: quote,
|
|
751
|
+
appDataInfo,
|
|
752
|
+
orderTypedData
|
|
753
|
+
},
|
|
754
|
+
orderBookApi
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
async function getTrader(swapParameters) {
|
|
758
|
+
const signer = getGlobalAdapter5().signerOrNull();
|
|
759
|
+
const account = swapParameters.owner || await signer?.getAddress();
|
|
760
|
+
return {
|
|
761
|
+
chainId: swapParameters.chainId,
|
|
762
|
+
appCode: swapParameters.appCode,
|
|
763
|
+
account
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
async function getQuoteWithSigner(swapParameters, advancedSettings, orderBookApi) {
|
|
767
|
+
const adapter = getGlobalAdapter5();
|
|
768
|
+
const signer = swapParameters.signer ? adapter.createSigner(swapParameters.signer) : adapter.signer;
|
|
769
|
+
const trader = await getTrader(swapParameters);
|
|
770
|
+
const result = await getQuote(swapParameters, trader, advancedSettings, orderBookApi);
|
|
771
|
+
return {
|
|
772
|
+
result: {
|
|
773
|
+
...result.result,
|
|
774
|
+
signer
|
|
775
|
+
},
|
|
776
|
+
orderBookApi: result.orderBookApi
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// src/postSwapOrder.ts
|
|
781
|
+
async function postSwapOrder(params, advancedSettings, orderBookApi) {
|
|
782
|
+
return postSwapOrderFromQuote(await getQuoteWithSigner(params, advancedSettings, orderBookApi), advancedSettings);
|
|
783
|
+
}
|
|
784
|
+
async function postSwapOrderFromQuote({
|
|
785
|
+
orderBookApi,
|
|
786
|
+
result: { signer, appDataInfo: _appDataInfo, quoteResponse, tradeParameters }
|
|
787
|
+
}, advancedSettings) {
|
|
788
|
+
const params = swapParamsToLimitOrderParams(tradeParameters, quoteResponse);
|
|
789
|
+
const appDataOverride = advancedSettings?.appData;
|
|
790
|
+
const appDataInfo = appDataOverride ? await mergeAppDataDoc(_appDataInfo.doc, appDataOverride) : _appDataInfo;
|
|
791
|
+
const appDataSlippageOverride = appDataOverride?.metadata?.quote?.slippageBips;
|
|
792
|
+
const partnerFeeOverride = appDataOverride?.metadata?.partnerFee;
|
|
793
|
+
if (typeof appDataSlippageOverride !== "undefined") {
|
|
794
|
+
params.slippageBps = appDataSlippageOverride;
|
|
795
|
+
}
|
|
796
|
+
if (partnerFeeOverride) {
|
|
797
|
+
params.partnerFee = partnerFeeOverride;
|
|
798
|
+
}
|
|
799
|
+
if (advancedSettings?.quoteRequest) {
|
|
800
|
+
const { receiver, validTo, sellToken, buyToken } = advancedSettings.quoteRequest;
|
|
801
|
+
if (receiver)
|
|
802
|
+
params.receiver = receiver;
|
|
803
|
+
if (validTo)
|
|
804
|
+
params.validTo = validTo;
|
|
805
|
+
if (sellToken)
|
|
806
|
+
params.sellToken = sellToken;
|
|
807
|
+
if (buyToken)
|
|
808
|
+
params.buyToken = buyToken;
|
|
809
|
+
}
|
|
810
|
+
return postCoWProtocolTrade(
|
|
811
|
+
orderBookApi,
|
|
812
|
+
appDataInfo,
|
|
813
|
+
params,
|
|
814
|
+
{
|
|
815
|
+
signingScheme: advancedSettings?.quoteRequest?.signingScheme,
|
|
816
|
+
networkCostsAmount: quoteResponse.quote.feeAmount,
|
|
817
|
+
...advancedSettings?.additionalParams
|
|
818
|
+
},
|
|
819
|
+
signer
|
|
820
|
+
);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// src/postLimitOrder.ts
|
|
824
|
+
import { OrderBookApi as OrderBookApi4 } from "@cowprotocol/sdk-order-book";
|
|
825
|
+
import { log as log4 } from "@cowprotocol/sdk-common";
|
|
826
|
+
async function postLimitOrder(params, advancedSettings, _orderBookApi) {
|
|
827
|
+
const appDataSlippage = advancedSettings?.appData?.metadata?.quote?.slippageBips;
|
|
828
|
+
const partnerFeeOverride = advancedSettings?.appData?.metadata?.partnerFee;
|
|
829
|
+
if (typeof appDataSlippage !== "undefined") {
|
|
830
|
+
params.slippageBps = appDataSlippage;
|
|
831
|
+
}
|
|
832
|
+
if (partnerFeeOverride) {
|
|
833
|
+
params.partnerFee = partnerFeeOverride;
|
|
834
|
+
}
|
|
835
|
+
if (!params.slippageBps) {
|
|
836
|
+
params.slippageBps = 0;
|
|
837
|
+
}
|
|
838
|
+
if (!params.env) {
|
|
839
|
+
params.env = "prod";
|
|
840
|
+
}
|
|
841
|
+
const { appCode, chainId, sellToken, buyToken, sellAmount, buyAmount, partnerFee } = params;
|
|
842
|
+
log4(`Limit order ${sellAmount} ${sellToken} for ${buyAmount} ${buyToken} on chain ${chainId}`);
|
|
843
|
+
const orderBookApi = _orderBookApi || new OrderBookApi4({ chainId, env: params.env });
|
|
844
|
+
log4("Building app data...");
|
|
845
|
+
const appDataInfo = await buildAppData(
|
|
846
|
+
{
|
|
847
|
+
slippageBps: params.slippageBps,
|
|
848
|
+
orderClass: "limit",
|
|
849
|
+
appCode,
|
|
850
|
+
partnerFee
|
|
851
|
+
},
|
|
852
|
+
advancedSettings?.appData
|
|
853
|
+
);
|
|
854
|
+
return postCoWProtocolTrade(orderBookApi, appDataInfo, params, advancedSettings?.additionalParams, params.signer);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
// src/getPreSignTransaction.ts
|
|
858
|
+
import { COW_PROTOCOL_SETTLEMENT_CONTRACT_ADDRESS } from "@cowprotocol/sdk-config";
|
|
859
|
+
import { ContractFactory as ContractFactory2 } from "@cowprotocol/sdk-common";
|
|
860
|
+
async function getPreSignTransaction(signer, chainId, account, orderId) {
|
|
861
|
+
const contract = ContractFactory2.createSettlementContract(account, signer);
|
|
862
|
+
const settlementContractAddress = COW_PROTOCOL_SETTLEMENT_CONTRACT_ADDRESS[chainId];
|
|
863
|
+
const preSignatureCall = contract.interface.encodeFunctionData("setPreSignature", [orderId, true]);
|
|
864
|
+
const gas = await contract.estimateGas.setPreSignature?.(orderId, true).catch(() => GAS_LIMIT_DEFAULT) || GAS_LIMIT_DEFAULT;
|
|
865
|
+
return {
|
|
866
|
+
data: preSignatureCall,
|
|
867
|
+
gasLimit: "0x" + calculateGasMargin(gas).toString(16),
|
|
868
|
+
to: settlementContractAddress,
|
|
869
|
+
// Para onde enviar a transação
|
|
870
|
+
value: "0"
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
// src/tradingSdk.ts
|
|
875
|
+
import { enableLogging, getGlobalAdapter as getGlobalAdapter6 } from "@cowprotocol/sdk-common";
|
|
876
|
+
import { setGlobalAdapter } from "@cowprotocol/sdk-common";
|
|
877
|
+
var utmContent = void 0;
|
|
878
|
+
var disableUtm = false;
|
|
879
|
+
var TradingSdk = class {
|
|
880
|
+
constructor(traderParams = {}, options = {}, adapter) {
|
|
881
|
+
this.traderParams = traderParams;
|
|
882
|
+
this.options = options;
|
|
883
|
+
if (options.enableLogging !== void 0) {
|
|
884
|
+
enableLogging(options.enableLogging);
|
|
885
|
+
}
|
|
886
|
+
if (adapter) {
|
|
887
|
+
setGlobalAdapter(adapter);
|
|
888
|
+
}
|
|
889
|
+
utmContent = options.utmContent;
|
|
890
|
+
disableUtm = options.disableUtm || false;
|
|
891
|
+
}
|
|
892
|
+
setTraderParams(params) {
|
|
893
|
+
this.traderParams = { ...this.traderParams, ...params };
|
|
894
|
+
return this;
|
|
895
|
+
}
|
|
896
|
+
async getQuote(params, advancedSettings) {
|
|
897
|
+
const quoteResults = await getQuoteWithSigner(this.mergeParams(params), advancedSettings, this.options.orderBookApi);
|
|
898
|
+
return {
|
|
899
|
+
quoteResults: quoteResults.result,
|
|
900
|
+
postSwapOrderFromQuote: (advancedSettings2) => postSwapOrderFromQuote(
|
|
901
|
+
{
|
|
902
|
+
...quoteResults,
|
|
903
|
+
result: {
|
|
904
|
+
...quoteResults.result,
|
|
905
|
+
tradeParameters: getTradeParametersAfterQuote({
|
|
906
|
+
quoteParameters: quoteResults.result.tradeParameters,
|
|
907
|
+
sellToken: params.sellToken
|
|
908
|
+
})
|
|
909
|
+
}
|
|
910
|
+
},
|
|
911
|
+
advancedSettings2
|
|
912
|
+
)
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
async getQuoteResults(params, advancedSettings) {
|
|
916
|
+
return getQuoteWithSigner(this.mergeParams(params), advancedSettings, this.options.orderBookApi);
|
|
917
|
+
}
|
|
918
|
+
async postSwapOrder(params, advancedSettings) {
|
|
919
|
+
return postSwapOrder(this.mergeParams(params), advancedSettings, this.options.orderBookApi);
|
|
920
|
+
}
|
|
921
|
+
async postLimitOrder(params, advancedSettings) {
|
|
922
|
+
return postLimitOrder(this.mergeParams(params), advancedSettings, this.options.orderBookApi);
|
|
923
|
+
}
|
|
924
|
+
/**
|
|
925
|
+
* Posts a sell order for native currency (e.g., ETH) using the EthFlow contract.
|
|
926
|
+
* This method creates an on-chain transaction for selling native tokens.
|
|
927
|
+
*
|
|
928
|
+
* @param params - The trade parameters including token addresses and amounts
|
|
929
|
+
* @param advancedSettings - Optional advanced settings for the swap
|
|
930
|
+
* @returns Promise resolving to the order posting result with transaction hash and order ID
|
|
931
|
+
*
|
|
932
|
+
* @example
|
|
933
|
+
* ```typescript
|
|
934
|
+
* const parameters: TradeParameters = {
|
|
935
|
+
* kind: OrderKind.SELL,
|
|
936
|
+
* sellToken: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // Native ETH
|
|
937
|
+
* sellTokenDecimals: 18,
|
|
938
|
+
* buyToken: '0x0625afb445c3b6b7b929342a04a22599fd5dbb59',
|
|
939
|
+
* buyTokenDecimals: 18,
|
|
940
|
+
* amount: '100000000000000000', // 0.1 ETH
|
|
941
|
+
* }
|
|
942
|
+
*
|
|
943
|
+
* const { orderId, txHash } = await sdk.postSellNativeCurrencyOrder(parameters)
|
|
944
|
+
* ```
|
|
945
|
+
*/
|
|
946
|
+
async postSellNativeCurrencyOrder(params, advancedSettings) {
|
|
947
|
+
const quoteResults = await getQuoteWithSigner(this.mergeParams(params), advancedSettings, this.options.orderBookApi);
|
|
948
|
+
const { tradeParameters, quoteResponse } = quoteResults.result;
|
|
949
|
+
return postSellNativeCurrencyOrder(
|
|
950
|
+
quoteResults.orderBookApi,
|
|
951
|
+
quoteResults.result.appDataInfo,
|
|
952
|
+
// Quote response always has an id
|
|
953
|
+
swapParamsToLimitOrderParams(
|
|
954
|
+
getTradeParametersAfterQuote({ quoteParameters: tradeParameters, sellToken: params.sellToken }),
|
|
955
|
+
quoteResponse
|
|
956
|
+
),
|
|
957
|
+
advancedSettings?.additionalParams,
|
|
958
|
+
quoteResults.result.signer
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
async getPreSignTransaction(params) {
|
|
962
|
+
const adapter = getGlobalAdapter6();
|
|
963
|
+
const traderParams = this.mergeParams(params);
|
|
964
|
+
const signer = traderParams.signer ? adapter.createSigner(traderParams.signer) : adapter.signer;
|
|
965
|
+
return getPreSignTransaction(signer, traderParams.chainId, params.account, params.orderId);
|
|
966
|
+
}
|
|
967
|
+
mergeParams(params) {
|
|
968
|
+
const { chainId, signer, appCode, env } = params;
|
|
969
|
+
const traderParams = {
|
|
970
|
+
chainId: chainId || this.traderParams.chainId,
|
|
971
|
+
signer: signer || this.traderParams.signer,
|
|
972
|
+
appCode: appCode || this.traderParams.appCode,
|
|
973
|
+
env: env || this.traderParams.env
|
|
974
|
+
};
|
|
975
|
+
assertTraderParams(traderParams);
|
|
976
|
+
return {
|
|
977
|
+
...params,
|
|
978
|
+
...traderParams
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
};
|
|
982
|
+
function assertTraderParams(params) {
|
|
983
|
+
if (!isTraderParameters(params)) {
|
|
984
|
+
throw new Error("Missing trader parameters: " + getMissingTraderParams(params).join(", "));
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
function getMissingTraderParams(params) {
|
|
988
|
+
const missingParams = [];
|
|
989
|
+
if (!params.chainId)
|
|
990
|
+
missingParams.push("chainId");
|
|
991
|
+
if (!params.signer)
|
|
992
|
+
missingParams.push("signer");
|
|
993
|
+
if (!params.appCode)
|
|
994
|
+
missingParams.push("appCode");
|
|
995
|
+
return missingParams;
|
|
996
|
+
}
|
|
997
|
+
function isTraderParameters(params) {
|
|
998
|
+
return getMissingTraderParams(params).length === 0;
|
|
999
|
+
}
|
|
1000
|
+
export {
|
|
1001
|
+
ORDER_PRIMARY_TYPE,
|
|
1002
|
+
TradingSdk,
|
|
1003
|
+
buildAppData,
|
|
1004
|
+
calculateUniqueOrderId,
|
|
1005
|
+
disableUtm,
|
|
1006
|
+
generateAppDataFromDoc,
|
|
1007
|
+
getEthFlowContract,
|
|
1008
|
+
getEthFlowTransaction,
|
|
1009
|
+
getOrderToSign,
|
|
1010
|
+
getPartnerFeeBps,
|
|
1011
|
+
getPreSignTransaction,
|
|
1012
|
+
getQuote,
|
|
1013
|
+
getQuoteWithSigner,
|
|
1014
|
+
getTradeParametersAfterQuote,
|
|
1015
|
+
mapQuoteAmountsAndCosts,
|
|
1016
|
+
mergeAppDataDoc,
|
|
1017
|
+
postCoWProtocolTrade,
|
|
1018
|
+
postLimitOrder,
|
|
1019
|
+
postSellNativeCurrencyOrder,
|
|
1020
|
+
postSwapOrder,
|
|
1021
|
+
postSwapOrderFromQuote,
|
|
1022
|
+
suggestSlippageBps,
|
|
1023
|
+
swapParamsToLimitOrderParams,
|
|
1024
|
+
utmContent
|
|
1025
|
+
};
|