@steerprotocol/curator-tools 1.7.0 → 1.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.
package/dist/index.d.mts CHANGED
@@ -42,20 +42,84 @@ interface StrategyStoreConfig {
42
42
  resolverAddress?: string;
43
43
  registryAddress?: string;
44
44
  }
45
+ interface EASAttestationRequestData {
46
+ recipient: Address;
47
+ expirationTime: bigint;
48
+ revocable: boolean;
49
+ refUID: string;
50
+ data: string;
51
+ value: bigint;
52
+ }
53
+ interface EASAttestationRequest {
54
+ schema: string;
55
+ data: EASAttestationRequestData;
56
+ }
57
+ interface SubmitOverrideAttestationOptions {
58
+ schemaUID?: string;
59
+ easAddress?: string;
60
+ refUID?: string;
61
+ skipCuratorCheck?: boolean;
62
+ easContract?: ethers.Contract;
63
+ }
64
+ interface SubmitOverrideAttestationResult {
65
+ request: EASAttestationRequest;
66
+ txHash: string;
67
+ uid?: string;
68
+ }
69
+ interface GetOverrideAttestationsOptions {
70
+ schemaUID?: string;
71
+ graphqlEndpoint?: string;
72
+ strategyTokenId?: bigint;
73
+ includeRevoked?: boolean;
74
+ includeExpired?: boolean;
75
+ pageSize?: number;
76
+ maxPages?: number;
77
+ timeoutMs?: number;
78
+ retries?: number;
79
+ fetchFn?: typeof fetch;
80
+ }
81
+ interface OverrideAttestationRecord {
82
+ uid: string;
83
+ attester: Address;
84
+ recipient: Address;
85
+ refUID: string;
86
+ revocable: boolean;
87
+ revocationTime: bigint;
88
+ expirationTime: bigint;
89
+ createdAt: bigint;
90
+ data: string;
91
+ vault: Address;
92
+ targetChainId: bigint;
93
+ strategyTokenId: bigint;
94
+ manifestCid: string;
95
+ isActive: boolean;
96
+ }
45
97
  declare class StrategyStore {
46
- static readonly ARBITRUM_ONE_RESOLVER_ADDRESS = "0x6628d1Bf82F34de132d0e1c60DEB574C1352d5A7";
47
- static readonly ARBITRUM_ONE_CROSSCHAIN_SCHEMA_UID = "0xf1a6a394d1f3dd832a15e5b750963d929812e2b74d2dcea68ddf9f75691f16bf";
98
+ static readonly BASE_MAINNET_EAS_ADDRESS: Address;
99
+ static readonly BASE_MAINNET_RESOLVER_ADDRESS: Address;
100
+ static readonly BASE_MAINNET_CROSSCHAIN_SCHEMA_UID: string;
101
+ /** @deprecated Use BASE_MAINNET_EAS_ADDRESS */
102
+ static readonly ARBITRUM_ONE_EAS_ADDRESS: `0x${string}`;
103
+ /** @deprecated Use BASE_MAINNET_RESOLVER_ADDRESS */
104
+ static readonly ARBITRUM_ONE_RESOLVER_ADDRESS: `0x${string}`;
105
+ /** @deprecated Use BASE_MAINNET_CROSSCHAIN_SCHEMA_UID */
106
+ static readonly ARBITRUM_ONE_CROSSCHAIN_SCHEMA_UID: string;
48
107
  static encodeOverrideAttestationData(vault: string, targetChainId: number | bigint, strategyTokenId: bigint, manifestCid: string): string;
108
+ static buildOverrideAttestationRequest(schemaUID: string, vault: string, targetChainId: number | bigint, strategyTokenId: bigint, manifestCid: string, refUID?: string): EASAttestationRequest;
49
109
  private resolver;
50
110
  private registry?;
51
111
  private resolverAddress;
52
112
  private registryAddress?;
53
- private chainId?;
113
+ private chainId;
114
+ private readonly runner;
54
115
  constructor(config: string | StrategyStoreConfig, providerOrSigner: ethers.Provider | ethers.Signer, overrides?: {
55
116
  resolver?: any;
56
117
  registry?: any;
57
118
  });
58
119
  private resolveChainId;
120
+ private getDefaultSchemaUID;
121
+ private getDefaultEASAddress;
122
+ private getSignerAddress;
59
123
  /**
60
124
  * Checks if an address is the top-level admin.
61
125
  * @param address The address to check.
@@ -79,6 +143,25 @@ declare class StrategyStore {
79
143
  to: string;
80
144
  data: string;
81
145
  }>;
146
+ /**
147
+ * Checks curator auth, builds an EAS request, and submits the attestation transaction.
148
+ * Uses computed recipient format, revocable=false, expirationTime=0 by default.
149
+ */
150
+ submitOverrideAttestation(vault: string, targetChainId: number | bigint, strategyTokenId: bigint, manifestCid: string, options?: SubmitOverrideAttestationOptions): Promise<SubmitOverrideAttestationResult>;
151
+ private static toBigInt;
152
+ private static isActiveAttestation;
153
+ private queryEASSubgraph;
154
+ private decodeOverrideAttestationRecord;
155
+ /**
156
+ * Returns full decoded override attestation history for a (vault, targetChainId) pair.
157
+ * Results are returned newest first according to subgraph ordering.
158
+ */
159
+ getOverrideAttestationHistory(vault: string, targetChainId: number | bigint, options?: GetOverrideAttestationsOptions): Promise<OverrideAttestationRecord[]>;
160
+ /**
161
+ * Returns the latest active override attestation for a (vault, targetChainId) pair.
162
+ * Active means not revoked and not expired.
163
+ */
164
+ getLatestOverrideAttestation(vault: string, targetChainId: number | bigint, options?: GetOverrideAttestationsOptions): Promise<OverrideAttestationRecord | null>;
82
165
  }
