@7kprotocol/sdk-ts 3.4.2-beta.4 → 3.4.2-beta.6

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.
Files changed (68) hide show
  1. package/README.md +151 -4
  2. package/lib/cjs/constants/_7k.js +5 -1
  3. package/lib/cjs/constants/sui.js +4 -0
  4. package/lib/cjs/features/metaAg/index.js +244 -0
  5. package/lib/cjs/features/metaAg/providers/bluefin.js +69 -0
  6. package/lib/cjs/features/metaAg/providers/cetus.js +67 -0
  7. package/lib/cjs/features/metaAg/providers/flowx.js +56 -0
  8. package/lib/cjs/index.js +6 -1
  9. package/lib/cjs/types/constants/_7k.d.ts +4 -0
  10. package/lib/cjs/types/constants/_7k.d.ts.map +1 -1
  11. package/lib/cjs/types/constants/sui.d.ts +2 -0
  12. package/lib/cjs/types/constants/sui.d.ts.map +1 -0
  13. package/lib/cjs/types/features/metaAg/index.d.ts +28 -0
  14. package/lib/cjs/types/features/metaAg/index.d.ts.map +1 -0
  15. package/lib/cjs/types/features/metaAg/providers/bluefin.d.ts +11 -0
  16. package/lib/cjs/types/features/metaAg/providers/bluefin.d.ts.map +1 -0
  17. package/lib/cjs/types/features/metaAg/providers/cetus.d.ts +13 -0
  18. package/lib/cjs/types/features/metaAg/providers/cetus.d.ts.map +1 -0
  19. package/lib/cjs/types/features/metaAg/providers/flowx.d.ts +14 -0
  20. package/lib/cjs/types/features/metaAg/providers/flowx.d.ts.map +1 -0
  21. package/lib/cjs/types/index.d.ts +4 -1
  22. package/lib/cjs/types/index.d.ts.map +1 -1
  23. package/lib/cjs/types/metaAg.js +12 -0
  24. package/lib/cjs/types/types/metaAg.d.ts +127 -0
  25. package/lib/cjs/types/types/metaAg.d.ts.map +1 -0
  26. package/lib/cjs/types/utils/ObjectCache.d.ts +87 -0
  27. package/lib/cjs/types/utils/ObjectCache.d.ts.map +1 -0
  28. package/lib/cjs/types/utils/SuiClientUtils.d.ts +15 -0
  29. package/lib/cjs/types/utils/SuiClientUtils.d.ts.map +1 -0
  30. package/lib/cjs/types/utils/condition.d.ts +2 -0
  31. package/lib/cjs/types/utils/condition.d.ts.map +1 -0
  32. package/lib/cjs/utils/ObjectCache.js +273 -0
  33. package/lib/cjs/utils/SuiClientUtils.js +50 -0
  34. package/lib/cjs/utils/condition.js +8 -0
  35. package/lib/esm/constants/_7k.js +4 -0
  36. package/lib/esm/constants/sui.js +1 -0
  37. package/lib/esm/features/metaAg/index.js +210 -0
  38. package/lib/esm/features/metaAg/providers/bluefin.js +67 -0
  39. package/lib/esm/features/metaAg/providers/cetus.js +66 -0
  40. package/lib/esm/features/metaAg/providers/flowx.js +56 -0
  41. package/lib/esm/index.mjs +5 -1
  42. package/lib/esm/types/constants/_7k.d.ts +4 -0
  43. package/lib/esm/types/constants/_7k.d.ts.map +1 -1
  44. package/lib/esm/types/constants/sui.d.ts +2 -0
  45. package/lib/esm/types/constants/sui.d.ts.map +1 -0
  46. package/lib/esm/types/features/metaAg/index.d.ts +28 -0
  47. package/lib/esm/types/features/metaAg/index.d.ts.map +1 -0
  48. package/lib/esm/types/features/metaAg/providers/bluefin.d.ts +11 -0
  49. package/lib/esm/types/features/metaAg/providers/bluefin.d.ts.map +1 -0
  50. package/lib/esm/types/features/metaAg/providers/cetus.d.ts +13 -0
  51. package/lib/esm/types/features/metaAg/providers/cetus.d.ts.map +1 -0
  52. package/lib/esm/types/features/metaAg/providers/flowx.d.ts +14 -0
  53. package/lib/esm/types/features/metaAg/providers/flowx.d.ts.map +1 -0
  54. package/lib/esm/types/index.d.ts +4 -1
  55. package/lib/esm/types/index.d.ts.map +1 -1
  56. package/lib/esm/types/metaAg.js +8 -0
  57. package/lib/esm/types/types/metaAg.d.ts +127 -0
  58. package/lib/esm/types/types/metaAg.d.ts.map +1 -0
  59. package/lib/esm/types/utils/ObjectCache.d.ts +87 -0
  60. package/lib/esm/types/utils/ObjectCache.d.ts.map +1 -0
  61. package/lib/esm/types/utils/SuiClientUtils.d.ts +15 -0
  62. package/lib/esm/types/utils/SuiClientUtils.d.ts.map +1 -0
  63. package/lib/esm/types/utils/condition.d.ts +2 -0
  64. package/lib/esm/types/utils/condition.d.ts.map +1 -0
  65. package/lib/esm/utils/ObjectCache.js +250 -0
  66. package/lib/esm/utils/SuiClientUtils.js +34 -0
  67. package/lib/esm/utils/condition.js +5 -0
  68. package/package.json +8 -1
