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
@@ -31,6 +31,8 @@ const redeemRequestedSignature = 'event RedeemRequested(bytes32 indexed requestI
31
31
  const venueSharesDepositedSignature = 'event VenueSharesDeposited(address indexed caller,address indexed receiver,uint256 requestedVenueShares,uint256 receivedVenueShares,uint256 earnShares)';
32
32
  const maxScannedDeployments = 250;
33
33
  const scanLimit = 50;
34
+ /** Block boundary that includes all indexed history. */
35
+ const beforeFirstBlockNumber = -1;
34
36
  /** Vault TVL is reported in USD only; the API exposes no denomination parameter. */
35
37
  const tvlDenomination = 'USD';
36
38
  /** `Valuation.valuationFor` floors to 6 dp, so 6 is the precision a valued amount carries. */
@@ -170,8 +172,8 @@ export var schema;
170
172
  id: Schema.Address.check(z.describe('Stable resource ID for these vault earnings, equal to the account address.'), z.meta({ examples: ['0x68f94cfca22e5969c0553bbeab00a2acde88939b'] })),
171
173
  });
172
174
  const earningsPeriod = z
173
- .enum(['active', 'lifetime'])
174
- .check(z.describe('Earnings period to calculate.'), z.meta({ examples: ['lifetime'] }));
175
+ .enum(['30d', 'active', 'lifetime'])
176
+ .check(z.describe('Earnings period to calculate: trailing 30 days, shares still held, or lifetime history.'), z.meta({ examples: ['lifetime'] }));
175
177
  const earnings = z.union([
176
178
  z.extend(earningsBase, {
177
179
  lifetimeEarnings: z
@@ -195,16 +197,27 @@ export var schema;
195
197
  .literal('complete')
196
198
  .check(z.describe('Earnings include a complete asset-denominated cost basis.'), z.meta({ examples: ['complete'] })),
197
199
  }),
200
+ z.extend(earningsBase, {
201
+ period: z
202
+ .literal('30d')
203
+ .check(z.describe('Returns cash-flow-adjusted earnings over the trailing 30 days.'), z.meta({ examples: ['30d'] })),
204
+ status: z
205
+ .literal('complete')
206
+ .check(z.describe('Earnings include a complete asset-denominated cost basis.'), z.meta({ examples: ['complete'] })),
207
+ windowEarnings: z
208
+ .string()
209
+ .check(z.regex(/^-?\d+$/), z.describe('Ending share value plus realized assets, minus deposits and opening share value, over the trailing 30 days.'), z.meta({ examples: ['0'] })),
210
+ }),
198
211
  z.extend(earningsBase, {
199
212
  period: earningsPeriod,
200
213
  status: z
201
214
  .literal('incomplete_cost_basis')
202
- .check(z.describe('Earnings are unavailable when indexed activity cannot reconstruct the remaining asset cost basis.'), z.meta({ examples: ['incomplete_cost_basis'] })),
215
+ .check(z.describe('Earnings are unavailable when indexed activity cannot reconstruct the asset cost basis for the requested period.'), z.meta({ examples: ['incomplete_cost_basis'] })),
203
216
  }),
204
217
  z.extend(earningsBase, {
205
218
  period: z
206
- .literal('lifetime')
207
- .check(z.describe('Returns lifetime net asset earnings.'), z.meta({ examples: ['lifetime'] })),
219
+ .enum(['30d', 'lifetime'])
220
+ .check(z.describe('Earnings period with an unresolved async redemption.'), z.meta({ examples: ['lifetime'] })),
208
221
  status: z
209
222
  .literal('pending_redemption')
210
223
  .check(z.describe('Earnings are unavailable while an async redemption remains open.'), z.meta({ examples: ['pending_redemption'] })),
@@ -510,7 +523,7 @@ export function earn(options = {}) {
510
523
  code: 'query_invalid',
511
524
  message: 'Invalid query parameters',
512
525
  }), OpenApi.describeRoute({
513
- description: 'Gets an account’s indexed asset value and earnings for lifetime history or shares still held.',
526
+ description: 'Gets an account’s indexed asset value and earnings for lifetime history, the trailing 30 days, or shares still held.',
514
527
  operationId: 'getEarnVaultEarnings',
515
528
  responses: OpenApi.responses({
516
529
  errors: {
@@ -538,7 +551,7 @@ export function earn(options = {}) {
538
551
  }), Cache.response({
539
552
  cacheControl: Cache.policies.state,
540
553
  key: (c) => Cache.urlKey(c, schema.getEarnVaultEarnings.Query),
541
- name: 'tempo-api:earn-vault-earnings:v2',
554
+ name: 'tempo-api:earn-vault-earnings:v3',
542
555
  }), async (c) => {
543
556
  if (Auth.narrowAccess)
544
557
  return Auth.paidAccessError(c);
@@ -660,7 +673,17 @@ export function earn(options = {}) {
660
673
  export async function getVaultEarnings(c, options) {
661
674
  const client = c.get('getClient')(options.chainId);
662
675
  const tidx = c.get('getTidx')(options.chainId);
663
- const blockNumber = await getLatestIndexedBlockNumber(tidx);
676
+ const block = await getLatestIndexedBlock(tidx);
677
+ const blockNumber = block.number;
678
+ if (options.period === '30d')
679
+ return getWindowVaultEarnings(c, {
680
+ account: options.account,
681
+ blockNumber,
682
+ chainId: options.chainId,
683
+ period: options.period,
684
+ timestamp: block.timestamp,
685
+ vault: options.vault,
686
+ });
664
687
  const position = client.earn.getPosition({
665
688
  account: options.account,
666
689
  blockNumber: BigInt(blockNumber),
@@ -694,6 +717,7 @@ export async function getVaultEarnings(c, options) {
694
717
  getVaultEarningsHistory(tidx, {
695
718
  account: options.account,
696
719
  blockNumber,
720
+ startBlockNumber: beforeFirstBlockNumber,
697
721
  vault: options.vault,
698
722
  }),
699
723
  position,
@@ -702,6 +726,7 @@ export async function getVaultEarnings(c, options) {
702
726
  account: options.account,
703
727
  blockNumber,
704
728
  shareToken: current.shareToken,
729
+ startBlockNumber: beforeFirstBlockNumber,
705
730
  vault: options.vault,
706
731
  });
707
732
  const base = {
@@ -718,15 +743,105 @@ export async function getVaultEarnings(c, options) {
718
743
  const lifetimeEarnings = current.value + history.redeemed + history.withdrewExact + history.finalized - history.deposited;
719
744
  return { ...base, lifetimeEarnings: lifetimeEarnings.toString(), status: 'complete' };
720
745
  }
746
+ /** Reads cash-flow-adjusted earnings over a trailing indexed window. */
747
+ async function getWindowVaultEarnings(c, options) {
748
+ const client = c.get('getClient')(options.chainId);
749
+ const tidx = c.get('getTidx')(options.chainId);
750
+ const [current, startBlockNumber] = await Promise.all([
751
+ client.earn.getPosition({
752
+ account: options.account,
753
+ blockNumber: BigInt(options.blockNumber),
754
+ vault: options.vault,
755
+ }),
756
+ getWindowStartBlockNumber(tidx, { days: 30, timestamp: options.timestamp }),
757
+ ]);
758
+ const [externalShareTransfer, history, opening] = await Promise.all([
759
+ hasExternalShareTransfer(tidx, {
760
+ account: options.account,
761
+ blockNumber: options.blockNumber,
762
+ shareToken: current.shareToken,
763
+ startBlockNumber,
764
+ vault: options.vault,
765
+ }),
766
+ getVaultEarningsHistory(tidx, {
767
+ account: options.account,
768
+ blockNumber: options.blockNumber,
769
+ startBlockNumber,
770
+ vault: options.vault,
771
+ }),
772
+ getWindowShareState(tidx, {
773
+ account: options.account,
774
+ blockNumber: options.blockNumber,
775
+ shareToken: current.shareToken,
776
+ startBlockNumber,
777
+ vault: options.vault,
778
+ }),
779
+ ]);
780
+ const base = {
781
+ account: options.account,
782
+ assetToken: current.assetToken,
783
+ currentValue: current.value.toString(),
784
+ id: options.account,
785
+ period: options.period,
786
+ };
787
+ if (opening === undefined ||
788
+ externalShareTransfer ||
789
+ history.incompleteCostBasis ||
790
+ opening.crossBoundaryRedemption ||
791
+ opening.endShares !== current.shareBalance)
792
+ return { ...base, status: 'incomplete_cost_basis' };
793
+ if (history.pendingRedemption)
794
+ return { ...base, status: 'pending_redemption' };
795
+ const openingValue = opening.startShares === 0n
796
+ ? 0n
797
+ : await client.earn.getRedeemQuote({
798
+ blockNumber: BigInt(startBlockNumber),
799
+ shareAmount: opening.startShares,
800
+ vault: options.vault,
801
+ });
802
+ const windowEarnings = calculateWindowEarnings({
803
+ deposited: history.deposited,
804
+ endingValue: current.value,
805
+ finalized: history.finalized,
806
+ openingValue,
807
+ redeemed: history.redeemed,
808
+ withdrewExact: history.withdrewExact,
809
+ });
810
+ return { ...base, status: 'complete', windowEarnings: windowEarnings.toString() };
811
+ }
812
+ /** Calculates cash-flow-adjusted earnings between two position snapshots. */
813
+ export function calculateWindowEarnings(options) {
814
+ return (options.endingValue +
815
+ options.redeemed +
816
+ options.withdrewExact +
817
+ options.finalized -
818
+ options.deposited -
819
+ options.openingValue);
820
+ }
721
821
  /** Reads the latest block whose indexed logs back the earnings calculation. */
722
- async function getLatestIndexedBlockNumber(tidx) {
822
+ async function getLatestIndexedBlock(tidx) {
723
823
  const result = await tidx.fetch({
724
824
  engine: 'clickhouse',
725
- query: 'SELECT num FROM blocks ORDER BY num DESC LIMIT 1',
825
+ query: 'SELECT num, timestamp FROM blocks ORDER BY num DESC LIMIT 1',
726
826
  });
727
- const blockNumber = Value.toNumber(result.rows[0]?.['num']);
728
- if (blockNumber === undefined)
827
+ const number = Value.toNumber(result.rows[0]?.['num']);
828
+ const timestamp = Value.toIsoDateTime(result.rows[0]?.['timestamp']);
829
+ if (number === undefined || timestamp === undefined)
729
830
  throw new Error('TIDX returned no indexed block.');
831
+ return { number, timestamp };
832
+ }
833
+ /** Resolves the last indexed block at or before a trailing-day boundary. */
834
+ async function getWindowStartBlockNumber(tidx, options) {
835
+ const cutoff = new Date(Date.parse(options.timestamp) - Ttl.days(options.days)).toISOString();
836
+ const result = await tidx.fetch({
837
+ query: `SELECT num FROM blocks WHERE timestamp <= '${cutoff}' ORDER BY num DESC LIMIT 1`,
838
+ });
839
+ const row = result.rows[0];
840
+ if (!row)
841
+ return beforeFirstBlockNumber;
842
+ const blockNumber = Value.toNumber(row['num']);
843
+ if (blockNumber === undefined)
844
+ throw new Error('TIDX returned no Earn earnings boundary.');
730
845
  return blockNumber;
731
846
  }
732
847
  /** Reads the indexed cash flows and exceptional states behind one earnings calculation. */
@@ -740,6 +855,7 @@ async function getVaultEarningsHistory(tidx, options) {
740
855
  FROM Deposited
741
856
  WHERE address = '${options.vault}'
742
857
  AND receiver = '${options.account}'
858
+ AND block_num > ${options.startBlockNumber}
743
859
  AND block_num <= ${options.blockNumber}
744
860
  ) AS deposited_assets,
745
861
  (
@@ -750,6 +866,7 @@ async function getVaultEarningsHistory(tidx, options) {
750
866
  AND requested."requestId" = finalized."requestId"
751
867
  WHERE finalized.address = '${options.vault}'
752
868
  AND requested.requester = '${options.account}'
869
+ AND finalized.block_num > ${options.startBlockNumber}
753
870
  AND finalized.block_num <= ${options.blockNumber}
754
871
  AND requested.block_num <= ${options.blockNumber}
755
872
  ) AS finalized_assets,
@@ -773,6 +890,7 @@ async function getVaultEarningsHistory(tidx, options) {
773
890
  FROM Redeemed
774
891
  WHERE address = '${options.vault}'
775
892
  AND caller = '${options.account}'
893
+ AND block_num > ${options.startBlockNumber}
776
894
  AND block_num <= ${options.blockNumber}
777
895
  ) AS redeemed_assets,
778
896
  (
@@ -782,6 +900,7 @@ async function getVaultEarningsHistory(tidx, options) {
782
900
  ON requested.address = cancelled.address
783
901
  AND requested."requestId" = cancelled."requestId"
784
902
  WHERE cancelled.address = '${options.vault}'
903
+ AND cancelled.block_num > ${options.startBlockNumber}
785
904
  AND cancelled.block_num <= ${options.blockNumber}
786
905
  AND requested.block_num <= ${options.blockNumber}
787
906
  AND requested.requester != cancelled.receiver
@@ -795,6 +914,7 @@ async function getVaultEarningsHistory(tidx, options) {
795
914
  FROM VenueSharesDeposited
796
915
  WHERE address = '${options.vault}'
797
916
  AND receiver = '${options.account}'
917
+ AND block_num > ${options.startBlockNumber}
798
918
  AND block_num <= ${options.blockNumber}
799
919
  ) AS venue_deposits,
800
920
  (
@@ -802,6 +922,7 @@ async function getVaultEarningsHistory(tidx, options) {
802
922
  FROM WithdrewExact
803
923
  WHERE address = '${options.vault}'
804
924
  AND caller = '${options.account}'
925
+ AND block_num > ${options.startBlockNumber}
805
926
  AND block_num <= ${options.blockNumber}
806
927
  ) AS withdrew_exact
807
928
  `,
@@ -840,6 +961,93 @@ async function getVaultEarningsHistory(tidx, options) {
840
961
  withdrewExact: BigInt(withdrewExact),
841
962
  };
842
963
  }
964
+ /** Reads share balances and cross-boundary redemptions for a trailing window. */
965
+ async function getWindowShareState(tidx, options) {
966
+ const result = await tidx.fetch({
967
+ engine: 'clickhouse',
968
+ query: `
969
+ SELECT
970
+ (
971
+ SELECT toString(sum(toUInt256(amount)))
972
+ FROM token_transfers
973
+ WHERE token = '${options.shareToken.toLowerCase()}'
974
+ AND "to" = '${options.account}'
975
+ AND block_num <= ${options.startBlockNumber}
976
+ ) AS received_start,
977
+ (
978
+ SELECT toString(sum(toUInt256(amount)))
979
+ FROM token_transfers
980
+ WHERE token = '${options.shareToken.toLowerCase()}'
981
+ AND "from" = '${options.account}'
982
+ AND block_num <= ${options.startBlockNumber}
983
+ ) AS sent_start,
984
+ (
985
+ SELECT toString(sum(toUInt256(amount)))
986
+ FROM token_transfers
987
+ WHERE token = '${options.shareToken.toLowerCase()}'
988
+ AND "to" = '${options.account}'
989
+ AND block_num <= ${options.blockNumber}
990
+ ) AS received_end,
991
+ (
992
+ SELECT toString(sum(toUInt256(amount)))
993
+ FROM token_transfers
994
+ WHERE token = '${options.shareToken.toLowerCase()}'
995
+ AND "from" = '${options.account}'
996
+ AND block_num <= ${options.blockNumber}
997
+ ) AS sent_end,
998
+ (
999
+ SELECT count()
1000
+ FROM (
1001
+ SELECT finalized."requestId"
1002
+ FROM RedeemFinalized AS finalized
1003
+ INNER JOIN RedeemRequested AS requested
1004
+ ON requested.address = finalized.address
1005
+ AND requested."requestId" = finalized."requestId"
1006
+ WHERE finalized.address = '${options.vault}'
1007
+ AND requested.requester = '${options.account}'
1008
+ AND requested.block_num <= ${options.startBlockNumber}
1009
+ AND finalized.block_num > ${options.startBlockNumber}
1010
+ AND finalized.block_num <= ${options.blockNumber}
1011
+ UNION ALL
1012
+ SELECT cancelled."requestId"
1013
+ FROM RedeemCancelled AS cancelled
1014
+ INNER JOIN RedeemRequested AS requested
1015
+ ON requested.address = cancelled.address
1016
+ AND requested."requestId" = cancelled."requestId"
1017
+ WHERE cancelled.address = '${options.vault}'
1018
+ AND requested.requester = '${options.account}'
1019
+ AND requested.block_num <= ${options.startBlockNumber}
1020
+ AND cancelled.block_num > ${options.startBlockNumber}
1021
+ AND cancelled.block_num <= ${options.blockNumber}
1022
+ ) AS cross_boundary
1023
+ ) AS cross_boundary_redemptions
1024
+ `,
1025
+ signatures: [redeemCancelledSignature, redeemFinalizedSignature, redeemRequestedSignature],
1026
+ });
1027
+ const row = result.rows[0];
1028
+ const crossBoundaryRedemptions = Value.toNumber(row?.['cross_boundary_redemptions']);
1029
+ const receivedEnd = Value.toIntegerString(row?.['received_end']);
1030
+ const receivedStart = Value.toIntegerString(row?.['received_start']);
1031
+ const sentEnd = Value.toIntegerString(row?.['sent_end']);
1032
+ const sentStart = Value.toIntegerString(row?.['sent_start']);
1033
+ if (crossBoundaryRedemptions === undefined ||
1034
+ receivedEnd === undefined ||
1035
+ receivedStart === undefined ||
1036
+ sentEnd === undefined ||
1037
+ sentStart === undefined)
1038
+ return undefined;
1039
+ const receivedEndValue = BigInt(receivedEnd);
1040
+ const receivedStartValue = BigInt(receivedStart);
1041
+ const sentEndValue = BigInt(sentEnd);
1042
+ const sentStartValue = BigInt(sentStart);
1043
+ if (sentEndValue > receivedEndValue || sentStartValue > receivedStartValue)
1044
+ return undefined;
1045
+ return {
1046
+ crossBoundaryRedemption: crossBoundaryRedemptions > 0,
1047
+ endShares: receivedEndValue - sentEndValue,
1048
+ startShares: receivedStartValue - sentStartValue,
1049
+ };
1050
+ }
843
1051
  /** Returns whether an account sent or received Earn shares outside known vault flows. */
844
1052
  async function hasExternalShareTransfer(tidx, options) {
845
1053
  // Vault exits pull shares into the vault before burning. Reconcile counts by transaction and amount so unmatched direct sends remain external.
@@ -851,10 +1059,15 @@ async function hasExternalShareTransfer(tidx, options) {
851
1059
  SELECT count()
852
1060
  FROM token_transfers
853
1061
  WHERE token = '${options.shareToken.toLowerCase()}'
1062
+ AND block_num > ${options.startBlockNumber}
854
1063
  AND block_num <= ${options.blockNumber}
855
1064
  AND (
856
1065
  ("from" = '${options.account}' AND "to" != '${options.vault}')
857
- OR ("to" = '${options.account}' AND "from" != '${zeroAddress}')
1066
+ OR (
1067
+ "to" = '${options.account}'
1068
+ AND "from" != '${zeroAddress}'
1069
+ AND "from" != '${options.vault}'
1070
+ )
858
1071
  )
859
1072
  ) + (
860
1073
  SELECT count()
@@ -864,6 +1077,7 @@ async function hasExternalShareTransfer(tidx, options) {
864
1077
  WHERE token = '${options.shareToken.toLowerCase()}'
865
1078
  AND "from" = '${options.account}'
866
1079
  AND "to" = '${options.vault}'
1080
+ AND block_num > ${options.startBlockNumber}
867
1081
  AND block_num <= ${options.blockNumber}
868
1082
  GROUP BY tx_hash, amount
869
1083
  ) AS candidate
@@ -874,27 +1088,58 @@ async function hasExternalShareTransfer(tidx, options) {
874
1088
  FROM Redeemed
875
1089
  WHERE address = '${options.vault}'
876
1090
  AND caller = '${options.account}'
1091
+ AND block_num > ${options.startBlockNumber}
877
1092
  AND block_num <= ${options.blockNumber}
878
1093
  UNION ALL
879
1094
  SELECT tx_hash, toUInt256(earnShares) AS amount
880
1095
  FROM RedeemRequested
881
1096
  WHERE address = '${options.vault}'
882
1097
  AND requester = '${options.account}'
1098
+ AND block_num > ${options.startBlockNumber}
883
1099
  AND block_num <= ${options.blockNumber}
884
1100
  UNION ALL
885
1101
  SELECT tx_hash, toUInt256(earnSharesBurned) AS amount
886
1102
  FROM WithdrewExact
887
1103
  WHERE address = '${options.vault}'
888
1104
  AND caller = '${options.account}'
1105
+ AND block_num > ${options.startBlockNumber}
889
1106
  AND block_num <= ${options.blockNumber}
890
1107
  ) AS protocol_exit
891
1108
  GROUP BY tx_hash, amount
892
1109
  ) AS matched
893
1110
  ON matched.tx_hash = candidate.tx_hash AND matched.amount = candidate.amount
894
1111
  WHERE candidate.transfer_count > coalesce(matched.exit_count, 0)
1112
+ ) + (
1113
+ SELECT count()
1114
+ FROM (
1115
+ SELECT tx_hash, toUInt256(amount) AS amount, count() AS transfer_count
1116
+ FROM token_transfers
1117
+ WHERE token = '${options.shareToken.toLowerCase()}'
1118
+ AND "from" = '${options.vault}'
1119
+ AND "to" = '${options.account}'
1120
+ AND block_num > ${options.startBlockNumber}
1121
+ AND block_num <= ${options.blockNumber}
1122
+ GROUP BY tx_hash, amount
1123
+ ) AS candidate
1124
+ LEFT JOIN (
1125
+ SELECT tx_hash, toUInt256(earnShares) AS amount, count() AS cancel_count
1126
+ FROM RedeemCancelled
1127
+ WHERE address = '${options.vault}'
1128
+ AND receiver = '${options.account}'
1129
+ AND block_num > ${options.startBlockNumber}
1130
+ AND block_num <= ${options.blockNumber}
1131
+ GROUP BY tx_hash, amount
1132
+ ) AS matched
1133
+ ON matched.tx_hash = candidate.tx_hash AND matched.amount = candidate.amount
1134
+ WHERE candidate.transfer_count > coalesce(matched.cancel_count, 0)
895
1135
  ) AS count
896
1136
  `,
897
- signatures: [redeemedSignature, redeemRequestedSignature, withdrewExactSignature],
1137
+ signatures: [
1138
+ redeemCancelledSignature,
1139
+ redeemedSignature,
1140
+ redeemRequestedSignature,
1141
+ withdrewExactSignature,
1142
+ ],
898
1143
  });
899
1144
  const count = Value.toNumber(result.rows[0]?.['count']);
900
1145
  if (count === undefined)