@pafi-dev/issuer 0.1.2 → 0.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/index.cjs +115 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +73 -15
- package/dist/index.d.ts +73 -15
- package/dist/index.js +115 -57
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -57,19 +57,21 @@ var MemoryPointLedger = class {
|
|
|
57
57
|
// -------------------------------------------------------------------------
|
|
58
58
|
// Read
|
|
59
59
|
// -------------------------------------------------------------------------
|
|
60
|
-
async getBalance(userAddress) {
|
|
61
|
-
const
|
|
60
|
+
async getBalance(userAddress, tokenAddress) {
|
|
61
|
+
const user = (0, import_viem.getAddress)(userAddress);
|
|
62
|
+
const token = normalizeToken(tokenAddress);
|
|
62
63
|
this.purgeExpired();
|
|
63
|
-
const total = this.balances.get(
|
|
64
|
-
const locked = this.lockedTotalFor(
|
|
64
|
+
const total = this.balances.get(balanceKey(user, token)) ?? 0n;
|
|
65
|
+
const locked = this.lockedTotalFor(user, token);
|
|
65
66
|
return total - locked;
|
|
66
67
|
}
|
|
67
|
-
async getLockedRequests(userAddress) {
|
|
68
|
-
const
|
|
68
|
+
async getLockedRequests(userAddress, tokenAddress) {
|
|
69
|
+
const user = (0, import_viem.getAddress)(userAddress);
|
|
70
|
+
const token = normalizeToken(tokenAddress);
|
|
69
71
|
this.purgeExpired();
|
|
70
72
|
const out = [];
|
|
71
73
|
for (const lock of this.locks.values()) {
|
|
72
|
-
if (lock.userAddress ===
|
|
74
|
+
if (lock.userAddress === user && lock.status === "PENDING" && (lock.tokenAddress ?? DEFAULT_TOKEN_KEY) === token) {
|
|
73
75
|
out.push({ ...lock });
|
|
74
76
|
}
|
|
75
77
|
}
|
|
@@ -78,25 +80,28 @@ var MemoryPointLedger = class {
|
|
|
78
80
|
// -------------------------------------------------------------------------
|
|
79
81
|
// Write
|
|
80
82
|
// -------------------------------------------------------------------------
|
|
81
|
-
async creditBalance(userAddress, amount, _reason) {
|
|
83
|
+
async creditBalance(userAddress, amount, _reason, tokenAddress) {
|
|
82
84
|
if (amount <= 0n) {
|
|
83
85
|
throw new Error("MemoryPointLedger: credit amount must be positive");
|
|
84
86
|
}
|
|
85
|
-
const
|
|
87
|
+
const user = (0, import_viem.getAddress)(userAddress);
|
|
88
|
+
const token = normalizeToken(tokenAddress);
|
|
89
|
+
const key = balanceKey(user, token);
|
|
86
90
|
const current = this.balances.get(key) ?? 0n;
|
|
87
91
|
this.balances.set(key, current + amount);
|
|
88
92
|
}
|
|
89
|
-
async lockForMinting(userAddress, amount, lockDurationMs) {
|
|
93
|
+
async lockForMinting(userAddress, amount, lockDurationMs, tokenAddress) {
|
|
90
94
|
if (amount <= 0n) {
|
|
91
95
|
throw new Error("MemoryPointLedger: lock amount must be positive");
|
|
92
96
|
}
|
|
93
97
|
if (lockDurationMs <= 0) {
|
|
94
98
|
throw new Error("MemoryPointLedger: lockDurationMs must be positive");
|
|
95
99
|
}
|
|
96
|
-
const
|
|
100
|
+
const user = (0, import_viem.getAddress)(userAddress);
|
|
101
|
+
const token = normalizeToken(tokenAddress);
|
|
97
102
|
this.purgeExpired();
|
|
98
|
-
const total = this.balances.get(
|
|
99
|
-
const alreadyLocked = this.lockedTotalFor(
|
|
103
|
+
const total = this.balances.get(balanceKey(user, token)) ?? 0n;
|
|
104
|
+
const alreadyLocked = this.lockedTotalFor(user, token);
|
|
100
105
|
const available = total - alreadyLocked;
|
|
101
106
|
if (available < amount) {
|
|
102
107
|
throw new Error(
|
|
@@ -105,14 +110,18 @@ var MemoryPointLedger = class {
|
|
|
105
110
|
}
|
|
106
111
|
const lockId = `lock-${this.nextLockId++}`;
|
|
107
112
|
const now = this.now();
|
|
108
|
-
|
|
113
|
+
const lock = {
|
|
109
114
|
lockId,
|
|
110
|
-
userAddress:
|
|
115
|
+
userAddress: user,
|
|
111
116
|
amount,
|
|
112
117
|
status: "PENDING",
|
|
113
118
|
createdAt: now,
|
|
114
119
|
expiresAt: now + lockDurationMs
|
|
115
|
-
}
|
|
120
|
+
};
|
|
121
|
+
if (tokenAddress !== void 0) {
|
|
122
|
+
lock.tokenAddress = (0, import_viem.getAddress)(tokenAddress);
|
|
123
|
+
}
|
|
124
|
+
this.locks.set(lockId, lock);
|
|
116
125
|
return lockId;
|
|
117
126
|
}
|
|
118
127
|
async releaseLock(lockId) {
|
|
@@ -122,11 +131,13 @@ var MemoryPointLedger = class {
|
|
|
122
131
|
this.locks.delete(lockId);
|
|
123
132
|
}
|
|
124
133
|
}
|
|
125
|
-
async deductBalance(userAddress, amount, txHash) {
|
|
134
|
+
async deductBalance(userAddress, amount, txHash, tokenAddress) {
|
|
126
135
|
if (amount <= 0n) {
|
|
127
136
|
throw new Error("MemoryPointLedger: deduct amount must be positive");
|
|
128
137
|
}
|
|
129
|
-
const
|
|
138
|
+
const user = (0, import_viem.getAddress)(userAddress);
|
|
139
|
+
const token = normalizeToken(tokenAddress);
|
|
140
|
+
const key = balanceKey(user, token);
|
|
130
141
|
const current = this.balances.get(key) ?? 0n;
|
|
131
142
|
if (current < amount) {
|
|
132
143
|
throw new Error(
|
|
@@ -135,7 +146,7 @@ var MemoryPointLedger = class {
|
|
|
135
146
|
}
|
|
136
147
|
this.balances.set(key, current - amount);
|
|
137
148
|
for (const lock of this.locks.values()) {
|
|
138
|
-
if (lock.userAddress ===
|
|
149
|
+
if (lock.userAddress === user && lock.status === "PENDING" && lock.amount === amount && (lock.tokenAddress ?? DEFAULT_TOKEN_KEY) === token) {
|
|
139
150
|
lock.status = "MINTED";
|
|
140
151
|
lock.txHash = txHash;
|
|
141
152
|
return;
|
|
@@ -165,16 +176,23 @@ var MemoryPointLedger = class {
|
|
|
165
176
|
}
|
|
166
177
|
}
|
|
167
178
|
}
|
|
168
|
-
lockedTotalFor(userAddress) {
|
|
179
|
+
lockedTotalFor(userAddress, tokenKey) {
|
|
169
180
|
let total = 0n;
|
|
170
181
|
for (const lock of this.locks.values()) {
|
|
171
|
-
if (lock.userAddress === userAddress && lock.status === "PENDING") {
|
|
182
|
+
if (lock.userAddress === userAddress && lock.status === "PENDING" && (lock.tokenAddress ?? DEFAULT_TOKEN_KEY) === tokenKey) {
|
|
172
183
|
total += lock.amount;
|
|
173
184
|
}
|
|
174
185
|
}
|
|
175
186
|
return total;
|
|
176
187
|
}
|
|
177
188
|
};
|
|
189
|
+
var DEFAULT_TOKEN_KEY = "default";
|
|
190
|
+
function normalizeToken(tokenAddress) {
|
|
191
|
+
return tokenAddress === void 0 ? DEFAULT_TOKEN_KEY : (0, import_viem.getAddress)(tokenAddress);
|
|
192
|
+
}
|
|
193
|
+
function balanceKey(user, tokenKey) {
|
|
194
|
+
return `${user}|${tokenKey}`;
|
|
195
|
+
}
|
|
178
196
|
|
|
179
197
|
// src/policy/defaultPolicy.ts
|
|
180
198
|
var DefaultPolicyEngine = class {
|
|
@@ -196,7 +214,10 @@ var DefaultPolicyEngine = class {
|
|
|
196
214
|
if (request.amount <= 0n) {
|
|
197
215
|
return { approved: false, reason: "Amount must be positive" };
|
|
198
216
|
}
|
|
199
|
-
const available = await this.ledger.getBalance(
|
|
217
|
+
const available = await this.ledger.getBalance(
|
|
218
|
+
request.userAddress,
|
|
219
|
+
request.pointTokenAddress
|
|
220
|
+
);
|
|
200
221
|
if (available < request.amount) {
|
|
201
222
|
return {
|
|
202
223
|
approved: false,
|
|
@@ -874,7 +895,8 @@ var MintingGateway = class {
|
|
|
874
895
|
lockId = await this.ledger.lockForMinting(
|
|
875
896
|
request.userAddress,
|
|
876
897
|
receiverConsent.amount,
|
|
877
|
-
lockDurationMs
|
|
898
|
+
lockDurationMs,
|
|
899
|
+
request.pointTokenAddress
|
|
878
900
|
);
|
|
879
901
|
} catch (err) {
|
|
880
902
|
throw new MintingGatewayError(
|
|
@@ -1164,11 +1186,19 @@ var PointIndexer = class {
|
|
|
1164
1186
|
* issuer to mint without going through the gateway.
|
|
1165
1187
|
*/
|
|
1166
1188
|
async finalize(evt) {
|
|
1167
|
-
const locks = await this.ledger.getLockedRequests(
|
|
1189
|
+
const locks = await this.ledger.getLockedRequests(
|
|
1190
|
+
evt.to,
|
|
1191
|
+
this.pointTokenAddress
|
|
1192
|
+
);
|
|
1168
1193
|
const match = pickMatchingLock(locks, evt.amount);
|
|
1169
1194
|
if (!match) return;
|
|
1170
1195
|
try {
|
|
1171
|
-
await this.ledger.deductBalance(
|
|
1196
|
+
await this.ledger.deductBalance(
|
|
1197
|
+
evt.to,
|
|
1198
|
+
evt.amount,
|
|
1199
|
+
evt.txHash,
|
|
1200
|
+
this.pointTokenAddress
|
|
1201
|
+
);
|
|
1172
1202
|
} catch {
|
|
1173
1203
|
return;
|
|
1174
1204
|
}
|
|
@@ -1198,7 +1228,15 @@ var IssuerApiHandlers = class {
|
|
|
1198
1228
|
gateway;
|
|
1199
1229
|
ledger;
|
|
1200
1230
|
provider;
|
|
1201
|
-
|
|
1231
|
+
/**
|
|
1232
|
+
* Set of supported PointToken addresses (checksum-normalized). Handlers
|
|
1233
|
+
* validate the request's `pointTokenAddress` against this set.
|
|
1234
|
+
*/
|
|
1235
|
+
supportedTokens;
|
|
1236
|
+
/** First supported token — used as default when a handler doesn't
|
|
1237
|
+
* receive a `pointTokenAddress` in the request (shouldn't happen in
|
|
1238
|
+
* practice, but keeps type-narrowing happy). */
|
|
1239
|
+
defaultToken;
|
|
1202
1240
|
chainId;
|
|
1203
1241
|
contracts;
|
|
1204
1242
|
feeManager;
|
|
@@ -1208,7 +1246,15 @@ var IssuerApiHandlers = class {
|
|
|
1208
1246
|
this.gateway = config.gateway;
|
|
1209
1247
|
this.ledger = config.ledger;
|
|
1210
1248
|
this.provider = config.provider;
|
|
1211
|
-
|
|
1249
|
+
const raw = config.pointTokenAddresses && config.pointTokenAddresses.length > 0 ? config.pointTokenAddresses : config.pointTokenAddress ? [config.pointTokenAddress] : [];
|
|
1250
|
+
if (raw.length === 0) {
|
|
1251
|
+
throw new Error(
|
|
1252
|
+
"IssuerApiHandlers: pointTokenAddress or pointTokenAddresses required"
|
|
1253
|
+
);
|
|
1254
|
+
}
|
|
1255
|
+
const normalized = raw.map((a) => (0, import_viem6.getAddress)(a));
|
|
1256
|
+
this.supportedTokens = new Set(normalized);
|
|
1257
|
+
this.defaultToken = normalized[0];
|
|
1212
1258
|
this.chainId = config.chainId;
|
|
1213
1259
|
this.contracts = config.contracts;
|
|
1214
1260
|
if (config.feeManager) this.feeManager = config.feeManager;
|
|
@@ -1305,7 +1351,7 @@ var IssuerApiHandlers = class {
|
|
|
1305
1351
|
);
|
|
1306
1352
|
}
|
|
1307
1353
|
const pointToken = (0, import_viem6.getAddress)(request.pointTokenAddress);
|
|
1308
|
-
if (
|
|
1354
|
+
if (!this.supportedTokens.has(pointToken)) {
|
|
1309
1355
|
throw new Error(
|
|
1310
1356
|
`handleUser: unsupported pointToken ${pointToken}`
|
|
1311
1357
|
);
|
|
@@ -1313,7 +1359,7 @@ var IssuerApiHandlers = class {
|
|
|
1313
1359
|
const [mintRequestNonce, receiverConsentNonce, offChainBalance, onChainBalance, minter] = await Promise.all([
|
|
1314
1360
|
(0, import_core5.getMintRequestNonce)(this.provider, pointToken, normalizedAuthed),
|
|
1315
1361
|
(0, import_core5.getReceiverConsentNonce)(this.provider, pointToken, normalizedAuthed),
|
|
1316
|
-
this.ledger.getBalance(normalizedAuthed),
|
|
1362
|
+
this.ledger.getBalance(normalizedAuthed, pointToken),
|
|
1317
1363
|
(0, import_core5.getPointTokenBalance)(this.provider, pointToken, normalizedAuthed),
|
|
1318
1364
|
(0, import_core5.isMinter)(this.provider, pointToken, normalizedAuthed)
|
|
1319
1365
|
]);
|
|
@@ -1348,7 +1394,7 @@ var IssuerApiHandlers = class {
|
|
|
1348
1394
|
);
|
|
1349
1395
|
}
|
|
1350
1396
|
const pointToken = (0, import_viem6.getAddress)(request.pointTokenAddress);
|
|
1351
|
-
if (
|
|
1397
|
+
if (!this.supportedTokens.has(pointToken)) {
|
|
1352
1398
|
throw new Error(
|
|
1353
1399
|
`handleBuildConsentTypedData: unsupported pointToken ${pointToken}`
|
|
1354
1400
|
);
|
|
@@ -1382,7 +1428,7 @@ var IssuerApiHandlers = class {
|
|
|
1382
1428
|
);
|
|
1383
1429
|
}
|
|
1384
1430
|
const pointToken = (0, import_viem6.getAddress)(request.pointTokenAddress);
|
|
1385
|
-
if (
|
|
1431
|
+
if (!this.supportedTokens.has(pointToken)) {
|
|
1386
1432
|
throw new Error(
|
|
1387
1433
|
`handleClaimAndSwap: unsupported pointToken ${pointToken}`
|
|
1388
1434
|
);
|
|
@@ -1620,6 +1666,7 @@ function toUsdtPerNative(priceFloat, usdtDecimals) {
|
|
|
1620
1666
|
}
|
|
1621
1667
|
|
|
1622
1668
|
// src/config.ts
|
|
1669
|
+
var import_viem7 = require("viem");
|
|
1623
1670
|
function createIssuerService(config) {
|
|
1624
1671
|
if (!config.provider) {
|
|
1625
1672
|
throw new Error("createIssuerService: provider is required");
|
|
@@ -1630,9 +1677,6 @@ function createIssuerService(config) {
|
|
|
1630
1677
|
if (!config.signer) {
|
|
1631
1678
|
throw new Error("createIssuerService: signer is required");
|
|
1632
1679
|
}
|
|
1633
|
-
if (!config.pointTokenAddress) {
|
|
1634
|
-
throw new Error("createIssuerService: pointTokenAddress is required");
|
|
1635
|
-
}
|
|
1636
1680
|
if (!config.relayAddress) {
|
|
1637
1681
|
throw new Error("createIssuerService: relayAddress is required");
|
|
1638
1682
|
}
|
|
@@ -1642,6 +1686,13 @@ function createIssuerService(config) {
|
|
|
1642
1686
|
if (!config.auth?.domain) {
|
|
1643
1687
|
throw new Error("createIssuerService: auth.domain is required");
|
|
1644
1688
|
}
|
|
1689
|
+
const rawAddresses = config.pointTokenAddresses && config.pointTokenAddresses.length > 0 ? config.pointTokenAddresses : config.pointTokenAddress ? [config.pointTokenAddress] : [];
|
|
1690
|
+
if (rawAddresses.length === 0) {
|
|
1691
|
+
throw new Error(
|
|
1692
|
+
"createIssuerService: at least one of pointTokenAddress / pointTokenAddresses is required"
|
|
1693
|
+
);
|
|
1694
|
+
}
|
|
1695
|
+
const tokenAddresses = rawAddresses.map((a) => (0, import_viem7.getAddress)(a));
|
|
1645
1696
|
const ledger = config.ledger ?? new MemoryPointLedger();
|
|
1646
1697
|
const sessionStore = config.sessionStore ?? new MemorySessionStore();
|
|
1647
1698
|
const policy = config.policy ?? new DefaultPolicyEngine({ ledger });
|
|
@@ -1685,33 +1736,37 @@ function createIssuerService(config) {
|
|
|
1685
1736
|
gatewayConfig.defaultLockBufferMs = config.gateway.defaultLockBufferMs;
|
|
1686
1737
|
}
|
|
1687
1738
|
const gateway = new MintingGateway(gatewayConfig);
|
|
1688
|
-
const
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1739
|
+
const indexers = /* @__PURE__ */ new Map();
|
|
1740
|
+
for (const tokenAddress of tokenAddresses) {
|
|
1741
|
+
const indexerConfig = {
|
|
1742
|
+
provider: config.provider,
|
|
1743
|
+
pointTokenAddress: tokenAddress,
|
|
1744
|
+
ledger
|
|
1745
|
+
};
|
|
1746
|
+
if (config.indexer?.fromBlock !== void 0) {
|
|
1747
|
+
indexerConfig.fromBlock = config.indexer.fromBlock;
|
|
1748
|
+
}
|
|
1749
|
+
if (config.indexer?.cursorStore) {
|
|
1750
|
+
indexerConfig.cursorStore = config.indexer.cursorStore;
|
|
1751
|
+
}
|
|
1752
|
+
if (config.indexer?.confirmations !== void 0) {
|
|
1753
|
+
indexerConfig.confirmations = config.indexer.confirmations;
|
|
1754
|
+
}
|
|
1755
|
+
if (config.indexer?.batchSize !== void 0) {
|
|
1756
|
+
indexerConfig.batchSize = config.indexer.batchSize;
|
|
1757
|
+
}
|
|
1758
|
+
if (config.indexer?.pollIntervalMs !== void 0) {
|
|
1759
|
+
indexerConfig.pollIntervalMs = config.indexer.pollIntervalMs;
|
|
1760
|
+
}
|
|
1761
|
+
indexers.set(tokenAddress, new PointIndexer(indexerConfig));
|
|
1707
1762
|
}
|
|
1708
|
-
const
|
|
1763
|
+
const firstIndexer = indexers.get(tokenAddresses[0]);
|
|
1709
1764
|
const handlersConfig = {
|
|
1710
1765
|
authService,
|
|
1711
1766
|
gateway,
|
|
1712
1767
|
ledger,
|
|
1713
1768
|
provider: config.provider,
|
|
1714
|
-
|
|
1769
|
+
pointTokenAddresses: tokenAddresses,
|
|
1715
1770
|
chainId: config.chainId,
|
|
1716
1771
|
contracts: config.contracts
|
|
1717
1772
|
};
|
|
@@ -1719,7 +1774,9 @@ function createIssuerService(config) {
|
|
|
1719
1774
|
if (config.poolsProvider) handlersConfig.poolsProvider = config.poolsProvider;
|
|
1720
1775
|
const handlers = new IssuerApiHandlers(handlersConfig);
|
|
1721
1776
|
if (config.indexer?.autoStart) {
|
|
1722
|
-
|
|
1777
|
+
for (const idx of indexers.values()) {
|
|
1778
|
+
idx.start();
|
|
1779
|
+
}
|
|
1723
1780
|
}
|
|
1724
1781
|
return {
|
|
1725
1782
|
authService,
|
|
@@ -1730,7 +1787,8 @@ function createIssuerService(config) {
|
|
|
1730
1787
|
relayService,
|
|
1731
1788
|
feeManager,
|
|
1732
1789
|
gateway,
|
|
1733
|
-
|
|
1790
|
+
indexers,
|
|
1791
|
+
indexer: firstIndexer,
|
|
1734
1792
|
handlers
|
|
1735
1793
|
};
|
|
1736
1794
|
}
|