@@ -0,0 +1,273 @@
1
+ "use strict";
2
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
5
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
+ };
7
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
8
+ if (kind === "m") throw new TypeError("Private method is not writable");
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
11
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
12
+ };
13
+ var _InMemoryObjectCache_caches, _CustomObjectCache_client, _CustomObjectCache_cache, _CustomObjectCache_onEffects;
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.CustomObjectCache = exports.InMemoryObjectCache = exports.AsyncCache = void 0;
16
+ const utils_1 = require("@mysten/sui/utils");
17
+ class AsyncCache {
18
+ async getObject(id) {
19
+ const [owned, shared] = await Promise.all([
20
+ this.get("OwnedObject", id),
21
+ this.get("SharedOrImmutableObject", id),
22
+ ]);
23
+ return owned ?? shared ?? null;
24
+ }
25
+ async getObjects(ids) {
26
+ return Promise.all(ids.map((id) => this.getObject(id)));
27
+ }
28
+ async addObject(object) {
29
+ if (object.owner) {
30
+ await this.set("OwnedObject", object.objectId, object);
31
+ }
32
+ else {
33
+ await this.set("SharedOrImmutableObject", object.objectId, object);
34
+ }
35
+ return object;
36
+ }
37
+ async addObjects(objects) {
38
+ await Promise.all(objects.map(async (object) => this.addObject(object)));
39
+ }
40
+ async deleteObject(id) {
41
+ await Promise.all([
42
+ this.delete("OwnedObject", id),
43
+ this.delete("SharedOrImmutableObject", id),
44
+ ]);
45
+ }
46
+ async deleteObjects(ids) {
47
+ await Promise.all(ids.map((id) => this.deleteObject(id)));
48
+ }
49
+ async getMoveFunctionDefinition(ref) {
50
+ const functionName = `${(0, utils_1.normalizeSuiAddress)(ref.package)}::${ref.module}::${ref.function}`;
51
+ return this.get("MoveFunction", functionName);
52
+ }
53
+ async addMoveFunctionDefinition(functionEntry) {
54
+ const pkg = (0, utils_1.normalizeSuiAddress)(functionEntry.package);
55
+ const functionName = `${pkg}::${functionEntry.module}::${functionEntry.function}`;
56
+ const entry = {
57
+ ...functionEntry,
58
+ package: pkg,
59
+ };
60
+ await this.set("MoveFunction", functionName, entry);
61
+ return entry;
62
+ }
63
+ async deleteMoveFunctionDefinition(ref) {
64
+ const functionName = `${(0, utils_1.normalizeSuiAddress)(ref.package)}::${ref.module}::${ref.function}`;
65
+ await this.delete("MoveFunction", functionName);
66
+ }
67
+ async getCustom(key) {
68
+ return this.get("Custom", key);
69
+ }
70
+ async setCustom(key, value) {
71
+ return this.set("Custom", key, value);
72
+ }
73
+ async deleteCustom(key) {
74
+ return this.delete("Custom", key);
75
+ }
76
+ }
77
+ exports.AsyncCache = AsyncCache;
78
+ class InMemoryObjectCache extends AsyncCache {
79
+ constructor() {
80
+ super(...arguments);
81
+ _InMemoryObjectCache_caches.set(this, {
82
+ OwnedObject: new Map(),
83
+ SharedOrImmutableObject: new Map(),
84
+ MoveFunction: new Map(),
85
+ Custom: new Map(),
86
+ });
87
+ }
88
+ async get(type, key) {
89
+ return __classPrivateFieldGet(this, _InMemoryObjectCache_caches, "f")[type].get(key) ?? null;
90
+ }
91
+ async set(type, key, value) {
92
+ __classPrivateFieldGet(this, _InMemoryObjectCache_caches, "f")[type].set(key, value);
93
+ }
94
+ async delete(type, key) {
95
+ __classPrivateFieldGet(this, _InMemoryObjectCache_caches, "f")[type].delete(key);
96
+ }
97
+ async clear(type) {
98
+ if (type) {
99
+ __classPrivateFieldGet(this, _InMemoryObjectCache_caches, "f")[type].clear();
100
+ }
101
+ else {
102
+ for (const cache of Object.values(__classPrivateFieldGet(this, _InMemoryObjectCache_caches, "f"))) {
103
+ cache.clear();
104
+ }
105
+ }
106
+ }
107
+ }
108
+ exports.InMemoryObjectCache = InMemoryObjectCache;
109
+ _InMemoryObjectCache_caches = new WeakMap();
110
+ class CustomObjectCache {
111
+ constructor({ cache = new InMemoryObjectCache(), onEffects, client, }) {
112
+ _CustomObjectCache_client.set(this, void 0);
113
+ _CustomObjectCache_cache.set(this, void 0);
114
+ _CustomObjectCache_onEffects.set(this, void 0);
115
+ __classPrivateFieldSet(this, _CustomObjectCache_client, client, "f");
116
+ __classPrivateFieldSet(this, _CustomObjectCache_cache, cache, "f");
117
+ __classPrivateFieldSet(this, _CustomObjectCache_onEffects, onEffects, "f");
118
+ }
119
+ async applyCache(transactionData, unresolvedObjects) {
120
+ const cached = (await __classPrivateFieldGet(this, _CustomObjectCache_cache, "f").getObjects(unresolvedObjects)).filter((obj) => obj !== null);
121
+ const byId = new Map(cached.map((obj) => [obj.objectId, obj]));
122
+ const unresolved = [];
123
+ for (const input of transactionData.inputs) {
124
+ if (!input.UnresolvedObject) {
125
+ continue;
126
+ }
127
+ const cached = byId.get(input.UnresolvedObject.objectId);
128
+ if (!cached) {
129
+ unresolved.push(input.UnresolvedObject.objectId);
130
+ continue;
131
+ }
132
+ if (cached.initialSharedVersion &&
133
+ !input.UnresolvedObject.initialSharedVersion) {
134
+ input.UnresolvedObject.initialSharedVersion =
135
+ cached.initialSharedVersion;
136
+ }
137
+ else {
138
+ if (cached.version && !input.UnresolvedObject.version) {
139
+ input.UnresolvedObject.version = cached.version;
140
+ }
141
+ if (cached.digest && !input.UnresolvedObject.digest) {
142
+ input.UnresolvedObject.digest = cached.digest;
143
+ }
144
+ }
145
+ }
146
+ return unresolved;
147
+ }
148
+ async resolveObjects(transactionData, unresolved) {
149
+ const unresolvedObjects = await this.applyCache(transactionData, unresolved);
150
+ if (unresolvedObjects.length === 0) {
151
+ return [];
152
+ }
153
+ const dedup = [...new Set(unresolvedObjects)];
154
+ const res = await __classPrivateFieldGet(this, _CustomObjectCache_client, "f").multiGetObjects({
155
+ ids: dedup,
156
+ options: {
157
+ showOwner: true,
158
+ },
159
+ });
160
+ const objects = [];
161
+ for (const obj of res || []) {
162
+ if (!obj.data) {
163
+ continue;
164
+ }
165
+ const owner = obj.data.owner;
166
+ const initialSharedVersion = owner && typeof owner === "object" && "Shared" in owner
167
+ ? owner.Shared.initial_shared_version
168
+ : null;
169
+ const ownerAddress = owner && typeof owner === "object" && "AddressOwner" in owner
170
+ ? owner.AddressOwner
171
+ : null;
172
+ const cached = {
173
+ objectId: obj.data.objectId,
174
+ version: obj.data.version,
175
+ digest: obj.data.digest,
176
+ initialSharedVersion,
177
+ owner: ownerAddress,
178
+ };
179
+ objects.push(cached);
180
+ }
181
+ await __classPrivateFieldGet(this, _CustomObjectCache_cache, "f").addObjects(objects);
182
+ return await this.applyCache(transactionData, unresolvedObjects);
183
+ }
184
+ asPlugin() {
185
+ return async (transactionData, _options, next) => {
186
+ const unresolvedObjects = transactionData.inputs
187
+ .filter((input) => input.UnresolvedObject)
188
+ .map((input) => input.UnresolvedObject.objectId);
189
+ // if object is not in cache yet, fetch from RPC and save to cache and resolve all objects
190
+ await this.resolveObjects(transactionData, unresolvedObjects);
191
+ await Promise.all(transactionData.commands.map(async (commands) => {
192
+ if (commands.MoveCall) {
193
+ const def = await this.getMoveFunctionDefinition({
194
+ package: commands.MoveCall.package,
195
+ module: commands.MoveCall.module,
196
+ function: commands.MoveCall.function,
197
+ });
198
+ if (def) {
199
+ commands.MoveCall._argumentTypes = def.parameters;
200
+ }
201
+ }
202
+ }));
203
+ await next();
204
+ await Promise.all(transactionData.commands.map(async (commands) => {
205
+ if (commands.MoveCall?._argumentTypes) {
206
+ await __classPrivateFieldGet(this, _CustomObjectCache_cache, "f").addMoveFunctionDefinition({
207
+ package: commands.MoveCall.package,
208
+ module: commands.MoveCall.module,
209
+ function: commands.MoveCall.function,
210
+ parameters: commands.MoveCall._argumentTypes,
211
+ });
212
+ }
213
+ }));
214
+ };
215
+ }
216
+ async clear() {
217
+ await __classPrivateFieldGet(this, _CustomObjectCache_cache, "f").clear();
218
+ }
219
+ async getMoveFunctionDefinition(ref) {
220
+ return __classPrivateFieldGet(this, _CustomObjectCache_cache, "f").getMoveFunctionDefinition(ref);
221
+ }
222
+ async getObjects(ids) {
223
+ return __classPrivateFieldGet(this, _CustomObjectCache_cache, "f").getObjects(ids);
224
+ }
225
+ async deleteObjects(ids) {
226
+ return __classPrivateFieldGet(this, _CustomObjectCache_cache, "f").deleteObjects(ids);
227
+ }
228
+ async clearOwnedObjects() {
229
+ await __classPrivateFieldGet(this, _CustomObjectCache_cache, "f").clear("OwnedObject");
230
+ }
231
+ async clearCustom() {
232
+ await __classPrivateFieldGet(this, _CustomObjectCache_cache, "f").clear("Custom");
233
+ }
234
+ async getCustom(key) {
235
+ return __classPrivateFieldGet(this, _CustomObjectCache_cache, "f").getCustom(key);
236
+ }
237
+ async setCustom(key, value) {
238
+ return __classPrivateFieldGet(this, _CustomObjectCache_cache, "f").setCustom(key, value);
239
+ }
240
+ async deleteCustom(key) {
241
+ return __classPrivateFieldGet(this, _CustomObjectCache_cache, "f").deleteCustom(key);
242
+ }
243
+ async applyEffects(effects) {
244
+ if (!effects.V2) {
245
+ throw new Error(`Unsupported transaction effects version ${effects.$kind}`);
246
+ }
247
+ const { lamportVersion, changedObjects } = effects.V2;
248
+ const deletedIds = [];
249
+ const addedObjects = [];
250
+ changedObjects.forEach(([id, change]) => {
251
+ if (change.outputState.NotExist) {
252
+ deletedIds.push(id);
253
+ }
254
+ else if (change.outputState.ObjectWrite) {
255
+ const [digest, owner] = change.outputState.ObjectWrite;
256
+ addedObjects.push({
257
+ objectId: id,
258
+ digest,
259
+ version: lamportVersion,
260
+ owner: owner.AddressOwner ?? owner.ObjectOwner ?? null,
261
+ initialSharedVersion: owner.Shared?.initialSharedVersion ?? null,
262
+ });
263
+ }
264
+ });
265
+ await Promise.all([
266
+ __classPrivateFieldGet(this, _CustomObjectCache_cache, "f").addObjects(addedObjects),
267
+ __classPrivateFieldGet(this, _CustomObjectCache_cache, "f").deleteObjects(deletedIds),
268
+ __classPrivateFieldGet(this, _CustomObjectCache_onEffects, "f")?.call(this, effects),
269
+ ]);
270
+ }
271
+ }
272
+ exports.CustomObjectCache = CustomObjectCache;
273
+ _CustomObjectCache_client = new WeakMap(), _CustomObjectCache_cache = new WeakMap(), _CustomObjectCache_onEffects = new WeakMap();
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
+ if (kind === "m") throw new TypeError("Private method is not writable");
4
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
+ };
8
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
+ };
13
+ var _SuiClientUtils_devInspectCache;
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.SuiClientUtils = void 0;
16
+ const transactions_1 = require("@mysten/sui/transactions");
17
+ const ObjectCache_1 = require("./ObjectCache");
18
+ /**
19
+ * Utility class for interacting with Sui blockchain coins
20
+ */
21
+ class SuiClientUtils {
22
+ /**
23
+ * Creates a new instance of SuiClientUtils
24
+ * @param client - The Sui client instance to use for blockchain interactions
25
+ */
26
+ constructor(client) {
27
+ this.client = client;
28
+ _SuiClientUtils_devInspectCache.set(this, void 0);
29
+ this.devInspectTransactionBlock = async (params) => {
30
+ if (params.transactionBlock instanceof transactions_1.Transaction) {
31
+ params.transactionBlock.addBuildPlugin(__classPrivateFieldGet(this, _SuiClientUtils_devInspectCache, "f").asPlugin());
32
+ }
33
+ try {
34
+ const res = await this.client.devInspectTransactionBlock(params);
35
+ return res;
36
+ }
37
+ catch (error) {
38
+ // clear all cache if devInspectTransactionBlock fails
39
+ await __classPrivateFieldGet(this, _SuiClientUtils_devInspectCache, "f").clear();
40
+ throw error;
41
+ }
42
+ finally {
43
+ await __classPrivateFieldGet(this, _SuiClientUtils_devInspectCache, "f").clearOwnedObjects();
44
+ }
45
+ };
46
+ __classPrivateFieldSet(this, _SuiClientUtils_devInspectCache, new ObjectCache_1.CustomObjectCache({ client: this.client }), "f");
47
+ }
48
+ }
49
+ exports.SuiClientUtils = SuiClientUtils;
50
+ _SuiClientUtils_devInspectCache = new WeakMap();
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assert = assert;
4
+ function assert(condition, message) {
5
+ if (!condition) {
6
+ throw new Error(message || "Assertion failed");
7
+ }
8
+ }
@@ -7,3 +7,7 @@ export const _7K_CONFIG = "0x47442a93f7727d188ba7cb71031170d1786af70013cb7ad5115
7
7
  //legacy v3: "0x0f8fc23dbcc9362b72c7a4c5aa53fcefa02ebfbb83a812c8c262ccd2c076d9ee";
