@d8x/perpetuals-sdk 0.0.1
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/LICENSE +21 -0
- package/README.md +17 -0
- package/abi/ERC20.json +288 -0
- package/abi/IPerpetualManager.json +4674 -0
- package/abi/LimitOrderBook.json +865 -0
- package/abi/LimitOrderBookFactory.json +166 -0
- package/config/defaultConfig.json +9 -0
- package/config/oldConfig.json +9 -0
- package/dist/accountTrade.d.ts +54 -0
- package/dist/accountTrade.js +164 -0
- package/dist/brokerTool.d.ts +41 -0
- package/dist/brokerTool.js +129 -0
- package/dist/d8XMath.d.ts +71 -0
- package/dist/d8XMath.js +162 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +49 -0
- package/dist/liquiditatorTool.d.ts +14 -0
- package/dist/liquiditatorTool.js +21 -0
- package/dist/liquidityProviderTool.d.ts +39 -0
- package/dist/liquidityProviderTool.js +100 -0
- package/dist/marketData.d.ts +39 -0
- package/dist/marketData.js +160 -0
- package/dist/nodeSDKTypes.d.ts +130 -0
- package/dist/nodeSDKTypes.js +52 -0
- package/dist/orderReferrerTool.d.ts +14 -0
- package/dist/orderReferrerTool.js +21 -0
- package/dist/perpetualDataHandler.d.ts +85 -0
- package/dist/perpetualDataHandler.js +474 -0
- package/dist/utils.d.ts +37 -0
- package/dist/utils.js +84 -0
- package/dist/writeAccessHandler.d.ts +36 -0
- package/dist/writeAccessHandler.js +95 -0
- package/module.d.ts +1 -0
- package/package.json +63 -0
- package/src/accountTrade.ts +217 -0
- package/src/brokerTool.ts +155 -0
- package/src/d8XMath.ts +176 -0
- package/src/index.ts +32 -0
- package/src/liquiditatorTool.ts +21 -0
- package/src/liquidityProviderTool.ts +100 -0
- package/src/marketData.ts +149 -0
- package/src/nodeSDKTypes.ts +158 -0
- package/src/orderReferrerTool.ts +17 -0
- package/src/perpetualDataHandler.ts +549 -0
- package/src/utils.ts +83 -0
- package/src/writeAccessHandler.ts +83 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const ethers_1 = require("ethers");
|
|
16
|
+
const perpetualDataHandler_1 = __importDefault(require("./perpetualDataHandler"));
|
|
17
|
+
const nodeSDKTypes_1 = require("./nodeSDKTypes");
|
|
18
|
+
const utils_1 = require("./utils");
|
|
19
|
+
const d8XMath_1 = require("./d8XMath");
|
|
20
|
+
/**
|
|
21
|
+
* This is a parent class for the classes that require
|
|
22
|
+
* write access to the contracts.
|
|
23
|
+
* This class requires a private key and executes smart-contract interaction that
|
|
24
|
+
* require gas-payments.
|
|
25
|
+
*/
|
|
26
|
+
class WriteAccessHandler extends perpetualDataHandler_1.default {
|
|
27
|
+
/**
|
|
28
|
+
* Constructor
|
|
29
|
+
* @param config configuration
|
|
30
|
+
* @param privateKey private key of account that trades
|
|
31
|
+
*/
|
|
32
|
+
constructor(config, privateKey) {
|
|
33
|
+
super(config);
|
|
34
|
+
this.traderAddr = "";
|
|
35
|
+
this.signer = null;
|
|
36
|
+
this.gasLimit = 15000000;
|
|
37
|
+
this.chainId = 0;
|
|
38
|
+
this.privateKey = privateKey;
|
|
39
|
+
if (config.gasLimit != undefined) {
|
|
40
|
+
this.gasLimit = config.gasLimit;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Initialize the AccountTrade-Class with this function
|
|
45
|
+
* to create instance of D8X perpetual contract and gather information
|
|
46
|
+
* about perpetual currencies
|
|
47
|
+
*/
|
|
48
|
+
createProxyInstance() {
|
|
49
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
50
|
+
this.provider = new ethers_1.ethers.providers.JsonRpcProvider(this.nodeURL);
|
|
51
|
+
const wallet = new ethers_1.ethers.Wallet(this.privateKey);
|
|
52
|
+
this.signer = wallet.connect(this.provider);
|
|
53
|
+
yield this.initContractsAndData(this.signer);
|
|
54
|
+
this.traderAddr = wallet.address;
|
|
55
|
+
this.chainId = (yield this.provider.getNetwork()).chainId;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Set allowance for ar margin token (e.g., MATIC, ETH, USDC)
|
|
60
|
+
* @param symbol token in 'long-form' such as MATIC, symbol also fine (ETH-USD-MATIC)
|
|
61
|
+
* @param amount optional, amount to approve if not 'infinity'
|
|
62
|
+
* @returns transaction hash
|
|
63
|
+
*/
|
|
64
|
+
setAllowance(symbol, amount = undefined) {
|
|
65
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
66
|
+
//extract margin-currency name
|
|
67
|
+
let symbolarr = symbol.split("-");
|
|
68
|
+
symbol = symbol.length == 3 ? symbolarr[2] : symbolarr[0];
|
|
69
|
+
//transform into bytes4 currencies (without the space): "BTC", "USD", "MATC"
|
|
70
|
+
symbol = (0, utils_1.to4Chars)(symbol);
|
|
71
|
+
symbol = symbol.replace(/\0/g, "");
|
|
72
|
+
let marginTokenAddr = this.symbolToTokenAddrMap.get(symbol);
|
|
73
|
+
if (marginTokenAddr == undefined || this.signer == null) {
|
|
74
|
+
throw Error("No margin token or signer defined, call createProxyInstance");
|
|
75
|
+
}
|
|
76
|
+
let amountDec18;
|
|
77
|
+
if (amount == undefined) {
|
|
78
|
+
amountDec18 = nodeSDKTypes_1.MAX_UINT_256;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
amountDec18 = (0, d8XMath_1.floatToDec18)(amount);
|
|
82
|
+
}
|
|
83
|
+
return WriteAccessHandler._setAllowance(marginTokenAddr, this.proxyAddr, this.signer, amountDec18);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
static _setAllowance(tokenAddr, proxyAddr, signer, amount) {
|
|
87
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
88
|
+
const marginToken = new ethers_1.ethers.Contract(tokenAddr, nodeSDKTypes_1.ERC20_ABI, signer);
|
|
89
|
+
let tx = yield marginToken.approve(proxyAddr, amount);
|
|
90
|
+
yield tx.wait();
|
|
91
|
+
return tx.hash;
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exports.default = WriteAccessHandler;
|
package/module.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
declare module "@d8x/perpetuals-sdk";
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"dependencies": {
|
|
3
|
+
"@babel/core": "^7.20.2",
|
|
4
|
+
"@types/jest": "^29.2.3",
|
|
5
|
+
"@types/node": "^18.11.9",
|
|
6
|
+
"babel-jest": "^29.3.1",
|
|
7
|
+
"ethers": "^5.7.2",
|
|
8
|
+
"jest": "^29.3.1",
|
|
9
|
+
"ts-jest": "^29.0.3",
|
|
10
|
+
"ts-node": "^10.9.1",
|
|
11
|
+
"typescript": "^4.9.3"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"build:doc": "jsdoc2md --files ./src/accountTrade.ts --configure ./jsdoc2md.json > ./doc/accountTrade.md",
|
|
16
|
+
"test": "jest",
|
|
17
|
+
"coverage": "nyc -r lcov -e .ts -x \"*.test.ts\" npm run test"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
|
21
|
+
"@babel/plugin-proposal-object-rest-spread": "^7.20.2",
|
|
22
|
+
"@babel/preset-env": "^7.20.2",
|
|
23
|
+
"@babel/preset-typescript": "^7.18.6",
|
|
24
|
+
"jsdoc-babel": "^0.5.0",
|
|
25
|
+
"jsdoc-to-markdown": "^7.1.1",
|
|
26
|
+
"json2md": "^2.0.0"
|
|
27
|
+
},
|
|
28
|
+
"name": "@d8x/perpetuals-sdk",
|
|
29
|
+
"description": "Node TypeScript SDK for D8X Perpetual Futures",
|
|
30
|
+
"version": "0.0.1",
|
|
31
|
+
"main": "./dist/index.js",
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"directories": {
|
|
34
|
+
"test": "test"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"module.d.ts",
|
|
38
|
+
"src/*.ts",
|
|
39
|
+
"src/*.json",
|
|
40
|
+
"src/*.md",
|
|
41
|
+
"dist/*.ts",
|
|
42
|
+
"dist/*.js",
|
|
43
|
+
"abi/*.json",
|
|
44
|
+
"config/*.json"
|
|
45
|
+
],
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "git+https://github.com/D8-X/d8x-futures-node-sdk.git"
|
|
49
|
+
},
|
|
50
|
+
"keywords": [
|
|
51
|
+
"d8x",
|
|
52
|
+
"perpetuals",
|
|
53
|
+
"node",
|
|
54
|
+
"sdk",
|
|
55
|
+
"api"
|
|
56
|
+
],
|
|
57
|
+
"author": "d8x",
|
|
58
|
+
"license": "UNLICENSED",
|
|
59
|
+
"bugs": {
|
|
60
|
+
"url": "https://github.com/D8-X/d8x-futures-node-sdk/issues"
|
|
61
|
+
},
|
|
62
|
+
"homepage": "https://github.com/D8-X/d8x-futures-node-sdk#readme"
|
|
63
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { BigNumber, BigNumberish, ethers, Wallet } from "ethers";
|
|
2
|
+
import {
|
|
3
|
+
BUY_SIDE,
|
|
4
|
+
NodeSDKConfig,
|
|
5
|
+
Order,
|
|
6
|
+
SmartContractOrder,
|
|
7
|
+
SELL_SIDE,
|
|
8
|
+
ZERO_ADDRESS,
|
|
9
|
+
MAX_64x64,
|
|
10
|
+
MAX_UINT_256,
|
|
11
|
+
ORDER_MAX_DURATION_SEC,
|
|
12
|
+
ORDER_TYPE_LIMIT,
|
|
13
|
+
ORDER_TYPE_MARKET,
|
|
14
|
+
ORDER_TYPE_STOP_MARKET,
|
|
15
|
+
ORDER_TYPE_STOP_LIMIT,
|
|
16
|
+
MASK_CLOSE_ONLY,
|
|
17
|
+
MASK_LIMIT_ORDER,
|
|
18
|
+
MASK_MARKET_ORDER,
|
|
19
|
+
MASK_STOP_ORDER,
|
|
20
|
+
MASK_KEEP_POS_LEVERAGE,
|
|
21
|
+
COLLATERAL_CURRENCY_BASE,
|
|
22
|
+
COLLATERAL_CURRENCY_QUOTE,
|
|
23
|
+
ERC20_ABI,
|
|
24
|
+
PerpetualStaticInfo,
|
|
25
|
+
} from "./nodeSDKTypes";
|
|
26
|
+
import { floatToABK64x64, ABK64x64ToFloat, dec18ToFloat } from "./d8XMath";
|
|
27
|
+
import { combineFlags, to4Chars } from "./utils";
|
|
28
|
+
import WriteAccessHandler from "./writeAccessHandler";
|
|
29
|
+
//import { abi, rawEncode } from "ethereumjs-abi";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Account and Trade.
|
|
33
|
+
* This class requires a private key and executes smart-contract interaction that
|
|
34
|
+
* require gas-payments.
|
|
35
|
+
*/
|
|
36
|
+
export default class AccountTrade extends WriteAccessHandler {
|
|
37
|
+
/**
|
|
38
|
+
* Constructor
|
|
39
|
+
* @param {NodeSDKConfig} config Configuration object, see PerpetualDataHandler.readSDKConfig.
|
|
40
|
+
* @param {string} privateKey Private key of account that trades.
|
|
41
|
+
*/
|
|
42
|
+
public constructor(config: NodeSDKConfig, privateKey: string) {
|
|
43
|
+
super(config, privateKey);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Cancels an existing order on the exchange.
|
|
48
|
+
* @param {string} symbol Symbol of the form ETH-USD-MATIC.
|
|
49
|
+
* @param {string} orderId ID of the order to be cancelled.
|
|
50
|
+
*/
|
|
51
|
+
public async cancelOrder(symbol: string, orderId: string): Promise<string | undefined> {
|
|
52
|
+
if (this.proxyContract == null || this.signer == null) {
|
|
53
|
+
throw Error("no proxy contract or wallet initialized. Use createProxyInstance().");
|
|
54
|
+
}
|
|
55
|
+
let orderBookContract: ethers.Contract | null = null;
|
|
56
|
+
orderBookContract = this.getOrderBookContract(symbol);
|
|
57
|
+
|
|
58
|
+
return await this._cancelOrder(symbol, orderId, orderBookContract);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/*
|
|
62
|
+
TODO: -deposit (margin into account)
|
|
63
|
+
-withdraw margin withdraw(uint24 _iPerpetualId, int128 _fAmount)
|
|
64
|
+
|
|
65
|
+
*/
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Submits an order to the exchange.
|
|
69
|
+
* @param {Order} order Order struct.
|
|
70
|
+
* @returns {string} Transaction hash.
|
|
71
|
+
*/
|
|
72
|
+
public async order(order: Order): Promise<string | undefined> {
|
|
73
|
+
if (this.proxyContract == null || this.signer == null) {
|
|
74
|
+
throw Error("no proxy contract or wallet initialized. Use createProxyInstance().");
|
|
75
|
+
}
|
|
76
|
+
let orderBookContract: ethers.Contract | null = null;
|
|
77
|
+
if (order.type != ORDER_TYPE_MARKET) {
|
|
78
|
+
orderBookContract = this.getOrderBookContract(order.symbol);
|
|
79
|
+
}
|
|
80
|
+
return await this._order(
|
|
81
|
+
order,
|
|
82
|
+
this.traderAddr,
|
|
83
|
+
this.symbolToPerpStaticInfo,
|
|
84
|
+
this.proxyContract,
|
|
85
|
+
orderBookContract,
|
|
86
|
+
this.chainId,
|
|
87
|
+
this.signer,
|
|
88
|
+
this.gasLimit
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Static order function
|
|
94
|
+
* @param order order type (not SmartContractOrder but Order)
|
|
95
|
+
* @param traderAddr trader address
|
|
96
|
+
* @param symbolToPerpetualMap maps the symbol (MATIC-USD-MATIC)-type format to the perpetual id
|
|
97
|
+
* @param proxyContract contract instance of D8X perpetuals
|
|
98
|
+
* @param orderBookContract order book contract or null
|
|
99
|
+
* @param chainId chain Id of network
|
|
100
|
+
* @param signer instance of ethers wallet that can write
|
|
101
|
+
* @param gasLimit gas limit to be used for the trade
|
|
102
|
+
* @returns transaction hash
|
|
103
|
+
* @ignore
|
|
104
|
+
*/
|
|
105
|
+
public async _order(
|
|
106
|
+
order: Order,
|
|
107
|
+
traderAddr: string,
|
|
108
|
+
symbolToPerpetualMap: Map<string, PerpetualStaticInfo>,
|
|
109
|
+
proxyContract: ethers.Contract,
|
|
110
|
+
orderBookContract: ethers.Contract | null,
|
|
111
|
+
chainId: number,
|
|
112
|
+
signer: ethers.Wallet,
|
|
113
|
+
gasLimit: number
|
|
114
|
+
): Promise<string | undefined> {
|
|
115
|
+
let scOrder = AccountTrade.toSmartContractOrder(order, traderAddr, symbolToPerpetualMap);
|
|
116
|
+
// if we are here, we have a clean order
|
|
117
|
+
// decide whether to send order to Limit Order Book or AMM based on order type
|
|
118
|
+
let tx: ethers.Transaction;
|
|
119
|
+
if (order.type == ORDER_TYPE_MARKET) {
|
|
120
|
+
// send market order
|
|
121
|
+
tx = await proxyContract.trade(scOrder, { gasLimit: gasLimit });
|
|
122
|
+
} else {
|
|
123
|
+
// conditional order so the order is sent to the order-book
|
|
124
|
+
if (orderBookContract == null) {
|
|
125
|
+
throw Error("Order book contract not provided.");
|
|
126
|
+
}
|
|
127
|
+
let signature = await this._createSignature(scOrder, chainId, true, signer, proxyContract.address);
|
|
128
|
+
tx = await orderBookContract.createLimitOrder(scOrder, signature, { gasLimit: gasLimit });
|
|
129
|
+
}
|
|
130
|
+
return tx.hash;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
protected async _cancelOrder(
|
|
134
|
+
symbol: string,
|
|
135
|
+
orderId: string,
|
|
136
|
+
orderBookContract: ethers.Contract | null
|
|
137
|
+
): Promise<string | undefined> {
|
|
138
|
+
if (orderBookContract == null || this.signer == null) {
|
|
139
|
+
throw Error(`Order Book contract for symbol ${symbol} or signer not defined`);
|
|
140
|
+
}
|
|
141
|
+
let scOrder: SmartContractOrder = await orderBookContract.orderOfDigest(orderId);
|
|
142
|
+
let signature = await this._createSignature(scOrder, this.chainId, false, this.signer, this.proxyAddr);
|
|
143
|
+
return await orderBookContract.cancelLimitOrder(orderId, signature);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Creates a signature
|
|
148
|
+
* @param order smart-contract-type order
|
|
149
|
+
* @param chainId chainId of network
|
|
150
|
+
* @param isNewOrder true unless we cancel
|
|
151
|
+
* @param signer ethereum-type wallet
|
|
152
|
+
* @param proxyAddress address of the contract
|
|
153
|
+
* @returns signature as string
|
|
154
|
+
* @ignore
|
|
155
|
+
*/
|
|
156
|
+
private async _createSignature(
|
|
157
|
+
order: SmartContractOrder,
|
|
158
|
+
chainId: number,
|
|
159
|
+
isNewOrder: boolean,
|
|
160
|
+
signer: ethers.Wallet,
|
|
161
|
+
proxyAddress: string
|
|
162
|
+
): Promise<String> {
|
|
163
|
+
const NAME = "Perpetual Trade Manager";
|
|
164
|
+
const DOMAIN_TYPEHASH = ethers.utils.keccak256(
|
|
165
|
+
Buffer.from("EIP712Domain(string name,uint256 chainId,address verifyingContract)")
|
|
166
|
+
);
|
|
167
|
+
let abiCoder = ethers.utils.defaultAbiCoder;
|
|
168
|
+
let domainSeparator = ethers.utils.keccak256(
|
|
169
|
+
abiCoder.encode(
|
|
170
|
+
["bytes32", "bytes32", "uint256", "address"],
|
|
171
|
+
[DOMAIN_TYPEHASH, ethers.utils.keccak256(Buffer.from(NAME)), chainId, proxyAddress]
|
|
172
|
+
)
|
|
173
|
+
);
|
|
174
|
+
const TRADE_ORDER_TYPEHASH = ethers.utils.keccak256(
|
|
175
|
+
Buffer.from(
|
|
176
|
+
"Order(uint24 iPerpetualId,uint16 brokerFeeTbps,address traderAddr,address brokerAddr,int128 fAmount,int128 fLimitPrice,int128 fTriggerPrice,uint256 iDeadline,uint32 flags,int128 fLeverage,uint256 createdTimestamp)"
|
|
177
|
+
)
|
|
178
|
+
);
|
|
179
|
+
let structHash = ethers.utils.keccak256(
|
|
180
|
+
abiCoder.encode(
|
|
181
|
+
[
|
|
182
|
+
"bytes32",
|
|
183
|
+
"uint24",
|
|
184
|
+
"uint16",
|
|
185
|
+
"address",
|
|
186
|
+
"address",
|
|
187
|
+
"int128",
|
|
188
|
+
"int128",
|
|
189
|
+
"int128",
|
|
190
|
+
"uint256",
|
|
191
|
+
"uint32",
|
|
192
|
+
"int128",
|
|
193
|
+
"uint256",
|
|
194
|
+
],
|
|
195
|
+
[
|
|
196
|
+
TRADE_ORDER_TYPEHASH,
|
|
197
|
+
order.iPerpetualId,
|
|
198
|
+
order.brokerFeeTbps,
|
|
199
|
+
order.traderAddr,
|
|
200
|
+
order.brokerAddr,
|
|
201
|
+
order.fAmount,
|
|
202
|
+
order.fLimitPrice,
|
|
203
|
+
order.fTriggerPrice,
|
|
204
|
+
order.iDeadline,
|
|
205
|
+
order.flags,
|
|
206
|
+
order.fLeverage,
|
|
207
|
+
order.createdTimestamp,
|
|
208
|
+
]
|
|
209
|
+
)
|
|
210
|
+
);
|
|
211
|
+
let digest = ethers.utils.keccak256(
|
|
212
|
+
abiCoder.encode(["bytes32", "bytes32", "bool"], [domainSeparator, structHash, isNewOrder])
|
|
213
|
+
);
|
|
214
|
+
let digestBuffer = Buffer.from(digest.substring(2, digest.length), "hex");
|
|
215
|
+
return await signer.signMessage(digestBuffer);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import WriteAccessHandler from "./writeAccessHandler";
|
|
2
|
+
import { NodeSDKConfig, Order, ORDER_MAX_DURATION_SEC, ZERO_ADDRESS } from "./nodeSDKTypes";
|
|
3
|
+
import PerpetualDataHandler from "./perpetualDataHandler";
|
|
4
|
+
import { ABK64x64ToFloat } from "./d8XMath";
|
|
5
|
+
import { text } from "stream/consumers";
|
|
6
|
+
import { ethers } from "ethers";
|
|
7
|
+
import AccountTrade from "./accountTrade";
|
|
8
|
+
/**
|
|
9
|
+
* BrokerTool.
|
|
10
|
+
* Signature method for brokers
|
|
11
|
+
*/
|
|
12
|
+
export default class BrokerTool extends WriteAccessHandler {
|
|
13
|
+
/**
|
|
14
|
+
* Constructor
|
|
15
|
+
* @param config configuration
|
|
16
|
+
* @param privateKey private key of account that trades
|
|
17
|
+
*/
|
|
18
|
+
public constructor(config: NodeSDKConfig, privateKey: string) {
|
|
19
|
+
super(config, privateKey);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
*
|
|
24
|
+
* @param symbol symbol of the form "ETH-USD-MATIC" or just "MATIC"
|
|
25
|
+
* @returns broker lot size in collateral currency, e.g. in MATIC for symbol ETH-USD-MATIC or MATIC
|
|
26
|
+
*/
|
|
27
|
+
public async getLotSize(symbol: string): Promise<number | undefined> {
|
|
28
|
+
if (this.proxyContract == null) {
|
|
29
|
+
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
30
|
+
}
|
|
31
|
+
let poolId = PerpetualDataHandler._getPoolIdFromSymbol(symbol, this.poolStaticInfos);
|
|
32
|
+
let pool = await this.proxyContract.getLiquidityPool(poolId);
|
|
33
|
+
let lot = pool?.fBrokerCollateralLotSize;
|
|
34
|
+
if (lot != undefined) {
|
|
35
|
+
lot = ABK64x64ToFloat(pool.fBrokerCollateralLotSize);
|
|
36
|
+
}
|
|
37
|
+
return lot;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public async brokerDepositToDefaultFund(symbol: string, lots: number): Promise<ethers.providers.TransactionResponse> {
|
|
41
|
+
if (this.proxyContract == null || this.signer == null) {
|
|
42
|
+
throw Error("no proxy contract or wallet initialized. Use createProxyInstance().");
|
|
43
|
+
}
|
|
44
|
+
let poolId = PerpetualDataHandler._getPoolIdFromSymbol(symbol, this.poolStaticInfos);
|
|
45
|
+
let tx = await this.proxyContract.brokerDepositToDefaultFund(poolId, lots, { gasLimit: this.gasLimit });
|
|
46
|
+
return tx;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public async getFeeForBrokerVolume(symbol: string): Promise<number | undefined> {
|
|
50
|
+
if (this.proxyContract == null) {
|
|
51
|
+
throw Error("no proxy contract initialized.");
|
|
52
|
+
}
|
|
53
|
+
let poolId = PerpetualDataHandler._getPoolIdFromSymbol(symbol, this.poolStaticInfos);
|
|
54
|
+
let feeTbps = await this.proxyContract.getFeeForBrokerVolume(poolId, this.traderAddr);
|
|
55
|
+
return feeTbps / 100_000;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
*
|
|
60
|
+
* @param symbol symbol of the form "ETH-USD-MATIC" or just "MATIC"
|
|
61
|
+
* @returns number of lots deposited by broker
|
|
62
|
+
*/
|
|
63
|
+
public async getBrokerDesignation(symbol: string): Promise<number> {
|
|
64
|
+
if (this.proxyContract == null) {
|
|
65
|
+
throw Error("no proxy contract initialized.");
|
|
66
|
+
}
|
|
67
|
+
let poolId = PerpetualDataHandler._getPoolIdFromSymbol(symbol, this.poolStaticInfos);
|
|
68
|
+
let designation = await this.proxyContract.getBrokerDesignation(poolId, this.traderAddr);
|
|
69
|
+
return designation;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @param symbol symbol of the form "ETH-USD-MATIC" or just "MATIC"
|
|
74
|
+
* @param lots number of lots for which to get the fee. Defaults to this broker's current deposit if not specified
|
|
75
|
+
* @returns fee in decimals based on given number of lots
|
|
76
|
+
*/
|
|
77
|
+
public async getFeeForBrokerDesignation(symbol: string, newLots: number = 0): Promise<number | undefined> {
|
|
78
|
+
if (this.proxyContract == null) {
|
|
79
|
+
throw Error("no proxy contract initialized.");
|
|
80
|
+
}
|
|
81
|
+
if (newLots < 0) {
|
|
82
|
+
throw Error("new lots must be a positive number.");
|
|
83
|
+
}
|
|
84
|
+
let lots = await this.getBrokerDesignation(symbol);
|
|
85
|
+
lots += newLots;
|
|
86
|
+
let feeTbps = await this.proxyContract.getFeeForBrokerDesignation(lots);
|
|
87
|
+
return feeTbps / 100_000;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @param order order for which to determine the trading fee
|
|
92
|
+
* @param traderAddr address of the trader for whom to determine the fee, defaults to lowest tier
|
|
93
|
+
* @returns fee in decimals (1% is 0.01)
|
|
94
|
+
*/
|
|
95
|
+
public async determineExchangeFee(order: Order, traderAddr: string = ZERO_ADDRESS): Promise<number | undefined> {
|
|
96
|
+
if (this.proxyContract == null) {
|
|
97
|
+
throw Error("no proxy contract initialized.");
|
|
98
|
+
}
|
|
99
|
+
// broker does not need to enter address in the order if he's signed in
|
|
100
|
+
if (order.brokerAddr == undefined) {
|
|
101
|
+
if (this.signer == null) {
|
|
102
|
+
throw Error("no wallet initialized.");
|
|
103
|
+
}
|
|
104
|
+
order.brokerAddr = this.traderAddr;
|
|
105
|
+
}
|
|
106
|
+
let scOrder = AccountTrade.toSmartContractOrder(order, traderAddr, this.symbolToPerpStaticInfo);
|
|
107
|
+
let feeTbps = await this.proxyContract.determineExchangeFee(scOrder);
|
|
108
|
+
return feeTbps / 100_000;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// public async sign(traderAddr: string, deadline: number, fee: number): Promise<string> {
|
|
112
|
+
// /**
|
|
113
|
+
// * structHash = keccak256(
|
|
114
|
+
// abi.encode(
|
|
115
|
+
// TRADE_BROKER_TYPEHASH,
|
|
116
|
+
// _order.iPerpetualId,
|
|
117
|
+
// _order.brokerFeeTbps,
|
|
118
|
+
// _order.traderAddr,
|
|
119
|
+
// _order.iDeadline
|
|
120
|
+
// )
|
|
121
|
+
// );
|
|
122
|
+
// return structHash;
|
|
123
|
+
// */
|
|
124
|
+
// const NAME = "Perpetual Trade Manager";
|
|
125
|
+
// const DOMAIN_TYPEHASH = ethers.utils.keccak256(
|
|
126
|
+
// Buffer.from("EIP712Domain(string name,uint256 chainId,address verifyingContract)")
|
|
127
|
+
// );
|
|
128
|
+
// let abiCoder = ethers.utils.defaultAbiCoder;
|
|
129
|
+
// let domainSeparator = ethers.utils.keccak256(
|
|
130
|
+
// abiCoder.encode(
|
|
131
|
+
// ["bytes32", "bytes32", "uint256", "address"],
|
|
132
|
+
// [DOMAIN_TYPEHASH, ethers.utils.keccak256(Buffer.from(NAME)), chainId, proxyAddress]
|
|
133
|
+
// )
|
|
134
|
+
// );
|
|
135
|
+
// let digest = ethers.utils.keccak256(
|
|
136
|
+
// abiCoder.encode(["bytes32", "bytes32", "bool"], [domainSeparator, structHash, isNewOrder])
|
|
137
|
+
// );
|
|
138
|
+
// let digestBuffer = Buffer.from(digest.substring(2, digest.length), "hex");
|
|
139
|
+
// return await signer.signMessage(digestBuffer);
|
|
140
|
+
// }
|
|
141
|
+
|
|
142
|
+
/*
|
|
143
|
+
TODO:
|
|
144
|
+
- get lot size DONE
|
|
145
|
+
- purchase n lots:
|
|
146
|
+
brokerDepositToDefaultFund(symbol, amountLots) DONE
|
|
147
|
+
- fees:
|
|
148
|
+
getFeeForBrokerVolume DONE
|
|
149
|
+
determineExchangeFee(order) DONE
|
|
150
|
+
getBrokerDesignation DONE
|
|
151
|
+
getFeeForBrokerDesignation DONE
|
|
152
|
+
- get fee for trader and broker
|
|
153
|
+
- sign {trader address, deadline, broker fee}
|
|
154
|
+
*/
|
|
155
|
+
}
|