@invisible-labs/sdk 0.9.0-devnet → 0.10.0-devnet

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/lp.js CHANGED
@@ -1,10 +1,104 @@
1
1
  import { isValidLpPositionId, LP_MAX_TOTAL_SHARDS, LP_MAX_INITIAL_SHARDS, LP_MAX_REFILL_BATCH_SIZE, LP_SHARD_PAGE_SIZE, LP_DEFAULT_REFILL_BATCH_SIZE, LP_DEFAULT_TARGET_SHARDS } from './chunk-HWRMSK7E.js';
2
2
  import { publicKey, assertAttested, lamports } from './chunk-EPWTRF5U.js';
3
- import { requestEnvelope, CoordinatorMessageType } from './chunk-ISIWWGSR.js';
3
+ import { requestEnvelope, CoordinatorMessageType } from './chunk-6AGC3IOB.js';
4
4
  import { getSessionState } from './chunk-6AKBRYKO.js';
5
5
  import { CommandError, WalletError, TransportError, PolicyValidationError, RoutingError, LpLifecycleError } from './chunk-RWKG7N7I.js';
6
6
  import './chunk-VR6T6OJS.js';
7
7
 
8
+ // src/lp/actorSync.ts
9
+ function normalizeLpActorSync(sync) {
10
+ const total = sync.totalNetFundsLamports;
11
+ if (total === void 0) return sync;
12
+ const available = sync.redeemablePrincipalLamports + sync.redeemableFeeLamports;
13
+ if (sync.redeemableProjectionAvailable === true && Number.isSafeInteger(total) && total >= 0 && Number.isSafeInteger(sync.redeemablePrincipalLamports) && sync.redeemablePrincipalLamports >= 0 && Number.isSafeInteger(sync.redeemableFeeLamports) && sync.redeemableFeeLamports >= 0 && Number.isSafeInteger(available) && available >= 0 && total >= available) {
14
+ return sync;
15
+ }
16
+ return { ...sync, totalNetFundsLamports: void 0 };
17
+ }
18
+ function mergeLpActorSync(previous, next) {
19
+ if (next === void 0) return void 0;
20
+ if (previous?.lpPositionId === next.lpPositionId && (next.stateVersion < previous.stateVersion || next.stateVersion === previous.stateVersion && next.updatedAtMs < previous.updatedAtMs)) {
21
+ return normalizeLpActorSync(previous);
22
+ }
23
+ return normalizeLpActorSync(next);
24
+ }
25
+
26
+ // src/lp/feePolicy.ts
27
+ var LP_FEE_POLICY_VERSION = 1;
28
+ var LP_PARTNER_COMMISSION_BPS = 6e3;
29
+ var LP_BASIS_POINT_DENOMINATOR = 10000n;
30
+ var LP_FEE_POLICY_HASHES = {
31
+ internal: "53479c39d822899c0abe21990aeff40ea74681277b2744ef86234152cc94ca5a",
32
+ partner: "3e1a307504043bc0b25f03ccffdff1b42cd2b38699f000f7eb70ce9433a5b2a7"
33
+ };
34
+ var LP_ECONOMIC_UNSIGNED_PATTERN = /^(0|[1-9][0-9]*)$/;
35
+ var LP_ECONOMIC_SIGNED_PATTERN = /^(0|-?[1-9][0-9]*)$/;
36
+ var LP_ECONOMIC_UNSIGNED_MAX = (1n << 128n) - 1n;
37
+ var LP_ECONOMIC_SIGNED_MIN = -(1n << 127n);
38
+ var LP_ECONOMIC_SIGNED_MAX = (1n << 127n) - 1n;
39
+ var LP_FEE_POLICY_INVALID_MESSAGE = "Coordinator LP fee policy evidence is missing or invalid";
40
+ function validateLpFeePolicy(value) {
41
+ if (typeof value !== "object" || value === null) {
42
+ throw new CommandError("REJECTED_STATE", LP_FEE_POLICY_INVALID_MESSAGE);
43
+ }
44
+ const policy = value;
45
+ if (policy.version !== LP_FEE_POLICY_VERSION || policy.profile !== "internal" && policy.profile !== "partner" || policy.commission_bps !== (policy.profile === "partner" ? LP_PARTNER_COMMISSION_BPS : 0) || typeof policy.policy_hash !== "string" || policy.policy_hash !== LP_FEE_POLICY_HASHES[policy.profile]) {
46
+ throw new CommandError("REJECTED_STATE", LP_FEE_POLICY_INVALID_MESSAGE);
47
+ }
48
+ return {
49
+ version: LP_FEE_POLICY_VERSION,
50
+ profile: policy.profile,
51
+ commission_bps: policy.profile === "partner" ? LP_PARTNER_COMMISSION_BPS : 0,
52
+ policy_hash: policy.policy_hash
53
+ };
54
+ }
55
+ function requireLpFeePolicyCapability(version) {
56
+ if (version !== LP_FEE_POLICY_VERSION) {
57
+ throw new RoutingError(
58
+ "VERSION_NOT_SUPPORTED",
59
+ "Coordinator does not support the LP fee policy contract"
60
+ );
61
+ }
62
+ }
63
+ function validateLpPositionFeePolicy(position, previous) {
64
+ if (position.feePolicy === void 0) {
65
+ if (previous?.feePolicy !== void 0 || position.actorSync?.feePolicy !== void 0 || position.actorSync?.feeBasisRevision !== void 0 || position.actorSync?.grossFeeLamports !== void 0 || position.actorSync?.protocolCommissionLamports !== void 0 || position.actorSync?.waivedProtocolCommissionLamports !== void 0) {
66
+ throw new CommandError("REJECTED_STATE", LP_FEE_POLICY_INVALID_MESSAGE);
67
+ }
68
+ return;
69
+ }
70
+ requireLpFeePolicyCapability(position.lpFeePolicyVersion);
71
+ const policy = validateLpFeePolicy(position.feePolicy);
72
+ const sync = position.actorSync;
73
+ const actorPolicy = validateLpFeePolicy(sync?.feePolicy);
74
+ if (JSON.stringify(policy) !== JSON.stringify(actorPolicy) || previous !== void 0 && (previous.feePolicy === void 0 || JSON.stringify(policy) !== JSON.stringify(validateLpFeePolicy(previous.feePolicy))) || sync?.lpPositionId !== position.id || sync?.redeemableProjectionAvailable !== true || !Number.isSafeInteger(sync.feeBasisRevision) || sync.feeBasisRevision < 0 || !Number.isSafeInteger(sync.grossFeeLamports) || sync.grossFeeLamports < 0 || !Number.isSafeInteger(sync.protocolCommissionLamports) || sync.protocolCommissionLamports < 0 || !Number.isSafeInteger(sync.waivedProtocolCommissionLamports) || sync.waivedProtocolCommissionLamports < 0 || sync.economicReturn === void 0) {
75
+ throw new CommandError("REJECTED_STATE", LP_FEE_POLICY_INVALID_MESSAGE);
76
+ }
77
+ if (BigInt(sync.protocolCommissionLamports) + BigInt(sync.waivedProtocolCommissionLamports) !== BigInt(sync.grossFeeLamports) * BigInt(policy.commission_bps) / LP_BASIS_POINT_DENOMINATOR) {
78
+ throw new CommandError("REJECTED_STATE", LP_FEE_POLICY_INVALID_MESSAGE);
79
+ }
80
+ for (const history of sync.redemptionHistory ?? []) {
81
+ if (history.feePolicyHash !== policy.policy_hash || !Number.isSafeInteger(history.feeBasisRevision) || history.feeBasisRevision < 0) {
82
+ throw new CommandError("REJECTED_STATE", LP_FEE_POLICY_INVALID_MESSAGE);
83
+ }
84
+ }
85
+ const summary = sync.economicReturn;
86
+ const totals = [
87
+ summary.providerRewardLamports,
88
+ summary.sourceExpenseCompensationLamports,
89
+ summary.chargedReimbursementLossLamports
90
+ ];
91
+ if (!totals.every(
92
+ (value) => typeof value === "string" && LP_ECONOMIC_UNSIGNED_PATTERN.test(value) && BigInt(value) <= LP_ECONOMIC_UNSIGNED_MAX
93
+ ) || typeof summary.netEconomicReturnLamports !== "string" || !LP_ECONOMIC_SIGNED_PATTERN.test(summary.netEconomicReturnLamports)) {
94
+ throw new CommandError("REJECTED_STATE", LP_FEE_POLICY_INVALID_MESSAGE);
95
+ }
96
+ const net = BigInt(summary.netEconomicReturnLamports);
97
+ if (net < LP_ECONOMIC_SIGNED_MIN || net > LP_ECONOMIC_SIGNED_MAX || net !== BigInt(summary.providerRewardLamports) - BigInt(summary.chargedReimbursementLossLamports) - BigInt(sync.protocolCommissionLamports)) {
98
+ throw new CommandError("REJECTED_STATE", LP_FEE_POLICY_INVALID_MESSAGE);
99
+ }
100
+ }
101
+
8
102
  // src/lp/positionCode.ts
