tapimo 0.8.0 → 0.9.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.
Files changed (80) hide show
  1. package/dist/App.d.ts +2095 -2111
  2. package/dist/App.d.ts.map +1 -1
  3. package/dist/App.js +0 -1
  4. package/dist/App.js.map +1 -1
  5. package/dist/admin/apps/verified-tokens.d.ts +166 -166
  6. package/dist/apps/data/App.d.ts +4084 -3845
  7. package/dist/apps/data/App.d.ts.map +1 -1
  8. package/dist/apps/data/routes/activities.d.ts +270 -270
  9. package/dist/apps/data/routes/addresses.d.ts +248 -17
  10. package/dist/apps/data/routes/addresses.d.ts.map +1 -1
  11. package/dist/apps/data/routes/balances.d.ts +272 -2
  12. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  13. package/dist/apps/data/routes/balances.js +114 -2
  14. package/dist/apps/data/routes/balances.js.map +1 -1
  15. package/dist/apps/data/routes/blocks.d.ts +123 -123
  16. package/dist/apps/data/routes/earn.d.ts +65 -3
  17. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  18. package/dist/apps/data/routes/earn.js +259 -14
  19. package/dist/apps/data/routes/earn.js.map +1 -1
  20. package/dist/apps/data/routes/rpc.d.ts +31 -31
  21. package/dist/apps/data/routes/tokens.d.ts +454 -454
  22. package/dist/apps/data/routes/transfers.d.ts +81 -81
  23. package/dist/apps/funding/App.d.ts +40 -299
  24. package/dist/apps/funding/App.d.ts.map +1 -1
  25. package/dist/apps/funding/App.js +20 -5
  26. package/dist/apps/funding/App.js.map +1 -1
  27. package/dist/apps/funding/routes/deposit-addresses.d.ts +43 -434
  28. package/dist/apps/funding/routes/deposit-addresses.d.ts.map +1 -1
  29. package/dist/apps/funding/routes/deposit-addresses.js +21 -103
  30. package/dist/apps/funding/routes/deposit-addresses.js.map +1 -1
  31. package/dist/apps/funding/routes/quotes.d.ts +89 -89
  32. package/dist/apps/funding/routes/transfers.js +5 -5
  33. package/dist/apps/funding/routes/transfers.js.map +1 -1
  34. package/dist/apps/management/routes/invitations.d.ts +134 -134
  35. package/dist/apps/management/routes/orgs.d.ts +98 -98
  36. package/dist/apps/management/routes/verified-token-requests.d.ts +83 -83
  37. package/dist/apps/mpp/App.d.ts +44 -44
  38. package/dist/db/Db.d.ts.map +1 -1
  39. package/dist/db/Db.js +8 -0
  40. package/dist/db/Db.js.map +1 -1
  41. package/dist/db/tables/fundingDeposits.d.ts +18 -1
  42. package/dist/db/tables/fundingDeposits.d.ts.map +1 -1
  43. package/dist/db/tables/fundingDeposits.js +46 -2
  44. package/dist/db/tables/fundingDeposits.js.map +1 -1
  45. package/dist/internal/Auth.d.ts +4 -0
  46. package/dist/internal/Auth.d.ts.map +1 -1
  47. package/dist/internal/Auth.js +11 -2
  48. package/dist/internal/Auth.js.map +1 -1
  49. package/dist/internal/funding/Provider.d.ts +6 -6
  50. package/dist/internal/funding/Provider.d.ts.map +1 -1
  51. package/dist/internal/funding/Reconciliation.d.ts.map +1 -1
  52. package/dist/internal/funding/Reconciliation.js +101 -16
  53. package/dist/internal/funding/Reconciliation.js.map +1 -1
  54. package/dist/internal/funding/providers/relay.d.ts.map +1 -1
  55. package/dist/internal/funding/providers/relay.js +6 -2
  56. package/dist/internal/funding/providers/relay.js.map +1 -1
  57. package/package.json +1 -1
  58. package/src/App.test.ts +32 -0
  59. package/src/App.ts +4 -1
  60. package/src/Client.test-d.ts +56 -33
  61. package/src/apps/composition.test.ts +39 -10
  62. package/src/apps/data/routes/balances.test.ts +42 -0
  63. package/src/apps/data/routes/balances.ts +218 -85
  64. package/src/apps/data/routes/earn.test.ts +89 -9
  65. package/src/apps/data/routes/earn.ts +355 -14
  66. package/src/apps/funding/App.ts +20 -5
  67. package/src/apps/funding/routes/deposit-addresses.test.ts +43 -22
  68. package/src/apps/funding/routes/deposit-addresses.ts +34 -117
  69. package/src/apps/funding/routes/transfers.test.ts +6 -25
  70. package/src/apps/funding/routes/transfers.ts +5 -5
  71. package/src/db/Db.ts +9 -0
  72. package/src/db/tables/fundingDeposits.test.ts +101 -0
  73. package/src/db/tables/fundingDeposits.ts +71 -2
  74. package/src/internal/Auth.test.ts +28 -0
  75. package/src/internal/Auth.ts +15 -1
  76. package/src/internal/funding/Provider.ts +4 -4
  77. package/src/internal/funding/Reconciliation.test.ts +292 -54
  78. package/src/internal/funding/Reconciliation.ts +160 -53
  79. package/src/internal/funding/SourceObservation.test.ts +2 -2
  80. package/src/internal/funding/providers/relay.ts +7 -2
