@gardenfi/orderbook 3.0.1-beta.1 → 3.0.2
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/index11.cjs +1 -1
- package/dist/index11.js +53 -65
- package/package.json +2 -2
package/dist/index11.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("@gardenfi/utils"),h=require("node-cache"),o=class o{constructor(e,t){this.policy=new h({stdTTL:36e3,checkperiod:3600}),typeof t=="string"?this.auth=new a.ApiKey(t):this.auth=t,typeof e=="string"?this.apiBaseUrl=new a.Url(e):this.apiBaseUrl=e}getPolicy(){return this.policy.get(o.POLICY_CACHE_KEY)}setPolicy(e){const t=this.getPolicy(),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("@gardenfi/utils"),h=require("node-cache"),o=class o{constructor(e,t){this.policy=new h({stdTTL:36e3,checkperiod:3600}),typeof t=="string"?this.auth=new a.ApiKey(t):this.auth=t,typeof e=="string"?this.apiBaseUrl=new a.Url(e):this.apiBaseUrl=e}getPolicy(){return this.policy.get(o.POLICY_CACHE_KEY)}setPolicy(e){const t=this.getPolicy(),s={default:e.default||(t==null?void 0:t.default)||"open",isolation_groups:[...new Set([...(t==null?void 0:t.isolation_groups)||[],...e.isolation_groups])],blacklist_pairs:[...new Set([...(t==null?void 0:t.blacklist_pairs)||[],...e.blacklist_pairs])],whitelist_overrides:[...new Set([...(t==null?void 0:t.whitelist_overrides)||[],...e.whitelist_overrides])]};return this.policy.set(o.POLICY_CACHE_KEY,s),s}async loadPolicy(){const e=this.getPolicy();if(e)return a.Ok(e);try{const t=await this.auth.getAuthHeaders();if(!t.ok)return a.Err(`Failed to get auth headers: ${t.error}`);const s=await a.Fetcher.get(this.apiBaseUrl,{headers:{"Content-Type":"application/json",...t.val}});return s.result?a.Ok(this.setPolicy(s.result)):a.Err(`API Error: ${s.error}`)}catch(t){return a.Err(`Failed to load policy: ${t}`)}}async isValidRoute(e,t){const s=await this.loadPolicy();if(!s.ok||e.toString()===t.toString())return!1;const{sortedIsolationRules:r,sortedBlacklistRules:i,sortedWhitelistRules:n}=this.preprocessRules(s.val),c=this.findMatchingRule(e,r);if(c&&!this.matchesRuleDestination(t,c))return!1;const l=this.findMatchingRule(t,r);return l&&l.rule.direction==="<->"&&!this.matchesRuleSource(e,l)?!1:this.matchesRuleList(e,t,i)?!!this.matchesRuleList(e,t,n):s.val.default==="open"}async getValidDestinations(e,t){const s=[];for(const r of t)await this.isValidRoute(e,r)&&s.push(r);return s}async getAllValidRoutes(e){const t=[];for(const s of e)for(const r of e)await this.isValidRoute(s,r)&&t.push({from:s,to:r});return t}preprocessRules(e){const t=e.isolation_groups.map(i=>this.parseRule(i)).sort((i,n)=>n.specificity-i.specificity),s=e.blacklist_pairs.map(i=>this.parseRule(i)).sort((i,n)=>n.specificity-i.specificity),r=e.whitelist_overrides.map(i=>this.parseRule(i)).sort((i,n)=>n.specificity-i.specificity);return{sortedIsolationRules:t,sortedBlacklistRules:s,sortedWhitelistRules:r}}parseRule(e){const s=e.includes("<->")?"<->":"->",[r,i]=e.split(s).map(n=>n.trim());return{pattern:e,fromPattern:r,toPattern:i,direction:s,specificity:this.calculateSpecificity(r,i)}}calculateSpecificity(e,t){const s=r=>{const i=r.toLowerCase();return i==="*"?0:i.includes("*")?1:2};return s(e)*10+s(t)}findMatchingRule(e,t){for(const s of t){if(this.matchesAssetPattern(e,s.fromPattern))return{rule:s,matchedAs:"from"};if(s.direction==="<->"&&this.matchesAssetPattern(e,s.toPattern))return{rule:s,matchedAs:"to"}}return null}matchesRuleDestination(e,t){return t.matchedAs==="from"?this.matchesAssetPattern(e,t.rule.toPattern):t.rule.direction!=="<->"?!1:this.matchesAssetPattern(e,t.rule.fromPattern)}matchesRuleSource(e,t){return t.matchedAs==="to"?this.matchesAssetPattern(e,t.rule.fromPattern):t.rule.direction!=="<->"?!1:this.matchesAssetPattern(e,t.rule.toPattern)}matchesRuleList(e,t,s){return s.some(r=>this.matchesRule(e,t,r))}matchesRule(e,t,s){const r=this.matchesAssetPattern(e,s.fromPattern)&&this.matchesAssetPattern(t,s.toPattern);if(s.direction==="<->"){const i=this.matchesAssetPattern(e,s.toPattern)&&this.matchesAssetPattern(t,s.fromPattern);return r||i}return r}matchesAssetPattern(e,t){const[s="",r=""]=t.split(":").map(c=>c.trim().toLowerCase()),i=s===""||s==="*"||s===e.chain.toLowerCase(),n=r===""||r==="*"||r===e.symbol.toLowerCase();return i&&n}async buildRouteMatrix(e){const t={};for(const s of e){const r=[];for(const i of e)await this.isValidRoute(s,i)&&r.push(i);t[s.toString()]=r}return t}};o.POLICY_CACHE_KEY="route_policy";let u=o;exports.RouteValidator=u;
|
package/dist/index11.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { ApiKey as f, Url as
|
|
2
|
-
import
|
|
1
|
+
import { ApiKey as f, Url as p, Ok as u, Err as l, Fetcher as d } from "@gardenfi/utils";
|
|
2
|
+
import m from "node-cache";
|
|
3
3
|
const a = class a {
|
|
4
4
|
constructor(e, t) {
|
|
5
|
-
this.policy = new
|
|
5
|
+
this.policy = new m({
|
|
6
6
|
stdTTL: 36e3,
|
|
7
7
|
// 10 hours in seconds
|
|
8
8
|
checkperiod: 3600
|
|
9
9
|
// Check for expired keys every hour
|
|
10
|
-
}), typeof t == "string" ? this.auth = new f(t) : this.auth = t, typeof e == "string" ? this.apiBaseUrl = new
|
|
10
|
+
}), typeof t == "string" ? this.auth = new f(t) : this.auth = t, typeof e == "string" ? this.apiBaseUrl = new p(e) : this.apiBaseUrl = e;
|
|
11
11
|
}
|
|
12
12
|
getPolicy() {
|
|
13
13
|
return this.policy.get(a.POLICY_CACHE_KEY);
|
|
14
14
|
}
|
|
15
15
|
setPolicy(e) {
|
|
16
|
-
const t = this.getPolicy(),
|
|
16
|
+
const t = this.getPolicy(), s = {
|
|
17
17
|
default: e.default || (t == null ? void 0 : t.default) || "open",
|
|
18
18
|
isolation_groups: [
|
|
19
19
|
.../* @__PURE__ */ new Set([
|
|
@@ -34,7 +34,7 @@ const a = class a {
|
|
|
34
34
|
])
|
|
35
35
|
]
|
|
36
36
|
};
|
|
37
|
-
return this.policy.set(a.POLICY_CACHE_KEY,
|
|
37
|
+
return this.policy.set(a.POLICY_CACHE_KEY, s), s;
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
40
40
|
* Loads the current route policy, cached or via API.
|
|
@@ -46,7 +46,7 @@ const a = class a {
|
|
|
46
46
|
const t = await this.auth.getAuthHeaders();
|
|
47
47
|
if (!t.ok)
|
|
48
48
|
return l(`Failed to get auth headers: ${t.error}`);
|
|
49
|
-
const
|
|
49
|
+
const s = await d.get(
|
|
50
50
|
this.apiBaseUrl,
|
|
51
51
|
{
|
|
52
52
|
headers: {
|
|
@@ -55,19 +55,7 @@ const a = class a {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
);
|
|
58
|
-
return
|
|
59
|
-
"*:* -> bnbchain:btcb",
|
|
60
|
-
"bnbchain:btcb -> *:*",
|
|
61
|
-
"*:* -> botanix:btc",
|
|
62
|
-
"botanix:btc -> *:*"
|
|
63
|
-
), i.result.whitelist_overrides.push(
|
|
64
|
-
"bitcoin:btc -> bnbchain:btcb",
|
|
65
|
-
"botanix:btc -> bnbchain:btcb",
|
|
66
|
-
"bnbchain:btcb -> bitcoin:btc",
|
|
67
|
-
"bnbchain:btcb -> botanix:btc",
|
|
68
|
-
"bitcoin:btc -> botanix:btc",
|
|
69
|
-
"botanix:btc -> bitcoin:btc"
|
|
70
|
-
), u(this.setPolicy(i.result))) : l(`API Error: ${i.error}`);
|
|
58
|
+
return s.result ? u(this.setPolicy(s.result)) : l(`API Error: ${s.error}`);
|
|
71
59
|
} catch (t) {
|
|
72
60
|
return l(`Failed to load policy: ${t}`);
|
|
73
61
|
}
|
|
@@ -76,89 +64,89 @@ const a = class a {
|
|
|
76
64
|
* Checks if a given route is valid based on all route rules.
|
|
77
65
|
*/
|
|
78
66
|
async isValidRoute(e, t) {
|
|
79
|
-
const
|
|
80
|
-
if (!
|
|
81
|
-
const { sortedIsolationRules:
|
|
67
|
+
const s = await this.loadPolicy();
|
|
68
|
+
if (!s.ok || e.toString() === t.toString()) return !1;
|
|
69
|
+
const { sortedIsolationRules: r, sortedBlacklistRules: i, sortedWhitelistRules: n } = this.preprocessRules(s.val), o = this.findMatchingRule(
|
|
82
70
|
e,
|
|
83
|
-
|
|
71
|
+
r
|
|
84
72
|
);
|
|
85
73
|
if (o && !this.matchesRuleDestination(t, o))
|
|
86
74
|
return !1;
|
|
87
75
|
const c = this.findMatchingRule(
|
|
88
76
|
t,
|
|
89
|
-
|
|
77
|
+
r
|
|
90
78
|
);
|
|
91
|
-
return c && c.rule.direction === "<->" && !this.matchesRuleSource(e, c) ? !1 : this.matchesRuleList(e, t,
|
|
79
|
+
return c && c.rule.direction === "<->" && !this.matchesRuleSource(e, c) ? !1 : this.matchesRuleList(e, t, i) ? !!this.matchesRuleList(e, t, n) : s.val.default === "open";
|
|
92
80
|
}
|
|
93
81
|
/**
|
|
94
82
|
* Returns all valid destinations for a given source asset.
|
|
95
83
|
*/
|
|
96
84
|
async getValidDestinations(e, t) {
|
|
97
|
-
const
|
|
98
|
-
for (const
|
|
99
|
-
await this.isValidRoute(e,
|
|
100
|
-
return
|
|
85
|
+
const s = [];
|
|
86
|
+
for (const r of t)
|
|
87
|
+
await this.isValidRoute(e, r) && s.push(r);
|
|
88
|
+
return s;
|
|
101
89
|
}
|
|
102
90
|
/**
|
|
103
91
|
* Returns every valid route (from-to pair) among the provided assets.
|
|
104
92
|
*/
|
|
105
93
|
async getAllValidRoutes(e) {
|
|
106
94
|
const t = [];
|
|
107
|
-
for (const
|
|
108
|
-
for (const
|
|
109
|
-
await this.isValidRoute(
|
|
95
|
+
for (const s of e)
|
|
96
|
+
for (const r of e)
|
|
97
|
+
await this.isValidRoute(s, r) && t.push({ from: s, to: r });
|
|
110
98
|
return t;
|
|
111
99
|
}
|
|
112
100
|
/**
|
|
113
101
|
* Turns policy string rules into sorted ParsedRule objects.
|
|
114
102
|
*/
|
|
115
103
|
preprocessRules(e) {
|
|
116
|
-
const t = e.isolation_groups.map((
|
|
117
|
-
return { sortedIsolationRules: t, sortedBlacklistRules:
|
|
104
|
+
const t = e.isolation_groups.map((i) => this.parseRule(i)).sort((i, n) => n.specificity - i.specificity), s = e.blacklist_pairs.map((i) => this.parseRule(i)).sort((i, n) => n.specificity - i.specificity), r = e.whitelist_overrides.map((i) => this.parseRule(i)).sort((i, n) => n.specificity - i.specificity);
|
|
105
|
+
return { sortedIsolationRules: t, sortedBlacklistRules: s, sortedWhitelistRules: r };
|
|
118
106
|
}
|
|
119
107
|
/**
|
|
120
108
|
* Parses a rule string (e.g. "ethereum:usdc -> base:usdt") into parts.
|
|
121
109
|
*/
|
|
122
110
|
parseRule(e) {
|
|
123
|
-
const
|
|
111
|
+
const s = e.includes(
|
|
124
112
|
"<->"
|
|
125
113
|
/* Bidirectional */
|
|
126
|
-
) ? "<->" : "->", [
|
|
114
|
+
) ? "<->" : "->", [r, i] = e.split(s).map((n) => n.trim());
|
|
127
115
|
return {
|
|
128
116
|
pattern: e,
|
|
129
|
-
fromPattern:
|
|
130
|
-
toPattern:
|
|
131
|
-
direction:
|
|
132
|
-
specificity: this.calculateSpecificity(
|
|
117
|
+
fromPattern: r,
|
|
118
|
+
toPattern: i,
|
|
119
|
+
direction: s,
|
|
120
|
+
specificity: this.calculateSpecificity(r, i)
|
|
133
121
|
};
|
|
134
122
|
}
|
|
135
123
|
/**
|
|
136
124
|
* Gives a specificity score to a rule pattern for prioritizing.
|
|
137
125
|
*/
|
|
138
126
|
calculateSpecificity(e, t) {
|
|
139
|
-
const
|
|
140
|
-
const
|
|
141
|
-
return
|
|
127
|
+
const s = (r) => {
|
|
128
|
+
const i = r.toLowerCase();
|
|
129
|
+
return i === "*" ? 0 : i.includes(
|
|
142
130
|
"*"
|
|
143
131
|
/* Any */
|
|
144
132
|
) ? 1 : 2;
|
|
145
133
|
};
|
|
146
|
-
return
|
|
134
|
+
return s(e) * 10 + s(t);
|
|
147
135
|
}
|
|
148
136
|
/**
|
|
149
137
|
* Finds the first matching rule for an asset given the rule "side".
|
|
150
138
|
*/
|
|
151
139
|
findMatchingRule(e, t) {
|
|
152
|
-
for (const
|
|
153
|
-
if (this.matchesAssetPattern(e,
|
|
140
|
+
for (const s of t) {
|
|
141
|
+
if (this.matchesAssetPattern(e, s.fromPattern))
|
|
154
142
|
return {
|
|
155
|
-
rule:
|
|
143
|
+
rule: s,
|
|
156
144
|
matchedAs: "from"
|
|
157
145
|
/* From */
|
|
158
146
|
};
|
|
159
|
-
if (
|
|
147
|
+
if (s.direction === "<->" && this.matchesAssetPattern(e, s.toPattern))
|
|
160
148
|
return {
|
|
161
|
-
rule:
|
|
149
|
+
rule: s,
|
|
162
150
|
matchedAs: "to"
|
|
163
151
|
/* To */
|
|
164
152
|
};
|
|
@@ -180,34 +168,34 @@ const a = class a {
|
|
|
180
168
|
/**
|
|
181
169
|
* Checks if any rule in a list matches fromAsset and toAsset.
|
|
182
170
|
*/
|
|
183
|
-
matchesRuleList(e, t,
|
|
184
|
-
return
|
|
171
|
+
matchesRuleList(e, t, s) {
|
|
172
|
+
return s.some((r) => this.matchesRule(e, t, r));
|
|
185
173
|
}
|
|
186
174
|
/**
|
|
187
175
|
* Checks if a rule matches fromAsset and toAsset (forward or backward if bidirectional).
|
|
188
176
|
*/
|
|
189
|
-
matchesRule(e, t,
|
|
190
|
-
const
|
|
191
|
-
if (
|
|
192
|
-
const
|
|
193
|
-
return
|
|
177
|
+
matchesRule(e, t, s) {
|
|
178
|
+
const r = this.matchesAssetPattern(e, s.fromPattern) && this.matchesAssetPattern(t, s.toPattern);
|
|
179
|
+
if (s.direction === "<->") {
|
|
180
|
+
const i = this.matchesAssetPattern(e, s.toPattern) && this.matchesAssetPattern(t, s.fromPattern);
|
|
181
|
+
return r || i;
|
|
194
182
|
}
|
|
195
|
-
return
|
|
183
|
+
return r;
|
|
196
184
|
}
|
|
197
185
|
/**
|
|
198
186
|
* Checks if an asset string matches a rule's pattern (wildcards supported).
|
|
199
187
|
*/
|
|
200
188
|
matchesAssetPattern(e, t) {
|
|
201
|
-
const [
|
|
202
|
-
return
|
|
189
|
+
const [s = "", r = ""] = t.split(":").map((o) => o.trim().toLowerCase()), i = s === "" || s === "*" || s === e.chain.toLowerCase(), n = r === "" || r === "*" || r === e.symbol.toLowerCase();
|
|
190
|
+
return i && n;
|
|
203
191
|
}
|
|
204
192
|
async buildRouteMatrix(e) {
|
|
205
193
|
const t = {};
|
|
206
|
-
for (const
|
|
207
|
-
const
|
|
208
|
-
for (const
|
|
209
|
-
await this.isValidRoute(
|
|
210
|
-
t[
|
|
194
|
+
for (const s of e) {
|
|
195
|
+
const r = [];
|
|
196
|
+
for (const i of e)
|
|
197
|
+
await this.isValidRoute(s, i) && r.push(i);
|
|
198
|
+
t[s.toString()] = r;
|
|
211
199
|
}
|
|
212
200
|
return t;
|
|
213
201
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gardenfi/orderbook",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@coral-xyz/anchor": "^0.31.1",
|
|
31
|
-
"@gardenfi/utils": "3.0.0
|
|
31
|
+
"@gardenfi/utils": "3.0.0",
|
|
32
32
|
"bufferutil": "^4.0.8",
|
|
33
33
|
"node-cache": "^5.1.2",
|
|
34
34
|
"siwe": "^2.1.4",
|