9
103
  var LEGACY_CODE_PREFIX = "ilp1";
10
104
  var CODE_PREFIX = "ilp2";
@@ -235,6 +329,7 @@ var LP_POSITION_HYDRATION_TIMEOUT_MS = LP_COMMAND_REQUEST_TIMEOUT_MS;
235
329
  var LP_POSITION_SNAPSHOT_MAX_ATTEMPTS = 3;
236
330
  var LP_SHARD_SNAPSHOT_CHANGED_MESSAGE = "LP shard snapshot changed";
237
331
  var LP_SHARD_PAGE_INVALID_MESSAGE = "coordinator LP shard page is invalid";
332
+ var LP_POSITION_OPEN_IDENTITY_MISMATCH_MESSAGE = "Coordinator returned a different LP position identity or creation intent";
238
333
  var LP_SHARD_SNAPSHOT_HASH_PATTERN = /^[0-9a-f]{64}$/;
239
334
  var LP_CREATION_CHALLENGE_REQUEST_TIMEOUT_MS = 3e4;
240
335
  var LP_CREATION_WALLET_SIGNATURE_TIMEOUT_MS = 45e3;
@@ -330,6 +425,16 @@ async function authorizePositionCreation(session, intent, signer) {
330
425
  "Coordinator returned an unexpected LP creation authorization response"
331
426
  );
