@sly-rentals/core 1.1.2 → 1.2.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/api.json +8611 -6670
- package/dist/cjs/instructions/acceptRental.js +39 -53
- package/dist/cjs/instructions/acceptRental.js.map +1 -1
- package/dist/cjs/instructions/closeContract.js +15 -13
- package/dist/cjs/instructions/closeContract.js.map +1 -1
- package/dist/cjs/instructions/closeRental.js +19 -15
- package/dist/cjs/instructions/closeRental.js.map +1 -1
- package/dist/cjs/instructions/reserveRental.js +34 -46
- package/dist/cjs/instructions/reserveRental.js.map +1 -1
- package/dist/cjs/legacy/index.js +1 -0
- package/dist/cjs/legacy/index.js.map +1 -1
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/utils/bidMath.js +6 -115
- package/dist/cjs/utils/bidMath.js.map +1 -1
- package/dist/cjs/utils/contractSnapshot.js +207 -0
- package/dist/cjs/utils/contractSnapshot.js.map +1 -0
- package/dist/cjs/utils/contractSnapshot.test.js +247 -0
- package/dist/cjs/utils/contractSnapshot.test.js.map +1 -0
- package/dist/cjs/utils/index.js +8 -3
- package/dist/cjs/utils/index.js.map +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/instructions/acceptRental.js +40 -54
- package/dist/esm/instructions/acceptRental.js.map +1 -1
- package/dist/esm/instructions/closeContract.js +15 -13
- package/dist/esm/instructions/closeContract.js.map +1 -1
- package/dist/esm/instructions/closeRental.js +20 -16
- package/dist/esm/instructions/closeRental.js.map +1 -1
- package/dist/esm/instructions/reserveRental.js +34 -46
- package/dist/esm/instructions/reserveRental.js.map +1 -1
- package/dist/esm/legacy/index.js +1 -0
- package/dist/esm/legacy/index.js.map +1 -1
- package/dist/esm/package.json +1 -1
- package/dist/esm/utils/bidMath.js +6 -114
- package/dist/esm/utils/bidMath.js.map +1 -1
- package/dist/esm/utils/contractSnapshot.js +201 -0
- package/dist/esm/utils/contractSnapshot.js.map +1 -0
- package/dist/esm/utils/contractSnapshot.test.js +245 -0
- package/dist/esm/utils/contractSnapshot.test.js.map +1 -0
- package/dist/esm/utils/index.js +4 -2
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/types/instructions/acceptRental.d.ts +8 -0
- package/dist/types/instructions/acceptRental.d.ts.map +1 -1
- package/dist/types/instructions/closeContract.d.ts +9 -0
- package/dist/types/instructions/closeContract.d.ts.map +1 -1
- package/dist/types/instructions/closeRental.d.ts +8 -0
- package/dist/types/instructions/closeRental.d.ts.map +1 -1
- package/dist/types/instructions/reserveRental.d.ts +8 -0
- package/dist/types/instructions/reserveRental.d.ts.map +1 -1
- package/dist/types/legacy/index.d.ts +1 -0
- package/dist/types/legacy/index.d.ts.map +1 -1
- package/dist/types/utils/bidMath.d.ts +6 -44
- package/dist/types/utils/bidMath.d.ts.map +1 -1
- package/dist/types/utils/contractSnapshot.d.ts +123 -0
- package/dist/types/utils/contractSnapshot.d.ts.map +1 -0
- package/dist/types/utils/contractSnapshot.test.d.ts +2 -0
- package/dist/types/utils/contractSnapshot.test.d.ts.map +1 -0
- package/dist/types/utils/index.d.ts +2 -1
- package/dist/types/utils/index.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,23 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* @purpose Reservation bid math
|
|
3
|
+
* @purpose Reservation bid math (pure formula + type)
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* Mirror of the on-chain `ConfigState::bid_min_stardust` formula so UIs
|
|
6
|
+
* can preview the contest minimum-bid floor without hitting an RPC for
|
|
7
|
+
* every keystroke. Fetch-aware helpers (`getMinimumBid`,
|
|
8
|
+
* `computeMinimumBidFromSnapshot`) live in `./contractSnapshot` — they
|
|
9
|
+
* call into the pure formula here.
|
|
10
10
|
*/
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.computeMinimumBid = computeMinimumBid;
|
|
13
|
-
exports.getMinimumBid = getMinimumBid;
|
|
14
|
-
const config_1 = require("../accounts/config");
|
|
15
|
-
const contract_1 = require("../accounts/contract");
|
|
16
|
-
const rental_1 = require("../accounts/rental");
|
|
17
|
-
const srsly_1 = require("../pda/srsly");
|
|
18
|
-
const config_2 = require("./config");
|
|
19
|
-
const rpc_1 = require("./rpc");
|
|
20
|
-
const SYSTEM_PROGRAM_ID = '11111111111111111111111111111111';
|
|
21
13
|
/**
|
|
22
14
|
* Pure math: contest minimum-bid floor in stardust.
|
|
23
15
|
*
|
|
@@ -46,105 +38,4 @@ function computeMinimumBid(args) {
|
|
|
46
38
|
const base = args.rateStardust > defenderBid ? args.rateStardust : defenderBid;
|
|
47
39
|
return (base * effBps) / 10000n;
|
|
48
40
|
}
|
|
49
|
-
/**
|
|
50
|
-
* High-level helper: compute the contest minimum bid for a contract right
|
|
51
|
-
* now (or at `now + delaySeconds`).
|
|
52
|
-
*
|
|
53
|
-
* Fetches `ConfigState`, `ContractState`, and the active/queued `RentalState`
|
|
54
|
-
* accounts, derives `closeness` from the active rental window, and returns
|
|
55
|
-
* the floor a challenger must clear plus enough context to render a UI.
|
|
56
|
-
*
|
|
57
|
-
* @example
|
|
58
|
-
* ```ts
|
|
59
|
-
* const floor = await getMinimumBid({ contractAddress: 'Abc...' });
|
|
60
|
-
* console.log('Bid at least', floor.minBidStardust, 'stardust');
|
|
61
|
-
*
|
|
62
|
-
* // Preview the floor 4 hours from now (snipe-window pricing):
|
|
63
|
-
* const later = await getMinimumBid({
|
|
64
|
-
* contractAddress: 'Abc...',
|
|
65
|
-
* delaySeconds: 4 * 60 * 60,
|
|
66
|
-
* });
|
|
67
|
-
* ```
|
|
68
|
-
*
|
|
69
|
-
* If the contract has no active rental yet, closeness = 0 and the floor
|
|
70
|
-
* collapses to the rate-bump floor (`rate × captureRate`).
|
|
71
|
-
*/
|
|
72
|
-
async function getMinimumBid(args) {
|
|
73
|
-
const rpcUrl = args.rpcUrl ?? (0, config_2.getRpcUrl)();
|
|
74
|
-
const rpc = (0, rpc_1.createRpc)(rpcUrl);
|
|
75
|
-
const cfgPromise = (0, config_1.fetchConfig)(rpcUrl);
|
|
76
|
-
const contractPromise = (0, contract_1.fetchContract)(args.contractAddress, rpcUrl);
|
|
77
|
-
const [cfg, contract] = await Promise.all([cfgPromise, contractPromise]);
|
|
78
|
-
const cfgData = cfg.data;
|
|
79
|
-
const contractData = contract.data;
|
|
80
|
-
const rateStardust = BigInt(contractData.rate);
|
|
81
|
-
const atlasPerPoint = args.atlasPerPoint ?? BigInt(cfgData.atlasPerPoint);
|
|
82
|
-
const stardustPerAtlas = BigInt(cfgData.stardustToAtlas);
|
|
83
|
-
const activeAddr = await (0, srsly_1.deriveActiveRental)(contract.address);
|
|
84
|
-
const queuedAddr = await (0, srsly_1.deriveQueuedRental)(contract.address);
|
|
85
|
-
// Active rental — only meaningful if the contract field points at it.
|
|
86
|
-
let activeStart = null;
|
|
87
|
-
let activeEnd = null;
|
|
88
|
-
if (contractData.activeRental && contractData.activeRental.toString() !== SYSTEM_PROGRAM_ID) {
|
|
89
|
-
try {
|
|
90
|
-
const active = await (0, rental_1.fetchRental)(activeAddr, rpcUrl);
|
|
91
|
-
const a = active.data;
|
|
92
|
-
activeStart = Number(a.startTime);
|
|
93
|
-
activeEnd = Number(a.endTime);
|
|
94
|
-
}
|
|
95
|
-
catch {
|
|
96
|
-
// Account missing despite contract pointer — treat as no active rental.
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
// Queued rental — defender bid lives here if a reservation exists.
|
|
100
|
-
let defenderBidStardust = 0n;
|
|
101
|
-
if (contractData.queuedRental && contractData.queuedRental.toString() !== SYSTEM_PROGRAM_ID) {
|
|
102
|
-
try {
|
|
103
|
-
const queued = await (0, rental_1.fetchRental)(queuedAddr, rpcUrl);
|
|
104
|
-
const q = queued.data;
|
|
105
|
-
const bidAtlas = BigInt(q.bidAtlas);
|
|
106
|
-
const bidPoints = BigInt(q.bidPoints);
|
|
107
|
-
// Points are 8-decimal dust; converting to stardust requires the same
|
|
108
|
-
// 8-decimal precision: stardust = points_dust * atlasPerPoint *
|
|
109
|
-
// stardustPerAtlas / 1e8. With both at 1e8 precision this collapses
|
|
110
|
-
// to points_dust * atlasPerPoint.
|
|
111
|
-
const pointsAsStardust = bidPoints > 0n ? (bidPoints * atlasPerPoint * stardustPerAtlas) / 100000000n : 0n;
|
|
112
|
-
defenderBidStardust = bidAtlas + pointsAsStardust;
|
|
113
|
-
}
|
|
114
|
-
catch {
|
|
115
|
-
// Missing queued account — leave defenderBidStardust = 0.
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
const evaluatedAtSeconds = args.nowSeconds !== undefined
|
|
119
|
-
? Math.floor(args.nowSeconds)
|
|
120
|
-
: Math.floor(Date.now() / 1000) + Math.max(0, args.delaySeconds ?? 0);
|
|
121
|
-
let closeness = 0;
|
|
122
|
-
if (activeStart !== null && activeEnd !== null && activeEnd > activeStart) {
|
|
123
|
-
const span = activeEnd - activeStart;
|
|
124
|
-
const elapsed = evaluatedAtSeconds - activeStart;
|
|
125
|
-
closeness = Math.max(0, Math.min(1, elapsed / span));
|
|
126
|
-
}
|
|
127
|
-
const minBidStardust = computeMinimumBid({
|
|
128
|
-
rateStardust,
|
|
129
|
-
defenderBidStardust,
|
|
130
|
-
contestedMultiplierMaxBps: cfgData.contestedMultiplierMaxBps,
|
|
131
|
-
captureRateBps: BigInt(cfgData.captureRateBps),
|
|
132
|
-
closenessFraction: closeness,
|
|
133
|
-
});
|
|
134
|
-
const baseStardust = rateStardust > defenderBidStardust ? rateStardust : defenderBidStardust;
|
|
135
|
-
const rampMultiplier = baseStardust > 0n ? Number(minBidStardust) / Number(baseStardust) : 1;
|
|
136
|
-
// RPC reference kept to match the codebase pattern even when unused;
|
|
137
|
-
// future refinements (e.g. fetching chain time) can plug in here.
|
|
138
|
-
void rpc;
|
|
139
|
-
return {
|
|
140
|
-
minBidStardust,
|
|
141
|
-
defenderBidStardust,
|
|
142
|
-
rateStardust,
|
|
143
|
-
closenessFraction: closeness,
|
|
144
|
-
rampMultiplier,
|
|
145
|
-
evaluatedAtSeconds,
|
|
146
|
-
activeEndSeconds: activeEnd,
|
|
147
|
-
activeStartSeconds: activeStart,
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
41
|
//# sourceMappingURL=bidMath.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bidMath.js","sourceRoot":"","sources":["../../../src/utils/bidMath.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;
|
|
1
|
+
{"version":3,"file":"bidMath.js","sourceRoot":"","sources":["../../../src/utils/bidMath.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;AAiBH,8CAkBC;AAjCD;;;;;;;;;;;;;;GAcG;AACH,SAAgB,iBAAiB,CAAC,IAMjC;IACC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACnE,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAC;IACrE,MAAM,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAC;IAC/B,kEAAkE;IAClE,MAAM,SAAS,GAAG,MAAO,GAAG,CAAC,QAAQ,GAAG,YAAY,CAAC,GAAG,IAAI,CAAC;IAC7D,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,GAAG,MAAO,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,MAAO,CAAC;IAC7E,MAAM,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;IACvD,MAAM,WAAW,GAAG,IAAI,CAAC,mBAAmB,IAAI,EAAE,CAAC;IACnD,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC;IAC/E,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,GAAG,MAAO,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @purpose Aggregated point-in-time view of a contract and its rentals
|
|
4
|
+
*
|
|
5
|
+
* One-shot fetch that pulls every on-chain account relevant to a single
|
|
6
|
+
* contract — `ConfigState`, `ContractState`, and the active / queued
|
|
7
|
+
* `RentalState`s (when they exist) — and also computes the contest
|
|
8
|
+
* minimum-bid floor evaluated at "now". The raw account states are
|
|
9
|
+
* exposed verbatim so callers decide what matters; `minimumBid` is the
|
|
10
|
+
* one piece of derived data that nearly every consumer of this snapshot
|
|
11
|
+
* needs.
|
|
12
|
+
*
|
|
13
|
+
* Granular `fetchConfig` / `fetchContract` / `fetchRental` remain
|
|
14
|
+
* available for narrow lookups that don't need the whole picture.
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.getContractSnapshot = getContractSnapshot;
|
|
18
|
+
exports.resolveContractSnapshot = resolveContractSnapshot;
|
|
19
|
+
exports.computeMinimumBidFromSnapshot = computeMinimumBidFromSnapshot;
|
|
20
|
+
exports.getMinimumBid = getMinimumBid;
|
|
21
|
+
const kit_1 = require("@solana/kit");
|
|
22
|
+
const config_1 = require("../accounts/config");
|
|
23
|
+
const contract_1 = require("../accounts/contract");
|
|
24
|
+
const rental_1 = require("../accounts/rental");
|
|
25
|
+
const srsly_1 = require("../pda/srsly");
|
|
26
|
+
const config_2 = require("./config");
|
|
27
|
+
const bidMath_1 = require("./bidMath");
|
|
28
|
+
const SYSTEM_PROGRAM_ID = '11111111111111111111111111111111';
|
|
29
|
+
/**
|
|
30
|
+
* Fetch a contract and every account directly attached to it in one shot,
|
|
31
|
+
* then derive the contest minimum-bid floor at "now".
|
|
32
|
+
*
|
|
33
|
+
* Strategy: fetch `ConfigState` and `ContractState` in parallel, then read
|
|
34
|
+
* the contract's `activeRental` / `queuedRental` pointers and fetch
|
|
35
|
+
* whichever ones exist (in parallel). Pointers that equal SystemProgram
|
|
36
|
+
* are skipped without an RPC call. The bid floor is computed locally
|
|
37
|
+
* once all states are in.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* const snap = await getContractSnapshot({ contractAddress: 'Abc...' });
|
|
42
|
+
* const rate = snap.contract.data.rate;
|
|
43
|
+
* const defenderBid = snap.queuedRental?.data.bidAtlas ?? 0n;
|
|
44
|
+
* const floorNow = snap.minimumBid.minBidStardust;
|
|
45
|
+
*
|
|
46
|
+
* // Project the floor 4 hours forward without re-fetching:
|
|
47
|
+
* const floorLater = computeMinimumBidFromSnapshot(snap, {
|
|
48
|
+
* delaySeconds: 4 * 60 * 60,
|
|
49
|
+
* });
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
async function getContractSnapshot(args) {
|
|
53
|
+
const rpcUrl = args.rpcUrl ?? (0, config_2.getRpcUrl)();
|
|
54
|
+
const [config, contract] = await Promise.all([
|
|
55
|
+
(0, config_1.fetchConfig)(rpcUrl),
|
|
56
|
+
(0, contract_1.fetchContract)(args.contractAddress, rpcUrl),
|
|
57
|
+
]);
|
|
58
|
+
const contractData = contract.data;
|
|
59
|
+
const activePromise = contractData.activeRental && contractData.activeRental.toString() !== SYSTEM_PROGRAM_ID
|
|
60
|
+
? (0, srsly_1.deriveActiveRental)(contract.address)
|
|
61
|
+
.then(addr => (0, rental_1.fetchRental)(addr, rpcUrl))
|
|
62
|
+
.catch(() => null)
|
|
63
|
+
: Promise.resolve(null);
|
|
64
|
+
const queuedPromise = contractData.queuedRental && contractData.queuedRental.toString() !== SYSTEM_PROGRAM_ID
|
|
65
|
+
? (0, srsly_1.deriveQueuedRental)(contract.address)
|
|
66
|
+
.then(addr => (0, rental_1.fetchRental)(addr, rpcUrl))
|
|
67
|
+
.catch(() => null)
|
|
68
|
+
: Promise.resolve(null);
|
|
69
|
+
const [activeRental, queuedRental] = await Promise.all([activePromise, queuedPromise]);
|
|
70
|
+
const partialSnap = { config, contract, activeRental, queuedRental };
|
|
71
|
+
const minimumBid = computeMinimumBidFromSnapshot(partialSnap);
|
|
72
|
+
return { ...partialSnap, minimumBid };
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Resolve a `ContractSnapshot` from caller-supplied data or fetch fresh.
|
|
76
|
+
*
|
|
77
|
+
* Designed for callers (e.g. UIs) that already have a snapshot in hand and
|
|
78
|
+
* want to skip the RPC roundtrip when building an instruction. Behavior:
|
|
79
|
+
*
|
|
80
|
+
* 1. If no snapshot is supplied → fetch a fresh one.
|
|
81
|
+
* 2. If snapshot's contract address doesn't match `contractAddress` →
|
|
82
|
+
* throw immediately (programmer error).
|
|
83
|
+
* 3. If snapshot's rental fields are stale relative to the contract's
|
|
84
|
+
* pointers (contract says a rental exists but snapshot has `null` —
|
|
85
|
+
* typical when the snapshot was fetched mid-state-change) → lazy
|
|
86
|
+
* refetch the snapshot once.
|
|
87
|
+
* 4. If still stale after the refetch → throw. The on-chain reality
|
|
88
|
+
* conflicts with itself; let the caller decide how to recover.
|
|
89
|
+
*/
|
|
90
|
+
async function resolveContractSnapshot(args) {
|
|
91
|
+
if (!args.snapshot) {
|
|
92
|
+
return getContractSnapshot({
|
|
93
|
+
contractAddress: args.contractAddress,
|
|
94
|
+
rpcUrl: args.rpcUrl,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
const requested = (0, kit_1.address)(args.contractAddress);
|
|
98
|
+
if (args.snapshot.contract.address !== requested) {
|
|
99
|
+
throw new Error(`Provided snapshot is for contract ${args.snapshot.contract.address}, expected ${requested}`);
|
|
100
|
+
}
|
|
101
|
+
if (!isSnapshotStale(args.snapshot)) {
|
|
102
|
+
return args.snapshot;
|
|
103
|
+
}
|
|
104
|
+
const fresh = await getContractSnapshot({
|
|
105
|
+
contractAddress: args.contractAddress,
|
|
106
|
+
rpcUrl: args.rpcUrl,
|
|
107
|
+
});
|
|
108
|
+
if (isSnapshotStale(fresh)) {
|
|
109
|
+
throw new Error(`Contract ${requested} has a rental pointer set but the rental account could not be loaded after lazy refetch`);
|
|
110
|
+
}
|
|
111
|
+
return fresh;
|
|
112
|
+
}
|
|
113
|
+
function isSnapshotStale(snap) {
|
|
114
|
+
const activeStale = snap.contract.data.activeRental.toString() !== SYSTEM_PROGRAM_ID && !snap.activeRental;
|
|
115
|
+
const queuedStale = snap.contract.data.queuedRental.toString() !== SYSTEM_PROGRAM_ID && !snap.queuedRental;
|
|
116
|
+
return activeStale || queuedStale;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Pure derivation of `MinimumBid` from an already-fetched snapshot. No RPC.
|
|
120
|
+
*
|
|
121
|
+
* Use when the caller has a snapshot and wants the floor at a custom time
|
|
122
|
+
* projection (`delaySeconds` / `nowSeconds`) or with an overridden
|
|
123
|
+
* `atlasPerPoint` ratio. For the at-fetch-time floor, read
|
|
124
|
+
* `snap.minimumBid` directly.
|
|
125
|
+
*/
|
|
126
|
+
function computeMinimumBidFromSnapshot(snap, opts = {}) {
|
|
127
|
+
const cfgData = snap.config.data;
|
|
128
|
+
const contractData = snap.contract.data;
|
|
129
|
+
const rateStardust = BigInt(contractData.rate);
|
|
130
|
+
const atlasPerPoint = opts.atlasPerPoint ?? BigInt(cfgData.atlasPerPoint);
|
|
131
|
+
const stardustPerAtlas = BigInt(cfgData.stardustToAtlas);
|
|
132
|
+
const activeStart = snap.activeRental ? Number(snap.activeRental.data.startTime) : null;
|
|
133
|
+
const activeEnd = snap.activeRental ? Number(snap.activeRental.data.endTime) : null;
|
|
134
|
+
let defenderBidStardust = 0n;
|
|
135
|
+
if (snap.queuedRental) {
|
|
136
|
+
const q = snap.queuedRental.data;
|
|
137
|
+
const bidAtlas = BigInt(q.bidAtlas);
|
|
138
|
+
const bidPoints = BigInt(q.bidPoints);
|
|
139
|
+
// Points are 8-decimal dust; converting to stardust requires the same
|
|
140
|
+
// 8-decimal precision: stardust = points_dust * atlasPerPoint *
|
|
141
|
+
// stardustPerAtlas / 1e8. With both at 1e8 precision this collapses
|
|
142
|
+
// to points_dust * atlasPerPoint.
|
|
143
|
+
const pointsAsStardust = bidPoints > 0n ? (bidPoints * atlasPerPoint * stardustPerAtlas) / 100000000n : 0n;
|
|
144
|
+
defenderBidStardust = bidAtlas + pointsAsStardust;
|
|
145
|
+
}
|
|
146
|
+
const evaluatedAtSeconds = opts.nowSeconds !== undefined
|
|
147
|
+
? Math.floor(opts.nowSeconds)
|
|
148
|
+
: Math.floor(Date.now() / 1000) + Math.max(0, opts.delaySeconds ?? 0);
|
|
149
|
+
let closeness = 0;
|
|
150
|
+
if (activeStart !== null && activeEnd !== null && activeEnd > activeStart) {
|
|
151
|
+
const span = activeEnd - activeStart;
|
|
152
|
+
const elapsed = evaluatedAtSeconds - activeStart;
|
|
153
|
+
closeness = Math.max(0, Math.min(1, elapsed / span));
|
|
154
|
+
}
|
|
155
|
+
const minBidStardust = (0, bidMath_1.computeMinimumBid)({
|
|
156
|
+
rateStardust,
|
|
157
|
+
defenderBidStardust,
|
|
158
|
+
contestedMultiplierMaxBps: cfgData.contestedMultiplierMaxBps,
|
|
159
|
+
captureRateBps: BigInt(cfgData.captureRateBps),
|
|
160
|
+
closenessFraction: closeness,
|
|
161
|
+
});
|
|
162
|
+
const baseStardust = rateStardust > defenderBidStardust ? rateStardust : defenderBidStardust;
|
|
163
|
+
const rampMultiplier = baseStardust > 0n ? Number(minBidStardust) / Number(baseStardust) : 1;
|
|
164
|
+
return {
|
|
165
|
+
minBidStardust,
|
|
166
|
+
defenderBidStardust,
|
|
167
|
+
rateStardust,
|
|
168
|
+
closenessFraction: closeness,
|
|
169
|
+
rampMultiplier,
|
|
170
|
+
evaluatedAtSeconds,
|
|
171
|
+
activeEndSeconds: activeEnd,
|
|
172
|
+
activeStartSeconds: activeStart,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Convenience wrapper: fetch a snapshot and return only its `minimumBid`.
|
|
177
|
+
*
|
|
178
|
+
* Same fetches as `getContractSnapshot` — if you need the contract / rental
|
|
179
|
+
* states too, call `getContractSnapshot` directly so you don't fetch twice.
|
|
180
|
+
*
|
|
181
|
+
* For time-projected floors, pass `delaySeconds` or `nowSeconds`; the
|
|
182
|
+
* underlying fetch is identical.
|
|
183
|
+
*/
|
|
184
|
+
async function getMinimumBid(args) {
|
|
185
|
+
if (args.snapshot) {
|
|
186
|
+
return computeMinimumBidFromSnapshot(args.snapshot, {
|
|
187
|
+
delaySeconds: args.delaySeconds,
|
|
188
|
+
nowSeconds: args.nowSeconds,
|
|
189
|
+
atlasPerPoint: args.atlasPerPoint,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
const snap = await getContractSnapshot({
|
|
193
|
+
contractAddress: args.contractAddress,
|
|
194
|
+
rpcUrl: args.rpcUrl,
|
|
195
|
+
});
|
|
196
|
+
if (args.delaySeconds === undefined &&
|
|
197
|
+
args.nowSeconds === undefined &&
|
|
198
|
+
args.atlasPerPoint === undefined) {
|
|
199
|
+
return snap.minimumBid;
|
|
200
|
+
}
|
|
201
|
+
return computeMinimumBidFromSnapshot(snap, {
|
|
202
|
+
delaySeconds: args.delaySeconds,
|
|
203
|
+
nowSeconds: args.nowSeconds,
|
|
204
|
+
atlasPerPoint: args.atlasPerPoint,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=contractSnapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contractSnapshot.js","sourceRoot":"","sources":["../../../src/utils/contractSnapshot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
vitest_1.vi.mock('../accounts/config', () => ({
|
|
5
|
+
fetchConfig: vitest_1.vi.fn(),
|
|
6
|
+
}));
|
|
7
|
+
vitest_1.vi.mock('../accounts/contract', () => ({
|
|
8
|
+
fetchContract: vitest_1.vi.fn(),
|
|
9
|
+
}));
|
|
10
|
+
vitest_1.vi.mock('../accounts/rental', () => ({
|
|
11
|
+
fetchRental: vitest_1.vi.fn(),
|
|
12
|
+
}));
|
|
13
|
+
vitest_1.vi.mock('../pda/srsly', () => ({
|
|
14
|
+
deriveActiveRental: vitest_1.vi.fn(),
|
|
15
|
+
deriveQueuedRental: vitest_1.vi.fn(),
|
|
16
|
+
}));
|
|
17
|
+
vitest_1.vi.mock('./config', () => ({
|
|
18
|
+
getRpcUrl: () => 'http://localhost:8899',
|
|
19
|
+
}));
|
|
20
|
+
const config_1 = require("../accounts/config");
|
|
21
|
+
const contract_1 = require("../accounts/contract");
|
|
22
|
+
const rental_1 = require("../accounts/rental");
|
|
23
|
+
const srsly_1 = require("../pda/srsly");
|
|
24
|
+
const contractSnapshot_1 = require("./contractSnapshot");
|
|
25
|
+
const SYSTEM = '11111111111111111111111111111111';
|
|
26
|
+
// Real validated 32-byte base58 addresses for test fixtures.
|
|
27
|
+
const CONTRACT_ADDR = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';
|
|
28
|
+
const ACTIVE_ADDR = 'So11111111111111111111111111111111111111112';
|
|
29
|
+
const QUEUED_ADDR = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA';
|
|
30
|
+
const OTHER_ADDR = 'BPFLoader2111111111111111111111111111111111';
|
|
31
|
+
const VAULT_ADDR = 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL';
|
|
32
|
+
const makeConfig = (overrides = {}) => ({
|
|
33
|
+
stardustToAtlas: 100000000n,
|
|
34
|
+
atlasPerPoint: 100n,
|
|
35
|
+
captureRateBps: 10500n,
|
|
36
|
+
contestedMultiplierMaxBps: 465,
|
|
37
|
+
slyvault: VAULT_ADDR,
|
|
38
|
+
atlasMint: VAULT_ADDR,
|
|
39
|
+
...overrides,
|
|
40
|
+
});
|
|
41
|
+
const makeContract = (overrides = {}) => ({
|
|
42
|
+
rate: 100000000n,
|
|
43
|
+
activeRental: SYSTEM,
|
|
44
|
+
queuedRental: SYSTEM,
|
|
45
|
+
fleet: VAULT_ADDR,
|
|
46
|
+
gameId: VAULT_ADDR,
|
|
47
|
+
thread: SYSTEM,
|
|
48
|
+
...overrides,
|
|
49
|
+
});
|
|
50
|
+
const makeRental = (overrides = {}) => ({
|
|
51
|
+
bidAtlas: 0n,
|
|
52
|
+
bidPoints: 0n,
|
|
53
|
+
startTime: 0n,
|
|
54
|
+
endTime: 0n,
|
|
55
|
+
...overrides,
|
|
56
|
+
});
|
|
57
|
+
(0, vitest_1.beforeEach)(() => {
|
|
58
|
+
vitest_1.vi.clearAllMocks();
|
|
59
|
+
vitest_1.vi.mocked(srsly_1.deriveActiveRental).mockResolvedValue(ACTIVE_ADDR);
|
|
60
|
+
vitest_1.vi.mocked(srsly_1.deriveQueuedRental).mockResolvedValue(QUEUED_ADDR);
|
|
61
|
+
});
|
|
62
|
+
(0, vitest_1.describe)('getContractSnapshot', () => {
|
|
63
|
+
(0, vitest_1.it)('returns null rentals when contract pointers are SystemProgram', async () => {
|
|
64
|
+
vitest_1.vi.mocked(config_1.fetchConfig).mockResolvedValue({ data: makeConfig(), address: 'CFG' });
|
|
65
|
+
vitest_1.vi.mocked(contract_1.fetchContract).mockResolvedValue({
|
|
66
|
+
data: makeContract(),
|
|
67
|
+
address: CONTRACT_ADDR,
|
|
68
|
+
});
|
|
69
|
+
const snap = await (0, contractSnapshot_1.getContractSnapshot)({ contractAddress: CONTRACT_ADDR });
|
|
70
|
+
(0, vitest_1.expect)(snap.activeRental).toBeNull();
|
|
71
|
+
(0, vitest_1.expect)(snap.queuedRental).toBeNull();
|
|
72
|
+
(0, vitest_1.expect)(rental_1.fetchRental).not.toHaveBeenCalled();
|
|
73
|
+
(0, vitest_1.expect)(snap.minimumBid).toBeDefined();
|
|
74
|
+
});
|
|
75
|
+
(0, vitest_1.it)('fetches active + queued when contract pointers are set', async () => {
|
|
76
|
+
vitest_1.vi.mocked(config_1.fetchConfig).mockResolvedValue({ data: makeConfig(), address: 'CFG' });
|
|
77
|
+
vitest_1.vi.mocked(contract_1.fetchContract).mockResolvedValue({
|
|
78
|
+
data: makeContract({ activeRental: ACTIVE_ADDR, queuedRental: QUEUED_ADDR }),
|
|
79
|
+
address: CONTRACT_ADDR,
|
|
80
|
+
});
|
|
81
|
+
vitest_1.vi.mocked(rental_1.fetchRental).mockImplementation(async (addr) => ({
|
|
82
|
+
data: makeRental(),
|
|
83
|
+
address: addr,
|
|
84
|
+
}));
|
|
85
|
+
const snap = await (0, contractSnapshot_1.getContractSnapshot)({ contractAddress: CONTRACT_ADDR });
|
|
86
|
+
(0, vitest_1.expect)(snap.activeRental?.address).toBe(ACTIVE_ADDR);
|
|
87
|
+
(0, vitest_1.expect)(snap.queuedRental?.address).toBe(QUEUED_ADDR);
|
|
88
|
+
(0, vitest_1.expect)(rental_1.fetchRental).toHaveBeenCalledTimes(2);
|
|
89
|
+
});
|
|
90
|
+
(0, vitest_1.it)('returns null when pointer is set but fetchRental throws (stale pointer)', async () => {
|
|
91
|
+
vitest_1.vi.mocked(config_1.fetchConfig).mockResolvedValue({ data: makeConfig(), address: 'CFG' });
|
|
92
|
+
vitest_1.vi.mocked(contract_1.fetchContract).mockResolvedValue({
|
|
93
|
+
data: makeContract({ activeRental: ACTIVE_ADDR }),
|
|
94
|
+
address: CONTRACT_ADDR,
|
|
95
|
+
});
|
|
96
|
+
vitest_1.vi.mocked(rental_1.fetchRental).mockRejectedValue(new Error('not found'));
|
|
97
|
+
const snap = await (0, contractSnapshot_1.getContractSnapshot)({ contractAddress: CONTRACT_ADDR });
|
|
98
|
+
(0, vitest_1.expect)(snap.activeRental).toBeNull();
|
|
99
|
+
(0, vitest_1.expect)(snap.queuedRental).toBeNull();
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
(0, vitest_1.describe)('computeMinimumBidFromSnapshot', () => {
|
|
103
|
+
const buildSnap = (parts) => ({
|
|
104
|
+
config: { data: makeConfig(), address: 'CFG' },
|
|
105
|
+
contract: {
|
|
106
|
+
data: makeContract({
|
|
107
|
+
rate: parts.rate ?? 100000000n,
|
|
108
|
+
activeRental: parts.activeStart !== undefined ? ACTIVE_ADDR : SYSTEM,
|
|
109
|
+
queuedRental: parts.queuedBidAtlas !== undefined || parts.queuedBidPoints !== undefined
|
|
110
|
+
? QUEUED_ADDR
|
|
111
|
+
: SYSTEM,
|
|
112
|
+
}),
|
|
113
|
+
address: CONTRACT_ADDR,
|
|
114
|
+
},
|
|
115
|
+
activeRental: parts.activeStart !== undefined
|
|
116
|
+
? {
|
|
117
|
+
data: makeRental({
|
|
118
|
+
startTime: parts.activeStart,
|
|
119
|
+
endTime: parts.activeEnd ?? parts.activeStart + 86400n,
|
|
120
|
+
}),
|
|
121
|
+
address: ACTIVE_ADDR,
|
|
122
|
+
}
|
|
123
|
+
: null,
|
|
124
|
+
queuedRental: parts.queuedBidAtlas !== undefined || parts.queuedBidPoints !== undefined
|
|
125
|
+
? {
|
|
126
|
+
data: makeRental({
|
|
127
|
+
bidAtlas: parts.queuedBidAtlas ?? 0n,
|
|
128
|
+
bidPoints: parts.queuedBidPoints ?? 0n,
|
|
129
|
+
}),
|
|
130
|
+
address: QUEUED_ADDR,
|
|
131
|
+
}
|
|
132
|
+
: null,
|
|
133
|
+
});
|
|
134
|
+
(0, vitest_1.it)('no defender → floor = rate × captureRate cap', async () => {
|
|
135
|
+
const snap = buildSnap({ rate: 100000000n });
|
|
136
|
+
const bid = (0, contractSnapshot_1.computeMinimumBidFromSnapshot)(snap);
|
|
137
|
+
(0, vitest_1.expect)(bid.defenderBidStardust).toBe(0n);
|
|
138
|
+
// rate * captureRateBps / baseBps = 100M * 10500 / 10000 = 105M
|
|
139
|
+
(0, vitest_1.expect)(bid.minBidStardust).toBe(105000000n);
|
|
140
|
+
(0, vitest_1.expect)(bid.closenessFraction).toBe(0);
|
|
141
|
+
});
|
|
142
|
+
(0, vitest_1.it)('defender ATLAS bid raises floor above rate when bid > rate', async () => {
|
|
143
|
+
const snap = buildSnap({ rate: 100000000n, queuedBidAtlas: 200000000n });
|
|
144
|
+
const bid = (0, contractSnapshot_1.computeMinimumBidFromSnapshot)(snap);
|
|
145
|
+
(0, vitest_1.expect)(bid.defenderBidStardust).toBe(200000000n);
|
|
146
|
+
// base = max(rate, defender) = 200M, ramp at closeness=0 capped to 10500/10000 = 1.05x
|
|
147
|
+
(0, vitest_1.expect)(bid.minBidStardust).toBe(210000000n);
|
|
148
|
+
});
|
|
149
|
+
(0, vitest_1.it)('closeness ramps from 1× to maxMult as active rental nears end', async () => {
|
|
150
|
+
const now = 1_000_000;
|
|
151
|
+
const start = BigInt(now - 50);
|
|
152
|
+
const end = BigInt(now + 50);
|
|
153
|
+
const snap = buildSnap({
|
|
154
|
+
rate: 100000000n,
|
|
155
|
+
queuedBidAtlas: 100000000n,
|
|
156
|
+
activeStart: start,
|
|
157
|
+
activeEnd: end,
|
|
158
|
+
});
|
|
159
|
+
const bid = (0, contractSnapshot_1.computeMinimumBidFromSnapshot)(snap, { nowSeconds: now });
|
|
160
|
+
// closeness = 50/100 = 0.5
|
|
161
|
+
(0, vitest_1.expect)(bid.closenessFraction).toBeCloseTo(0.5, 5);
|
|
162
|
+
// ramp_bps = 10000 + (465 - 100) * 5000 / 100 = 10000 + 18250 = 28250 → 2.825×
|
|
163
|
+
// floor = 100M * 28250 / 10000 = 282_500_000
|
|
164
|
+
(0, vitest_1.expect)(bid.minBidStardust).toBe(282500000n);
|
|
165
|
+
});
|
|
166
|
+
(0, vitest_1.it)('delaySeconds projects closeness forward without RPC', async () => {
|
|
167
|
+
const start = 1000000n;
|
|
168
|
+
const end = 1000100n;
|
|
169
|
+
const snap = buildSnap({
|
|
170
|
+
rate: 100000000n,
|
|
171
|
+
queuedBidAtlas: 100000000n,
|
|
172
|
+
activeStart: start,
|
|
173
|
+
activeEnd: end,
|
|
174
|
+
});
|
|
175
|
+
const now = (0, contractSnapshot_1.computeMinimumBidFromSnapshot)(snap, { nowSeconds: 1_000_000 });
|
|
176
|
+
const later = (0, contractSnapshot_1.computeMinimumBidFromSnapshot)(snap, { nowSeconds: 1_000_050 });
|
|
177
|
+
(0, vitest_1.expect)(now.closenessFraction).toBe(0);
|
|
178
|
+
(0, vitest_1.expect)(later.closenessFraction).toBeCloseTo(0.5, 5);
|
|
179
|
+
(0, vitest_1.expect)(later.minBidStardust).toBeGreaterThan(now.minBidStardust);
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
(0, vitest_1.describe)('resolveContractSnapshot', () => {
|
|
183
|
+
(0, vitest_1.it)('fetches fresh when no snapshot provided', async () => {
|
|
184
|
+
vitest_1.vi.mocked(config_1.fetchConfig).mockResolvedValue({ data: makeConfig(), address: 'CFG' });
|
|
185
|
+
vitest_1.vi.mocked(contract_1.fetchContract).mockResolvedValue({
|
|
186
|
+
data: makeContract(),
|
|
187
|
+
address: CONTRACT_ADDR,
|
|
188
|
+
});
|
|
189
|
+
await (0, contractSnapshot_1.resolveContractSnapshot)({ contractAddress: CONTRACT_ADDR });
|
|
190
|
+
(0, vitest_1.expect)(contract_1.fetchContract).toHaveBeenCalledTimes(1);
|
|
191
|
+
});
|
|
192
|
+
(0, vitest_1.it)('returns provided snapshot as-is when address matches and no staleness', async () => {
|
|
193
|
+
vitest_1.vi.mocked(config_1.fetchConfig).mockResolvedValue({ data: makeConfig(), address: 'CFG' });
|
|
194
|
+
vitest_1.vi.mocked(contract_1.fetchContract).mockResolvedValue({
|
|
195
|
+
data: makeContract(),
|
|
196
|
+
address: CONTRACT_ADDR,
|
|
197
|
+
});
|
|
198
|
+
const snap = await (0, contractSnapshot_1.getContractSnapshot)({ contractAddress: CONTRACT_ADDR });
|
|
199
|
+
vitest_1.vi.clearAllMocks();
|
|
200
|
+
const resolved = await (0, contractSnapshot_1.resolveContractSnapshot)({
|
|
201
|
+
contractAddress: CONTRACT_ADDR,
|
|
202
|
+
snapshot: snap,
|
|
203
|
+
});
|
|
204
|
+
(0, vitest_1.expect)(resolved).toBe(snap);
|
|
205
|
+
(0, vitest_1.expect)(contract_1.fetchContract).not.toHaveBeenCalled();
|
|
206
|
+
});
|
|
207
|
+
(0, vitest_1.it)('throws when snapshot contract address does not match', async () => {
|
|
208
|
+
vitest_1.vi.mocked(config_1.fetchConfig).mockResolvedValue({ data: makeConfig(), address: VAULT_ADDR });
|
|
209
|
+
vitest_1.vi.mocked(contract_1.fetchContract).mockResolvedValue({ data: makeContract(), address: OTHER_ADDR });
|
|
210
|
+
const snap = await (0, contractSnapshot_1.getContractSnapshot)({ contractAddress: OTHER_ADDR });
|
|
211
|
+
await (0, vitest_1.expect)((0, contractSnapshot_1.resolveContractSnapshot)({ contractAddress: CONTRACT_ADDR, snapshot: snap })).rejects.toThrow(/snapshot is for contract/);
|
|
212
|
+
});
|
|
213
|
+
(0, vitest_1.it)('lazy-refetches when snapshot is stale (pointer set, rental null)', async () => {
|
|
214
|
+
// First fetch: pointer set but rental fetch fails → snap.activeRental = null (stale)
|
|
215
|
+
vitest_1.vi.mocked(config_1.fetchConfig).mockResolvedValue({ data: makeConfig(), address: 'CFG' });
|
|
216
|
+
vitest_1.vi.mocked(contract_1.fetchContract).mockResolvedValue({
|
|
217
|
+
data: makeContract({ activeRental: ACTIVE_ADDR }),
|
|
218
|
+
address: CONTRACT_ADDR,
|
|
219
|
+
});
|
|
220
|
+
vitest_1.vi.mocked(rental_1.fetchRental).mockRejectedValueOnce(new Error('not found'));
|
|
221
|
+
const staleSnap = await (0, contractSnapshot_1.getContractSnapshot)({ contractAddress: CONTRACT_ADDR });
|
|
222
|
+
(0, vitest_1.expect)(staleSnap.activeRental).toBeNull();
|
|
223
|
+
// Refetch succeeds — rental now loads
|
|
224
|
+
vitest_1.vi.mocked(rental_1.fetchRental).mockResolvedValueOnce({
|
|
225
|
+
data: makeRental(),
|
|
226
|
+
address: ACTIVE_ADDR,
|
|
227
|
+
});
|
|
228
|
+
const resolved = await (0, contractSnapshot_1.resolveContractSnapshot)({
|
|
229
|
+
contractAddress: CONTRACT_ADDR,
|
|
230
|
+
snapshot: staleSnap,
|
|
231
|
+
});
|
|
232
|
+
(0, vitest_1.expect)(resolved.activeRental).not.toBeNull();
|
|
233
|
+
// resolve called fetchContract once more for refetch
|
|
234
|
+
(0, vitest_1.expect)(contract_1.fetchContract).toHaveBeenCalledTimes(2);
|
|
235
|
+
});
|
|
236
|
+
(0, vitest_1.it)('throws when still stale after lazy refetch', async () => {
|
|
237
|
+
vitest_1.vi.mocked(config_1.fetchConfig).mockResolvedValue({ data: makeConfig(), address: 'CFG' });
|
|
238
|
+
vitest_1.vi.mocked(contract_1.fetchContract).mockResolvedValue({
|
|
239
|
+
data: makeContract({ activeRental: ACTIVE_ADDR }),
|
|
240
|
+
address: CONTRACT_ADDR,
|
|
241
|
+
});
|
|
242
|
+
vitest_1.vi.mocked(rental_1.fetchRental).mockRejectedValue(new Error('not found'));
|
|
243
|
+
const staleSnap = await (0, contractSnapshot_1.getContractSnapshot)({ contractAddress: CONTRACT_ADDR });
|
|
244
|
+
await (0, vitest_1.expect)((0, contractSnapshot_1.resolveContractSnapshot)({ contractAddress: CONTRACT_ADDR, snapshot: staleSnap })).rejects.toThrow(/could not be loaded after lazy refetch/);
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
//# sourceMappingURL=contractSnapshot.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contractSnapshot.test.js","sourceRoot":"","sources":["../../../src/utils/contractSnapshot.test.ts"],"names":[],"mappings":"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"}
|