@@ -56,6 +56,8 @@ const venueSharesDepositedSignature =
56
56
 
57
57
  const maxScannedDeployments = 250
58
58
  const scanLimit = 50
59
+ /** Block boundary that includes all indexed history. */
60
+ const beforeFirstBlockNumber = -1
59
61
 
60
62
  /** Vault TVL is reported in USD only; the API exposes no denomination parameter. */
61
63
  const tvlDenomination = 'USD'
@@ -345,8 +347,13 @@ export namespace schema {
345
347
  })
346
348
 
347
349
  const earningsPeriod = z
348
- .enum(['active', 'lifetime'])
349
- .check(z.describe('Earnings period to calculate.'), z.meta({ examples: ['lifetime'] }))
350
+ .enum(['30d', 'active', 'lifetime'])
351
+ .check(
352
+ z.describe(
353
+ 'Earnings period to calculate: trailing 30 days, shares still held, or lifetime history.',
354
+ ),
355
+ z.meta({ examples: ['lifetime'] }),
356
+ )
350
357
 
351
358
  const earnings = z.union([
352
359
  z.extend(earningsBase, {
@@ -395,22 +402,45 @@ export namespace schema {
395
402
  z.meta({ examples: ['complete'] }),
396
403
  ),
397
404
  }),
405
+ z.extend(earningsBase, {
406
+ period: z
407
+ .literal('30d')
408
+ .check(
409
+ z.describe('Returns cash-flow-adjusted earnings over the trailing 30 days.'),
410
+ z.meta({ examples: ['30d'] }),
411
+ ),
412
+ status: z
413
+ .literal('complete')
414
+ .check(
415
+ z.describe('Earnings include a complete asset-denominated cost basis.'),
416
+ z.meta({ examples: ['complete'] }),
417
+ ),
418
+ windowEarnings: z
419
+ .string()
420
+ .check(
421
+ z.regex(/^-?\d+$/),
422
+ z.describe(
423
+ 'Ending share value plus realized assets, minus deposits and opening share value, over the trailing 30 days.',
424
+ ),
425
+ z.meta({ examples: ['0'] }),
426
+ ),
427
+ }),
398
428
  z.extend(earningsBase, {
399
429
  period: earningsPeriod,
400
430
  status: z
401
431
  .literal('incomplete_cost_basis')
402
432
  .check(
403
433
  z.describe(
404
- 'Earnings are unavailable when indexed activity cannot reconstruct the remaining asset cost basis.',
434
+ 'Earnings are unavailable when indexed activity cannot reconstruct the asset cost basis for the requested period.',
405
435
  ),
406
436
  z.meta({ examples: ['incomplete_cost_basis'] }),
407
437
  ),
408
438
  }),
409
439
  z.extend(earningsBase, {
410
440
  period: z
411
- .literal('lifetime')
441
+ .enum(['30d', 'lifetime'])
412
442
  .check(
413
- z.describe('Returns lifetime net asset earnings.'),
443
+ z.describe('Earnings period with an unresolved async redemption.'),
414
444
  z.meta({ examples: ['lifetime'] }),
415
445
  ),
416
446
  status: z
@@ -791,7 +821,7 @@ export function earn(options: earn.Options = {}) {
791
821
  }),
792
822
  OpenApi.describeRoute({
793
823
  description:
794
- 'Gets an account’s indexed asset value and earnings for lifetime history or shares still held.',
824
+ 'Gets an account’s indexed asset value and earnings for lifetime history, the trailing 30 days, or shares still held.',
795
825
  operationId: 'getEarnVaultEarnings',
796
826
  responses: OpenApi.responses({
797
827
  errors: {
@@ -820,7 +850,7 @@ export function earn(options: earn.Options = {}) {
820
850
  Cache.response<App.Environment>({
821
851
  cacheControl: Cache.policies.state,
822
852
  key: (c) => Cache.urlKey(c, schema.getEarnVaultEarnings.Query),
823
- name: 'tempo-api:earn-vault-earnings:v2',
853
+ name: 'tempo-api:earn-vault-earnings:v3',
824
854
  }),
825
855
  async (c) => {
826
856
  if (Auth.narrowAccess) return Auth.paidAccessError(c)
@@ -962,7 +992,17 @@ export async function getVaultEarnings(
962
992
  ) {
963
993
  const client = c.get('getClient')(options.chainId)
964
994
  const tidx = c.get('getTidx')(options.chainId)
965
- const blockNumber = await getLatestIndexedBlockNumber(tidx)
995
+ const block = await getLatestIndexedBlock(tidx)
996
+ const blockNumber = block.number
997
+ if (options.period === '30d')
998
+ return getWindowVaultEarnings(c, {
999
+ account: options.account,
1000
+ blockNumber,
1001
+ chainId: options.chainId,
1002
+ period: options.period,
1003
+ timestamp: block.timestamp,
1004
+ vault: options.vault,
1005
+ })
966
1006
  const position = client.earn.getPosition({
967
1007
  account: options.account,
968
1008
  blockNumber: BigInt(blockNumber),
@@ -995,6 +1035,7 @@ export async function getVaultEarnings(
995
1035
  getVaultEarningsHistory(tidx, {
996
1036
  account: options.account,
997
1037
  blockNumber,
1038
+ startBlockNumber: beforeFirstBlockNumber,
998
1039
  vault: options.vault,
999
1040
  }),
1000
1041
  position,
@@ -1003,6 +1044,7 @@ export async function getVaultEarnings(
1003
1044
  account: options.account,
1004
1045
  blockNumber,
1005
1046
  shareToken: current.shareToken,
1047
+ startBlockNumber: beforeFirstBlockNumber,
1006
1048
  vault: options.vault,
1007
1049
  })
1008
1050
  const base = {
@@ -1020,6 +1062,126 @@ export async function getVaultEarnings(
1020
1062
  return { ...base, lifetimeEarnings: lifetimeEarnings.toString(), status: 'complete' as const }
1021
1063
  }
1022
1064
 
1065
+ /** Reads cash-flow-adjusted earnings over a trailing indexed window. */
1066
+ async function getWindowVaultEarnings(
1067
+ c: Context<App.Environment>,
1068
+ options: getWindowVaultEarnings.Options,
1069
+ ) {
1070
+ const client = c.get('getClient')(options.chainId)
1071
+ const tidx = c.get('getTidx')(options.chainId)
1072
+ const [current, startBlockNumber] = await Promise.all([
1073
+ client.earn.getPosition({
1074
+ account: options.account,
1075
+ blockNumber: BigInt(options.blockNumber),
1076
+ vault: options.vault,
1077
+ }),
1078
+ getWindowStartBlockNumber(tidx, { days: 30, timestamp: options.timestamp }),
1079
+ ])
1080
+ const [externalShareTransfer, history, opening] = await Promise.all([
1081
+ hasExternalShareTransfer(tidx, {
1082
+ account: options.account,
1083
+ blockNumber: options.blockNumber,
1084
+ shareToken: current.shareToken,
1085
+ startBlockNumber,
1086
+ vault: options.vault,
1087
+ }),
1088
+ getVaultEarningsHistory(tidx, {
1089
+ account: options.account,
1090
+ blockNumber: options.blockNumber,
1091
+ startBlockNumber,
1092
+ vault: options.vault,
1093
+ }),
1094
+ getWindowShareState(tidx, {
1095
+ account: options.account,
1096
+ blockNumber: options.blockNumber,
1097
+ shareToken: current.shareToken,
1098
+ startBlockNumber,
1099
+ vault: options.vault,
1100
+ }),
1101
+ ])
1102
+ const base = {
1103
+ account: options.account,
1104
+ assetToken: current.assetToken,
1105
+ currentValue: current.value.toString(),
1106
+ id: options.account,
1107
+ period: options.period,
1108
+ }
1109
+ if (
1110
+ opening === undefined ||
1111
+ externalShareTransfer ||
1112
+ history.incompleteCostBasis ||
1113
+ opening.crossBoundaryRedemption ||
1114
+ opening.endShares !== current.shareBalance
1115
+ )
1116
+ return { ...base, status: 'incomplete_cost_basis' as const }
1117
+ if (history.pendingRedemption) return { ...base, status: 'pending_redemption' as const }
1118
+ const openingValue =
1119
+ opening.startShares === 0n
1120
+ ? 0n
1121
+ : await client.earn.getRedeemQuote({
1122
+ blockNumber: BigInt(startBlockNumber),
1123
+ shareAmount: opening.startShares,
1124
+ vault: options.vault,
1125
+ })
1126
+ const windowEarnings = calculateWindowEarnings({
1127
+ deposited: history.deposited,
1128
+ endingValue: current.value,
1129
+ finalized: history.finalized,
1130
+ openingValue,
1131
+ redeemed: history.redeemed,
1132
+ withdrewExact: history.withdrewExact,
1133
+ })
1134
+ return { ...base, status: 'complete' as const, windowEarnings: windowEarnings.toString() }
1135
+ }
1136
+
1137
+ declare namespace getWindowVaultEarnings {
1138
+ /** Inputs identifying one account, vault, and indexed window end. */
1139
+ type Options = {
1140
+ /** Account whose earnings are calculated. */
1141
+ account: z.output<typeof Schema.Address>
1142
+ /** Latest indexed block number. */
1143
+ blockNumber: number
1144
+ /** Tempo chain containing the vault. */
1145
+ chainId: z.output<typeof Schema.ChainId>
1146
+ /** Trailing earnings period. */
1147
+ period: '30d'
1148
+ /** Latest indexed block timestamp. */
1149
+ timestamp: string
1150
+ /** Earn vault contract address. */
1151
+ vault: z.output<typeof Schema.Address>
1152
+ }
1153
+ }
1154
+
1155
+ /** Calculates cash-flow-adjusted earnings between two position snapshots. */
1156
+ export function calculateWindowEarnings(options: calculateWindowEarnings.Options) {
1157
+ return (
1158
+ options.endingValue +
1159
+ options.redeemed +
1160
+ options.withdrewExact +
1161
+ options.finalized -
1162
+ options.deposited -
1163
+ options.openingValue
1164
+ )
1165
+ }
1166
+
1167
+ export declare namespace calculateWindowEarnings {
1168
+ /** Asset-denominated values spanning one earnings window. */
1169
+ type Options = {
1170
+ /** Assets deposited during the window. */
1171
+ deposited: bigint
1172
+ /** Asset value of shares held at the ending boundary. */
1173
+ endingValue: bigint
1174
+ /** Assets received from async redemptions finalized during the window. */
1175
+ finalized: bigint
1176
+ /** Asset value of shares held at the opening boundary. */
1177
+ openingValue: bigint
1178
+ /** Assets received from redemptions during the window. */
1179
+ redeemed: bigint
1180
+ /** Assets received from exact withdrawals during the window. */
1181
+ withdrewExact: bigint
1182
+ }
1183
+ }
1184
+
1023
1185
  export declare namespace getVaultEarnings {
1024
1186
  /** Inputs identifying the account and vault to calculate. */
1025
1187
  type Options = {
@@ -1031,16 +1193,45 @@ export declare namespace getVaultEarnings {
1031
1193
  }
1032
1194
 
1033
1195
  /** Reads the latest block whose indexed logs back the earnings calculation. */
1034
- async function getLatestIndexedBlockNumber(tidx: Tidx.Client) {
1196
+ async function getLatestIndexedBlock(tidx: Tidx.Client) {
1035
1197
  const result = await tidx.fetch({
1036
1198
  engine: 'clickhouse',
1037
- query: 'SELECT num FROM blocks ORDER BY num DESC LIMIT 1' as string,
1199
+ query: 'SELECT num, timestamp FROM blocks ORDER BY num DESC LIMIT 1' as string,
1200
+ })
1201
+ const number = Value.toNumber(result.rows[0]?.['num'])
1202
+ const timestamp = Value.toIsoDateTime(result.rows[0]?.['timestamp'])
1203
+ if (number === undefined || timestamp === undefined)
1204
+ throw new Error('TIDX returned no indexed block.')
1205
+ return { number, timestamp }
1206
+ }
1207
+
1208
+ /** Resolves the last indexed block at or before a trailing-day boundary. */
1209
+ async function getWindowStartBlockNumber(
1210
+ tidx: Tidx.Client,
1211
+ options: getWindowStartBlockNumber.Options,
1212
+ ) {
1213
+ const cutoff = new Date(Date.parse(options.timestamp) - Ttl.days(options.days)).toISOString()
1214
+ const result = await tidx.fetch({
1215
+ query:
1216
+ `SELECT num FROM blocks WHERE timestamp <= '${cutoff}' ORDER BY num DESC LIMIT 1` as string,
1038
1217
  })
1039
- const blockNumber = Value.toNumber(result.rows[0]?.['num'])
1040
- if (blockNumber === undefined) throw new Error('TIDX returned no indexed block.')
1218
+ const row = result.rows[0]
1219
+ if (!row) return beforeFirstBlockNumber
1220
+ const blockNumber = Value.toNumber(row['num'])
1221
+ if (blockNumber === undefined) throw new Error('TIDX returned no Earn earnings boundary.')
1041
1222
  return blockNumber
1042
1223
  }
1043
1224
 
1225
+ declare namespace getWindowStartBlockNumber {
1226
+ /** Inputs defining a trailing boundary from an indexed timestamp. */
1227
+ type Options = {
1228
+ /** Number of trailing days. */
1229
+ days: number
1230
+ /** Timestamp anchoring the end of the window. */
1231
+ timestamp: string
1232
+ }
1233
+ }
1234
+
1044
1235
  /** Reads the indexed cash flows and exceptional states behind one earnings calculation. */
1045
1236
  async function getVaultEarningsHistory(
1046
1237
  tidx: Tidx.Client,
@@ -1055,6 +1246,7 @@ async function getVaultEarningsHistory(
1055
1246
  FROM Deposited
1056
1247
  WHERE address = '${options.vault}'
1057
1248
  AND receiver = '${options.account}'
1249
+ AND block_num > ${options.startBlockNumber}
1058
1250
  AND block_num <= ${options.blockNumber}
1059
1251
  ) AS deposited_assets,
1060
1252
  (
@@ -1065,6 +1257,7 @@ async function getVaultEarningsHistory(
1065
1257
  AND requested."requestId" = finalized."requestId"
1066
1258
  WHERE finalized.address = '${options.vault}'
1067
1259
  AND requested.requester = '${options.account}'
1260
+ AND finalized.block_num > ${options.startBlockNumber}
1068
1261
  AND finalized.block_num <= ${options.blockNumber}
1069
1262
  AND requested.block_num <= ${options.blockNumber}
1070
1263
  ) AS finalized_assets,
@@ -1088,6 +1281,7 @@ async function getVaultEarningsHistory(
1088
1281
  FROM Redeemed
1089
1282
  WHERE address = '${options.vault}'
1090
1283
  AND caller = '${options.account}'
1284
+ AND block_num > ${options.startBlockNumber}
1091
1285
  AND block_num <= ${options.blockNumber}
1092
1286
  ) AS redeemed_assets,
1093
1287
  (
@@ -1097,6 +1291,7 @@ async function getVaultEarningsHistory(
1097
1291
  ON requested.address = cancelled.address
1098
1292
  AND requested."requestId" = cancelled."requestId"
1099
1293
  WHERE cancelled.address = '${options.vault}'
1294
+ AND cancelled.block_num > ${options.startBlockNumber}
1100
1295
  AND cancelled.block_num <= ${options.blockNumber}
1101
1296
  AND requested.block_num <= ${options.blockNumber}
1102
1297
  AND requested.requester != cancelled.receiver
@@ -1110,6 +1305,7 @@ async function getVaultEarningsHistory(
1110
1305
  FROM VenueSharesDeposited
1111
1306
  WHERE address = '${options.vault}'
1112
1307
  AND receiver = '${options.account}'
1308
+ AND block_num > ${options.startBlockNumber}
1113
1309
  AND block_num <= ${options.blockNumber}
1114
1310
  ) AS venue_deposits,
1115
1311
  (
@@ -1117,6 +1313,7 @@ async function getVaultEarningsHistory(
1117
1313
  FROM WithdrewExact
1118
1314
  WHERE address = '${options.vault}'
1119
1315
  AND caller = '${options.account}'
1316
+ AND block_num > ${options.startBlockNumber}
1120
1317
  AND block_num <= ${options.blockNumber}
1121
1318
  ) AS withdrew_exact
1122
1319
  ` as string,
@@ -1162,6 +1359,112 @@ declare namespace getVaultEarningsHistory {
1162
1359
  type Options = {
1163
1360
  account: z.output<typeof Schema.Address>
1164
1361
  blockNumber: number
1362
+ startBlockNumber: number
1363
+ vault: z.output<typeof Schema.Address>
1364
+ }
1365
+ }
1366
+
1367
+ /** Reads share balances and cross-boundary redemptions for a trailing window. */
1368
+ async function getWindowShareState(tidx: Tidx.Client, options: getWindowShareState.Options) {
1369
+ const result = await tidx.fetch({
1370
+ engine: 'clickhouse',
1371
+ query: `
1372
+ SELECT
1373
+ (
1374
+ SELECT toString(sum(toUInt256(amount)))
1375
+ FROM token_transfers
1376
+ WHERE token = '${options.shareToken.toLowerCase()}'
1377
+ AND "to" = '${options.account}'
1378
+ AND block_num <= ${options.startBlockNumber}
1379
+ ) AS received_start,
1380
+ (
1381
+ SELECT toString(sum(toUInt256(amount)))
1382
+ FROM token_transfers
1383
+ WHERE token = '${options.shareToken.toLowerCase()}'
1384
+ AND "from" = '${options.account}'
1385
+ AND block_num <= ${options.startBlockNumber}
1386
+ ) AS sent_start,
1387
+ (
1388
+ SELECT toString(sum(toUInt256(amount)))
1389
+ FROM token_transfers
1390
+ WHERE token = '${options.shareToken.toLowerCase()}'
1391
+ AND "to" = '${options.account}'
1392
+ AND block_num <= ${options.blockNumber}
1393
+ ) AS received_end,
1394
+ (
1395
+ SELECT toString(sum(toUInt256(amount)))
1396
+ FROM token_transfers
1397
+ WHERE token = '${options.shareToken.toLowerCase()}'
1398
+ AND "from" = '${options.account}'
1399
+ AND block_num <= ${options.blockNumber}
1400
+ ) AS sent_end,
1401
+ (
1402
+ SELECT count()
1403
+ FROM (
1404
+ SELECT finalized."requestId"
1405
+ FROM RedeemFinalized AS finalized
1406
+ INNER JOIN RedeemRequested AS requested
1407
+ ON requested.address = finalized.address
1408
+ AND requested."requestId" = finalized."requestId"
1409
+ WHERE finalized.address = '${options.vault}'
1410
+ AND requested.requester = '${options.account}'
1411
+ AND requested.block_num <= ${options.startBlockNumber}
1412
+ AND finalized.block_num > ${options.startBlockNumber}
1413
+ AND finalized.block_num <= ${options.blockNumber}
1414
+ UNION ALL
1415
+ SELECT cancelled."requestId"
1416
+ FROM RedeemCancelled AS cancelled
1417
+ INNER JOIN RedeemRequested AS requested
1418
+ ON requested.address = cancelled.address
1419
+ AND requested."requestId" = cancelled."requestId"
1420
+ WHERE cancelled.address = '${options.vault}'
1421
+ AND requested.requester = '${options.account}'
1422
+ AND requested.block_num <= ${options.startBlockNumber}
1423
+ AND cancelled.block_num > ${options.startBlockNumber}
1424
+ AND cancelled.block_num <= ${options.blockNumber}
1425
+ ) AS cross_boundary
1426
+ ) AS cross_boundary_redemptions
1427
+ ` as string,
1428
+ signatures: [redeemCancelledSignature, redeemFinalizedSignature, redeemRequestedSignature],
1429
+ })
1430
+ const row = result.rows[0]
1431
+ const crossBoundaryRedemptions = Value.toNumber(row?.['cross_boundary_redemptions'])
1432
+ const receivedEnd = Value.toIntegerString(row?.['received_end'])
1433
+ const receivedStart = Value.toIntegerString(row?.['received_start'])
1434
+ const sentEnd = Value.toIntegerString(row?.['sent_end'])
1435
+ const sentStart = Value.toIntegerString(row?.['sent_start'])
1436
+ if (
1437
+ crossBoundaryRedemptions === undefined ||
1438
+ receivedEnd === undefined ||
1439
+ receivedStart === undefined ||
1440
+ sentEnd === undefined ||
1441
+ sentStart === undefined
1442
+ )
1443
+ return undefined
1444
+ const receivedEndValue = BigInt(receivedEnd)
1445
+ const receivedStartValue = BigInt(receivedStart)
1446
+ const sentEndValue = BigInt(sentEnd)
1447
+ const sentStartValue = BigInt(sentStart)
1448
+ if (sentEndValue > receivedEndValue || sentStartValue > receivedStartValue) return undefined
1449
+ return {
1450
+ crossBoundaryRedemption: crossBoundaryRedemptions > 0,
1451
+ endShares: receivedEndValue - sentEndValue,
1452
+ startShares: receivedStartValue - sentStartValue,
1453
+ }
1454
+ }
1455
+
1456
+ declare namespace getWindowShareState {
1457
+ /** Inputs identifying one account's share history window. */
1458
+ type Options = {
1459
+ /** Account whose share history is read. */
1460
+ account: z.output<typeof Schema.Address>
1461
+ /** Ending indexed block number. */
1462
+ blockNumber: number
1463
+ /** Earn share token contract address. */
1464
+ shareToken: z.output<typeof Schema.Address>
1465
+ /** Opening indexed block number. */
1466
+ startBlockNumber: number
1467
+ /** Earn vault contract address. */
1165
1468
  vault: z.output<typeof Schema.Address>
1166
1469
  }
1167
1470
  }
@@ -1180,10 +1483,15 @@ async function hasExternalShareTransfer(
1180
1483
  SELECT count()
1181
1484
  FROM token_transfers
1182
1485
  WHERE token = '${options.shareToken.toLowerCase()}'
1486
+ AND block_num > ${options.startBlockNumber}
1183
1487
  AND block_num <= ${options.blockNumber}
1184
1488
  AND (
1185
1489
  ("from" = '${options.account}' AND "to" != '${options.vault}')
1186
- OR ("to" = '${options.account}' AND "from" != '${zeroAddress}')
1490
+ OR (
1491
+ "to" = '${options.account}'
1492
+ AND "from" != '${zeroAddress}'
1493
+ AND "from" != '${options.vault}'
1494
+ )
1187
1495
  )
1188
1496
  ) + (
1189
1497
  SELECT count()
@@ -1193,6 +1501,7 @@ async function hasExternalShareTransfer(
1193
1501
  WHERE token = '${options.shareToken.toLowerCase()}'
1194
1502
  AND "from" = '${options.account}'
1195
1503
  AND "to" = '${options.vault}'
1504
+ AND block_num > ${options.startBlockNumber}
1196
1505
  AND block_num <= ${options.blockNumber}
1197
1506
  GROUP BY tx_hash, amount
1198
1507
  ) AS candidate
@@ -1203,27 +1512,58 @@ async function hasExternalShareTransfer(
1203
1512
  FROM Redeemed
1204
1513
  WHERE address = '${options.vault}'
1205
1514
  AND caller = '${options.account}'
1515
+ AND block_num > ${options.startBlockNumber}
1206
1516
  AND block_num <= ${options.blockNumber}
1207
1517
  UNION ALL
1208
1518
  SELECT tx_hash, toUInt256(earnShares) AS amount
1209
1519
  FROM RedeemRequested
1210
1520
  WHERE address = '${options.vault}'
1211
1521
  AND requester = '${options.account}'
1522
+ AND block_num > ${options.startBlockNumber}
1212
1523
  AND block_num <= ${options.blockNumber}
1213
1524
  UNION ALL
1214
1525
  SELECT tx_hash, toUInt256(earnSharesBurned) AS amount
1215
1526
  FROM WithdrewExact
1216
1527
  WHERE address = '${options.vault}'
1217
1528
  AND caller = '${options.account}'
1529
+ AND block_num > ${options.startBlockNumber}
1218
1530
  AND block_num <= ${options.blockNumber}
1219
1531
  ) AS protocol_exit
1220
1532
  GROUP BY tx_hash, amount
1221
1533
  ) AS matched
1222
1534
  ON matched.tx_hash = candidate.tx_hash AND matched.amount = candidate.amount
1223
1535
  WHERE candidate.transfer_count > coalesce(matched.exit_count, 0)
1536
+ ) + (
1537
+ SELECT count()
1538
+ FROM (
1539
+ SELECT tx_hash, toUInt256(amount) AS amount, count() AS transfer_count
1540
+ FROM token_transfers
1541
+ WHERE token = '${options.shareToken.toLowerCase()}'
1542
+ AND "from" = '${options.vault}'
1543
+ AND "to" = '${options.account}'
1544
+ AND block_num > ${options.startBlockNumber}
1545
+ AND block_num <= ${options.blockNumber}
1546
+ GROUP BY tx_hash, amount
1547
+ ) AS candidate
1548
+ LEFT JOIN (
1549
+ SELECT tx_hash, toUInt256(earnShares) AS amount, count() AS cancel_count
1550
+ FROM RedeemCancelled
1551
+ WHERE address = '${options.vault}'
1552
+ AND receiver = '${options.account}'
1553
+ AND block_num > ${options.startBlockNumber}
1554
+ AND block_num <= ${options.blockNumber}
1555
+ GROUP BY tx_hash, amount
1556
+ ) AS matched
1557
+ ON matched.tx_hash = candidate.tx_hash AND matched.amount = candidate.amount
1558
+ WHERE candidate.transfer_count > coalesce(matched.cancel_count, 0)
1224
1559
  ) AS count
1225
1560
  ` as string,
1226
- signatures: [redeemedSignature, redeemRequestedSignature, withdrewExactSignature],
1561
+ signatures: [
1562
+ redeemCancelledSignature,
1563
+ redeemedSignature,
1564
+ redeemRequestedSignature,
1565
+ withdrewExactSignature,
1566
+ ],
1227
1567
  })
1228
1568
  const count = Value.toNumber(result.rows[0]?.['count'])
1229
1569
  if (count === undefined) throw new Error('TIDX returned an invalid Earn-share transfer count.')
@@ -1235,6 +1575,7 @@ declare namespace hasExternalShareTransfer {
1235
1575
  account: z.output<typeof Schema.Address>
1236
1576
  blockNumber: number
1237
1577
  shareToken: z.output<typeof Schema.Address>
1578
+ startBlockNumber: number
1238
1579
  vault: z.output<typeof Schema.Address>
1239
1580
  }
1240
1581
  }
@@ -42,22 +42,37 @@ export declare namespace funding {
42
42
 
43
43
  const openapi = {
44
44
  tags: [
45
- { name: 'Chains', description: 'Source chains and stablecoins supported for funding.' },
45
+ {
46
+ name: 'Chains',
47
+ description: 'Source chains and stablecoins supported for funding.',
48
+ 'x-pagePath': 'funding/chains',
49
+ },
46
50
  {
47
51
  name: 'Deposit Addresses',
48
52
  description: 'Reusable funding addresses and deposits detected at those addresses.',
53
+ 'x-pagePath': 'funding/deposit-addresses',
54
+ },
55
+ {
56
+ name: 'Providers',
57
+ description: 'Providers available for inbound funding.',
58
+ 'x-pagePath': 'funding/providers',
59
+ },
60
+ {
61
+ name: 'Quotes',
62
+ description: 'Live quotes for funding Tempo from other chains.',
63
+ 'x-pagePath': 'funding/quotes',
49
64
  },
50
- { name: 'Providers', description: 'Providers available for inbound funding.' },
51
- { name: 'Quotes', description: 'Live quotes for funding Tempo from other chains.' },
52
65
  {
53
- name: 'Transfers',
66
+ name: 'Funding Transfers',
54
67
  description: 'Inbound funding transfers.',
68
+ 'x-displayName': 'Transfers',
69
+ 'x-pagePath': 'funding/transfers',
55
70
  },
56
71
  ],
57
72
  'x-tagGroups': [
58
73
  {
59
74
  name: 'Funding & Bridge API',
60
- tags: ['Chains', 'Deposit Addresses', 'Providers', 'Quotes', 'Transfers'],
75
+ tags: ['Chains', 'Deposit Addresses', 'Providers', 'Quotes', 'Funding Transfers'],
61
76
  },
62
77
  ],
63
78
  } satisfies App.create.Metadata