332
427
  }
428
+ requireLpFeePolicyCapability(challenge.value.lp_fee_policy_version);
429
+ const feePolicy = validateLpFeePolicy(challenge.value.fee_policy);
430
+ const consentLine = `LP Fee Policy: ${feePolicy.policy_hash}`;
431
+ const policyResource = `&fee_policy_hash=${feePolicy.policy_hash}&fee_policy_version=${feePolicy.version}`;
432
+ if (!challenge.value.message.split("\n").includes(consentLine) || !challenge.value.message.includes(policyResource)) {
433
+ throw new CommandError(
434
+ "REJECTED_STATE",
435
+ "Coordinator LP creation challenge does not bind the authorized fee policy"
436
+ );
437
+ }
333
438
  const localAuthorizationDeadlineMs = challengeRequestStartedAtMs + challenge.value.valid_for_ms;
334
439
  const walletTimeoutMs = lpCreationAuthorizationStepTimeout(
335
440
  localAuthorizationDeadlineMs,
@@ -401,7 +506,11 @@ async function authorizePositionCreation(session, intent, signer) {
401
506
  LP_CREATION_AUTHORIZATION_MARGIN_MS,
402
507
  LP_CREATION_MIN_STEP_TIMEOUT_MS
403
508
  );
404
- return { authorizationId: authorization.value.authorization_id };
509
+ requireLpFeePolicyCapability(authorization.value.lp_fee_policy_version);
510
+ if (JSON.stringify(validateLpFeePolicy(authorization.value.fee_policy)) !== JSON.stringify(feePolicy)) {
511
+ throw new CommandError("REJECTED_STATE", "Coordinator changed the authorized LP fee policy");
512
+ }
513
+ return { authorizationId: authorization.value.authorization_id, feePolicy };
405
514
  }