83
166
 
84
- export { CHAINS, type ChainConfig, StrategyStore, type StrategyStoreConfig, computeVaultIdentifier };
167
+ export { CHAINS, type ChainConfig, type EASAttestationRequest, type EASAttestationRequestData, type GetOverrideAttestationsOptions, type OverrideAttestationRecord, StrategyStore, type StrategyStoreConfig, type SubmitOverrideAttestationOptions, type SubmitOverrideAttestationResult, computeVaultIdentifier };
package/dist/index.mjs CHANGED
@@ -3,7 +3,7 @@ import { ethers } from "ethers";
3
3
  import { z } from "zod";
4
4
  import { getContractAddressByChainIdAndContractName } from "@steerprotocol/sdk";
5
5
  import { encodePacked, keccak256 } from "viem";
6
- import { base } from "viem/chains";
6
+ import { arbitrum, base } from "viem/chains";
7
7
 
8
8
  // deployments/8453.json
9
9
  var __default = {
@@ -17,7 +17,7 @@ var __default = {
17
17
  SteerAuthorityResolver: {
18
18
  address: "0xdf351177442462498f76fd9230bff050e4b8588d",
19
19
  deployer: "0xe445be10273c1520d6f112cff1dd96f38be9ec49",
20
- deployedAt: "2026-01-07T11:55:32.000Z",
20
+ deployedAt: "2026-01-07T11:51:37.000Z",
21
21
  blockNumber: "0x269f5f3",
22
22
  transaction: "0xc1547acfc6f373c64f68d1bf572d056587f5b19b5e04cadd83d06f777c445f2b",
23
23
  gasUsed: "0x214ed7",
@@ -38,7 +38,7 @@ var __default = {
38
38
  gasUsed: "0x28304"
39
39
  },
40
40
  metadata: {
41
- lastUpdated: "2026-01-07T12:13:05.000Z",
41
+ lastUpdated: "2026-01-07T11:51:37.000Z",
42
42
  totalDeployments: 1
43
43
  }
44
44
  };
@@ -676,7 +676,66 @@ var REGISTRY_ABI = [
676
676
  "function totalVaultCount() view returns (uint256)",
677
677
  "function getVaultDetails(address _address) view returns (tuple(uint8 state, uint256 tokenId, uint256 vaultID, string payloadIpfs, address vaultAddress, string beaconName))"
678
678
  ];
679
+ var EAS_ABI = [
680
+ "event Attested(address indexed recipient, address indexed attester, bytes32 uid, bytes32 indexed schemaUID)",
681
+ "function attest((bytes32 schema,(address recipient,uint64 expirationTime,bool revocable,bytes32 refUID,bytes data,uint256 value) data) request) payable returns (bytes32)"
682
+ ];
683
+ var DEFAULT_EAS_SUBGRAPH_ENDPOINT = "https://base.easscan.org/graphql";
684
+ var DEFAULT_SUBGRAPH_PAGE_SIZE = 100;
685
+ var DEFAULT_SUBGRAPH_MAX_PAGES = 20;
686
+ var DEFAULT_SUBGRAPH_TIMEOUT_MS = 15e3;
687
+ var DEFAULT_SUBGRAPH_RETRIES = 2;
688
+ var DEFAULT_CHAIN_ID = __default.chainId;
689
+ var EAS_ATTESTATION_HISTORY_QUERY = `
690
+ query AttestationHistory($schemaUID: String!, $recipient: String!, $take: Int!, $skip: Int!) {
691
+ attestations(
692
+ where: { schemaId: { equals: $schemaUID }, recipient: { equals: $recipient } }
693
+ orderBy: [{ timeCreated: desc }]
694
+ take: $take
695
+ skip: $skip
696
+ ) {
697
+ id
698
+ attester
699
+ recipient
700
+ refUID
701
+ revocable
702
+ revocationTime
703
+ expirationTime
704
+ time
705
+ timeCreated
706
+ data
707
+ }
708
+ }
709
+ `;
710
+ var EAS_ATTESTATION_HISTORY_FALLBACK_QUERY = `
711
+ query AttestationHistoryFallback($take: Int!, $skip: Int!) {
712
+ attestations(take: $take, skip: $skip) {
713
+ id
714
+ attester
715
+ recipient
716
+ refUID
717
+ revocable
718
+ revocationTime
719
+ expirationTime
720
+ time
721
+ timeCreated
722
+ data
723
+ }
724
+ }
725
+ `;
726
+ var ARBITRUM_ONE_DEPLOYMENT = {
727
+ chainId: 42161,
728
+ chainName: "Arbitrum One",
729
+ chain: arbitrum,
730
+ rpcUrl: "https://arb1.arbitrum.io/rpc",
731
+ explorerUrl: "https://arbiscan.io",
732
+ easAddress: "0xbD75f629A22Dc1ceD33dDA0b68c546A1c035c458",
733
+ schemaRegistry: "0xA310da9c5B885E7fb3fbA9D66E9Ba6Df512b78eB",
734
+ resolverAddress: "0x6628d1Bf82F34de132d0e1c60DEB574C1352d5A7",
735
+ schemaUID: "0xf1a6a394d1f3dd832a15e5b750963d929812e2b74d2dcea68ddf9f75691f16bf"
736
+ };
679
737
  var CHAINS = {
738
+ ARBITRUM_ONE: ARBITRUM_ONE_DEPLOYMENT,
680
739
  BASE_MAINNET: {
681
740
  chainId: __default.chainId,
682
741
  chainName: __default.chainName,
@@ -700,9 +759,19 @@ function computeVaultIdentifier(vault, chainId) {
700
759
  const hash = keccak256(packed);
701
760
  return `0x${hash.slice(-40)}`;
702
761
  }
762
+ var Bytes32Schema = z.string().regex(/^0x[a-fA-F0-9]{64}$/, {
763
+ message: "Invalid bytes32 hex string"
764
+ });
703
765
  var StrategyStore = class _StrategyStore {
704
- static ARBITRUM_ONE_RESOLVER_ADDRESS = "0x6628d1Bf82F34de132d0e1c60DEB574C1352d5A7";
705
- static ARBITRUM_ONE_CROSSCHAIN_SCHEMA_UID = "0xf1a6a394d1f3dd832a15e5b750963d929812e2b74d2dcea68ddf9f75691f16bf";
766
+ static BASE_MAINNET_EAS_ADDRESS = __default.easAddress;
767
+ static BASE_MAINNET_RESOLVER_ADDRESS = __default.deployments.SteerAuthorityResolver.address;
768
+ static BASE_MAINNET_CROSSCHAIN_SCHEMA_UID = __default.schema.uid;
769
+ /** @deprecated Use BASE_MAINNET_EAS_ADDRESS */
770
+ static ARBITRUM_ONE_EAS_ADDRESS = ARBITRUM_ONE_DEPLOYMENT.easAddress;
771
+ /** @deprecated Use BASE_MAINNET_RESOLVER_ADDRESS */
772
+ static ARBITRUM_ONE_RESOLVER_ADDRESS = ARBITRUM_ONE_DEPLOYMENT.resolverAddress;
773
+ /** @deprecated Use BASE_MAINNET_CROSSCHAIN_SCHEMA_UID */
774
+ static ARBITRUM_ONE_CROSSCHAIN_SCHEMA_UID = ARBITRUM_ONE_DEPLOYMENT.schemaUID;
706
775
  static encodeOverrideAttestationData(vault, targetChainId, strategyTokenId, manifestCid) {
707
776
  const validatedVault = AddressSchema.parse(vault);
708
777
  return ethers.AbiCoder.defaultAbiCoder().encode(
@@ -710,35 +779,61 @@ var StrategyStore = class _StrategyStore {
710
779
  [validatedVault, targetChainId, strategyTokenId, manifestCid]
711
780
  );
712
781
  }
782
+ static buildOverrideAttestationRequest(schemaUID, vault, targetChainId, strategyTokenId, manifestCid, refUID = ethers.ZeroHash) {
783
+ const validatedSchemaUID = Bytes32Schema.parse(schemaUID);
784
+ const validatedVault = AddressSchema.parse(vault);
785
+ const validatedRefUID = Bytes32Schema.parse(refUID);
786
+ const normalizedTargetChainId = BigInt(targetChainId);
787
+ const data = _StrategyStore.encodeOverrideAttestationData(
788
+ validatedVault,
789
+ normalizedTargetChainId,
790
+ strategyTokenId,
791
+ manifestCid
792
+ );
793
+ return {
794
+ schema: validatedSchemaUID,
795
+ data: {
796
+ recipient: computeVaultIdentifier(validatedVault, normalizedTargetChainId),
797
+ expirationTime: 0n,
798
+ revocable: false,
799
+ refUID: validatedRefUID,
800
+ data,
801
+ value: 0n
802
+ }
803
+ };
804
+ }
713
805
  resolver;
714
806
  registry;
715
807
  resolverAddress;
716
808
  registryAddress;
717
- chainId;
809
+ chainId = DEFAULT_CHAIN_ID;
810
+ runner;
718
811
  constructor(config, providerOrSigner, overrides) {
719
812
  let resAddr;
720
813
  let regAddr;
814
+ this.runner = providerOrSigner;
721
815
  if (typeof config === "string") {
722
816
  resAddr = config;
817
+ this.chainId = DEFAULT_CHAIN_ID;
723
818
  } else {
724
819
  resAddr = config.resolverAddress;
725
820
  regAddr = config.registryAddress;
726
- this.chainId = config.chainId;
727
- const chainConfig = config.chainId ? getChainConfigByChainId(config.chainId) : void 0;
821
+ this.chainId = config.chainId ?? DEFAULT_CHAIN_ID;
822
+ const chainConfig = getChainConfigByChainId(this.chainId);
728
823
  if (!resAddr && chainConfig?.resolverAddress) {
729
824
  resAddr = chainConfig.resolverAddress;
730
825
  }
731
- if (!resAddr && config.chainId) {
732
- if (config.chainId === 42161) {
826
+ if (!resAddr) {
827
+ if (this.chainId === 42161) {
733
828
  resAddr = _StrategyStore.ARBITRUM_ONE_RESOLVER_ADDRESS;
734
829
  } else {
735
- resAddr = getContractAddressByChainIdAndContractName(config.chainId, "SteerAuthorityResolver");
830
+ resAddr = getContractAddressByChainIdAndContractName(this.chainId, "SteerAuthorityResolver");
736
831
  }
737
832
  }
738
- if (!regAddr && config.chainId) {
739
- regAddr = getContractAddressByChainIdAndContractName(config.chainId, "VaultRegistry");
833
+ if (!regAddr && config.chainId !== void 0) {
834
+ regAddr = getContractAddressByChainIdAndContractName(this.chainId, "VaultRegistry");
740
835
  if (!regAddr) {
741
- throw new Error(`VaultRegistry address not found for chainId ${config.chainId}`);
836
+ throw new Error(`VaultRegistry address not found for chainId ${this.chainId}`);
742
837
  }
743
838
  }
744
839
  }
@@ -753,11 +848,20 @@ var StrategyStore = class _StrategyStore {
753
848
  }
754
849
  }
755
850
  resolveChainId(chainId) {
756
- const resolvedChainId = chainId ?? this.chainId;
757
- if (resolvedChainId === void 0) {
758
- throw new Error("chainId is required to perform this action");
851
+ return chainId ?? this.chainId;
852
+ }
853
+ getDefaultSchemaUID() {
854
+ return _StrategyStore.BASE_MAINNET_CROSSCHAIN_SCHEMA_UID;
855
+ }
856
+ getDefaultEASAddress() {
857
+ const chainConfig = getChainConfigByChainId(this.chainId);
858
+ return chainConfig?.easAddress ?? _StrategyStore.BASE_MAINNET_EAS_ADDRESS;
859
+ }
860
+ async getSignerAddress() {
861
+ if (!("getAddress" in this.runner) || typeof this.runner.getAddress !== "function") {
862
+ throw new Error("A signer is required to submit attestations");
759
863
  }
760
- return resolvedChainId;
864
+ return await this.runner.getAddress();
761
865
  }
762
866
  /**
763
867
  * Checks if an address is the top-level admin.
@@ -817,6 +921,260 @@ var StrategyStore = class _StrategyStore {
817
921
  data
818
922
  };
819
923
  }
924
+ /**
925
+ * Checks curator auth, builds an EAS request, and submits the attestation transaction.
926
+ * Uses computed recipient format, revocable=false, expirationTime=0 by default.
927
+ */
928
+ async submitOverrideAttestation(vault, targetChainId, strategyTokenId, manifestCid, options) {
929
+ const resolvedSchemaUID = options?.schemaUID ?? this.getDefaultSchemaUID();
930
+ const resolvedEASAddress = options?.easAddress ?? this.getDefaultEASAddress();
931
+ const signerAddress = await this.getSignerAddress();
932
+ if (!options?.skipCuratorCheck) {
933
+ const authorized = await this.isCurator(vault, signerAddress, targetChainId);
934
+ if (!authorized) {
935
+ throw new Error(
936
+ `Address ${signerAddress} is not authorized as curator for vault ${vault} on chain ${targetChainId}`
937
+ );
938
+ }
939
+ }
940
+ const request = _StrategyStore.buildOverrideAttestationRequest(
941
+ resolvedSchemaUID,
942
+ vault,
943
+ targetChainId,
944
+ strategyTokenId,
945
+ manifestCid,
946
+ options?.refUID
947
+ );
948
+ const eas = options?.easContract || new ethers.Contract(AddressSchema.parse(resolvedEASAddress), EAS_ABI, this.runner);
949
+ const tx = await eas.attest(request);
950
+ const receipt = await tx.wait();
951
+ let uid;
952
+ for (const log of receipt.logs) {
953
+ try {
954
+ const parsed = eas.interface.parseLog(log);
955
+ if (!parsed || parsed.name !== "Attested") {
956
+ continue;
957
+ }
958
+ const eventAttester = String(parsed.args[1]).toLowerCase();
959
+ const eventUid = String(parsed.args[2]);
960
+ const eventSchemaUID = String(parsed.args[3]).toLowerCase();
961
+ if (eventAttester === signerAddress.toLowerCase() && eventSchemaUID === resolvedSchemaUID.toLowerCase()) {
962
+ uid = eventUid;
963
+ break;
964
+ }
965
+ } catch {
966
+ }
967
+ }
968
+ return {
969
+ request,
970
+ txHash: tx.hash,
971
+ uid
972
+ };
973
+ }
974
+ static toBigInt(value) {
975
+ if (value === null || value === void 0) {
976
+ return 0n;
977
+ }
978
+ if (typeof value === "bigint") {
979
+ return value;
980
+ }
981
+ if (typeof value === "number") {
982
+ return BigInt(value);
983
+ }
984
+ if (value.startsWith("0x") || value.startsWith("0X")) {
985
+ return BigInt(value);
986
+ }
987
+ return BigInt(value || "0");
988
+ }
989
+ static isActiveAttestation(record) {
990
+ const now = BigInt(Math.floor(Date.now() / 1e3));
991
+ const notRevoked = record.revocationTime === 0n;
992
+ const notExpired = record.expirationTime === 0n || record.expirationTime > now;
993
+ return notRevoked && notExpired;
994
+ }
995
+ async queryEASSubgraph(query, variables, endpoint, timeoutMs, retries, fetchFn) {
996
+ const resolvedFetchFn = fetchFn ?? globalThis.fetch;
997
+ if (!resolvedFetchFn) {
998
+ throw new Error("No fetch implementation available for subgraph requests");
999
+ }
1000
+ let lastError;
1001
+ for (let attempt = 0; attempt <= retries; attempt++) {
1002
+ const controller = new AbortController();
1003
+ const timeoutHandle = setTimeout(() => controller.abort(), timeoutMs);
1004
+ try {
1005
+ const response = await resolvedFetchFn(endpoint, {
1006
+ method: "POST",
1007
+ headers: {
1008
+ "content-type": "application/json"
1009
+ },
1010
+ body: JSON.stringify({ query, variables }),
1011
+ signal: controller.signal
1012
+ });
1013
+ if (!response.ok) {
1014
+ throw new Error(`Subgraph HTTP ${response.status} ${response.statusText}`);
1015
+ }
1016
+ const payload = await response.json();
1017
+ if (payload.errors && payload.errors.length > 0) {
1018
+ const errorMessages = payload.errors.map((error) => error.message || "Unknown GraphQL error").join("; ");
1019
+ throw new Error(`Subgraph GraphQL error: ${errorMessages}`);
1020
+ }
1021
+ if (!payload.data) {
1022
+ throw new Error("Subgraph response missing data");
1023
+ }
1024
+ return payload.data;
1025
+ } catch (error) {
1026
+ lastError = error instanceof Error ? error : new Error(String(error));
1027
+ if (attempt === retries) {
1028
+ break;
1029
+ }
1030
+ const backoffMs = 300 * (attempt + 1);
1031
+ await new Promise((resolve) => setTimeout(resolve, backoffMs));
1032
+ } finally {
1033
+ clearTimeout(timeoutHandle);
1034
+ }
1035
+ }
1036
+ throw new Error(`Failed to query EAS subgraph after ${retries + 1} attempts: ${lastError?.message || "unknown error"}`);
1037
+ }
1038
+ decodeOverrideAttestationRecord(raw) {
1039
+ try {
1040
+ const decoded = ethers.AbiCoder.defaultAbiCoder().decode(
1041
+ ["address", "uint256", "uint256", "string"],
1042
+ raw.data
1043
+ );
1044
+ const vault = decoded[0];
1045
+ const targetChainId = decoded[1];
1046
+ const strategyTokenId = decoded[2];
1047
+ const manifestCid = decoded[3];
1048
+ const record = {
1049
+ uid: raw.id,
1050
+ attester: AddressSchema.parse(raw.attester),
1051
+ recipient: AddressSchema.parse(raw.recipient),
1052
+ refUID: raw.refUID,
1053
+ revocable: raw.revocable,
1054
+ revocationTime: _StrategyStore.toBigInt(raw.revocationTime),
1055
+ expirationTime: _StrategyStore.toBigInt(raw.expirationTime),
1056
+ createdAt: _StrategyStore.toBigInt(raw.timeCreated ?? raw.time),
1057
+ data: raw.data,
1058
+ vault: AddressSchema.parse(vault),
1059
+ targetChainId: _StrategyStore.toBigInt(targetChainId),
1060
+ strategyTokenId: _StrategyStore.toBigInt(strategyTokenId),
1061
+ manifestCid,
1062
+ isActive: false
1063
+ };
1064
+ record.isActive = _StrategyStore.isActiveAttestation(record);
1065
+ return record;
1066
+ } catch {
1067
+ return null;
1068
+ }
1069
+ }
1070
+ /**
1071
+ * Returns full decoded override attestation history for a (vault, targetChainId) pair.
1072
+ * Results are returned newest first according to subgraph ordering.
1073
+ */
1074
+ async getOverrideAttestationHistory(vault, targetChainId, options) {
1075
+ const validatedVault = AddressSchema.parse(vault);
1076
+ const normalizedTargetChainId = BigInt(targetChainId);
1077
+ const recipient = computeVaultIdentifier(validatedVault, normalizedTargetChainId);
1078
+ const schemaUID = options?.schemaUID ?? this.getDefaultSchemaUID();
1079
+ const endpoint = options?.graphqlEndpoint ?? DEFAULT_EAS_SUBGRAPH_ENDPOINT;
1080
+ const pageSize = options?.pageSize ?? DEFAULT_SUBGRAPH_PAGE_SIZE;
1081
+ const maxPages = options?.maxPages ?? DEFAULT_SUBGRAPH_MAX_PAGES;
1082
+ const timeoutMs = options?.timeoutMs ?? DEFAULT_SUBGRAPH_TIMEOUT_MS;
1083
+ const retries = options?.retries ?? DEFAULT_SUBGRAPH_RETRIES;
1084
+ const includeRevoked = options?.includeRevoked ?? true;
1085
+ const includeExpired = options?.includeExpired ?? true;
1086
+ const all = [];
1087
+ let useFallbackQuery = false;
1088
+ for (let page = 0; page < maxPages; page++) {
1089
+ const skip = page * pageSize;
1090
+ let response;
1091
+ if (!useFallbackQuery) {
1092
+ try {
1093
+ response = await this.queryEASSubgraph(
1094
+ EAS_ATTESTATION_HISTORY_QUERY,
1095
+ {
1096
+ schemaUID,
1097
+ recipient,
1098
+ take: pageSize,
1099
+ skip
1100
+ },
1101
+ endpoint,
1102
+ timeoutMs,
1103
+ retries,
1104
+ options?.fetchFn
1105
+ );
1106
+ } catch {
1107
+ useFallbackQuery = true;
1108
+ response = await this.queryEASSubgraph(
1109
+ EAS_ATTESTATION_HISTORY_FALLBACK_QUERY,
1110
+ {
1111
+ take: pageSize,
1112
+ skip
1113
+ },
1114
+ endpoint,
1115
+ timeoutMs,
1116
+ retries,
1117
+ options?.fetchFn
1118
+ );
1119
+ }
1120
+ } else {
1121
+ response = await this.queryEASSubgraph(
1122
+ EAS_ATTESTATION_HISTORY_FALLBACK_QUERY,
1123
+ {
1124
+ take: pageSize,
1125
+ skip
1126
+ },
1127
+ endpoint,
1128
+ timeoutMs,
1129
+ retries,
1130
+ options?.fetchFn
1131
+ );
1132
+ }
1133
+ const pageRows = response.attestations || [];
1134
+ for (const row of pageRows) {
1135
+ const decoded = this.decodeOverrideAttestationRecord(row);
1136
+ if (!decoded) {
1137
+ continue;
1138
+ }
1139
+ if (decoded.vault.toLowerCase() !== validatedVault.toLowerCase()) {
1140
+ continue;
1141
+ }
1142
+ if (decoded.targetChainId !== normalizedTargetChainId) {
1143
+ continue;
1144
+ }
1145
+ if (decoded.recipient.toLowerCase() !== recipient.toLowerCase()) {
1146
+ continue;
1147
+ }
1148
+ if (options?.strategyTokenId !== void 0 && decoded.strategyTokenId !== options.strategyTokenId) {
1149
+ continue;
1150
+ }
1151
+ if (!includeRevoked && decoded.revocationTime !== 0n) {
1152
+ continue;
1153
+ }
1154
+ if (!includeExpired && decoded.expirationTime !== 0n && decoded.expirationTime <= BigInt(Math.floor(Date.now() / 1e3))) {
1155
+ continue;
1156
+ }
1157
+ all.push(decoded);
1158
+ }
1159
+ if (pageRows.length < pageSize) {
1160
+ break;
1161
+ }
1162
+ }
1163
+ return all;
1164
+ }
1165
+ /**
1166
+ * Returns the latest active override attestation for a (vault, targetChainId) pair.
1167
+ * Active means not revoked and not expired.
1168
+ */
1169
+ async getLatestOverrideAttestation(vault, targetChainId, options) {
1170
+ const history = await this.getOverrideAttestationHistory(vault, targetChainId, options);
1171
+ for (const item of history) {
1172
+ if (item.isActive) {
1173
+ return item;
1174
+ }
1175
+ }
1176
+ return null;
1177
+ }
820
1178
  };
821
1179
  export {
822
1180
  CHAINS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steerprotocol/curator-tools",
3
- "version": "1.7.0",
3
+ "version": "1.9.0",
4
4
  "description": "Steer Protocol Curator Override Tools",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -9,13 +9,17 @@
9
9
  "module": "./dist/index.mjs",
10
10
  "types": "./dist/index.d.mts",
11
11
  "files": [
12
- "dist"
12
+ "dist",
13
+ "deployments/*.json",
14
+ "deployments/abis/*.json"
13
15
  ],
14
16
  "exports": {
15
17
  ".": {
16
18
  "types": "./dist/index.d.mts",
17
19
  "import": "./dist/index.mjs"
18
- }
20
+ },
21
+ "./deployments/*.json": "./deployments/*.json",
22
+ "./deployments/abis/*.json": "./deployments/abis/*.json"
19
23
  },
20
24
  "directories": {
21
25
  "lib": "lib",
@@ -27,7 +31,9 @@
27
31
  "test:sol": "forge test",
28
32
  "test:all": "npm run test:sol && npm run test",
29
33
  "build": "tsup src/index.ts --format esm --dts --clean",
30
- "prepublishOnly": "npm run build"
34
+ "sync:deployments": "node script/sync-deployments.mjs",
35
+ "prepack": "npm run sync:deployments && npm run build",
36
+ "prepublishOnly": "npm run sync:deployments && npm run build"
31
37
  },
32
38
  "keywords": [],
33
39
  "author": "Derek Barrera",