@gearbox-protocol/sdk 10.4.5 → 10.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/cjs/abi/310/generated.js +239 -25
- package/dist/cjs/dev/RevolverTransport.js +124 -83
- package/dist/cjs/sdk/market/MarketSuite.js +4 -0
- package/dist/cjs/sdk/market/credit/CreditFacadeV300Contract.js +4 -1
- package/dist/cjs/sdk/market/credit/CreditFacadeV310Contract.js +2 -2
- package/dist/cjs/sdk/market/loss-policy/AliasLossPolicyV310Contract.js +40 -0
- package/dist/cjs/sdk/market/loss-policy/LossPolicyContract.js +40 -0
- package/dist/cjs/sdk/market/loss-policy/createLossPolicy.js +48 -0
- package/dist/cjs/sdk/market/loss-policy/index.js +28 -0
- package/dist/cjs/sdk/market/loss-policy/types.js +16 -0
- package/dist/esm/abi/310/generated.js +238 -25
- package/dist/esm/dev/RevolverTransport.js +125 -83
- package/dist/esm/sdk/market/MarketSuite.js +6 -0
- package/dist/esm/sdk/market/credit/CreditFacadeV300Contract.js +4 -1
- package/dist/esm/sdk/market/credit/CreditFacadeV310Contract.js +2 -2
- package/dist/esm/sdk/market/loss-policy/AliasLossPolicyV310Contract.js +16 -0
- package/dist/esm/sdk/market/loss-policy/LossPolicyContract.js +16 -0
- package/dist/esm/sdk/market/loss-policy/createLossPolicy.js +24 -0
- package/dist/esm/sdk/market/loss-policy/index.js +4 -0
- package/dist/esm/sdk/market/loss-policy/types.js +0 -0
- package/dist/types/abi/310/generated.d.ts +292 -22
- package/dist/types/dev/RevolverTransport.d.ts +14 -6
- package/dist/types/sdk/market/MarketSuite.d.ts +2 -0
- package/dist/types/sdk/market/credit/CreditFacadeV300Contract.d.ts +2 -2
- package/dist/types/sdk/market/credit/CreditFacadeV310Contract.d.ts +2 -2
- package/dist/types/sdk/market/loss-policy/AliasLossPolicyV310Contract.d.ts +277 -0
- package/dist/types/sdk/market/loss-policy/LossPolicyContract.d.ts +133 -0
- package/dist/types/sdk/market/loss-policy/createLossPolicy.d.ts +16 -0
- package/dist/types/sdk/market/loss-policy/index.d.ts +4 -0
- package/dist/types/sdk/market/loss-policy/types.d.ts +5 -0
- package/dist/types/sdk/types/state-human.d.ts +1 -0
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BaseError,
|
|
3
|
+
CallExecutionError,
|
|
3
4
|
HttpRequestError,
|
|
4
5
|
http,
|
|
5
6
|
InvalidInputRpcError,
|
|
@@ -16,11 +17,11 @@ class NoAvailableTransportsError extends BaseError {
|
|
|
16
17
|
}
|
|
17
18
|
}
|
|
18
19
|
class RevolverTransport {
|
|
19
|
-
#transports;
|
|
20
|
-
#index = 0;
|
|
21
20
|
#config;
|
|
22
|
-
#rotating = false;
|
|
23
21
|
#requests = /* @__PURE__ */ new WeakMap();
|
|
22
|
+
#selector;
|
|
23
|
+
#rotating = false;
|
|
24
|
+
#isSingle;
|
|
24
25
|
overrides;
|
|
25
26
|
/**
|
|
26
27
|
* Create a new RevolverTransport
|
|
@@ -44,9 +45,9 @@ class RevolverTransport {
|
|
|
44
45
|
...config,
|
|
45
46
|
shouldRetry: config.shouldRetry ?? defaultShouldRetry
|
|
46
47
|
};
|
|
47
|
-
|
|
48
|
+
const transports = config.providers.map(
|
|
48
49
|
({ url, name, cooldown }) => ({
|
|
49
|
-
|
|
50
|
+
name,
|
|
50
51
|
transport: http(url, {
|
|
51
52
|
retryCount: config.retryCount,
|
|
52
53
|
retryDelay: config.retryDelay,
|
|
@@ -60,40 +61,45 @@ class RevolverTransport {
|
|
|
60
61
|
cooldown: cooldown ?? 0
|
|
61
62
|
})
|
|
62
63
|
);
|
|
63
|
-
if (
|
|
64
|
+
if (transports.length === 0) {
|
|
64
65
|
throw new NoAvailableTransportsError();
|
|
65
66
|
}
|
|
67
|
+
this.#isSingle = transports.length === 1;
|
|
68
|
+
const selectionStrategy = config.selectionStrategy ?? "simple";
|
|
69
|
+
this.#selector = selectionStrategy === "simple" ? new SimpleTransportSelector(transports, config.cooldown) : new OrderedTransportSelector(transports, config.cooldown);
|
|
66
70
|
}
|
|
67
71
|
get value() {
|
|
68
72
|
return {
|
|
69
73
|
rotate: (reason) => this.rotate(reason),
|
|
70
|
-
currentTransportName: () => this.
|
|
71
|
-
statuses: () => this.statuses()
|
|
74
|
+
currentTransportName: () => this.#selector.transportName(),
|
|
75
|
+
statuses: () => this.#selector.statuses()
|
|
72
76
|
};
|
|
73
77
|
}
|
|
74
78
|
request = async (r) => {
|
|
75
|
-
if (this.#
|
|
76
|
-
return this.#
|
|
79
|
+
if (this.#isSingle) {
|
|
80
|
+
return this.#selector.select()({
|
|
81
|
+
...this.overrides
|
|
82
|
+
}).request(r);
|
|
77
83
|
}
|
|
78
84
|
let error;
|
|
79
85
|
do {
|
|
80
86
|
try {
|
|
81
|
-
this.#requests.set(r, this.
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
);
|
|
87
|
+
this.#requests.set(r, this.#selector.transportName());
|
|
88
|
+
const transport = this.#selector.select()({
|
|
89
|
+
...this.overrides
|
|
90
|
+
});
|
|
91
|
+
const resp = await withRetry(() => transport.request(r), {
|
|
92
|
+
delay: this.#config.retryDelay,
|
|
93
|
+
retryCount: this.#config.retryCount,
|
|
94
|
+
shouldRetry: this.#config.shouldRetry
|
|
95
|
+
});
|
|
90
96
|
this.#requests.delete(r);
|
|
91
97
|
return resp;
|
|
92
98
|
} catch (e) {
|
|
93
99
|
error = error ?? e;
|
|
94
100
|
if (e instanceof RpcError || e instanceof HttpRequestError) {
|
|
95
101
|
const reqTransport = this.#requests.get(r);
|
|
96
|
-
if (reqTransport === this.
|
|
102
|
+
if (reqTransport === this.#selector.transportName()) {
|
|
97
103
|
await this.rotate(e);
|
|
98
104
|
} else {
|
|
99
105
|
this.#logger?.debug(
|
|
@@ -105,7 +111,7 @@ class RevolverTransport {
|
|
|
105
111
|
throw e;
|
|
106
112
|
}
|
|
107
113
|
}
|
|
108
|
-
} while (this.#
|
|
114
|
+
} while (this.#selector.canRotate());
|
|
109
115
|
this.#requests.delete(r);
|
|
110
116
|
throw new NoAvailableTransportsError(error);
|
|
111
117
|
};
|
|
@@ -127,82 +133,34 @@ class RevolverTransport {
|
|
|
127
133
|
* @returns true if rotation was successful
|
|
128
134
|
*/
|
|
129
135
|
async rotate(reason) {
|
|
130
|
-
if (this.#transports.length === 1) {
|
|
131
|
-
return true;
|
|
132
|
-
}
|
|
133
136
|
if (this.#rotating) {
|
|
134
137
|
this.#logger?.debug("already rotating, skipping");
|
|
135
|
-
return
|
|
138
|
+
return;
|
|
136
139
|
}
|
|
137
140
|
this.#rotating = true;
|
|
138
|
-
this.#
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
"rotating transport"
|
|
145
|
-
);
|
|
146
|
-
const oldTransportName = this.currentTransportName();
|
|
147
|
-
const now = Date.now();
|
|
148
|
-
this.#transports[this.#index].cooldown = now + (this.#config.cooldown ?? 6e4);
|
|
149
|
-
for (let i = 0; i < this.#transports.length - 1; i++) {
|
|
150
|
-
this.#index = (this.#index + 1) % this.#transports.length;
|
|
151
|
-
if (this.#transports[this.#index].cooldown < now) {
|
|
152
|
-
this.#logger?.info(
|
|
153
|
-
{
|
|
154
|
-
current: this.currentTransportName,
|
|
155
|
-
total: this.#transports.length
|
|
156
|
-
},
|
|
157
|
-
"switched to next transport"
|
|
158
|
-
);
|
|
141
|
+
const from = this.#selector.transportName();
|
|
142
|
+
const success = this.#selector.rotate();
|
|
143
|
+
const to = this.#selector.transportName();
|
|
144
|
+
if (success) {
|
|
145
|
+
if (from !== to) {
|
|
146
|
+
this.#logger?.debug({ from, to, reason }, "transport rotated");
|
|
159
147
|
try {
|
|
160
|
-
await this.#config.onRotateSuccess?.(
|
|
161
|
-
oldTransportName,
|
|
162
|
-
this.currentTransportName(),
|
|
163
|
-
reason
|
|
164
|
-
);
|
|
148
|
+
await this.#config.onRotateSuccess?.(from, to, reason);
|
|
165
149
|
} catch {
|
|
166
150
|
}
|
|
167
|
-
this.#rotating = false;
|
|
168
|
-
return true;
|
|
169
|
-
} else {
|
|
170
|
-
this.#logger?.warn(
|
|
171
|
-
{
|
|
172
|
-
current: this.currentTransportName,
|
|
173
|
-
total: this.#transports.length
|
|
174
|
-
},
|
|
175
|
-
"transport is still on cooldown"
|
|
176
|
-
);
|
|
177
151
|
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
152
|
+
} else {
|
|
153
|
+
this.#logger?.warn({ from, reason }, "transport rotation failed");
|
|
154
|
+
try {
|
|
155
|
+
await this.#config.onRotateFailed?.(from, reason);
|
|
156
|
+
} catch {
|
|
157
|
+
}
|
|
182
158
|
}
|
|
183
159
|
this.#rotating = false;
|
|
184
|
-
return false;
|
|
185
|
-
}
|
|
186
|
-
currentTransportName() {
|
|
187
|
-
return this.#transport({}).config.name;
|
|
188
|
-
}
|
|
189
|
-
statuses() {
|
|
190
|
-
const now = Date.now();
|
|
191
|
-
return this.#transports.map((t, i) => ({
|
|
192
|
-
id: t.transport({}).config.name,
|
|
193
|
-
status: t.cooldown < now ? this.#index === i ? "active" : "standby" : "cooldown"
|
|
194
|
-
}));
|
|
195
160
|
}
|
|
196
161
|
get #logger() {
|
|
197
162
|
return this.#config.logger;
|
|
198
163
|
}
|
|
199
|
-
get #transport() {
|
|
200
|
-
return this.#transports[this.#index].transport;
|
|
201
|
-
}
|
|
202
|
-
get #hasAvailableTransports() {
|
|
203
|
-
const now = Date.now();
|
|
204
|
-
return this.#transports.some((t) => t.cooldown < now);
|
|
205
|
-
}
|
|
206
164
|
}
|
|
207
165
|
const retryCodes = /* @__PURE__ */ new Set([
|
|
208
166
|
InvalidRequestRpcError.code,
|
|
@@ -214,11 +172,95 @@ const retryCodes = /* @__PURE__ */ new Set([
|
|
|
214
172
|
const defaultShouldRetry = ({
|
|
215
173
|
error
|
|
216
174
|
}) => {
|
|
175
|
+
if (error instanceof CallExecutionError && error.details === "header not found") {
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
217
178
|
if ("code" in error && typeof error.code === "number") {
|
|
218
179
|
return retryCodes.has(error.code);
|
|
219
180
|
}
|
|
220
181
|
return false;
|
|
221
182
|
};
|
|
183
|
+
class AbstractTransportSelector {
|
|
184
|
+
transports;
|
|
185
|
+
cooldown;
|
|
186
|
+
index = 0;
|
|
187
|
+
constructor(transports, cooldown = 6e4) {
|
|
188
|
+
this.transports = transports;
|
|
189
|
+
this.cooldown = cooldown;
|
|
190
|
+
}
|
|
191
|
+
transportName() {
|
|
192
|
+
return this.transports[this.index].name;
|
|
193
|
+
}
|
|
194
|
+
canRotate() {
|
|
195
|
+
const now = Date.now();
|
|
196
|
+
return this.transports.some((t) => t.cooldown < now);
|
|
197
|
+
}
|
|
198
|
+
statuses() {
|
|
199
|
+
const now = Date.now();
|
|
200
|
+
return this.transports.map((t, i) => ({
|
|
201
|
+
id: t.name,
|
|
202
|
+
status: t.cooldown < now ? this.index === i ? "active" : "standby" : "cooldown"
|
|
203
|
+
}));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
class SimpleTransportSelector extends AbstractTransportSelector {
|
|
207
|
+
/**
|
|
208
|
+
* For simple selector, transport status is not re-evaluated on each request
|
|
209
|
+
* @returns
|
|
210
|
+
*/
|
|
211
|
+
select() {
|
|
212
|
+
return this.transports[this.index].transport;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Simply selects next transport that is not in cooldown by checking all transports in cyclic order
|
|
216
|
+
* @returns true if rotation was successful
|
|
217
|
+
*/
|
|
218
|
+
rotate() {
|
|
219
|
+
if (this.transports.length === 1) {
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
const now = Date.now();
|
|
223
|
+
this.transports[this.index].cooldown = now + this.cooldown;
|
|
224
|
+
for (let i = 0; i < this.transports.length - 1; i++) {
|
|
225
|
+
this.index = (this.index + 1) % this.transports.length;
|
|
226
|
+
if (this.transports[this.index].cooldown < now) {
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
class OrderedTransportSelector extends AbstractTransportSelector {
|
|
234
|
+
/**
|
|
235
|
+
* Will select first transport that is not in cooldown
|
|
236
|
+
* @returns
|
|
237
|
+
*/
|
|
238
|
+
select() {
|
|
239
|
+
this.#updateIndex(Date.now());
|
|
240
|
+
return this.transports[this.index].transport;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Will put current transport into cooldown and select first available transport that is not in cooldown
|
|
244
|
+
* @returns true if rotation was successful
|
|
245
|
+
*/
|
|
246
|
+
rotate() {
|
|
247
|
+
if (this.transports.length === 1) {
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
const now = Date.now();
|
|
251
|
+
this.transports[this.index].cooldown = now + this.cooldown;
|
|
252
|
+
return this.#updateIndex(now);
|
|
253
|
+
}
|
|
254
|
+
#updateIndex(now) {
|
|
255
|
+
for (let i = 0; i < this.transports.length; i++) {
|
|
256
|
+
if (this.transports[i].cooldown < now) {
|
|
257
|
+
this.index = i;
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
222
264
|
export {
|
|
223
265
|
NoAvailableTransportsError,
|
|
224
266
|
RevolverTransport
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { SDKConstruct } from "../base/index.js";
|
|
2
2
|
import { CreditSuite } from "./credit/index.js";
|
|
3
|
+
import {
|
|
4
|
+
createLossPolicy
|
|
5
|
+
} from "./loss-policy/index.js";
|
|
3
6
|
import { MarketConfiguratorContract } from "./MarketConfiguratorContract.js";
|
|
4
7
|
import { getOrCreatePriceOracle } from "./oracle/index.js";
|
|
5
8
|
import { PoolSuite } from "./pool/index.js";
|
|
@@ -9,6 +12,7 @@ class MarketSuite extends SDKConstruct {
|
|
|
9
12
|
configurator;
|
|
10
13
|
pool;
|
|
11
14
|
priceOracle;
|
|
15
|
+
lossPolicy;
|
|
12
16
|
creditManagers = [];
|
|
13
17
|
/**
|
|
14
18
|
* Original data received from compressor
|
|
@@ -35,6 +39,7 @@ class MarketSuite extends SDKConstruct {
|
|
|
35
39
|
this.creditManagers.push(new CreditSuite(sdk, marketData, i));
|
|
36
40
|
}
|
|
37
41
|
this.priceOracle = getOrCreatePriceOracle(sdk, marketData.priceOracle);
|
|
42
|
+
this.lossPolicy = createLossPolicy(sdk, marketData.lossPolicy);
|
|
38
43
|
}
|
|
39
44
|
get dirty() {
|
|
40
45
|
return this.configurator.dirty || this.pool.dirty || this.priceOracle.dirty || this.creditManagers.some((cm) => cm.dirty);
|
|
@@ -54,6 +59,7 @@ class MarketSuite extends SDKConstruct {
|
|
|
54
59
|
pool: this.pool.stateHuman(raw),
|
|
55
60
|
creditManagers: this.creditManagers.map((cm) => cm.stateHuman(raw)),
|
|
56
61
|
priceOracle: this.priceOracle.stateHuman(raw),
|
|
62
|
+
lossPolicy: this.lossPolicy.stateHuman(raw),
|
|
57
63
|
pausableAdmins: this.state.pausableAdmins.map((a) => this.labelAddress(a)),
|
|
58
64
|
unpausableAdmins: this.state.unpausableAdmins.map(
|
|
59
65
|
(a) => this.labelAddress(a)
|
|
@@ -61,7 +61,10 @@ class CreditFacadeV300Contract extends BaseContract {
|
|
|
61
61
|
break;
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
|
-
liquidateCreditAccount(ca, to, calls) {
|
|
64
|
+
liquidateCreditAccount(ca, to, calls, lossPolicyData) {
|
|
65
|
+
if (lossPolicyData) {
|
|
66
|
+
this.logger?.warn("loss policy data is not supported");
|
|
67
|
+
}
|
|
65
68
|
return this.createRawTx({
|
|
66
69
|
functionName: "liquidateCreditAccount",
|
|
67
70
|
args: [ca, to, calls]
|
|
@@ -61,10 +61,10 @@ class CreditFacadeV310Contract extends BaseContract {
|
|
|
61
61
|
break;
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
|
-
liquidateCreditAccount(ca, to, calls) {
|
|
64
|
+
liquidateCreditAccount(ca, to, calls, lossPolicyData) {
|
|
65
65
|
return this.createRawTx({
|
|
66
66
|
functionName: "liquidateCreditAccount",
|
|
67
|
-
args: [ca, to, calls]
|
|
67
|
+
args: lossPolicyData ? [ca, to, calls, lossPolicyData] : [ca, to, calls]
|
|
68
68
|
});
|
|
69
69
|
}
|
|
70
70
|
closeCreditAccount(ca, calls) {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { iAliasedLossPolicyV310Abi } from "../../../abi/310/generated.js";
|
|
2
|
+
import { BaseContract } from "../../base/index.js";
|
|
3
|
+
const abi = iAliasedLossPolicyV310Abi;
|
|
4
|
+
class AliasLossPolicyV310Contract extends BaseContract {
|
|
5
|
+
constructor(sdk, params) {
|
|
6
|
+
super(sdk, {
|
|
7
|
+
abi,
|
|
8
|
+
addr: params.addr,
|
|
9
|
+
contractType: params.contractType,
|
|
10
|
+
version: params.version
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
AliasLossPolicyV310Contract
|
|
16
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { iLossPolicyV310Abi } from "../../../abi/310/generated.js";
|
|
2
|
+
import { BaseContract } from "../../base/index.js";
|
|
3
|
+
const abi = iLossPolicyV310Abi;
|
|
4
|
+
class LossPolicyContract extends BaseContract {
|
|
5
|
+
constructor(sdk, params) {
|
|
6
|
+
super(sdk, {
|
|
7
|
+
abi,
|
|
8
|
+
addr: params.addr,
|
|
9
|
+
contractType: params.contractType,
|
|
10
|
+
version: params.version
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
LossPolicyContract
|
|
16
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { bytes32ToString } from "../../index.js";
|
|
2
|
+
import { AliasLossPolicyV310Contract } from "./AliasLossPolicyV310Contract.js";
|
|
3
|
+
import { LossPolicyContract } from "./LossPolicyContract.js";
|
|
4
|
+
function createLossPolicy(sdk, { baseParams }) {
|
|
5
|
+
const existing = sdk.contracts.get(baseParams.addr);
|
|
6
|
+
if (existing) {
|
|
7
|
+
return existing;
|
|
8
|
+
}
|
|
9
|
+
const contractType = bytes32ToString(baseParams.contractType);
|
|
10
|
+
switch (contractType) {
|
|
11
|
+
case "LOSS_POLICY::ALIASED":
|
|
12
|
+
return new AliasLossPolicyV310Contract(sdk, baseParams);
|
|
13
|
+
case "LOSS_POLICY::DEFAULT":
|
|
14
|
+
return new LossPolicyContract(sdk, baseParams);
|
|
15
|
+
default:
|
|
16
|
+
if (sdk.strictContractTypes) {
|
|
17
|
+
throw new Error(`unsupported loss policy type ${contractType}`);
|
|
18
|
+
}
|
|
19
|
+
return new LossPolicyContract(sdk, baseParams);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
createLossPolicy
|
|
24
|
+
};
|
|
File without changes
|