@pafi-dev/issuer-postgres 0.1.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/README.md +178 -0
- package/dist/entities/index.cjs +303 -0
- package/dist/entities/index.cjs.map +1 -0
- package/dist/entities/index.d.cts +122 -0
- package/dist/entities/index.d.ts +122 -0
- package/dist/entities/index.js +292 -0
- package/dist/entities/index.js.map +1 -0
- package/dist/index.cjs +764 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +97 -0
- package/dist/index.d.ts +97 -0
- package/dist/index.js +749 -0
- package/dist/index.js.map +1 -0
- package/dist/migrations/index.cjs +138 -0
- package/dist/migrations/index.cjs.map +1 -0
- package/dist/migrations/index.d.cts +41 -0
- package/dist/migrations/index.d.ts +41 -0
- package/dist/migrations/index.js +110 -0
- package/dist/migrations/index.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { MintingStatus } from '@pafi-dev/issuer';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A reservation against a user's off-chain balance.
|
|
5
|
+
*
|
|
6
|
+
* Lifecycle:
|
|
7
|
+
* PENDING ── PointIndexer matches Mint event ──▶ MINTED
|
|
8
|
+
* │
|
|
9
|
+
* ├── deadline elapsed ────────────────────▶ EXPIRED
|
|
10
|
+
* │
|
|
11
|
+
* └── tx reverted ─────────────────────────▶ FAILED
|
|
12
|
+
*
|
|
13
|
+
* The `(userAddress, status)` composite index keeps the "sum all
|
|
14
|
+
* PENDING locks" hot path of `lockForMinting()` fast under load.
|
|
15
|
+
*/
|
|
16
|
+
declare class LockedMintEntity {
|
|
17
|
+
id: string;
|
|
18
|
+
userAddress: string;
|
|
19
|
+
tokenAddress: string;
|
|
20
|
+
amount: bigint;
|
|
21
|
+
status: MintingStatus;
|
|
22
|
+
createdAt: Date;
|
|
23
|
+
expiresAt: Date;
|
|
24
|
+
txHash?: string | null;
|
|
25
|
+
/**
|
|
26
|
+
* ERC-4337 userOpHash returned by the bundler at /claim/submit.
|
|
27
|
+
* Bound to the lock so `/claim/status` can fall back to the bundler
|
|
28
|
+
* receipt — required when multiple PENDING locks share the same
|
|
29
|
+
* `amount` (PointIndexer matches by amount and can pick the wrong
|
|
30
|
+
* sibling lock).
|
|
31
|
+
*/
|
|
32
|
+
userOpHash?: string | null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
type PendingCreditStatus = "PENDING" | "RESOLVED" | "EXPIRED";
|
|
36
|
+
/**
|
|
37
|
+
* Reverse flow — user burns on-chain PT, `BurnIndexer` observes
|
|
38
|
+
* `Transfer(user → 0x0)`, the credit is settled to the off-chain ledger.
|
|
39
|
+
*
|
|
40
|
+
* Lifecycle:
|
|
41
|
+
* PENDING ── Burn tx observed by indexer ──▶ RESOLVED
|
|
42
|
+
* │
|
|
43
|
+
* └── deadline elapsed ────────────────▶ EXPIRED
|
|
44
|
+
*
|
|
45
|
+
* The credit is reserved BEFORE the UserOp is submitted so the
|
|
46
|
+
* indexer can correlate `(user, amount, token)` back to the off-chain
|
|
47
|
+
* row when the burn lands.
|
|
48
|
+
*/
|
|
49
|
+
declare class PendingCreditEntity {
|
|
50
|
+
id: string;
|
|
51
|
+
userAddress: string;
|
|
52
|
+
tokenAddress: string;
|
|
53
|
+
amount: bigint;
|
|
54
|
+
status: PendingCreditStatus;
|
|
55
|
+
/** On-chain burn tx that settled this credit. Null until indexer resolves. */
|
|
56
|
+
txHash?: string | null;
|
|
57
|
+
/** ERC-4337 userOpHash bound at /redeem/submit. See `LockedMintEntity`. */
|
|
58
|
+
userOpHash?: string | null;
|
|
59
|
+
createdAt: Date;
|
|
60
|
+
expiresAt: Date;
|
|
61
|
+
resolvedAt?: Date | null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Off-chain point balance per `(userAddress, tokenAddress)`.
|
|
66
|
+
*
|
|
67
|
+
* `balance` is the **total** owned; pending reservations live in
|
|
68
|
+
* `LockedMintEntity`. Available balance = total − sum(PENDING locks)
|
|
69
|
+
* — `getBalance` in `PostgresPointLedger` does this subtraction
|
|
70
|
+
* inside a transaction so reads are race-free.
|
|
71
|
+
*
|
|
72
|
+
* All amounts are `numeric(78, 0)` for full bigint precision (uint256
|
|
73
|
+
* fits in 78 decimal digits). TypeORM transforms bigint ↔ string at
|
|
74
|
+
* the boundary; in JS/TS code we always deal with `bigint`.
|
|
75
|
+
*/
|
|
76
|
+
declare class UserBalanceEntity {
|
|
77
|
+
userAddress: string;
|
|
78
|
+
tokenAddress: string;
|
|
79
|
+
balance: bigint;
|
|
80
|
+
updatedAt: Date;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Append-only audit trail for every balance mutation. Used for
|
|
85
|
+
* reconciliation, customer support, and regulatory reporting.
|
|
86
|
+
*
|
|
87
|
+
* Sign convention:
|
|
88
|
+
* - positive `delta` — credit (merchant award, refund, manual top-up)
|
|
89
|
+
* - negative `delta` — debit (mint confirmation against the off-chain
|
|
90
|
+
* balance; `txHash` references the on-chain Mint event)
|
|
91
|
+
*/
|
|
92
|
+
declare class LedgerJournalEntity {
|
|
93
|
+
id: string;
|
|
94
|
+
userAddress: string;
|
|
95
|
+
tokenAddress: string;
|
|
96
|
+
delta: bigint;
|
|
97
|
+
reason: string;
|
|
98
|
+
txHash?: string | null;
|
|
99
|
+
createdAt: Date;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Persistent cursor for `PointIndexer` / `BurnIndexer`. Multiple rows
|
|
104
|
+
* coexist keyed by `id` (e.g. `default` for the mint indexer,
|
|
105
|
+
* `burn:0x...` for each per-token burn indexer).
|
|
106
|
+
*
|
|
107
|
+
* Stores the **next** block to scan, not the last processed one.
|
|
108
|
+
* Indexer reads on startup and resumes from there.
|
|
109
|
+
*/
|
|
110
|
+
declare class IndexerCursorEntity {
|
|
111
|
+
id: string;
|
|
112
|
+
nextBlock: bigint;
|
|
113
|
+
updatedAt: Date;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* All entities in one array — drop into TypeORM's `entities` config or
|
|
118
|
+
* NestJS's `TypeOrmModule.forFeature(PAFI_ENTITIES)`.
|
|
119
|
+
*/
|
|
120
|
+
declare const PAFI_ENTITIES: readonly [typeof LockedMintEntity, typeof PendingCreditEntity, typeof UserBalanceEntity, typeof LedgerJournalEntity, typeof IndexerCursorEntity];
|
|
121
|
+
|
|
122
|
+
export { IndexerCursorEntity, LedgerJournalEntity, LockedMintEntity, PAFI_ENTITIES, PendingCreditEntity, type PendingCreditStatus, UserBalanceEntity };
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
4
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
5
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
6
|
+
if (decorator = decorators[i])
|
|
7
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
8
|
+
if (kind && result) __defProp(target, key, result);
|
|
9
|
+
return result;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/entities/locked-mint.entity.ts
|
|
13
|
+
import {
|
|
14
|
+
Column,
|
|
15
|
+
CreateDateColumn,
|
|
16
|
+
Entity,
|
|
17
|
+
Index,
|
|
18
|
+
PrimaryGeneratedColumn
|
|
19
|
+
} from "typeorm";
|
|
20
|
+
var LockedMintEntity = class {
|
|
21
|
+
id;
|
|
22
|
+
userAddress;
|
|
23
|
+
tokenAddress;
|
|
24
|
+
amount;
|
|
25
|
+
status;
|
|
26
|
+
createdAt;
|
|
27
|
+
expiresAt;
|
|
28
|
+
txHash;
|
|
29
|
+
userOpHash;
|
|
30
|
+
};
|
|
31
|
+
__decorateClass([
|
|
32
|
+
PrimaryGeneratedColumn("uuid")
|
|
33
|
+
], LockedMintEntity.prototype, "id", 2);
|
|
34
|
+
__decorateClass([
|
|
35
|
+
Column({ name: "user_address", type: "varchar", length: 42 })
|
|
36
|
+
], LockedMintEntity.prototype, "userAddress", 2);
|
|
37
|
+
__decorateClass([
|
|
38
|
+
Column({ name: "token_address", type: "varchar", length: 42 })
|
|
39
|
+
], LockedMintEntity.prototype, "tokenAddress", 2);
|
|
40
|
+
__decorateClass([
|
|
41
|
+
Column({
|
|
42
|
+
name: "amount",
|
|
43
|
+
type: "numeric",
|
|
44
|
+
precision: 78,
|
|
45
|
+
scale: 0,
|
|
46
|
+
transformer: {
|
|
47
|
+
to: (value) => value.toString(),
|
|
48
|
+
from: (value) => BigInt(value)
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
], LockedMintEntity.prototype, "amount", 2);
|
|
52
|
+
__decorateClass([
|
|
53
|
+
Column({
|
|
54
|
+
name: "status",
|
|
55
|
+
type: "varchar",
|
|
56
|
+
length: 16,
|
|
57
|
+
default: "PENDING"
|
|
58
|
+
})
|
|
59
|
+
], LockedMintEntity.prototype, "status", 2);
|
|
60
|
+
__decorateClass([
|
|
61
|
+
CreateDateColumn({ name: "created_at" })
|
|
62
|
+
], LockedMintEntity.prototype, "createdAt", 2);
|
|
63
|
+
__decorateClass([
|
|
64
|
+
Column({ name: "expires_at", type: "timestamp with time zone" })
|
|
65
|
+
], LockedMintEntity.prototype, "expiresAt", 2);
|
|
66
|
+
__decorateClass([
|
|
67
|
+
Column({ name: "tx_hash", type: "varchar", length: 66, nullable: true })
|
|
68
|
+
], LockedMintEntity.prototype, "txHash", 2);
|
|
69
|
+
__decorateClass([
|
|
70
|
+
Column({
|
|
71
|
+
name: "user_op_hash",
|
|
72
|
+
type: "varchar",
|
|
73
|
+
length: 66,
|
|
74
|
+
nullable: true
|
|
75
|
+
})
|
|
76
|
+
], LockedMintEntity.prototype, "userOpHash", 2);
|
|
77
|
+
LockedMintEntity = __decorateClass([
|
|
78
|
+
Entity({ name: "locked_mint_requests" }),
|
|
79
|
+
Index(["userAddress", "status"])
|
|
80
|
+
], LockedMintEntity);
|
|
81
|
+
|
|
82
|
+
// src/entities/pending-credit.entity.ts
|
|
83
|
+
import {
|
|
84
|
+
Column as Column2,
|
|
85
|
+
CreateDateColumn as CreateDateColumn2,
|
|
86
|
+
Entity as Entity2,
|
|
87
|
+
Index as Index2,
|
|
88
|
+
PrimaryGeneratedColumn as PrimaryGeneratedColumn2
|
|
89
|
+
} from "typeorm";
|
|
90
|
+
var PendingCreditEntity = class {
|
|
91
|
+
id;
|
|
92
|
+
userAddress;
|
|
93
|
+
tokenAddress;
|
|
94
|
+
amount;
|
|
95
|
+
status;
|
|
96
|
+
txHash;
|
|
97
|
+
userOpHash;
|
|
98
|
+
createdAt;
|
|
99
|
+
expiresAt;
|
|
100
|
+
resolvedAt;
|
|
101
|
+
};
|
|
102
|
+
__decorateClass([
|
|
103
|
+
PrimaryGeneratedColumn2("uuid")
|
|
104
|
+
], PendingCreditEntity.prototype, "id", 2);
|
|
105
|
+
__decorateClass([
|
|
106
|
+
Column2({ name: "user_address", type: "varchar", length: 42 })
|
|
107
|
+
], PendingCreditEntity.prototype, "userAddress", 2);
|
|
108
|
+
__decorateClass([
|
|
109
|
+
Column2({ name: "token_address", type: "varchar", length: 42 })
|
|
110
|
+
], PendingCreditEntity.prototype, "tokenAddress", 2);
|
|
111
|
+
__decorateClass([
|
|
112
|
+
Column2({
|
|
113
|
+
name: "amount",
|
|
114
|
+
type: "numeric",
|
|
115
|
+
precision: 78,
|
|
116
|
+
scale: 0,
|
|
117
|
+
transformer: {
|
|
118
|
+
to: (value) => value.toString(),
|
|
119
|
+
from: (value) => BigInt(value)
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
], PendingCreditEntity.prototype, "amount", 2);
|
|
123
|
+
__decorateClass([
|
|
124
|
+
Column2({
|
|
125
|
+
name: "status",
|
|
126
|
+
type: "varchar",
|
|
127
|
+
length: 16,
|
|
128
|
+
default: "PENDING"
|
|
129
|
+
})
|
|
130
|
+
], PendingCreditEntity.prototype, "status", 2);
|
|
131
|
+
__decorateClass([
|
|
132
|
+
Column2({ name: "tx_hash", type: "varchar", length: 66, nullable: true })
|
|
133
|
+
], PendingCreditEntity.prototype, "txHash", 2);
|
|
134
|
+
__decorateClass([
|
|
135
|
+
Column2({
|
|
136
|
+
name: "user_op_hash",
|
|
137
|
+
type: "varchar",
|
|
138
|
+
length: 66,
|
|
139
|
+
nullable: true
|
|
140
|
+
})
|
|
141
|
+
], PendingCreditEntity.prototype, "userOpHash", 2);
|
|
142
|
+
__decorateClass([
|
|
143
|
+
CreateDateColumn2({ name: "created_at" })
|
|
144
|
+
], PendingCreditEntity.prototype, "createdAt", 2);
|
|
145
|
+
__decorateClass([
|
|
146
|
+
Column2({ name: "expires_at", type: "timestamp with time zone" })
|
|
147
|
+
], PendingCreditEntity.prototype, "expiresAt", 2);
|
|
148
|
+
__decorateClass([
|
|
149
|
+
Column2({
|
|
150
|
+
name: "resolved_at",
|
|
151
|
+
type: "timestamp with time zone",
|
|
152
|
+
nullable: true
|
|
153
|
+
})
|
|
154
|
+
], PendingCreditEntity.prototype, "resolvedAt", 2);
|
|
155
|
+
PendingCreditEntity = __decorateClass([
|
|
156
|
+
Entity2({ name: "pending_credits" }),
|
|
157
|
+
Index2(["userAddress", "status"]),
|
|
158
|
+
Index2(["txHash"])
|
|
159
|
+
], PendingCreditEntity);
|
|
160
|
+
|
|
161
|
+
// src/entities/user-balance.entity.ts
|
|
162
|
+
import { Column as Column3, Entity as Entity3, PrimaryColumn, UpdateDateColumn } from "typeorm";
|
|
163
|
+
var UserBalanceEntity = class {
|
|
164
|
+
userAddress;
|
|
165
|
+
tokenAddress;
|
|
166
|
+
balance;
|
|
167
|
+
updatedAt;
|
|
168
|
+
};
|
|
169
|
+
__decorateClass([
|
|
170
|
+
PrimaryColumn({ name: "user_address", type: "varchar", length: 42 })
|
|
171
|
+
], UserBalanceEntity.prototype, "userAddress", 2);
|
|
172
|
+
__decorateClass([
|
|
173
|
+
PrimaryColumn({ name: "token_address", type: "varchar", length: 42 })
|
|
174
|
+
], UserBalanceEntity.prototype, "tokenAddress", 2);
|
|
175
|
+
__decorateClass([
|
|
176
|
+
Column3({
|
|
177
|
+
name: "balance",
|
|
178
|
+
type: "numeric",
|
|
179
|
+
precision: 78,
|
|
180
|
+
scale: 0,
|
|
181
|
+
default: 0,
|
|
182
|
+
transformer: {
|
|
183
|
+
to: (value) => value.toString(),
|
|
184
|
+
from: (value) => BigInt(value)
|
|
185
|
+
}
|
|
186
|
+
})
|
|
187
|
+
], UserBalanceEntity.prototype, "balance", 2);
|
|
188
|
+
__decorateClass([
|
|
189
|
+
UpdateDateColumn({ name: "updated_at" })
|
|
190
|
+
], UserBalanceEntity.prototype, "updatedAt", 2);
|
|
191
|
+
UserBalanceEntity = __decorateClass([
|
|
192
|
+
Entity3({ name: "user_balances" })
|
|
193
|
+
], UserBalanceEntity);
|
|
194
|
+
|
|
195
|
+
// src/entities/ledger-journal.entity.ts
|
|
196
|
+
import {
|
|
197
|
+
Column as Column4,
|
|
198
|
+
CreateDateColumn as CreateDateColumn3,
|
|
199
|
+
Entity as Entity4,
|
|
200
|
+
Index as Index3,
|
|
201
|
+
PrimaryGeneratedColumn as PrimaryGeneratedColumn3
|
|
202
|
+
} from "typeorm";
|
|
203
|
+
var LedgerJournalEntity = class {
|
|
204
|
+
id;
|
|
205
|
+
userAddress;
|
|
206
|
+
tokenAddress;
|
|
207
|
+
delta;
|
|
208
|
+
reason;
|
|
209
|
+
txHash;
|
|
210
|
+
createdAt;
|
|
211
|
+
};
|
|
212
|
+
__decorateClass([
|
|
213
|
+
PrimaryGeneratedColumn3("uuid")
|
|
214
|
+
], LedgerJournalEntity.prototype, "id", 2);
|
|
215
|
+
__decorateClass([
|
|
216
|
+
Column4({ name: "user_address", type: "varchar", length: 42 })
|
|
217
|
+
], LedgerJournalEntity.prototype, "userAddress", 2);
|
|
218
|
+
__decorateClass([
|
|
219
|
+
Column4({ name: "token_address", type: "varchar", length: 42 })
|
|
220
|
+
], LedgerJournalEntity.prototype, "tokenAddress", 2);
|
|
221
|
+
__decorateClass([
|
|
222
|
+
Column4({
|
|
223
|
+
name: "delta",
|
|
224
|
+
type: "numeric",
|
|
225
|
+
precision: 78,
|
|
226
|
+
scale: 0,
|
|
227
|
+
transformer: {
|
|
228
|
+
to: (value) => value.toString(),
|
|
229
|
+
from: (value) => BigInt(value)
|
|
230
|
+
}
|
|
231
|
+
})
|
|
232
|
+
], LedgerJournalEntity.prototype, "delta", 2);
|
|
233
|
+
__decorateClass([
|
|
234
|
+
Column4({ name: "reason", type: "varchar", length: 128 })
|
|
235
|
+
], LedgerJournalEntity.prototype, "reason", 2);
|
|
236
|
+
__decorateClass([
|
|
237
|
+
Column4({ name: "tx_hash", type: "varchar", length: 66, nullable: true })
|
|
238
|
+
], LedgerJournalEntity.prototype, "txHash", 2);
|
|
239
|
+
__decorateClass([
|
|
240
|
+
CreateDateColumn3({ name: "created_at" })
|
|
241
|
+
], LedgerJournalEntity.prototype, "createdAt", 2);
|
|
242
|
+
LedgerJournalEntity = __decorateClass([
|
|
243
|
+
Entity4({ name: "ledger_journal" }),
|
|
244
|
+
Index3(["userAddress", "createdAt"])
|
|
245
|
+
], LedgerJournalEntity);
|
|
246
|
+
|
|
247
|
+
// src/entities/indexer-cursor.entity.ts
|
|
248
|
+
import { Column as Column5, Entity as Entity5, PrimaryColumn as PrimaryColumn2, UpdateDateColumn as UpdateDateColumn2 } from "typeorm";
|
|
249
|
+
var IndexerCursorEntity = class {
|
|
250
|
+
id;
|
|
251
|
+
nextBlock;
|
|
252
|
+
updatedAt;
|
|
253
|
+
};
|
|
254
|
+
__decorateClass([
|
|
255
|
+
PrimaryColumn2({ type: "varchar", length: 64 })
|
|
256
|
+
], IndexerCursorEntity.prototype, "id", 2);
|
|
257
|
+
__decorateClass([
|
|
258
|
+
Column5({
|
|
259
|
+
name: "next_block",
|
|
260
|
+
type: "numeric",
|
|
261
|
+
precision: 78,
|
|
262
|
+
scale: 0,
|
|
263
|
+
transformer: {
|
|
264
|
+
to: (value) => value.toString(),
|
|
265
|
+
from: (value) => BigInt(value)
|
|
266
|
+
}
|
|
267
|
+
})
|
|
268
|
+
], IndexerCursorEntity.prototype, "nextBlock", 2);
|
|
269
|
+
__decorateClass([
|
|
270
|
+
UpdateDateColumn2({ name: "updated_at" })
|
|
271
|
+
], IndexerCursorEntity.prototype, "updatedAt", 2);
|
|
272
|
+
IndexerCursorEntity = __decorateClass([
|
|
273
|
+
Entity5({ name: "indexer_cursors" })
|
|
274
|
+
], IndexerCursorEntity);
|
|
275
|
+
|
|
276
|
+
// src/entities/index.ts
|
|
277
|
+
var PAFI_ENTITIES = [
|
|
278
|
+
LockedMintEntity,
|
|
279
|
+
PendingCreditEntity,
|
|
280
|
+
UserBalanceEntity,
|
|
281
|
+
LedgerJournalEntity,
|
|
282
|
+
IndexerCursorEntity
|
|
283
|
+
];
|
|
284
|
+
export {
|
|
285
|
+
IndexerCursorEntity,
|
|
286
|
+
LedgerJournalEntity,
|
|
287
|
+
LockedMintEntity,
|
|
288
|
+
PAFI_ENTITIES,
|
|
289
|
+
PendingCreditEntity,
|
|
290
|
+
UserBalanceEntity
|
|
291
|
+
};
|
|
292
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/entities/locked-mint.entity.ts","../../src/entities/pending-credit.entity.ts","../../src/entities/user-balance.entity.ts","../../src/entities/ledger-journal.entity.ts","../../src/entities/indexer-cursor.entity.ts","../../src/entities/index.ts"],"sourcesContent":["import {\n Column,\n CreateDateColumn,\n Entity,\n Index,\n PrimaryGeneratedColumn,\n} from \"typeorm\";\nimport type { MintingStatus } from \"@pafi-dev/issuer\";\n\n/**\n * A reservation against a user's off-chain balance.\n *\n * Lifecycle:\n * PENDING ── PointIndexer matches Mint event ──▶ MINTED\n * │\n * ├── deadline elapsed ────────────────────▶ EXPIRED\n * │\n * └── tx reverted ─────────────────────────▶ FAILED\n *\n * The `(userAddress, status)` composite index keeps the \"sum all\n * PENDING locks\" hot path of `lockForMinting()` fast under load.\n */\n@Entity({ name: \"locked_mint_requests\" })\n@Index([\"userAddress\", \"status\"])\nexport class LockedMintEntity {\n @PrimaryGeneratedColumn(\"uuid\")\n id!: string;\n\n @Column({ name: \"user_address\", type: \"varchar\", length: 42 })\n userAddress!: string;\n\n @Column({ name: \"token_address\", type: \"varchar\", length: 42 })\n tokenAddress!: string;\n\n @Column({\n name: \"amount\",\n type: \"numeric\",\n precision: 78,\n scale: 0,\n transformer: {\n to: (value: bigint) => value.toString(),\n from: (value: string) => BigInt(value),\n },\n })\n amount!: bigint;\n\n @Column({\n name: \"status\",\n type: \"varchar\",\n length: 16,\n default: \"PENDING\",\n })\n status!: MintingStatus;\n\n @CreateDateColumn({ name: \"created_at\" })\n createdAt!: Date;\n\n @Column({ name: \"expires_at\", type: \"timestamp with time zone\" })\n expiresAt!: Date;\n\n @Column({ name: \"tx_hash\", type: \"varchar\", length: 66, nullable: true })\n txHash?: string | null;\n\n /**\n * ERC-4337 userOpHash returned by the bundler at /claim/submit.\n * Bound to the lock so `/claim/status` can fall back to the bundler\n * receipt — required when multiple PENDING locks share the same\n * `amount` (PointIndexer matches by amount and can pick the wrong\n * sibling lock).\n */\n @Column({\n name: \"user_op_hash\",\n type: \"varchar\",\n length: 66,\n nullable: true,\n })\n userOpHash?: string | null;\n}\n","import {\n Column,\n CreateDateColumn,\n Entity,\n Index,\n PrimaryGeneratedColumn,\n} from \"typeorm\";\n\nexport type PendingCreditStatus = \"PENDING\" | \"RESOLVED\" | \"EXPIRED\";\n\n/**\n * Reverse flow — user burns on-chain PT, `BurnIndexer` observes\n * `Transfer(user → 0x0)`, the credit is settled to the off-chain ledger.\n *\n * Lifecycle:\n * PENDING ── Burn tx observed by indexer ──▶ RESOLVED\n * │\n * └── deadline elapsed ────────────────▶ EXPIRED\n *\n * The credit is reserved BEFORE the UserOp is submitted so the\n * indexer can correlate `(user, amount, token)` back to the off-chain\n * row when the burn lands.\n */\n@Entity({ name: \"pending_credits\" })\n@Index([\"userAddress\", \"status\"])\n@Index([\"txHash\"])\nexport class PendingCreditEntity {\n @PrimaryGeneratedColumn(\"uuid\")\n id!: string;\n\n @Column({ name: \"user_address\", type: \"varchar\", length: 42 })\n userAddress!: string;\n\n @Column({ name: \"token_address\", type: \"varchar\", length: 42 })\n tokenAddress!: string;\n\n @Column({\n name: \"amount\",\n type: \"numeric\",\n precision: 78,\n scale: 0,\n transformer: {\n to: (value: bigint) => value.toString(),\n from: (value: string) => BigInt(value),\n },\n })\n amount!: bigint;\n\n @Column({\n name: \"status\",\n type: \"varchar\",\n length: 16,\n default: \"PENDING\",\n })\n status!: PendingCreditStatus;\n\n /** On-chain burn tx that settled this credit. Null until indexer resolves. */\n @Column({ name: \"tx_hash\", type: \"varchar\", length: 66, nullable: true })\n txHash?: string | null;\n\n /** ERC-4337 userOpHash bound at /redeem/submit. See `LockedMintEntity`. */\n @Column({\n name: \"user_op_hash\",\n type: \"varchar\",\n length: 66,\n nullable: true,\n })\n userOpHash?: string | null;\n\n @CreateDateColumn({ name: \"created_at\" })\n createdAt!: Date;\n\n @Column({ name: \"expires_at\", type: \"timestamp with time zone\" })\n expiresAt!: Date;\n\n @Column({\n name: \"resolved_at\",\n type: \"timestamp with time zone\",\n nullable: true,\n })\n resolvedAt?: Date | null;\n}\n","import { Column, Entity, PrimaryColumn, UpdateDateColumn } from \"typeorm\";\n\n/**\n * Off-chain point balance per `(userAddress, tokenAddress)`.\n *\n * `balance` is the **total** owned; pending reservations live in\n * `LockedMintEntity`. Available balance = total − sum(PENDING locks)\n * — `getBalance` in `PostgresPointLedger` does this subtraction\n * inside a transaction so reads are race-free.\n *\n * All amounts are `numeric(78, 0)` for full bigint precision (uint256\n * fits in 78 decimal digits). TypeORM transforms bigint ↔ string at\n * the boundary; in JS/TS code we always deal with `bigint`.\n */\n@Entity({ name: \"user_balances\" })\nexport class UserBalanceEntity {\n @PrimaryColumn({ name: \"user_address\", type: \"varchar\", length: 42 })\n userAddress!: string;\n\n @PrimaryColumn({ name: \"token_address\", type: \"varchar\", length: 42 })\n tokenAddress!: string;\n\n @Column({\n name: \"balance\",\n type: \"numeric\",\n precision: 78,\n scale: 0,\n default: 0,\n transformer: {\n to: (value: bigint) => value.toString(),\n from: (value: string) => BigInt(value),\n },\n })\n balance!: bigint;\n\n @UpdateDateColumn({ name: \"updated_at\" })\n updatedAt!: Date;\n}\n","import {\n Column,\n CreateDateColumn,\n Entity,\n Index,\n PrimaryGeneratedColumn,\n} from \"typeorm\";\n\n/**\n * Append-only audit trail for every balance mutation. Used for\n * reconciliation, customer support, and regulatory reporting.\n *\n * Sign convention:\n * - positive `delta` — credit (merchant award, refund, manual top-up)\n * - negative `delta` — debit (mint confirmation against the off-chain\n * balance; `txHash` references the on-chain Mint event)\n */\n@Entity({ name: \"ledger_journal\" })\n@Index([\"userAddress\", \"createdAt\"])\nexport class LedgerJournalEntity {\n @PrimaryGeneratedColumn(\"uuid\")\n id!: string;\n\n @Column({ name: \"user_address\", type: \"varchar\", length: 42 })\n userAddress!: string;\n\n @Column({ name: \"token_address\", type: \"varchar\", length: 42 })\n tokenAddress!: string;\n\n @Column({\n name: \"delta\",\n type: \"numeric\",\n precision: 78,\n scale: 0,\n transformer: {\n to: (value: bigint) => value.toString(),\n from: (value: string) => BigInt(value),\n },\n })\n delta!: bigint;\n\n @Column({ name: \"reason\", type: \"varchar\", length: 128 })\n reason!: string;\n\n @Column({ name: \"tx_hash\", type: \"varchar\", length: 66, nullable: true })\n txHash?: string | null;\n\n @CreateDateColumn({ name: \"created_at\" })\n createdAt!: Date;\n}\n","import { Column, Entity, PrimaryColumn, UpdateDateColumn } from \"typeorm\";\n\n/**\n * Persistent cursor for `PointIndexer` / `BurnIndexer`. Multiple rows\n * coexist keyed by `id` (e.g. `default` for the mint indexer,\n * `burn:0x...` for each per-token burn indexer).\n *\n * Stores the **next** block to scan, not the last processed one.\n * Indexer reads on startup and resumes from there.\n */\n@Entity({ name: \"indexer_cursors\" })\nexport class IndexerCursorEntity {\n @PrimaryColumn({ type: \"varchar\", length: 64 })\n id!: string;\n\n @Column({\n name: \"next_block\",\n type: \"numeric\",\n precision: 78,\n scale: 0,\n transformer: {\n to: (value: bigint) => value.toString(),\n from: (value: string) => BigInt(value),\n },\n })\n nextBlock!: bigint;\n\n @UpdateDateColumn({ name: \"updated_at\" })\n updatedAt!: Date;\n}\n","export { LockedMintEntity } from \"./locked-mint.entity\";\nexport {\n PendingCreditEntity,\n type PendingCreditStatus,\n} from \"./pending-credit.entity\";\nexport { UserBalanceEntity } from \"./user-balance.entity\";\nexport { LedgerJournalEntity } from \"./ledger-journal.entity\";\nexport { IndexerCursorEntity } from \"./indexer-cursor.entity\";\n\nimport { LockedMintEntity } from \"./locked-mint.entity\";\nimport { PendingCreditEntity } from \"./pending-credit.entity\";\nimport { UserBalanceEntity } from \"./user-balance.entity\";\nimport { LedgerJournalEntity } from \"./ledger-journal.entity\";\nimport { IndexerCursorEntity } from \"./indexer-cursor.entity\";\n\n/**\n * All entities in one array — drop into TypeORM's `entities` config or\n * NestJS's `TypeOrmModule.forFeature(PAFI_ENTITIES)`.\n */\nexport const PAFI_ENTITIES = [\n LockedMintEntity,\n PendingCreditEntity,\n UserBalanceEntity,\n LedgerJournalEntity,\n IndexerCursorEntity,\n] as const;\n"],"mappings":"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","names":["Column","CreateDateColumn","Entity","Index","PrimaryGeneratedColumn","PrimaryGeneratedColumn","Column","CreateDateColumn","Entity","Index","Column","Entity","Column","Entity","Column","CreateDateColumn","Entity","Index","PrimaryGeneratedColumn","PrimaryGeneratedColumn","Column","CreateDateColumn","Entity","Index","Column","Entity","PrimaryColumn","UpdateDateColumn","PrimaryColumn","Column","UpdateDateColumn","Entity"]}
|