406
515
  function lpCreationAuthorizationStepTimeout(localDeadlineMs, reservedMs, maximumTimeoutMs) {
407
516
  const availableMs = localDeadlineMs - Date.now() - reservedMs;
@@ -492,6 +601,7 @@ async function openPosition(session, input, auth, reconnectSession) {
492
601
  case: "positionOpen",
493
602
  value: {
494
603
  creation_authorization_id: input.creationAuthorizationId,
604
+ fee_policy: input.feePolicy,
495
605
  auth_public_key: Uint8Array.from(input.authPublicKey),
496
606
  refill_public_key: Uint8Array.from(input.refillPublicKey),
497
607
  redemption_commitment: Uint8Array.from(input.withdrawalCommitment),
@@ -511,6 +621,7 @@ async function openPosition(session, input, auth, reconnectSession) {
511
621
  timeoutMs: LP_POSITION_OPEN_REQUEST_TIMEOUT_MS
512
622
  };
513
623
  let response;
624
+ let responseSession = session;
514
625
  try {
515
626
  response = await requestForPosition(
516
627
  session,
@@ -522,17 +633,27 @@ async function openPosition(session, input, auth, reconnectSession) {
522
633
  );
523
634
  } catch (error) {
524
635
  if (!isAmbiguousLpPositionOpenFailure(error)) throw error;
525
- const replaySession = reconnectSession === void 0 ? session : await reconnectSessionWithinDeadline(reconnectSession, commandDeadlineMs);
526
- response = await requestForPosition(
527
- replaySession,
528
- input.lpPositionId,
529
- auth,
530
- "position_open",
531
- payload,
532
- commandOptions
636
+ responseSession = reconnectSession === void 0 ? session : await reconnectSessionWithinDeadline(reconnectSession, commandDeadlineMs);
637
+ }
638
+ const position = await hydratePositionResponse(
639
+ responseSession,
640
+ auth.lpPositionId,
641
+ auth,
642
+ response,
643
+ {
644
+ deadlineMs: commandDeadlineMs
645
+ }
646
+ );
647
+ if (position.authPublicKey !== bytesToHex(Uint8Array.from(input.authPublicKey)) || position.refillPublicKey !== bytesToHex(Uint8Array.from(input.refillPublicKey)) || position.withdrawalCommitment !== bytesToHex(Uint8Array.from(input.withdrawalCommitment)) || position.committedLamports !== input.committedLamports || position.targetShardCount !== input.shardCount || position.refillThreshold !== input.refillThreshold || position.createdAt !== input.createdAtMs) {
648
+ throw new CommandError("REJECTED_STATE", LP_POSITION_OPEN_IDENTITY_MISMATCH_MESSAGE);
649
+ }
650
+ if (input.feePolicy !== void 0 && position.feePolicy?.policy_hash !== input.feePolicy.policy_hash) {
651
+ throw new CommandError(
652
+ "REJECTED_STATE",
653
+ "Coordinator opened the LP position with a different fee policy"
533
654
  );
534
655
  }
535
- return hydratePositionResponse(session, auth.lpPositionId, auth, response);
656
+ return position;
536
657
  }
537
658
  async function reconnectSessionWithinDeadline(reconnectSession, deadlineMs) {
538
659
  const remainingMs = deadlineMs - Date.now();
@@ -650,6 +771,7 @@ async function hydratePositionResponse(session, lpPositionId, auth, initialRespo
650
771
  if (first.shards_snapshot_hash !== void 0)
651
772
  assertShardPage(first, historyPage, lpPositionId, auth, 0);
652
773
  const historyView = mapPosition(historyPage);
774
+ validateLpPositionFeePolicy(historyView, position);
653
775
  const merged = mergePositionHistoryPages(position, historyView);
654
776
  position = first.shards_snapshot_hash === void 0 ? merged : {
655
777
  ...position,
@@ -677,7 +799,7 @@ function assertShardPage(first, page, lpPositionId, auth, startIndex) {
677
799
  const invalid = () => {
678
800
  throw new CommandError("REJECTED_STATE", LP_SHARD_PAGE_INVALID_MESSAGE);
679
801
  };
680
- if (total === void 0 || !Number.isInteger(total) || total < 1 || total > LP_MAX_TOTAL_SHARDS || total > first.target_shard_count || first.status !== "dkg_pending" && total !== first.target_shard_count || first.shards_snapshot_hash === void 0 || !LP_SHARD_SNAPSHOT_HASH_PATTERN.test(first.shards_snapshot_hash) || page.lp_position_id !== lpPositionId || page.shards_snapshot_hash !== first.shards_snapshot_hash || page.shards_total_count !== total || page.target_shard_count !== first.target_shard_count || page.status !== "dkg_pending" && total !== page.target_shard_count || page.created_at_ms !== first.created_at_ms || page.committed_lamports !== first.committed_lamports || page.earned_lamports !== first.earned_lamports || page.refill_threshold !== first.refill_threshold || bytesToHex(page.auth_public_key) !== bytesToHex(auth.authPublicKey) || bytesToHex(page.refill_public_key) !== bytesToHex(first.refill_public_key) || bytesToHex(page.redemption_commitment) !== bytesToHex(first.redemption_commitment) || page.shards.length !== Math.min(LP_SHARD_PAGE_SIZE, total - startIndex) || page.shards.length === 0)
802
+ if (total === void 0 || !Number.isInteger(total) || total < 1 || total > LP_MAX_TOTAL_SHARDS || total > first.target_shard_count || first.status !== "dkg_pending" && total !== first.target_shard_count || first.shards_snapshot_hash === void 0 || !LP_SHARD_SNAPSHOT_HASH_PATTERN.test(first.shards_snapshot_hash) || page.lp_position_id !== lpPositionId || page.shards_snapshot_hash !== first.shards_snapshot_hash || page.shards_total_count !== total || page.target_shard_count !== first.target_shard_count || page.status !== "dkg_pending" && total !== page.target_shard_count || page.created_at_ms !== first.created_at_ms || page.committed_lamports !== first.committed_lamports || page.earned_lamports !== first.earned_lamports || page.refill_threshold !== first.refill_threshold || page.fee_policy?.policy_hash !== first.fee_policy?.policy_hash || page.lp_fee_policy_version !== first.lp_fee_policy_version || bytesToHex(page.auth_public_key) !== bytesToHex(auth.authPublicKey) || bytesToHex(page.refill_public_key) !== bytesToHex(first.refill_public_key) || bytesToHex(page.redemption_commitment) !== bytesToHex(first.redemption_commitment) || page.shards.length !== Math.min(LP_SHARD_PAGE_SIZE, total - startIndex) || page.shards.length === 0)
681
803
  invalid();
682
804
  for (const [offset, shard] of page.shards.entries()) {
683
805
  const index = startIndex + offset;
@@ -805,13 +927,21 @@ async function executeWithdrawal(session, input, auth) {
805
927
  deposit_principal_lamports: input.withdrawalMode === "max_available" ? 0 : input.depositPrincipalLamports,
806
928
  earned_fee_lamports: input.withdrawalMode === "max_available" ? 0 : input.earnedFeeLamports,
807
929
  withdrawal_mode: input.withdrawalMode,
808
- requested_at_ms: input.requestedAtMs
930
+ requested_at_ms: input.requestedAtMs,
931
+ fee_policy_hash: input.feePolicyHash,
932
+ fee_basis_revision: input.feeBasisRevision
809
933
  }
810
934
  });
811
935
  if (response.case !== "withdrawalExecution") {
812
936
  throw new Error("Unexpected LP withdrawal execution response");
813
937
  }
814
938
  const execution = response.value;
939
+ if (execution.fee_policy_hash !== input.feePolicyHash || execution.fee_basis_revision !== input.feeBasisRevision) {
940
+ throw new PolicyValidationError(
941
+ "INVALID_WITHDRAWAL_PLAN",
942
+ "Coordinator accepted a different LP fee policy or fee basis"
943
+ );
944
+ }
815
945
  if (BigInt(execution.accepted_lamports) !== BigInt(execution.accepted_deposit_principal_lamports) + BigInt(execution.accepted_earned_fee_lamports)) {
816
946
  throw new PolicyValidationError(
817
947
  "INVALID_WITHDRAWAL_PLAN",
@@ -825,6 +955,8 @@ async function executeWithdrawal(session, input, auth) {
825
955
  );
826
956
  }
827
957
  return {
958
+ feePolicyHash: execution.fee_policy_hash,
959
+ feeBasisRevision: execution.fee_basis_revision,
828
960
  withdrawalId: execution.withdrawal_id,
829
961
  txSignatures: [...execution.tx_signatures],
830
962
  acceptedLamports: execution.accepted_lamports,
@@ -872,7 +1004,9 @@ function assertAuthMatchesPosition(lpPositionId, auth) {
872
1004
  );
873
1005
  }
874
1006
  function mapPosition(position) {
875
- return {
1007
+ const mapped = {
1008
+ feePolicy: position.fee_policy === void 0 ? void 0 : validateLpFeePolicy(position.fee_policy),
1009
+ lpFeePolicyVersion: position.lp_fee_policy_version,
876
1010
  id: position.lp_position_id,
877
1011
  status: position.status,
878
1012
  targetShardCount: position.target_shard_count,
@@ -887,6 +1021,8 @@ function mapPosition(position) {
887
1021
  redemptionPermission: mapLpRedemptionPermission(position.redemption_permission),
888
1022
  ...position.actor_sync === void 0 ? {} : { actorSync: mapLpActorSync(position.actor_sync) }
889
1023
  };
1024
+ validateLpPositionFeePolicy(mapped);
1025
+ return mapped;
890
1026
  }
891
1027
  function mapLpRedemptionPermission(permission) {
892
1028
  if (permission === void 0) {
@@ -916,11 +1052,22 @@ function mapLpActorSync(actorSync) {
916
1052
  );
917
1053
  }
918
1054
  const redeemableProjectionAvailable = redeemableBucketCount === redeemableBucketValues.length;
919
- return {
920
- ...actorSync.economic_return === void 0 ? {} : { economicReturn: mapLpEconomicReturn(actorSync.economic_return) },
1055
+ return normalizeLpActorSync({
1056
+ ...actorSync.economic_return === void 0 ? {} : {
1057
+ economicReturn: mapLpEconomicReturn(
1058
+ actorSync.economic_return,
1059
+ actorSync.protocol_commission_lamports ?? 0
1060
+ )
1061
+ },
1062
+ feePolicy: actorSync.fee_policy === void 0 ? void 0 : validateLpFeePolicy(actorSync.fee_policy),
1063
+ feeBasisRevision: actorSync.fee_basis_revision,
1064
+ grossFeeLamports: actorSync.gross_fee_lamports,
1065
+ protocolCommissionLamports: actorSync.protocol_commission_lamports,
1066
+ waivedProtocolCommissionLamports: actorSync.waived_protocol_commission_lamports,
921
1067
  lpPositionId: actorSync.lp_position_id,
922
1068
  status: actorSync.status,
923
1069
  sourceLiquidityUse: actorSync.source_liquidity_use,
1070
+ totalNetFundsLamports: actorSync.total_net_funds_lamports,
924
1071
  redeemableProjectionAvailable,
925
1072
  redeemablePrincipalLamports: actorSync.redeemable_principal_lamports ?? 0,
926
1073
  redeemableFeeLamports: actorSync.redeemable_fee_lamports ?? 0,
@@ -946,14 +1093,14 @@ function mapLpActorSync(actorSync) {
946
1093
  ...actorSync.redemption_history_next_cursor === void 0 ? {} : { redemptionHistoryNextCursor: actorSync.redemption_history_next_cursor },
947
1094
  stateVersion: actorSync.state_version,
948
1095
  updatedAtMs: actorSync.updated_at_ms
949
- };
1096
+ });
950
1097
  }
951
1098
  var LP_ECONOMIC_UNSIGNED_TOTAL_MAX = (1n << 128n) - 1n;
952
1099
  var LP_ECONOMIC_SIGNED_TOTAL_MIN = -(1n << 127n);
953
1100
  var LP_ECONOMIC_SIGNED_TOTAL_MAX = (1n << 127n) - 1n;
954
1101
  var LP_ECONOMIC_UNSIGNED_DECIMAL = /^(0|[1-9][0-9]*)$/;
955
1102
  var LP_ECONOMIC_SIGNED_DECIMAL = /^(0|-?[1-9][0-9]*)$/;
956
- function mapLpEconomicReturn(summary) {
1103
+ function mapLpEconomicReturn(summary, protocolCommissionLamports) {
957
1104
  const unsigned = [
958
1105
  summary.provider_reward_lamports,
959
1106
  summary.source_expense_compensation_lamports,
@@ -965,7 +1112,7 @@ function mapLpEconomicReturn(summary) {
965
1112
  if (!valid)
966
1113
  throw new CommandError("REJECTED_STATE", "coordinator LP economic return totals are invalid");
967
1114
  const net = BigInt(summary.net_economic_return_lamports);
968
- if (net < LP_ECONOMIC_SIGNED_TOTAL_MIN || net > LP_ECONOMIC_SIGNED_TOTAL_MAX || net !== BigInt(summary.provider_reward_lamports) - BigInt(summary.charged_reimbursement_loss_lamports)) {
1115
+ if (net < LP_ECONOMIC_SIGNED_TOTAL_MIN || net > LP_ECONOMIC_SIGNED_TOTAL_MAX || net !== BigInt(summary.provider_reward_lamports) - BigInt(summary.charged_reimbursement_loss_lamports) - BigInt(protocolCommissionLamports)) {
969
1116
  throw new CommandError("REJECTED_STATE", "coordinator LP economic return invariant is invalid");
970
1117
  }
971
1118
  return {
@@ -996,6 +1143,8 @@ function mergePositionHistoryPages(first, next) {
996
1143
  }
997
1144
  function mapLpRedemptionHistory(history) {
998
1145
  return {
1146
+ feePolicyHash: history.fee_policy_hash,
1147
+ feeBasisRevision: history.fee_basis_revision,
999
1148
  redemptionId: history.redemption_id,
1000
1149
  state: history.state,
1001
1150
  ...history.withdrawal_mode === void 0 ? {} : { withdrawalMode: history.withdrawal_mode },
@@ -1077,7 +1226,7 @@ function randomBytes(length) {
1077
1226
  return bytes;
1078
1227
  }
1079
1228
  function loadProtocol() {
1080
- protocolPromise ??= import('./coordinator-DHL3AP7V.js');
1229
+ protocolPromise ??= import('./coordinator-T2B7253V.js');
1081
1230
  return protocolPromise;
1082
1231
  }
1083
1232
 
@@ -1375,6 +1524,7 @@ function isLpPositionAuthMissingError(error) {
1375
1524
  return error instanceof LpPositionAuthMissingError || error instanceof Error && error.message === LP_MISSING_POSITION_CODE_MESSAGE;
1376
1525
  }
1377
1526
  function previewLpWithdrawalPlan(position, args = {}) {
1527
+ validateLpPositionFeePolicy(position);
1378
1528
  const claim = resolveWithdrawalClaim(position, args);
1379
1529
  return {
1380
1530
  ...claim,
@@ -1407,11 +1557,13 @@ function createLpLifecycleClient(session, runtime = {}) {
1407
1557
  return auth;
1408
1558
  };
1409
1559
  const rememberPosition = (position) => {
1560
+ validateLpPositionFeePolicy(position, state.positions.get(position.id));
1410
1561
  const snapshot = clonePosition(position);
1411
1562
  const previous = state.positions.get(snapshot.id);
1412
- const merged = previous === void 0 ? snapshot : {
1563
+ const merged = {
1413
1564
  ...snapshot,
1414
- redemptionPermission: mergeLpRedemptionPermission(
1565
+ actorSync: mergeLpActorSync(previous?.actorSync, snapshot.actorSync),
1566
+ redemptionPermission: previous === void 0 ? snapshot.redemptionPermission : mergeLpRedemptionPermission(
1415
1567
  previous.redemptionPermission,
1416
1568
  snapshot.redemptionPermission
1417
1569
  )
@@ -1532,6 +1684,7 @@ function createLpLifecycleClient(session, runtime = {}) {
1532
1684
  {
1533
1685
  lpPositionId: positionId,
1534
1686
  creationAuthorizationId: creationAuthorization.authorizationId,
1687
+ feePolicy: creationAuthorization.feePolicy,
1535
1688
  authPublicKey: Array.from(auth.authPublicKey),
1536
1689
  refillPublicKey: Array.from(auth.refillPublicKey),
1537
1690
  withdrawalCommitment: Array.from(auth.withdrawalCommitment),
@@ -1692,6 +1845,8 @@ function createLpLifecycleClient(session, runtime = {}) {
1692
1845
  const existingRedemption = findOpenRedemptionHistory(before, args);
1693
1846
  if (existingRedemption !== void 0) {
1694
1847
  const execution2 = {
1848
+ feePolicyHash: existingRedemption.feePolicyHash,
1849
+ feeBasisRevision: existingRedemption.feeBasisRevision,
1695
1850
  withdrawalId: existingRedemption.redemptionId,
1696
1851
  txSignatures: [...existingRedemption.txSignatures],
1697
1852
  acceptedLamports: existingRedemption.acceptedLamports,
@@ -1736,6 +1891,8 @@ function createLpLifecycleClient(session, runtime = {}) {
1736
1891
  earnedFeeLamports: args.withdrawalMode === "max_available" ? 0 : preview.earnedFeeLamports,
1737
1892
  withdrawalMode: args.withdrawalMode,
1738
1893
  requestedAtMs,
1894
+ feePolicyHash: before.feePolicy?.policy_hash,
1895
+ feeBasisRevision: before.actorSync?.feeBasisRevision,
1739
1896
  allowManyToOne: args.allowManyToOne === true || preview?.sourceCount === 1
1740
1897
  },
1741
1898
  auth
@@ -1864,6 +2021,7 @@ async function tryRefreshCompletedDkgWindow({
1864
2021
  const position = await client.getPosition(positionId, auth).catch(() => null);
1865
2022
  if (position === null) return null;
1866
2023
  if (!hasCompletedDkgWindow(position, startIndex, total, expectedAddresses)) return null;
2024
+ validateLpPositionFeePolicy(position, state.positions.get(position.id));
1867
2025
  state.positions.set(position.id, clonePosition(position));
1868
2026
  return position;
1869
2027
  }
@@ -1962,7 +2120,9 @@ function hasActorSyncLpActivity(sync) {
1962
2120
  }
1963
2121
  function resolveRedeemablePrincipalLamports(sync, legacyAvailableLamports, actorRedeemablePrincipalLamports, actorRedeemableFeeLamports) {
1964
2122
  if (sync?.redeemableProjectionAvailable !== true) return legacyAvailableLamports;
1965
- if (legacyAvailableLamports <= 0) return actorRedeemablePrincipalLamports;
2123
+ if (sync.feePolicy !== void 0 || legacyAvailableLamports <= 0) {
2124
+ return actorRedeemablePrincipalLamports;
2125
+ }
1966
2126
  if (actorRedeemablePrincipalLamports >= legacyAvailableLamports || hasActorSyncLpActivity(sync)) {
1967
2127
  return actorRedeemablePrincipalLamports;
1968
2128
  }
@@ -2067,6 +2227,8 @@ function buildLpRedemptionRecord({
2067
2227
  nowMs
2068
2228
  }) {
2069
2229
  return {
2230
+ feePolicyHash: execution.feePolicyHash,
2231
+ feeBasisRevision: execution.feeBasisRevision,
2070
2232
  redemptionId: execution.withdrawalId,
2071
2233
  lpPositionId: position.id,
2072
2234
  requestedAt: nowMs,
@@ -2115,7 +2277,7 @@ function reconcileLpRedemptionFromActorSync(record, position) {
2115
2277
  function reconcileLpRedemptionFromHistory(record, history) {
2116
2278
  const observedStateVersion = record.coordinatorStateVersion ?? 0;
2117
2279
  if (history.stateVersion < observedStateVersion) return record;
2118
- if (record.acceptedLamports !== void 0 && history.acceptedLamports !== record.acceptedLamports || history.detailsTruncated !== true && !sameStringList(history.destinationAddresses, record.destinationAddresses)) {
2280
+ if (history.feePolicyHash !== record.feePolicyHash || history.feeBasisRevision !== record.feeBasisRevision || record.acceptedLamports !== void 0 && history.acceptedLamports !== record.acceptedLamports || history.detailsTruncated !== true && !sameStringList(history.destinationAddresses, record.destinationAddresses)) {
2119
2281
  return {
2120
2282
  ...record,
2121
2283
  status: "failed",
@@ -2165,6 +2327,8 @@ function hydrateLpRedemptionsFromPosition(state, position) {
2165
2327
  }
2166
2328
  function lpWithdrawalRecordFromHistory(position, history) {
2167
2329
  const record = {
2330
+ feePolicyHash: history.feePolicyHash,
2331
+ feeBasisRevision: history.feeBasisRevision,
2168
2332
  redemptionId: history.redemptionId,
2169
2333
  lpPositionId: position.id,
2170
2334
  requestedAt: history.createdAtMs,
@@ -2194,6 +2358,7 @@ function uniqueStrings(values) {
2194
2358
  function clonePosition(position) {
2195
2359
  return {
2196
2360
  ...position,
2361
+ feePolicy: position.feePolicy === void 0 ? void 0 : { ...position.feePolicy },
2197
2362
  shards: position.shards.map((shard) => ({ ...shard })),
2198
2363
  actorSync: position.actorSync === void 0 ? void 0 : {
2199
2364
  ...position.actorSync,
@@ -2306,6 +2471,6 @@ function listPositions(session) {
2306
2471
  return defaultLpLifecycleClient(session).listPositions();
2307
2472
  }
2308
2473
 
2309
- export { LP_COMMAND_REQUEST_TIMEOUT_MS, LP_DKG_ABORT_CLEANUP_TIMEOUT_MS, LP_DKG_ABORT_REQUEST_TIMEOUT_MS, LP_DKG_WORKER_REQUEST_TIMEOUT_MESSAGE, LP_DKG_WORKER_REQUEST_TIMEOUT_MS, LP_FEE_SOURCE_COUNT_UNAVAILABLE_MESSAGE, LP_MISSING_POSITION_CODE_MESSAGE, LP_REDEMPTION_RECONCILING_MESSAGE, bytesToHex, completeDkgBatch, confirmPositionCodeSaved, createLpCoordinatorClient, createLpDkgBatch, createLpLifecycleClient, createPosition, defaultLpLifecycleClient, deriveLpPositionCodeAuth, generateLpPositionCode, isLpPositionAuthMissingError, isLpRedemptionReconcilingError, listPositions, normalizeLpPositionCode, prepareInitialFunding, prepareTopUp2 as prepareTopUp, previewLpWithdrawalPlan, reconcileFunding2 as reconcileFunding, recoverPosition, refill, refreshPosition, signLpCommandBytes, waitForTopUp, waitForWithdrawalConfirmation, withdrawFees, withdrawPosition };
2474
+ export { LP_COMMAND_REQUEST_TIMEOUT_MS, LP_DKG_ABORT_CLEANUP_TIMEOUT_MS, LP_DKG_ABORT_REQUEST_TIMEOUT_MS, LP_DKG_WORKER_REQUEST_TIMEOUT_MESSAGE, LP_DKG_WORKER_REQUEST_TIMEOUT_MS, LP_FEE_SOURCE_COUNT_UNAVAILABLE_MESSAGE, LP_MISSING_POSITION_CODE_MESSAGE, LP_REDEMPTION_RECONCILING_MESSAGE, bytesToHex, completeDkgBatch, confirmPositionCodeSaved, createLpCoordinatorClient, createLpDkgBatch, createLpLifecycleClient, createPosition, defaultLpLifecycleClient, deriveLpPositionCodeAuth, generateLpPositionCode, isLpPositionAuthMissingError, isLpRedemptionReconcilingError, listPositions, mergeLpActorSync, normalizeLpActorSync, normalizeLpPositionCode, prepareInitialFunding, prepareTopUp2 as prepareTopUp, previewLpWithdrawalPlan, reconcileFunding2 as reconcileFunding, recoverPosition, refill, refreshPosition, signLpCommandBytes, validateLpPositionFeePolicy, waitForTopUp, waitForWithdrawalConfirmation, withdrawFees, withdrawPosition };
2310
2475
  //# sourceMappingURL=lp.js.map
2311
2476
  //# sourceMappingURL=lp.js.map