8
8
  export const _7K_VAULT = "0x442ad50389ed5cda6f7a6f5a7ae6361a4c05ef1d9fb2e54fbba5a268d690bfe6";
9
9
  //legacy v3: "0x39a3c55742c0e011b6f65548e73cf589e1ae5e82dbfab449ca57f24c3bcd9514";
10
+ export const _7K_META_PUBLISHED_AT = "0x17c0b1f7a6ad73f51268f16b8c06c049eecc2f28a270cdd29c06e3d2dea23302";
11
+ export const _7K_META_PACKAGE_ID = "0x17c0b1f7a6ad73f51268f16b8c06c049eecc2f28a270cdd29c06e3d2dea23302";
12
+ export const _7K_META_VAULT = "0x9a8abd32fe5721307ce3b697cf982ee84e9ffbd58d667a4a199f1683c1a3d23c";
13
+ export const _7K_META_CONFIG = "0xbbb3a51877ed9b492f26f4e2181811cfb2bd70c532f6f7621263d122d5e96b56";
@@ -0,0 +1 @@
1
+ export const SUI_ADDRESS_ZERO = "0x0000000000000000000000000000000000000000000000000000000000000000";
@@ -0,0 +1,210 @@
1
+ import { getFullnodeUrl, SuiClient } from "@mysten/sui/client";
2
+ import { coinWithBalance, Transaction, } from "@mysten/sui/transactions";
3
+ import { _7K_META_CONFIG, _7K_META_PACKAGE_ID, _7K_META_PUBLISHED_AT, _7K_META_VAULT, } from "../../constants/_7k";
4
+ import { SUI_ADDRESS_ZERO } from "../../constants/sui";
5
+ import { EProvider, } from "../../types/metaAg";
6
+ import { assert } from "../../utils/condition";
7
+ import { SuiClientUtils } from "../../utils/SuiClientUtils";
8
+ import { getExpectedReturn } from "../swap/buildTx";
9
+ import { BluefinProvider } from "./providers/bluefin";
10
+ const HERMES_API = "https://hermes.pyth.network";
11
+ const DEFAULT_PROVIDERS = {
12
+ [EProvider.BLUEFIN7K]: {},
13
+ [EProvider.FLOWX]: {},
14
+ [EProvider.CETUS]: {},
15
+ };
16
+ export class MetaAg {
17
+ client;
18
+ providers = {};
19
+ inspector;
20
+ options;
21
+ constructor(options) {
22
+ this.options = {
23
+ providers: options?.providers ?? DEFAULT_PROVIDERS,
24
+ slippageBps: options?.slippageBps ?? 100,
25
+ fullnodeUrl: options?.fullnodeUrl ?? getFullnodeUrl("mainnet"),
26
+ hermesApi: options?.hermesApi ?? HERMES_API,
27
+ partner: options?.partner ?? SUI_ADDRESS_ZERO,
28
+ partnerCommissionBps: options?.partnerCommissionBps ?? 0,
29
+ tipBps: options?.tipBps ?? 0,
30
+ };
31
+ this.client = new SuiClient({
32
+ url: this.options.fullnodeUrl,
33
+ });
34
+ this.inspector = new SuiClientUtils(this.client);
35
+ }
36
+ async _getProvider(provider) {
37
+ const p = this.providers[provider];
38
+ if (p)
39
+ return p;
40
+ switch (provider) {
41
+ case EProvider.BLUEFIN7K:
42
+ const bluefinOptions = this.options.providers[provider];
43
+ assert(!!bluefinOptions, `Provider not found: ${provider}`);
44
+ this.providers[EProvider.BLUEFIN7K] = new BluefinProvider(bluefinOptions, this.options, this.client);
45
+ break;
46
+ case EProvider.FLOWX:
47
+ const flowxOptions = this.options.providers[provider];
48
+ assert(!!flowxOptions, `Provider not found: ${provider}`);
49
+ const { FlowxProvider } = await import("./providers/flowx").catch(catchImportError(EProvider.FLOWX));
50
+ this.providers[EProvider.FLOWX] = new FlowxProvider(flowxOptions, this.options, this.client);
51
+ break;
52
+ case EProvider.CETUS:
53
+ const cetusOptions = this.options.providers[provider];
54
+ assert(!!cetusOptions, `Provider not found: ${provider}`);
55
+ const { CetusProvider } = await import("./providers/cetus").catch(catchImportError(EProvider.CETUS));
56
+ this.providers[EProvider.CETUS] = new CetusProvider(cetusOptions, this.options, this.client);
57
+ break;
58
+ default:
59
+ throw new Error(`Provider not supported: ${provider}`);
60
+ }
61
+ return this.providers[provider];
62
+ }
63
+ async _simulate(provider, quote, simulation) {
64
+ try {
65
+ const tx = new Transaction();
66
+ const id = quote.id;
67
+ const coinOut = await provider.swap({
68
+ quote,
69
+ coinIn: coinWithBalance({
70
+ balance: BigInt(quote.amountIn),
71
+ type: quote.coinTypeIn,
72
+ }),
73
+ signer: simulation.sender,
74
+ tx,
75
+ });
76
+ tx.add(metaSettle(quote, coinOut, 10000, this.options.tipBps, this.options.partner, this.options.partnerCommissionBps));
77
+ tx.transferObjects([coinOut], simulation.sender);
78
+ const res = await timeout(() => this.inspector.devInspectTransactionBlock({
79
+ sender: simulation.sender,
80
+ transactionBlock: tx,
81
+ }), simulation.timeout ?? 2000, `simulation for ${provider.kind} provider with id ${id}`);
82
+ const amountOut = extractAmountOutWrapper(res.events);
83
+ return {
84
+ id,
85
+ simulatedAmountOut: amountOut,
86
+ gasUsed: res.effects.gasUsed,
87
+ provider: provider.kind,
88
+ };
89
+ }
90
+ catch (error) {
91
+ console.warn(`Failed to simulate ${provider.kind}: `, error);
92
+ }
93
+ }
94
+ async _quote(provider, options, simulation) {
95
+ const quote = await timeout(() => provider.quote(options), options.timeout ?? 2000, `quote for ${provider.kind} provider from ${options.coinInType} to ${options.coinOutType}`);
96
+ if (simulation) {
97
+ if (simulation.onSimulated) {
98
+ this._simulate(provider, quote, simulation).then((payload) => {
99
+ payload && simulation.onSimulated?.(payload);
100
+ });
101
+ }
102
+ else {
103
+ const updated = await this._simulate(provider, quote, simulation);
104
+ quote.simulatedAmountOut = updated?.simulatedAmountOut;
105
+ quote.gasUsed = updated?.gasUsed;
106
+ }
107
+ }
108
+ return quote;
109
+ }
110
+ /**
111
+ * Get quotes from all providers
112
+ * @param options - quote options
113
+ * @param simulation - if present, the quote will be simulated
114
+ * @returns quotes from all providers
115
+ */
116
+ async quote(options, simulation) {
117
+ const quotes = await Promise.allSettled(Object.keys(this.options.providers).map(async (provider) => {
118
+ const p = await this._getProvider(provider);
119
+ return this._quote(p, options, simulation);
120
+ }));
121
+ return quotes
122
+ .map((quote) => quote.status === "fulfilled"
123
+ ? quote.value
124
+ : (console.log(quote.reason), null))
125
+ .filter((quote) => quote !== null);
126
+ }
127
+ /**
128
+ * Build transaction from quote
129
+ * @param options - build tx options
130
+ * @param slippageBps - slippage bps if not specified, fallback to global slippage bps, if none of them specified, default to 100
131
+ * @returns coin out object, you must consume it by transferObjects, or other sub sequence commands
132
+ */
133
+ async swap(options, slippageBps) {
134
+ const provider = await this._getProvider(options.quote.provider);
135
+ assert(!!provider, `Provider not found: ${options.quote.provider}`);
136
+ const coinOut = await provider.swap(options);
137
+ options.tx.add(metaSettle(options.quote, coinOut, slippageBps ?? this.options.slippageBps ?? 100, this.options.tipBps, this.options.partner, this.options.partnerCommissionBps));
138
+ options.tx.setSenderIfNotSet(options.signer);
139
+ return coinOut;
140
+ }
141
+ }
142
+ /**
143
+ * this settlement does not charge commission fee for partner, since all integrated aggregators already charge commission fee for partner
144
+ * @param quote Meta Aggregator Quote
145
+ * @param coinOut Coin Out Object
146
+ * @param slippageBps Slippage Bps
147
+ * @param tipBps Tip Bps default = 0
148
+ * @param partner address of partner for analytic default is zero address
149
+ */
150
+ const metaSettle = (quote, coinOut, slippageBps = 100, tipBps = 0, partner, commissionBps = 0) => {
151
+ return (tx) => {
152
+ const { minAmount, expectedAmount } = getExpectedReturn(quote.rawAmountOut, slippageBps, commissionBps, // use for calculate expected amount out
153
+ tipBps);
154
+ if (tipBps > 0) {
155
+ tx.moveCall({
156
+ target: `${_7K_META_PUBLISHED_AT}::vault::collect_tip`,
157
+ typeArguments: [quote.coinTypeOut],
158
+ arguments: [
159
+ tx.object(_7K_META_VAULT),
160
+ tx.object(_7K_META_CONFIG),
161
+ coinOut,
162
+ tx.pure.u64(tipBps),
163
+ ],
164
+ });
165
+ }
166
+ tx.moveCall({
167
+ target: `${_7K_META_PUBLISHED_AT}::settle::settle`,
168
+ typeArguments: [quote.coinTypeIn, quote.coinTypeOut],
169
+ arguments: [
170
+ tx.object(_7K_META_CONFIG),
171
+ tx.object(_7K_META_VAULT),
172
+ tx.pure.u64(quote.amountIn),
173
+ coinOut,
174
+ tx.pure.u64(minAmount),
175
+ tx.pure.u64(expectedAmount),
176
+ tx.pure.option("address", partner),
177
+ tx.pure.u64(0), // commission must be 0 since all integrated aggregators already charge commission fee for partner
178
+ tx.pure.u64(0), // ps
179
+ ],
180
+ });
181
+ };
182
+ };
183
+ const extractAmountOutWrapper = (events) => {
184
+ const swapEvent = events
185
+ .filter((event) => event.type === `${_7K_META_PACKAGE_ID}::settle::Swap`)
186
+ ?.pop();
187
+ return swapEvent?.parsedJson?.amount_out;
188
+ };
189
+ const catchImportError = (provider) => {
190
+ return (e) => {
191
+ const map = {
192
+ [EProvider.CETUS]: "@cetusprotocol/aggregator-sdk",
193
+ [EProvider.FLOWX]: "@flowx-finance/sdk",
194
+ [EProvider.BLUEFIN7K]: "@7kprotocol/sdk-ts",
195
+ };
196
+ console.warn(`Please install ${map[provider]} to use ${provider} provider`);
197
+ throw e;
198
+ };
199
+ };
200
+ const timeout = async (fn, timeout, msg) => {
201
+ if (timeout <= 0)
202
+ return fn();
203
+ return new Promise((resolve, reject) => {
204
+ const timer = setTimeout(() => reject(new Error(`Timeout ${msg ?? "operation"}`)), timeout);
205
+ fn()
206
+ .then(resolve)
207
+ .catch(reject)
208
+ .finally(() => clearTimeout(timer));
209
+ });
210
+ };
@@ -0,0 +1,67 @@
1
+ import { SuiPriceServiceConnection, SuiPythClient, } from "@pythnetwork/pyth-sui-js";
2
+ import { v4 } from "uuid";
3
+ import { Config } from "../../../config";
4
+ import { API_ENDPOINTS } from "../../../constants/apiEndpoints";
5
+ import { SUI_ADDRESS_ZERO } from "../../../constants/sui";
6
+ import { EProvider, } from "../../../types/metaAg";
7
+ import { assert } from "../../../utils/condition";
8
+ import { getExpectedReturn } from "../../swap/buildTx";
9
+ import { buildTxV2 } from "../../swap/buildTxV2";
10
+ import { getQuote } from "../../swap/getQuote";
11
+ const WORMHOLE_STATE_ID = "0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c";
12
+ const PYTH_STATE_ID = "0x1f9310238ee9298fb703c3419030b35b22bb1cc37113e3bb5007c99aec79e5b8";
13
+ export class BluefinProvider {
14
+ options;
15
+ metaOptions;
16
+ kind = EProvider.BLUEFIN7K;
17
+ constructor(options, metaOptions, client) {
18
+ this.options = options;
19
+ this.metaOptions = metaOptions;
20
+ const pythClient = new SuiPythClient(client, PYTH_STATE_ID, WORMHOLE_STATE_ID);
21
+ const pythConnection = new SuiPriceServiceConnection(this.metaOptions.hermesApi);
22
+ options.apiKey && Config.setApiKey(options.apiKey);
23
+ Config.setSuiClient(client);
24
+ Config.setPythClient(pythClient);
25
+ Config.setPythConnection(pythConnection);
26
+ }
27
+ async quote(options) {
28
+ const quote = await getQuote({
29
+ amountIn: options.amountIn,
30
+ tokenIn: options.coinInType,
31
+ tokenOut: options.coinOutType,
32
+ api: this.options.api || API_ENDPOINTS.MAIN,
33
+ sources: this.options.sources,
34
+ maxPaths: this.options.maxPaths,
35
+ excludedPools: this.options.excludedPools,
36
+ targetPools: this.options.targetPools,
37
+ });
38
+ const { expectedAmount } = getExpectedReturn(quote.returnAmountWithDecimal.toString(), 0, this.metaOptions.partnerCommissionBps ?? 0, this.metaOptions.tipBps ?? 0);
39
+ return {
40
+ id: v4(),
41
+ provider: EProvider.BLUEFIN7K,
42
+ quote,
43
+ amountIn: quote.swapAmountWithDecimal,
44
+ rawAmountOut: quote.returnAmountWithDecimal,
45
+ amountOut: expectedAmount,
46
+ coinTypeIn: quote.tokenIn,
47
+ coinTypeOut: quote.tokenOut,
48
+ };
49
+ }
50
+ async swap({ quote, signer, tx, coinIn }) {
51
+ assert(quote.provider === EProvider.BLUEFIN7K, "Invalid quote");
52
+ const { coinOut } = await buildTxV2({
53
+ quoteResponse: quote.quote,
54
+ accountAddress: signer,
55
+ commission: {
56
+ commissionBps: this.metaOptions.partnerCommissionBps ?? 0,
57
+ partner: this.metaOptions.partner ?? SUI_ADDRESS_ZERO,
58
+ },
59
+ slippage: 1,
60
+ extendTx: {
61
+ tx,
62
+ coinIn,
63
+ },
64
+ });
65
+ return coinOut;
66
+ }
67
+ }