@sage-protocol/sdk 0.1.17 → 0.1.21

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.cjs CHANGED
@@ -14,7 +14,7 @@ var require_package = __commonJS({
14
14
  "package.json"(exports2, module2) {
15
15
  module2.exports = {
16
16
  name: "@sage-protocol/sdk",
17
- version: "0.1.17",
17
+ version: "0.1.21",
18
18
  description: "Backend-agnostic SDK for interacting with the Sage Protocol (governance, SubDAOs, tokens).",
19
19
  main: "dist/index.cjs",
20
20
  module: "dist/index.mjs",
@@ -130,7 +130,6 @@ var require_abi = __commonJS({
130
130
  "function stableCreationFee() view returns (uint256)",
131
131
  "function stableFeeReceiver() view returns (address)",
132
132
  "function stableCreationEnabled() view returns (bool)",
133
- "function stablePromptForkFee() view returns (uint256)",
134
133
  "function stableForkFee() view returns (uint256)",
135
134
  // Core factory reads
136
135
  "function timelockMinDelay() view returns (uint256)",
@@ -172,13 +171,18 @@ var require_abi = __commonJS({
172
171
  "function maxCreationBurn() view returns (uint256)"
173
172
  ];
174
173
  var LibraryRegistry = [
175
- "function libraryByDAO(address) view returns (string manifestCID, address lastUpdater, uint256 lastUpdated, string version)",
174
+ "function libraryByDAO(address) view returns (string manifestCID, address lastUpdater, uint256 lastUpdated, string version, address forkedFromDAO, uint256 sxxxForkFee)",
176
175
  "function daoTimelock(address) view returns (address)",
177
- "function getLibrary(address) view returns (tuple(string manifestCID, address lastUpdater, uint256 lastUpdated, string version))",
176
+ "function getLibrary(address) view returns (tuple(string manifestCID, address lastUpdater, uint256 lastUpdated, string version, address forkedFromDAO, uint256 sxxxForkFee))",
177
+ "function getLibraryForkFee(address dao) view returns (uint256)",
178
+ "function setLibraryForkFee(address dao, uint256 fee)",
178
179
  "function updateLibrary(address dao, string manifestCID, string version)",
179
180
  "function registerDAO(address dao, address timelock)",
181
+ "function registerForkedDAO(address childDAO, address childTimelock, address parentDAO, string manifestCID, string version)",
180
182
  "event LibraryUpdated(address indexed dao, string manifestCID, address indexed timelock, string version)",
181
- "event DAORegistered(address indexed dao, address indexed timelock)"
183
+ "event DAORegistered(address indexed dao, address indexed timelock)",
184
+ "event LibraryForked(address indexed parentDAO, address indexed childDAO)",
185
+ "event LibraryForkFeeUpdated(address indexed dao, uint256 fee)"
182
186
  ];
183
187
  var PromptRegistry = [
184
188
  "function prompts(string key) view returns (string cid, uint256 version, uint256 timestamp, address author, string forkedFromCID, address originalAuthor, bool isFork, uint256 forkDepth)",
@@ -293,6 +297,186 @@ var require_abi = __commonJS({
293
297
  "function create(uint256 proposalId, address token, uint256 perVoter, uint256 maxVoters)",
294
298
  "function fund(uint256 proposalId, uint256 amount)"
295
299
  ];
300
+ var VotingMultiplierNFT = [
301
+ // Constants
302
+ "function MINTER_ROLE() view returns (bytes32)",
303
+ "function MAX_NFTS_PER_ACCOUNT() view returns (uint256)",
304
+ // Tier Management
305
+ "function createTier(address dao, string name, uint256 multiplier, uint256 maxSupply, uint256 price) returns (uint256 tierId)",
306
+ "function getTier(uint256 tierId) view returns (tuple(string name, uint256 multiplier, uint256 maxSupply, uint256 minted, uint256 price, address dao))",
307
+ "function tierCount() view returns (uint256)",
308
+ "function tiers(uint256) view returns (string name, uint256 multiplier, uint256 maxSupply, uint256 minted, uint256 price, address dao)",
309
+ // Minting
310
+ "function mint(address to, uint256 tierId, string uri) returns (uint256 tokenId)",
311
+ "function publicMint(uint256 tierId, string uri) payable returns (uint256 tokenId)",
312
+ // Multiplier Functions
313
+ "function getMultiplier(address account, address dao) view returns (uint256)",
314
+ "function getPastMultiplier(address account, address dao, uint256 timepoint) view returns (uint256)",
315
+ "function getTokenMultiplier(uint256 tokenId) view returns (uint256)",
316
+ "function getTokenDAO(uint256 tokenId) view returns (address)",
317
+ // Token Info
318
+ "function tokenMultiplier(uint256) view returns (uint256)",
319
+ "function tokenDAO(uint256) view returns (address)",
320
+ "function tokenTier(uint256) view returns (uint256)",
321
+ "function getTokenInfo(uint256 tokenId) view returns (address owner, uint256 tierId, uint256 multiplier, string uri)",
322
+ // ERC721 Standard
323
+ "function balanceOf(address owner) view returns (uint256)",
324
+ "function ownerOf(uint256 tokenId) view returns (address)",
325
+ "function tokenOfOwnerByIndex(address owner, uint256 index) view returns (uint256)",
326
+ "function tokenURI(uint256 tokenId) view returns (string)",
327
+ "function transferFrom(address from, address to, uint256 tokenId)",
328
+ "function safeTransferFrom(address from, address to, uint256 tokenId)",
329
+ "function approve(address to, uint256 tokenId)",
330
+ "function setApprovalForAll(address operator, bool approved)",
331
+ "function getApproved(uint256 tokenId) view returns (address)",
332
+ "function isApprovedForAll(address owner, address operator) view returns (bool)",
333
+ // Admin
334
+ "function withdrawFunds(address to)",
335
+ "function grantRole(bytes32 role, address account)",
336
+ "function revokeRole(bytes32 role, address account)",
337
+ "function hasRole(bytes32 role, address account) view returns (bool)",
338
+ // Events
339
+ "event TierCreated(uint256 indexed tierId, address indexed dao, string name, uint256 multiplier, uint256 maxSupply, uint256 price)",
340
+ "event NFTMinted(address indexed to, uint256 indexed tokenId, address indexed dao, uint256 tierId, uint256 multiplier)",
341
+ "event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)"
342
+ ];
343
+ var MultipliedVotes = [
344
+ // Core IVotes Interface
345
+ "function getVotes(address account) view returns (uint256)",
346
+ "function getPastVotes(address account, uint256 timepoint) view returns (uint256)",
347
+ "function getPastTotalSupply(uint256 timepoint) view returns (uint256)",
348
+ "function delegates(address account) view returns (address)",
349
+ "function delegate(address delegatee)",
350
+ "function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s)",
351
+ // IERC6372 Clock Interface
352
+ "function clock() view returns (uint48)",
353
+ "function CLOCK_MODE() view returns (string)",
354
+ // View Helpers
355
+ "function getVotingBreakdown(address account) view returns (uint256 baseVotes, uint256 multiplier, uint256 effectiveVotes)",
356
+ "function getPastVotingBreakdown(address account, uint256 timepoint) view returns (uint256 baseVotes, uint256 multiplier, uint256 effectiveVotes)",
357
+ "function hasMultiplierBonus(address account) view returns (bool)",
358
+ // Immutable Config
359
+ "function baseToken() view returns (address)",
360
+ "function multiplierNFT() view returns (address)",
361
+ "function dao() view returns (address)",
362
+ "function BASIS() view returns (uint256)"
363
+ ];
364
+ var SageAuctionHouse = [
365
+ // Core Auction Functions
366
+ "function createBid(uint256 nftId) payable",
367
+ "function settleCurrentAndCreateNewAuction()",
368
+ "function settleAuction()",
369
+ "function createAuction()",
370
+ // Current Auction State
371
+ "function auction() view returns (uint256 nftId, uint256 amount, uint256 startTime, uint256 endTime, address bidder, bool settled)",
372
+ // Configuration
373
+ "function nft() view returns (address)",
374
+ "function treasury() view returns (address)",
375
+ "function weth() view returns (address)",
376
+ "function timeBuffer() view returns (uint256)",
377
+ "function reservePrice() view returns (uint256)",
378
+ "function minBidIncrementPercentage() view returns (uint256)",
379
+ "function duration() view returns (uint256)",
380
+ "function mintTierId() view returns (uint256)",
381
+ "function defaultTokenURI() view returns (string)",
382
+ // Admin Functions
383
+ "function pause()",
384
+ "function unpause()",
385
+ "function paused() view returns (bool)",
386
+ "function setTimeBuffer(uint256 _timeBuffer)",
387
+ "function setReservePrice(uint256 _reservePrice)",
388
+ "function setMinBidIncrementPercentage(uint256 _minBidIncrementPercentage)",
389
+ "function setDuration(uint256 _duration)",
390
+ "function setMintTierId(uint256 _tierId)",
391
+ "function setDefaultTokenURI(string _uri)",
392
+ "function owner() view returns (address)",
393
+ "function transferOwnership(address newOwner)",
394
+ // Events
395
+ "event AuctionCreated(uint256 indexed nftId, uint256 startTime, uint256 endTime)",
396
+ "event AuctionBid(uint256 indexed nftId, address sender, uint256 value, bool extended)",
397
+ "event AuctionExtended(uint256 indexed nftId, uint256 endTime)",
398
+ "event AuctionSettled(uint256 indexed nftId, address winner, uint256 amount)",
399
+ "event AuctionTimeBufferUpdated(uint256 timeBuffer)",
400
+ "event AuctionReservePriceUpdated(uint256 reservePrice)",
401
+ "event AuctionMinBidIncrementPercentageUpdated(uint256 minBidIncrementPercentage)",
402
+ "event AuctionDurationUpdated(uint256 duration)"
403
+ ];
404
+ var SimpleBountySystem = [
405
+ // Constants
406
+ "function GOVERNANCE_ROLE() view returns (bytes32)",
407
+ "function MAX_SUBMISSIONS_PER_BOUNTY() view returns (uint256)",
408
+ // Bounty Creation
409
+ "function createBounty(string title, string description, string ipfsCID, uint256 reward, uint256 deadline) returns (uint256)",
410
+ "function createBountyAdvanced(string title, string description, string ipfsCID, uint256 reward, uint256 deadline, uint256 votingDuration, uint8 mode, uint8 libraryAction, address assignee, string libraryKey) returns (uint256)",
411
+ // Submission & Claiming
412
+ "function claimBounty(uint256 bountyId)",
413
+ "function submitEntry(uint256 bountyId, string promptIPFS, string deliverableIPFS) returns (uint256)",
414
+ "function completeBounty(uint256 bountyId, string deliverableIPFS)",
415
+ // Voting (COMPETITIVE mode)
416
+ "function startVoting(uint256 bountyId)",
417
+ "function vote(uint256 bountyId, uint256 submissionId)",
418
+ "function finalizeCompetitive(uint256 bountyId)",
419
+ // Approval
420
+ "function approveSubmission(uint256 bountyId, uint256 submissionId)",
421
+ "function approveBountyCompletion(uint256 bountyId, string)",
422
+ // Cancellation & Expiry
423
+ "function cancelBounty(uint256 bountyId)",
424
+ "function expireBounty(uint256 bountyId)",
425
+ // Reward Management
426
+ "function increaseReward(uint256 bountyId, uint256 additionalReward)",
427
+ "function slashCreator(uint256 bountyId, uint256 amount, address to)",
428
+ // Gate Management
429
+ "function setGates(uint256 bountyId, uint256 minTokenBalance, uint256 requiredBadgeId)",
430
+ "function addToWhitelist(uint256 bountyId, address[] addresses)",
431
+ "function removeFromWhitelist(uint256 bountyId, address[] addresses)",
432
+ "function canSubmit(uint256 bountyId, address submitter) view returns (bool)",
433
+ // View Functions
434
+ "function getBounty(uint256 bountyId) view returns (tuple(address creator, uint256 id, string title, string description, string ipfsCID, uint256 reward, uint256 creatorDeposit, uint256 minContributorLevel, uint256 minTokenBalance, uint256 requiredBadgeId, uint256 deadline, uint256 votingEndTime, uint256 snapshotBlock, uint8 mode, uint8 status, uint8 libraryAction, address assignee, address winner, uint256 winningSubmissionId, string libraryKey, uint256 governanceProposalId))",
435
+ "function getSubmission(uint256 bountyId, uint256 submissionId) view returns (tuple(uint256 id, uint256 bountyId, address submitter, string promptIPFS, string deliverableIPFS, uint256 timestamp, uint256 voteCount, bool exists))",
436
+ "function getSubmissionCount(uint256 bountyId) view returns (uint256)",
437
+ "function getLeadingSubmission(uint256 bountyId) view returns (uint256 submissionId, uint256 votes)",
438
+ "function calculateStake(uint256 reward) view returns (uint256)",
439
+ // State Mappings
440
+ "function bounties(uint256) view returns (address creator, uint256 id, string title, string description, string ipfsCID, uint256 reward, uint256 creatorDeposit, uint256 minContributorLevel, uint256 minTokenBalance, uint256 requiredBadgeId, uint256 deadline, uint256 votingEndTime, uint256 snapshotBlock, uint8 mode, uint8 status, uint8 libraryAction, address assignee, address winner, uint256 winningSubmissionId, string libraryKey, uint256 governanceProposalId)",
441
+ "function nextBountyId() view returns (uint256)",
442
+ "function submissionCount(uint256) view returns (uint256)",
443
+ "function submitterToSubmission(uint256, address) view returns (uint256)",
444
+ "function hasVotedInBounty(uint256, address) view returns (bool)",
445
+ "function voterChosenSubmission(uint256, address) view returns (uint256)",
446
+ "function whitelist(uint256, address) view returns (bool)",
447
+ "function hasWhitelist(uint256) view returns (bool)",
448
+ // External Contracts
449
+ "function sxxxToken() view returns (address)",
450
+ "function contributorSystem() view returns (address)",
451
+ "function governanceConfig() view returns (address)",
452
+ "function communityTreasury() view returns (address)",
453
+ "function governanceContract() view returns (address)",
454
+ "function libraryRegistry() view returns (address)",
455
+ "function subdao() view returns (address)",
456
+ "function soulboundBadge() view returns (address)",
457
+ // Admin
458
+ "function setGovernanceContract(address _gov)",
459
+ "function setCommunityTreasury(address _treasury)",
460
+ "function setLibraryRegistry(address _registry)",
461
+ "function setSoulboundBadge(address _sbtAddress)",
462
+ "function grantRole(bytes32 role, address account)",
463
+ "function revokeRole(bytes32 role, address account)",
464
+ "function hasRole(bytes32 role, address account) view returns (bool)",
465
+ // Events
466
+ "event BountyCreated(uint256 indexed bountyId, address indexed creator, string title, uint256 reward, uint256 deposit, uint8 mode, address assignee)",
467
+ "event SubmissionReceived(uint256 indexed bountyId, uint256 indexed submissionId, address indexed submitter, string promptIPFS)",
468
+ "event BountyClaimed(uint256 indexed bountyId, address indexed claimant)",
469
+ "event BountyUnderReview(uint256 indexed bountyId, address indexed claimant, uint256 proposalId)",
470
+ "event VoteCast(uint256 indexed bountyId, uint256 indexed submissionId, address indexed voter, uint256 weight)",
471
+ "event VotingStarted(uint256 indexed bountyId, uint256 votingEndTime)",
472
+ "event BountyCompleted(uint256 indexed bountyId, address indexed winner, uint256 reward, string deliverable)",
473
+ "event BountyAutoApproved(uint256 indexed bountyId, address indexed winner)",
474
+ "event PromptAddedToLibrary(uint256 indexed bountyId, string libraryKey, string promptIPFS)",
475
+ "event BountyCancelled(uint256 indexed bountyId, address indexed creator)",
476
+ "event BountyExpired(uint256 indexed bountyId)",
477
+ "event BountyRewardIncreased(uint256 indexed bountyId, uint256 additionalReward, uint256 newTotal)",
478
+ "event CreatorSlashed(uint256 indexed bountyId, uint256 amount, address indexed to)"
479
+ ];
296
480
  var Events = {
297
481
  ProposalCreated: "event ProposalCreated(uint256 id, address proposer, address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, uint256 startBlock, uint256 endBlock, string description)"
298
482
  };
@@ -315,6 +499,13 @@ var require_abi = __commonJS({
315
499
  // Protocol treasury (replaces SageTreasury)
316
500
  GovernanceBoostMerkle,
317
501
  GovernanceBoostDirect,
502
+ // Voting Multiplier System
503
+ VotingMultiplierNFT,
504
+ MultipliedVotes,
505
+ // Auction House
506
+ SageAuctionHouse,
507
+ // Bounty System
508
+ SimpleBountySystem,
318
509
  Events
319
510
  };
320
511
  }
@@ -672,6 +863,409 @@ var require_subgraph = __commonJS({
672
863
  listLibraries,
673
864
  getSubdaoLibraries,
674
865
  getSubdaoPrompts,
866
+ /**
867
+ * Bounty dashboards (SimpleBountySystem)
868
+ */
869
+ async listBounties({ url, first = 50, skip = 0, status = null, creator = null }) {
870
+ if (!url) throw new Error("subgraph url required");
871
+ const filters = [];
872
+ if (status != null) filters.push(`status: ${Number(status)}`);
873
+ if (creator) {
874
+ const addr = safeGetAddress(creator);
875
+ if (!addr) throw new Error("invalid creator address");
876
+ filters.push(`creator: "${addr.toLowerCase()}"`);
877
+ }
878
+ const where = filters.length ? `where:{ ${filters.join(", ")} }` : "";
879
+ const doc = `
880
+ query($first:Int!,$skip:Int!){
881
+ bounties(
882
+ ${where}
883
+ first:$first
884
+ skip:$skip
885
+ orderBy: createdAt
886
+ orderDirection: desc
887
+ ){
888
+ id
889
+ contract
890
+ bountyId
891
+ creator
892
+ title
893
+ reward
894
+ creatorDeposit
895
+ mode
896
+ status
897
+ libraryAction
898
+ assignee
899
+ winner
900
+ winningSubmissionId
901
+ libraryKey
902
+ deadline
903
+ votingEndTime
904
+ createdAt
905
+ updatedAt
906
+ }
907
+ }
908
+ `;
909
+ const data = await query(url, doc, {
910
+ first: Math.min(Math.max(1, Number(first || 50)), 200),
911
+ skip: Number(skip || 0)
912
+ });
913
+ return mapSafe(data?.bounties, (row) => {
914
+ const contract = safeGetAddress(row.contract);
915
+ const creatorAddr = safeGetAddress(row.creator);
916
+ const assignee = row.assignee ? safeGetAddress(row.assignee) : null;
917
+ const winner = row.winner ? safeGetAddress(row.winner) : null;
918
+ if (!contract || !creatorAddr) return null;
919
+ return {
920
+ id: String(row.id),
921
+ contract,
922
+ bountyId: BigInt(String(row.bountyId || "0")),
923
+ creator: creatorAddr,
924
+ title: String(row.title || ""),
925
+ reward: BigInt(String(row.reward || "0")),
926
+ creatorDeposit: BigInt(String(row.creatorDeposit || "0")),
927
+ mode: Number(row.mode || 0),
928
+ status: Number(row.status || 0),
929
+ libraryAction: row.libraryAction != null ? Number(row.libraryAction) : null,
930
+ assignee,
931
+ winner,
932
+ winningSubmissionId: row.winningSubmissionId != null ? BigInt(String(row.winningSubmissionId)) : null,
933
+ libraryKey: row.libraryKey || null,
934
+ deadline: row.deadline != null ? Number(row.deadline) : null,
935
+ votingEndTime: row.votingEndTime != null ? Number(row.votingEndTime) : null,
936
+ createdAt: Number(row.createdAt || 0),
937
+ updatedAt: Number(row.updatedAt || 0)
938
+ };
939
+ });
940
+ },
941
+ async getBounty({ url, id: id2 }) {
942
+ if (!url) throw new Error("subgraph url required");
943
+ const doc = `
944
+ query($id:ID!){
945
+ bounty(id:$id){
946
+ id
947
+ contract
948
+ bountyId
949
+ creator
950
+ title
951
+ reward
952
+ creatorDeposit
953
+ mode
954
+ status
955
+ libraryAction
956
+ assignee
957
+ winner
958
+ winningSubmissionId
959
+ libraryKey
960
+ deadline
961
+ votingEndTime
962
+ snapshotBlock
963
+ governanceProposalId
964
+ createdAt
965
+ updatedAt
966
+ }
967
+ }
968
+ `;
969
+ const data = await query(url, doc, { id: String(id2) });
970
+ const row = data?.bounty;
971
+ if (!row) return null;
972
+ const contract = safeGetAddress(row.contract);
973
+ const creatorAddr = safeGetAddress(row.creator);
974
+ if (!contract || !creatorAddr) return null;
975
+ return {
976
+ id: String(row.id),
977
+ contract,
978
+ bountyId: BigInt(String(row.bountyId || "0")),
979
+ creator: creatorAddr,
980
+ title: String(row.title || ""),
981
+ reward: BigInt(String(row.reward || "0")),
982
+ creatorDeposit: BigInt(String(row.creatorDeposit || "0")),
983
+ mode: Number(row.mode || 0),
984
+ status: Number(row.status || 0),
985
+ libraryAction: row.libraryAction != null ? Number(row.libraryAction) : null,
986
+ assignee: row.assignee ? safeGetAddress(row.assignee) : null,
987
+ winner: row.winner ? safeGetAddress(row.winner) : null,
988
+ winningSubmissionId: row.winningSubmissionId != null ? BigInt(String(row.winningSubmissionId)) : null,
989
+ libraryKey: row.libraryKey || null,
990
+ deadline: row.deadline != null ? Number(row.deadline) : null,
991
+ votingEndTime: row.votingEndTime != null ? Number(row.votingEndTime) : null,
992
+ snapshotBlock: row.snapshotBlock != null ? Number(row.snapshotBlock) : null,
993
+ governanceProposalId: row.governanceProposalId != null ? BigInt(String(row.governanceProposalId)) : null,
994
+ createdAt: Number(row.createdAt || 0),
995
+ updatedAt: Number(row.updatedAt || 0)
996
+ };
997
+ },
998
+ async listBountySubmissions({ url, bountyId, first = 50, skip = 0 }) {
999
+ if (!url) throw new Error("subgraph url required");
1000
+ const doc = `
1001
+ query($bountyId:BigInt!,$first:Int!,$skip:Int!){
1002
+ bountySubmissions(
1003
+ where:{ bountyId:$bountyId }
1004
+ first:$first
1005
+ skip:$skip
1006
+ orderBy: timestamp
1007
+ orderDirection: asc
1008
+ ){
1009
+ id
1010
+ bountyId
1011
+ submissionId
1012
+ submitter
1013
+ promptIPFS
1014
+ deliverableIPFS
1015
+ timestamp
1016
+ voteCount
1017
+ }
1018
+ }
1019
+ `;
1020
+ const data = await query(url, doc, {
1021
+ bountyId: String(bountyId),
1022
+ first: Math.min(Math.max(1, Number(first || 50)), 200),
1023
+ skip: Number(skip || 0)
1024
+ });
1025
+ return mapSafe(data?.bountySubmissions, (row) => {
1026
+ const submitter = safeGetAddress(row.submitter);
1027
+ if (!submitter) return null;
1028
+ return {
1029
+ id: String(row.id),
1030
+ bountyId: BigInt(String(row.bountyId || "0")),
1031
+ submissionId: BigInt(String(row.submissionId || "0")),
1032
+ submitter,
1033
+ promptIPFS: String(row.promptIPFS || ""),
1034
+ deliverableIPFS: String(row.deliverableIPFS || ""),
1035
+ timestamp: Number(row.timestamp || 0),
1036
+ voteCount: BigInt(String(row.voteCount || "0"))
1037
+ };
1038
+ });
1039
+ },
1040
+ async listBountyVotes({ url, bountyId, first = 100, skip = 0 }) {
1041
+ if (!url) throw new Error("subgraph url required");
1042
+ const doc = `
1043
+ query($bountyId:BigInt!,$first:Int!,$skip:Int!){
1044
+ bountyVotes(
1045
+ where:{ bountyId:$bountyId }
1046
+ first:$first
1047
+ skip:$skip
1048
+ orderBy: blockTimestamp
1049
+ orderDirection: desc
1050
+ ){
1051
+ id
1052
+ bountyId
1053
+ submissionId
1054
+ voter
1055
+ weight
1056
+ blockNumber
1057
+ blockTimestamp
1058
+ transactionHash
1059
+ }
1060
+ }
1061
+ `;
1062
+ const data = await query(url, doc, {
1063
+ bountyId: String(bountyId),
1064
+ first: Math.min(Math.max(1, Number(first || 100)), 500),
1065
+ skip: Number(skip || 0)
1066
+ });
1067
+ return mapSafe(data?.bountyVotes, (row) => {
1068
+ const voter = safeGetAddress(row.voter);
1069
+ if (!voter) return null;
1070
+ return {
1071
+ id: String(row.id),
1072
+ bountyId: BigInt(String(row.bountyId || "0")),
1073
+ submissionId: BigInt(String(row.submissionId || "0")),
1074
+ voter,
1075
+ weight: BigInt(String(row.weight || "0")),
1076
+ blockNumber: Number(row.blockNumber || 0),
1077
+ blockTimestamp: Number(row.blockTimestamp || 0),
1078
+ transactionHash: row.transactionHash || null
1079
+ };
1080
+ });
1081
+ },
1082
+ /**
1083
+ * Multiplier dashboards (VotingMultiplierNFT + SageAuctionHouse)
1084
+ */
1085
+ async listMultiplierAccounts({ url, dao, first = 100, skip = 0 }) {
1086
+ if (!url) throw new Error("subgraph url required");
1087
+ const daoAddr = safeGetAddress(dao);
1088
+ if (!daoAddr) throw new Error("invalid dao address");
1089
+ const doc = `
1090
+ query($dao:Bytes!,$first:Int!,$skip:Int!){
1091
+ multiplierAccounts(
1092
+ where:{ dao: $dao }
1093
+ first:$first
1094
+ skip:$skip
1095
+ orderBy: currentMultiplierBps
1096
+ orderDirection: desc
1097
+ ){
1098
+ id
1099
+ dao
1100
+ account
1101
+ currentMultiplierBps
1102
+ tokenCount
1103
+ updatedAt
1104
+ }
1105
+ }
1106
+ `;
1107
+ const data = await query(url, doc, {
1108
+ dao: daoAddr.toLowerCase(),
1109
+ first: Math.min(Math.max(1, Number(first || 100)), 500),
1110
+ skip: Number(skip || 0)
1111
+ });
1112
+ return mapSafe(data?.multiplierAccounts, (row) => {
1113
+ const daoNorm = safeGetAddress(row.dao);
1114
+ const account = safeGetAddress(row.account);
1115
+ if (!daoNorm || !account) return null;
1116
+ return {
1117
+ id: String(row.id),
1118
+ dao: daoNorm,
1119
+ account,
1120
+ multiplierBps: BigInt(String(row.currentMultiplierBps || "0")),
1121
+ tokenCount: Number(row.tokenCount || 0),
1122
+ updatedAt: Number(row.updatedAt || 0)
1123
+ };
1124
+ });
1125
+ },
1126
+ async listMultiplierNFTs({ url, dao, owner = null, first = 100, skip = 0 }) {
1127
+ if (!url) throw new Error("subgraph url required");
1128
+ const daoAddr = safeGetAddress(dao);
1129
+ if (!daoAddr) throw new Error("invalid dao address");
1130
+ const ownerAddr = owner ? safeGetAddress(owner) : null;
1131
+ const filters = [`dao: $dao`];
1132
+ if (ownerAddr) filters.push(`owner: $owner`);
1133
+ const where = `where:{ ${filters.join(", ")} }`;
1134
+ const doc = `
1135
+ query($dao:Bytes!,$owner:Bytes,$first:Int!,$skip:Int!){
1136
+ multiplierNFTs(
1137
+ ${where}
1138
+ first:$first
1139
+ skip:$skip
1140
+ orderBy: mintedAt
1141
+ orderDirection: desc
1142
+ ){
1143
+ id
1144
+ owner
1145
+ dao
1146
+ tier { id name multiplier maxSupply minted price }
1147
+ multiplier
1148
+ tokenURI
1149
+ mintedAt
1150
+ transactionHash
1151
+ }
1152
+ }
1153
+ `;
1154
+ const variables = {
1155
+ dao: daoAddr.toLowerCase(),
1156
+ owner: ownerAddr ? ownerAddr.toLowerCase() : null,
1157
+ first: Math.min(Math.max(1, Number(first || 100)), 500),
1158
+ skip: Number(skip || 0)
1159
+ };
1160
+ const data = await query(url, doc, variables);
1161
+ return mapSafe(data?.multiplierNFTs, (row) => {
1162
+ const ownerNorm = safeGetAddress(row.owner);
1163
+ const daoNorm = safeGetAddress(row.dao);
1164
+ if (!ownerNorm || !daoNorm) return null;
1165
+ return {
1166
+ id: String(row.id),
1167
+ owner: ownerNorm,
1168
+ dao: daoNorm,
1169
+ tier: row.tier ? {
1170
+ id: String(row.tier.id),
1171
+ name: String(row.tier.name || ""),
1172
+ multiplier: Number(row.tier.multiplier || 0),
1173
+ maxSupply: BigInt(String(row.tier.maxSupply || "0")),
1174
+ minted: BigInt(String(row.tier.minted || "0")),
1175
+ price: BigInt(String(row.tier.price || "0"))
1176
+ } : null,
1177
+ multiplier: Number(row.multiplier || 0),
1178
+ tokenURI: row.tokenURI || null,
1179
+ mintedAt: Number(row.mintedAt || 0),
1180
+ transactionHash: row.transactionHash || null
1181
+ };
1182
+ });
1183
+ },
1184
+ async getCurrentAuction({ url, auctionHouse }) {
1185
+ if (!url) throw new Error("subgraph url required");
1186
+ const addr = safeGetAddress(auctionHouse);
1187
+ if (!addr) throw new Error("invalid auctionHouse address");
1188
+ const doc = `
1189
+ query($id:ID!){
1190
+ multiplierAuction(id:$id){
1191
+ id
1192
+ auctionHouse
1193
+ nft
1194
+ treasury
1195
+ currentNftId
1196
+ currentAmount
1197
+ currentBidder
1198
+ startTime
1199
+ endTime
1200
+ settled
1201
+ updatedAt
1202
+ }
1203
+ }
1204
+ `;
1205
+ const data = await query(url, doc, { id: addr.toLowerCase() });
1206
+ const row = data?.multiplierAuction;
1207
+ if (!row) return null;
1208
+ return {
1209
+ id: String(row.id),
1210
+ auctionHouse: safeGetAddress(row.auctionHouse) || addr,
1211
+ nft: safeGetAddress(row.nft),
1212
+ treasury: safeGetAddress(row.treasury),
1213
+ currentNftId: BigInt(String(row.currentNftId || "0")),
1214
+ currentAmount: BigInt(String(row.currentAmount || "0")),
1215
+ currentBidder: safeGetAddress(row.currentBidder || "0x0000000000000000000000000000000000000000"),
1216
+ startTime: Number(row.startTime || 0),
1217
+ endTime: Number(row.endTime || 0),
1218
+ settled: !!row.settled,
1219
+ updatedAt: Number(row.updatedAt || 0)
1220
+ };
1221
+ },
1222
+ async listAuctionBids({ url, auctionHouse, first = 100, skip = 0 }) {
1223
+ if (!url) throw new Error("subgraph url required");
1224
+ const addr = safeGetAddress(auctionHouse);
1225
+ if (!addr) throw new Error("invalid auctionHouse address");
1226
+ const doc = `
1227
+ query($auctionHouse:Bytes!,$first:Int!,$skip:Int!){
1228
+ multiplierAuctionBids(
1229
+ where:{ auctionHouse:$auctionHouse }
1230
+ first:$first
1231
+ skip:$skip
1232
+ orderBy: blockTimestamp
1233
+ orderDirection: desc
1234
+ ){
1235
+ id
1236
+ auctionHouse
1237
+ nftId
1238
+ bidder
1239
+ amount
1240
+ extended
1241
+ blockNumber
1242
+ blockTimestamp
1243
+ transactionHash
1244
+ }
1245
+ }
1246
+ `;
1247
+ const data = await query(url, doc, {
1248
+ auctionHouse: addr.toLowerCase(),
1249
+ first: Math.min(Math.max(1, Number(first || 100)), 500),
1250
+ skip: Number(skip || 0)
1251
+ });
1252
+ return mapSafe(data?.multiplierAuctionBids, (row) => {
1253
+ const bidder = safeGetAddress(row.bidder);
1254
+ const ah = safeGetAddress(row.auctionHouse);
1255
+ if (!ah || !bidder) return null;
1256
+ return {
1257
+ id: String(row.id),
1258
+ auctionHouse: ah,
1259
+ nftId: BigInt(String(row.nftId || "0")),
1260
+ bidder,
1261
+ amount: BigInt(String(row.amount || "0")),
1262
+ extended: !!row.extended,
1263
+ blockNumber: Number(row.blockNumber || 0),
1264
+ blockTimestamp: Number(row.blockTimestamp || 0),
1265
+ transactionHash: row.transactionHash || null
1266
+ };
1267
+ });
1268
+ },
675
1269
  /**
676
1270
  * Canonical proposal timeline. Tries common fields first, then event-style fallbacks.
677
1271
  * Returns { id, createdAt, queuedAt, executedAt, canceledAt, eta, state } (numbers/strings may be null when unavailable).
@@ -1160,7 +1754,6 @@ var require_ipfs = __commonJS({
1160
1754
  headers["X-Wallet-Address"] = auth.address;
1161
1755
  headers["X-Wallet-Signature"] = auth.signature;
1162
1756
  headers["X-Wallet-Nonce"] = auth.nonce;
1163
- headers["X-Wallet-Message"] = auth.message;
1164
1757
  }
1165
1758
  return { headers, auth };
1166
1759
  }
@@ -1181,8 +1774,7 @@ var require_ipfs = __commonJS({
1181
1774
  ...extraHeaders,
1182
1775
  "X-Wallet-Address": auth.address,
1183
1776
  "X-Wallet-Signature": auth.signature,
1184
- "X-Wallet-Nonce": auth.nonce,
1185
- "X-Wallet-Message": auth.message
1777
+ "X-Wallet-Nonce": auth.nonce
1186
1778
  };
1187
1779
  return { headers, auth };
1188
1780
  }
@@ -1203,6 +1795,13 @@ var require_ipfs = __commonJS({
1203
1795
  order.push(name);
1204
1796
  };
1205
1797
  const normalizedPreference = Array.isArray(preference) ? preference.map((p) => toLowerSafe(p)).filter(Boolean) : preference ? [toLowerSafe(preference)].filter(Boolean) : [];
1798
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
1799
+ console.log("[SDK DEBUG] resolveProviderOrder preference:", preference);
1800
+ console.log("[SDK DEBUG] normalizedPreference:", normalizedPreference);
1801
+ console.log("[SDK DEBUG] config.provider:", config.provider);
1802
+ console.log("[SDK DEBUG] shouldUseWorker():", shouldUseWorker());
1803
+ console.log("[SDK DEBUG] hasPinataCreds():", hasPinataCreds());
1804
+ }
1206
1805
  normalizedPreference.forEach(append);
1207
1806
  if (shouldUseWorker()) append("worker");
1208
1807
  if (hasPinataCreds()) append("pinata");
@@ -1210,17 +1809,90 @@ var require_ipfs = __commonJS({
1210
1809
  if (config.simulate) append("simulate");
1211
1810
  return order;
1212
1811
  }
1213
- async function uploadViaWorker(payload, { warm, gateways } = {}) {
1812
+ async function uploadViaWorker(payload, { warm, gateways, pin: pin2 } = {}) {
1813
+ const uploadUrl = workerUrl("upload");
1814
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
1815
+ console.log("[SDK DEBUG] uploadViaWorker called");
1816
+ console.log("[SDK DEBUG] workerBaseUrl:", workerBaseUrl());
1817
+ console.log("[SDK DEBUG] uploadUrl:", uploadUrl);
1818
+ console.log("[SDK DEBUG] workerHasAuth:", workerHasAuth());
1819
+ }
1214
1820
  const { headers, auth } = await buildWorkerAuthHeaders({ "Content-Type": "application/json" });
1215
1821
  const body = { ...payload };
1216
1822
  if (auth) body.auth = auth;
1217
- const response = await axiosInstance.post(workerUrl("upload"), body, { headers, timeout: config.timeoutMs });
1218
- const cid = response?.data?.cid || response?.data?.IpfsHash;
1823
+ if (pin2) {
1824
+ body.pin = typeof pin2 === "string" ? { duration: pin2 } : pin2;
1825
+ }
1826
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
1827
+ console.log("[SDK DEBUG] headers:", Object.keys(headers));
1828
+ console.log("[SDK DEBUG] hasAuth:", !!auth);
1829
+ if (pin2) console.log("[SDK DEBUG] pin:", JSON.stringify(body.pin));
1830
+ }
1831
+ let response;
1832
+ try {
1833
+ response = await axiosInstance.post(uploadUrl, body, { headers, timeout: config.timeoutMs });
1834
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
1835
+ console.log("[SDK DEBUG] Upload response status:", response?.status);
1836
+ console.log("[SDK DEBUG] Upload response data:", JSON.stringify(response?.data || {}));
1837
+ }
1838
+ } catch (uploadErr) {
1839
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
1840
+ console.log("[SDK DEBUG] Upload error:", uploadErr.message);
1841
+ console.log("[SDK DEBUG] Response status:", uploadErr.response?.status);
1842
+ console.log("[SDK DEBUG] Response data:", JSON.stringify(uploadErr.response?.data || {}));
1843
+ }
1844
+ const status = uploadErr.response?.status;
1845
+ const data2 = uploadErr.response?.data;
1846
+ if (status === 400 && data2?.error === "content_blocked") {
1847
+ const error = new Error("content_blocked");
1848
+ error.code = "CONTENT_BLOCKED";
1849
+ error.categories = data2.categories || [];
1850
+ error.reason = data2.reason;
1851
+ error.response = data2;
1852
+ throw error;
1853
+ }
1854
+ if (status === 402) {
1855
+ const error = new Error("payment_required");
1856
+ error.code = "PAYMENT_REQUIRED";
1857
+ error.creditsNeeded = data2?.creditsNeeded;
1858
+ error.balance = data2?.balance;
1859
+ error.duration = data2?.duration;
1860
+ error.accepts = data2?.accepts;
1861
+ error.response = data2;
1862
+ throw error;
1863
+ }
1864
+ throw uploadErr;
1865
+ }
1866
+ const data = response?.data || {};
1867
+ const cid = data.cid || data.IpfsHash;
1868
+ if (response?.status === 202 || data.status === "pending_review") {
1869
+ return {
1870
+ cid: cid || null,
1871
+ provider: "worker",
1872
+ status: "pending_review",
1873
+ categories: data.categories || [],
1874
+ response: data
1875
+ };
1876
+ }
1219
1877
  if (!cid) {
1220
1878
  throw new Error("Worker response missing cid");
1221
1879
  }
1222
1880
  if (warm || config.shouldWarm) await warmGateways(cid, { gateways });
1223
- return { cid, provider: "worker", response: response?.data || null };
1881
+ const result = {
1882
+ cid,
1883
+ provider: "worker",
1884
+ response: data
1885
+ };
1886
+ if (data.moderation) {
1887
+ result.moderation = data.moderation;
1888
+ }
1889
+ if (data.pinned !== void 0) {
1890
+ result.pinned = data.pinned;
1891
+ result.expiresAt = data.expiresAt;
1892
+ result.creditsPaid = data.creditsPaid;
1893
+ result.urls = data.urls;
1894
+ }
1895
+ return result;
1224
1896
  }
1225
1897
  async function uploadToPinata(payload, { filename = "payload.json", metadata, warm, gateways } = {}) {
1226
1898
  if (!hasPinataCreds()) {
@@ -1298,7 +1970,7 @@ var require_ipfs = __commonJS({
1298
1970
  return { cid, provider: "simulate" };
1299
1971
  }
1300
1972
  async function uploadPayload(payload, options2 = {}) {
1301
- const { providers, provider, warm, gateways, filename, metadata } = options2;
1973
+ const { providers, provider, warm, gateways, filename, metadata, pin: pin2 } = options2;
1302
1974
  const order = resolveProviderOrder(providers || provider);
1303
1975
  if (!order.length) {
1304
1976
  throw new Error("No IPFS providers configured. Set Pinata credentials, worker upload, or enable test mode");
@@ -1307,7 +1979,7 @@ var require_ipfs = __commonJS({
1307
1979
  for (const candidate of order) {
1308
1980
  try {
1309
1981
  if (candidate === "worker") {
1310
- return await uploadViaWorker(payload, { warm, gateways });
1982
+ return await uploadViaWorker(payload, { warm, gateways, pin: pin2 });
1311
1983
  }
1312
1984
  if (candidate === "pinata") {
1313
1985
  return await uploadToPinata(payload, { filename, metadata, warm, gateways });
@@ -1319,6 +1991,9 @@ var require_ipfs = __commonJS({
1319
1991
  return await uploadSimulated(payload, { warm, gateways });
1320
1992
  }
1321
1993
  } catch (error2) {
1994
+ if (error2.code === "CONTENT_BLOCKED" || error2.code === "PAYMENT_REQUIRED") {
1995
+ throw error2;
1996
+ }
1322
1997
  errors2.push({ provider: candidate, error: error2 });
1323
1998
  }
1324
1999
  }
@@ -1327,7 +2002,7 @@ var require_ipfs = __commonJS({
1327
2002
  throw error;
1328
2003
  }
1329
2004
  async function uploadPrompt(options2 = {}) {
1330
- const { prompt: prompt2, providers, provider, warm, gateways } = options2;
2005
+ const { prompt: prompt2, providers, provider, warm, gateways, pin: pin2 } = options2;
1331
2006
  if (!prompt2 || typeof prompt2 !== "object") {
1332
2007
  throw new Error("prompt payload required");
1333
2008
  }
@@ -1353,6 +2028,7 @@ var require_ipfs = __commonJS({
1353
2028
  provider,
1354
2029
  warm,
1355
2030
  gateways,
2031
+ pin: pin2,
1356
2032
  filename: `${prompt2.name || "prompt"}.json`,
1357
2033
  metadata
1358
2034
  });
@@ -1587,8 +2263,7 @@ var require_ipfs = __commonJS({
1587
2263
  "Content-Type": "application/json",
1588
2264
  "X-Wallet-Address": address,
1589
2265
  "X-Wallet-Signature": signature,
1590
- "X-Wallet-Nonce": nonce,
1591
- "X-Wallet-Message": message
2266
+ "X-Wallet-Nonce": nonce
1592
2267
  };
1593
2268
  let verified = false;
1594
2269
  try {
@@ -2446,13 +3121,10 @@ var require_governance = __commonJS({
2446
3121
  } else {
2447
3122
  const govAddr = normaliseGovernor(governor);
2448
3123
  try {
2449
- const iface = new Interface(["function sxxxToken() view returns (address)"]);
2450
- const data = iface.encodeFunctionData("sxxxToken", []);
2451
- const ret = await provider.call({ to: govAddr, data });
2452
- const [tok] = AbiCoder.defaultAbiCoder().decode(["address"], ret);
2453
- addr = getAddress(tok);
3124
+ const chain = await resolveVotesTokenChain({ provider, governor: govAddr });
3125
+ addr = getAddress(chain.votingToken);
2454
3126
  } catch (err) {
2455
- throw new SageSDKError(CODES.NOT_FOUND, "failed to resolve governance token from governor", { cause: err });
3127
+ throw new SageSDKError(CODES.NOT_FOUND, "failed to resolve votes token from governor", { cause: err });
2456
3128
  }
2457
3129
  }
2458
3130
  const user = getAddress(account);
@@ -2533,6 +3205,210 @@ var require_governance = __commonJS({
2533
3205
  const token2 = await g.sxxxToken();
2534
3206
  return buildDelegateTx({ token: token2, delegatee: account });
2535
3207
  }
3208
+ async function resolveVotesTokenChain({ provider, subdao: subdao2, governor }) {
3209
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3210
+ if (!subdao2 && !governor) throw new SageSDKError(CODES.INVALID_ARGS, "subdao or governor required");
3211
+ let votingToken = null;
3212
+ if (governor) {
3213
+ const govAddr = normaliseGovernor(governor);
3214
+ try {
3215
+ const iTok = new Interface(["function token() view returns (address)"]);
3216
+ const data = iTok.encodeFunctionData("token", []);
3217
+ const ret = await provider.call({ to: govAddr, data });
3218
+ if (ret && ret !== "0x") {
3219
+ const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], ret);
3220
+ votingToken = addr;
3221
+ }
3222
+ } catch (_) {
3223
+ }
3224
+ if (!votingToken) {
3225
+ try {
3226
+ const iGov = new Interface(["function sxxxToken() view returns (address)"]);
3227
+ const d2 = iGov.encodeFunctionData("sxxxToken", []);
3228
+ const r2 = await provider.call({ to: govAddr, data: d2 });
3229
+ if (r2 && r2 !== "0x") {
3230
+ const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], r2);
3231
+ votingToken = addr;
3232
+ }
3233
+ } catch (_) {
3234
+ }
3235
+ }
3236
+ }
3237
+ if (!votingToken && subdao2) {
3238
+ try {
3239
+ const subAddr = getAddress(subdao2);
3240
+ const iSub = new Interface(["function stakeToken() view returns (address)"]);
3241
+ const d3 = iSub.encodeFunctionData("stakeToken", []);
3242
+ const r3 = await provider.call({ to: subAddr, data: d3 });
3243
+ if (r3 && r3 !== "0x") {
3244
+ const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], r3);
3245
+ votingToken = addr;
3246
+ }
3247
+ } catch (_) {
3248
+ }
3249
+ }
3250
+ if (!votingToken) {
3251
+ throw new SageSDKError(CODES.NOT_FOUND, "failed to resolve votes token");
3252
+ }
3253
+ const votingTokenNorm = getAddress(votingToken);
3254
+ let baseToken = votingTokenNorm;
3255
+ let isWrapper = false;
3256
+ try {
3257
+ const wrapperIface = new Interface([
3258
+ "function baseToken() view returns (address)",
3259
+ "function dao() view returns (address)"
3260
+ ]);
3261
+ const [rawBase, rawDao] = await Promise.all([
3262
+ provider.call({ to: votingTokenNorm, data: wrapperIface.encodeFunctionData("baseToken", []) }),
3263
+ provider.call({ to: votingTokenNorm, data: wrapperIface.encodeFunctionData("dao", []) })
3264
+ ]);
3265
+ if (rawBase && rawBase !== "0x" && rawDao && rawDao !== "0x") {
3266
+ const [decodedBase] = AbiCoder.defaultAbiCoder().decode(["address"], rawBase);
3267
+ const [decodedDao] = AbiCoder.defaultAbiCoder().decode(["address"], rawDao);
3268
+ const baseNorm = getAddress(decodedBase);
3269
+ const daoNorm = getAddress(decodedDao);
3270
+ if (!subdao2 || daoNorm === getAddress(subdao2)) {
3271
+ baseToken = baseNorm;
3272
+ isWrapper = true;
3273
+ }
3274
+ }
3275
+ } catch (_) {
3276
+ }
3277
+ return { votingToken: votingTokenNorm, baseToken, isWrapper };
3278
+ }
3279
+ async function describeVotesToken({ provider, subdao: subdao2, governor }) {
3280
+ const { votingToken, baseToken, isWrapper } = await resolveVotesTokenChain({ provider, subdao: subdao2, governor });
3281
+ let multiplierNFT = null;
3282
+ let basis = null;
3283
+ if (isWrapper) {
3284
+ try {
3285
+ const wrapper = new Contract(votingToken, ABI.MultipliedVotes, provider);
3286
+ multiplierNFT = await wrapper.multiplierNFT().catch(() => null);
3287
+ basis = await wrapper.BASIS().catch(() => null);
3288
+ } catch (_) {
3289
+ }
3290
+ }
3291
+ const votingNorm = getAddress(votingToken);
3292
+ const baseNorm = getAddress(baseToken);
3293
+ const multiplierNorm = multiplierNFT && /^0x[0-9a-fA-F]{40}$/.test(String(multiplierNFT)) ? getAddress(multiplierNFT) : null;
3294
+ const basisBig = basis != null ? BigInt(String(basis)) : null;
3295
+ let description;
3296
+ if (!isWrapper) {
3297
+ description = `Voting token = ERC20Votes at ${votingNorm}`;
3298
+ } else {
3299
+ const basisStr = basisBig != null ? basisBig.toString() : "10000";
3300
+ description = `Voting token = MultipliedVotes(base=${baseNorm}, multiplierNFT=${multiplierNorm || "unknown"}, BASIS=${basisStr})`;
3301
+ if (subdao2) {
3302
+ description += ` for DAO ${getAddress(subdao2)}`;
3303
+ }
3304
+ }
3305
+ return {
3306
+ votingToken: votingNorm,
3307
+ baseToken: baseNorm,
3308
+ isWrapper,
3309
+ multiplierNFT: multiplierNorm,
3310
+ basis: basisBig,
3311
+ description
3312
+ };
3313
+ }
3314
+ async function getVotingStatus({ provider, subdao: subdao2, governor, account }) {
3315
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3316
+ if (!governor && !subdao2) throw new SageSDKError(CODES.INVALID_ARGS, "governor or subdao required");
3317
+ if (!account) throw new SageSDKError(CODES.INVALID_ARGS, "account required");
3318
+ const acct = getAddress(account);
3319
+ let govAddr = null;
3320
+ let subdaoAddr = null;
3321
+ if (governor) {
3322
+ govAddr = normaliseGovernor(governor);
3323
+ }
3324
+ if (subdao2) {
3325
+ subdaoAddr = getAddress(subdao2);
3326
+ if (!govAddr) {
3327
+ try {
3328
+ const sub = new Contract(subdaoAddr, ["function governor() view returns (address)"], provider);
3329
+ govAddr = getAddress(await sub.governor());
3330
+ } catch (_) {
3331
+ }
3332
+ }
3333
+ }
3334
+ if (!govAddr) throw new SageSDKError(CODES.INVALID_ARGS, "could not resolve governor address");
3335
+ let threshold = null;
3336
+ try {
3337
+ const g = new Contract(govAddr, ABI.Governor, provider);
3338
+ const t = await g.proposalThreshold();
3339
+ threshold = BigInt(t.toString());
3340
+ } catch (_) {
3341
+ }
3342
+ const desc = await describeVotesToken({ provider, subdao: subdaoAddr || void 0, governor: govAddr });
3343
+ let stakeToken = null;
3344
+ if (subdaoAddr) {
3345
+ try {
3346
+ const sub = new Contract(subdaoAddr, ["function stakeToken() view returns (address)"], provider);
3347
+ const st = await sub.stakeToken();
3348
+ if (st && /^0x[0-9a-fA-F]{40}$/.test(String(st))) {
3349
+ stakeToken = getAddress(st);
3350
+ }
3351
+ } catch (_) {
3352
+ }
3353
+ }
3354
+ const VotesABI = [
3355
+ "function getVotes(address) view returns (uint256)",
3356
+ "function delegates(address) view returns (address)",
3357
+ "function balanceOf(address) view returns (uint256)"
3358
+ ];
3359
+ let votingPower = null;
3360
+ let delegate = null;
3361
+ let tokenBalance = null;
3362
+ try {
3363
+ const votingC = new Contract(desc.votingToken, VotesABI, provider);
3364
+ const vp = await votingC.getVotes(acct).catch(() => null);
3365
+ if (vp != null) votingPower = BigInt(vp.toString());
3366
+ const del = await votingC.delegates(acct).catch(() => null);
3367
+ if (del && /^0x[0-9a-fA-F]{40}$/.test(String(del))) delegate = getAddress(del);
3368
+ const bal = await votingC.balanceOf(acct).catch(() => null);
3369
+ if (bal != null) tokenBalance = BigInt(bal.toString());
3370
+ } catch (_) {
3371
+ }
3372
+ const canPropose = threshold != null && votingPower != null ? votingPower >= threshold : null;
3373
+ let stakeTokenVotes = null;
3374
+ let stakeTokenDelegate = null;
3375
+ let stakeTokenBalance = null;
3376
+ const tokenMismatch = !!stakeToken && stakeToken.toLowerCase() !== desc.votingToken.toLowerCase();
3377
+ if (stakeToken && tokenMismatch) {
3378
+ try {
3379
+ const stakeC = new Contract(stakeToken, VotesABI, provider);
3380
+ const sv = await stakeC.getVotes(acct).catch(() => null);
3381
+ if (sv != null) stakeTokenVotes = BigInt(sv.toString());
3382
+ const sd = await stakeC.delegates(acct).catch(() => null);
3383
+ if (sd && /^0x[0-9a-fA-F]{40}$/.test(String(sd))) {
3384
+ stakeTokenDelegate = getAddress(sd);
3385
+ }
3386
+ const sb = await stakeC.balanceOf(acct).catch(() => null);
3387
+ if (sb != null) stakeTokenBalance = BigInt(sb.toString());
3388
+ } catch (_) {
3389
+ }
3390
+ }
3391
+ return {
3392
+ subdao: subdaoAddr,
3393
+ governor: govAddr,
3394
+ stakeToken,
3395
+ votingToken: desc.votingToken,
3396
+ baseToken: desc.baseToken,
3397
+ isWrapper: desc.isWrapper,
3398
+ multiplierNFT: desc.multiplierNFT,
3399
+ basis: desc.basis,
3400
+ threshold,
3401
+ votingPower,
3402
+ tokenBalance,
3403
+ delegate,
3404
+ canPropose,
3405
+ tokenMismatch,
3406
+ stakeTokenVotes,
3407
+ stakeTokenDelegate,
3408
+ stakeTokenBalance,
3409
+ description: desc.description
3410
+ };
3411
+ }
2536
3412
  module2.exports = {
2537
3413
  getGovernorInfo,
2538
3414
  getProposal,
@@ -2564,52 +3440,28 @@ var require_governance = __commonJS({
2564
3440
  * - SubDAO.stakeToken() (when subdao provided)
2565
3441
  */
2566
3442
  resolveVotesToken: async function resolveVotesToken({ provider, subdao: subdao2, governor }) {
2567
- if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
2568
- if (!subdao2 && !governor) throw new SageSDKError(CODES.INVALID_ARGS, "subdao or governor required");
2569
- if (governor) {
2570
- const govAddr = normaliseGovernor(governor);
2571
- try {
2572
- const iTok = new Interface(["function token() view returns (address)"]);
2573
- const data = iTok.encodeFunctionData("token", []);
2574
- const ret = await provider.call({ to: govAddr, data });
2575
- if (ret && ret !== "0x") {
2576
- const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], ret);
2577
- return getAddress(addr);
2578
- }
2579
- } catch (_) {
2580
- }
2581
- try {
2582
- const iGov = new Interface(["function sxxxToken() view returns (address)"]);
2583
- const d2 = iGov.encodeFunctionData("sxxxToken", []);
2584
- const r2 = await provider.call({ to: govAddr, data: d2 });
2585
- if (r2 && r2 !== "0x") {
2586
- const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], r2);
2587
- return getAddress(addr);
2588
- }
2589
- } catch (_) {
2590
- }
2591
- }
2592
- if (subdao2) {
2593
- try {
2594
- const subAddr = getAddress(subdao2);
2595
- const iSub = new Interface(["function stakeToken() view returns (address)"]);
2596
- const d3 = iSub.encodeFunctionData("stakeToken", []);
2597
- const r3 = await provider.call({ to: subAddr, data: d3 });
2598
- if (r3 && r3 !== "0x") {
2599
- const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], r3);
2600
- return getAddress(addr);
2601
- }
2602
- } catch (_) {
2603
- }
2604
- }
2605
- throw new SageSDKError(CODES.NOT_FOUND, "failed to resolve votes token");
3443
+ const { votingToken } = await resolveVotesTokenChain({ provider, subdao: subdao2, governor });
3444
+ return votingToken;
2606
3445
  },
3446
+ /**
3447
+ * Resolve the IVotes token chain used for voting (wrapper + base token).
3448
+ * See resolveVotesTokenChain() for details.
3449
+ */
3450
+ resolveVotesTokenChain,
3451
+ /**
3452
+ * Human-friendly description of the voting token wiring for a Governor/SubDAO.
3453
+ */
3454
+ describeVotesToken,
3455
+ /**
3456
+ * Get voting status for an account relative to a Governor/SubDAO.
3457
+ */
3458
+ getVotingStatus,
2607
3459
  /** Build a delegate(self) tx using the preferred votes token resolution path. */
2608
3460
  buildDelegateSelfPreferred: async function buildDelegateSelfPreferred({ provider, subdao: subdao2, governor, account }) {
2609
3461
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
2610
3462
  if (!account) throw new SageSDKError(CODES.INVALID_ARGS, "account required");
2611
- const token2 = await this.resolveVotesToken({ provider, subdao: subdao2, governor });
2612
- return buildDelegateTx({ token: token2, delegatee: account });
3463
+ const { baseToken } = await resolveVotesTokenChain({ provider, subdao: subdao2, governor });
3464
+ return buildDelegateTx({ token: baseToken, delegatee: account });
2613
3465
  },
2614
3466
  /**
2615
3467
  * Send a delegate(self) and verify votes at latest-1.
@@ -2618,15 +3470,15 @@ var require_governance = __commonJS({
2618
3470
  delegateSelfAndVerify: async function delegateSelfAndVerify({ provider, subdao: subdao2, governor, account, signer = null, minVotes = null }) {
2619
3471
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
2620
3472
  if (!account) throw new SageSDKError(CODES.INVALID_ARGS, "account required");
2621
- const token2 = await this.resolveVotesToken({ provider, subdao: subdao2, governor });
2622
- const payload = buildDelegateTx({ token: token2, delegatee: account });
3473
+ const { votingToken, baseToken } = await resolveVotesTokenChain({ provider, subdao: subdao2, governor });
3474
+ const payload = buildDelegateTx({ token: baseToken, delegatee: account });
2623
3475
  let txHash = null;
2624
3476
  if (signer && typeof signer.sendTransaction === "function") {
2625
3477
  const tx = await signer.sendTransaction({ to: payload.to, data: payload.data, value: payload.value });
2626
3478
  txHash = tx?.hash || null;
2627
3479
  if (tx?.wait) await tx.wait();
2628
3480
  }
2629
- const votes = await getVotesLatestMinusOne({ provider, token: token2, account });
3481
+ const votes = await getVotesLatestMinusOne({ provider, token: votingToken, account });
2630
3482
  const ok = minVotes != null ? votes >= BigInt(minVotes) : votes > 0n;
2631
3483
  return { txHash, ok, votes, payload };
2632
3484
  },
@@ -2680,8 +3532,8 @@ var require_governance = __commonJS({
2680
3532
  }
2681
3533
  let votesOk = null;
2682
3534
  try {
2683
- const token2 = sxxx || await this.resolveVotesToken({ provider, governor });
2684
- const votes = await getVotesLatestMinusOne({ provider, token: token2, account: user });
3535
+ const { votingToken } = await resolveVotesTokenChain({ provider, governor });
3536
+ const votes = await getVotesLatestMinusOne({ provider, token: votingToken, account: user });
2685
3537
  const th = threshold != null ? BigInt(threshold) : 0n;
2686
3538
  votesOk = votes >= th;
2687
3539
  } catch (_) {
@@ -3215,6 +4067,602 @@ var require_templates = __commonJS({
3215
4067
  }
3216
4068
  });
3217
4069
 
4070
+ // src/browser/utils.js
4071
+ var require_utils = __commonJS({
4072
+ "src/browser/utils.js"(exports2, module2) {
4073
+ function getAddress(address) {
4074
+ if (!address) return address;
4075
+ const addr = String(address).trim();
4076
+ const normalized = addr.startsWith("0x") ? addr.slice(2).toLowerCase() : addr.toLowerCase();
4077
+ return `0x${normalized}`;
4078
+ }
4079
+ async function keccak256Async(data) {
4080
+ const encoder = new TextEncoder();
4081
+ const dataBuffer = typeof data === "string" ? encoder.encode(data) : data;
4082
+ const hashBuffer = await crypto.subtle.digest("SHA-256", dataBuffer);
4083
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
4084
+ const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
4085
+ return `0x${hashHex}`;
4086
+ }
4087
+ function keccak256Sync(data) {
4088
+ const str = typeof data === "string" ? data : JSON.stringify(data);
4089
+ let hash = 0;
4090
+ for (let i = 0; i < str.length; i++) {
4091
+ const char = str.charCodeAt(i);
4092
+ hash = (hash << 5) - hash + char;
4093
+ hash = hash & hash;
4094
+ }
4095
+ const hex = Math.abs(hash).toString(16).padStart(8, "0");
4096
+ return `0x${hex.repeat(8)}`.slice(0, 66);
4097
+ }
4098
+ module2.exports = {
4099
+ getAddress,
4100
+ keccak256Async,
4101
+ keccak256Sync
4102
+ };
4103
+ }
4104
+ });
4105
+
4106
+ // src/browser/subgraph.js
4107
+ var require_subgraph2 = __commonJS({
4108
+ "src/browser/subgraph.js"(exports2, module2) {
4109
+ var { getAddress } = require_utils();
4110
+ function sanitizeOrderBy(orderBy, allowed, fallback) {
4111
+ const value = (orderBy || "").toString();
4112
+ return allowed.includes(value) ? value : fallback;
4113
+ }
4114
+ function sanitizeOrderDirection(direction, fallback = "desc") {
4115
+ const v = (direction || "").toString().toLowerCase();
4116
+ return v === "asc" ? "asc" : "desc";
4117
+ }
4118
+ function safeGetAddress(value) {
4119
+ try {
4120
+ return getAddress(value);
4121
+ } catch {
4122
+ return null;
4123
+ }
4124
+ }
4125
+ function mapSafe(list, mapper) {
4126
+ const out = [];
4127
+ for (const item of list || []) {
4128
+ try {
4129
+ const v = mapper(item);
4130
+ if (v != null) out.push(v);
4131
+ } catch {
4132
+ }
4133
+ }
4134
+ return out;
4135
+ }
4136
+ async function query(url, document, variables) {
4137
+ if (!url) throw new Error("subgraph url required");
4138
+ const controller = new AbortController();
4139
+ const timeoutId = setTimeout(() => controller.abort(), 1e4);
4140
+ try {
4141
+ const resp = await fetch(url, {
4142
+ method: "POST",
4143
+ headers: { "Content-Type": "application/json" },
4144
+ body: JSON.stringify({ query: document, variables }),
4145
+ signal: controller.signal
4146
+ });
4147
+ clearTimeout(timeoutId);
4148
+ if (!resp.ok) {
4149
+ throw new Error(`HTTP ${resp.status}: ${resp.statusText}`);
4150
+ }
4151
+ const data = await resp.json();
4152
+ if (data && data.errors) {
4153
+ throw new Error(data.errors.map((e) => e.message).join("; "));
4154
+ }
4155
+ return data.data;
4156
+ } catch (error) {
4157
+ clearTimeout(timeoutId);
4158
+ throw error;
4159
+ }
4160
+ }
4161
+ async function listProposals({ url, governor, first = 20, skip = 0 }) {
4162
+ const data = await query(url, `
4163
+ query($governor: Bytes!, $first: Int!, $skip: Int!) {
4164
+ proposals(where: { governor: $governor }, first: $first, skip: $skip, orderBy: createdAt, orderDirection: desc) {
4165
+ id
4166
+ proposer
4167
+ description
4168
+ createdAt
4169
+ targets
4170
+ values
4171
+ calldatas
4172
+ }
4173
+ }
4174
+ `, { governor: String(governor).toLowerCase(), first, skip });
4175
+ return mapSafe(data?.proposals, (p) => {
4176
+ const proposer = safeGetAddress(p.proposer);
4177
+ if (!proposer) return null;
4178
+ const targets = (p.targets || []).map((t) => safeGetAddress(t)).filter(Boolean);
4179
+ if (!targets.length && (p.targets || []).length) return null;
4180
+ return {
4181
+ id: BigInt(p.id),
4182
+ proposer,
4183
+ description: p.description,
4184
+ createdAt: Number(p.createdAt || 0),
4185
+ targets,
4186
+ values: (p.values || []).map((value) => BigInt(String(value))),
4187
+ calldatas: p.calldatas || []
4188
+ };
4189
+ });
4190
+ }
4191
+ var STATE_STRING_TO_NUMBER = {
4192
+ PENDING: 0,
4193
+ ACTIVE: 1,
4194
+ CANCELED: 2,
4195
+ CANCELLED: 2,
4196
+ // some indexes may use British spelling
4197
+ DEFEATED: 3,
4198
+ SUCCEEDED: 4,
4199
+ QUEUED: 5,
4200
+ EXPIRED: 6,
4201
+ EXECUTED: 7
4202
+ };
4203
+ async function listProposalsFiltered({ url, governor, states, fromTimestamp, toTimestamp, first = 20, skip = 0, orderBy = "createdAt", orderDirection = "desc" }) {
4204
+ const govLower = governor ? String(governor).toLowerCase() : null;
4205
+ const statesUpper = Array.isArray(states) && states.length ? states.map((s) => String(s).toUpperCase()) : null;
4206
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["createdAt", "updatedAt", "eta"], "createdAt");
4207
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
4208
+ const doc = `
4209
+ query($first: Int!, $skip: Int!, $governor: Bytes, $states: [String!], $from: Int, $to: Int) {
4210
+ proposals(
4211
+ where: {
4212
+ ${governor ? "governor: $governor," : ""}
4213
+ ${statesUpper ? "state_in: $states," : ""}
4214
+ ${fromTimestamp !== void 0 ? "createdAt_gte: $from," : ""}
4215
+ ${toTimestamp !== void 0 ? "createdAt_lte: $to," : ""}
4216
+ }
4217
+ first: $first
4218
+ skip: $skip
4219
+ orderBy: ${safeOrderBy}
4220
+ orderDirection: ${safeOrderDirection}
4221
+ ) {
4222
+ id
4223
+ proposer
4224
+ description
4225
+ createdAt
4226
+ updatedAt
4227
+ state
4228
+ eta
4229
+ targets
4230
+ values
4231
+ calldatas
4232
+ }
4233
+ }
4234
+ `;
4235
+ const variables = { first, skip };
4236
+ if (govLower) variables.governor = govLower;
4237
+ if (statesUpper) variables.states = statesUpper;
4238
+ if (fromTimestamp !== void 0) variables.from = Number(fromTimestamp);
4239
+ if (toTimestamp !== void 0) variables.to = Number(toTimestamp);
4240
+ const data = await query(url, doc, variables);
4241
+ return mapSafe(data?.proposals, (p) => {
4242
+ const stateStr = String(p.state || "").toUpperCase();
4243
+ const stateNum = STATE_STRING_TO_NUMBER[stateStr] != null ? STATE_STRING_TO_NUMBER[stateStr] : null;
4244
+ const proposer = safeGetAddress(p.proposer);
4245
+ if (!proposer) return null;
4246
+ const targets = (p.targets || []).map((t) => safeGetAddress(t)).filter(Boolean);
4247
+ if (!targets.length && (p.targets || []).length) return null;
4248
+ return {
4249
+ id: BigInt(p.id),
4250
+ proposer,
4251
+ description: p.description || "",
4252
+ createdAt: Number(p.createdAt || 0),
4253
+ updatedAt: Number(p.updatedAt || 0),
4254
+ state: stateStr,
4255
+ stateNum,
4256
+ eta: p.eta ? BigInt(String(p.eta)) : null,
4257
+ targets,
4258
+ values: (p.values || []).map((value) => BigInt(String(value))),
4259
+ calldatas: p.calldatas || []
4260
+ };
4261
+ });
4262
+ }
4263
+ async function listLibraries({ url, subdao: subdao2, first = 50, skip = 0 }) {
4264
+ const where = subdao2 ? `where: { subDAO: "${String(subdao2).toLowerCase()}" }` : "";
4265
+ const data = await query(url, `
4266
+ query($first: Int!, $skip: Int!) {
4267
+ libraries(${where} first: $first, skip: $skip, orderBy: createdAt, orderDirection: desc) {
4268
+ id
4269
+ manifestCID
4270
+ subDAO
4271
+ proposer
4272
+ createdAt
4273
+ }
4274
+ }
4275
+ `, { first, skip });
4276
+ return mapSafe(data?.libraries, (lib) => {
4277
+ const sub = safeGetAddress(lib.subDAO);
4278
+ const proposer = safeGetAddress(lib.proposer);
4279
+ if (!sub || !proposer) return null;
4280
+ return {
4281
+ id: lib.id,
4282
+ manifestCID: lib.manifestCID,
4283
+ subdao: sub,
4284
+ proposer,
4285
+ createdAt: Number(lib.createdAt || 0)
4286
+ };
4287
+ });
4288
+ }
4289
+ async function getSubdaoLibraries({ url, subdao: subdao2, first = 20, skip = 0 }) {
4290
+ if (!url) throw new Error("subgraph url required");
4291
+ const hasFilter = !!subdao2;
4292
+ const whereClause = hasFilter ? "where:{ subdao:$subdao }" : "";
4293
+ const doc = `
4294
+ query($subdao:Bytes,$first:Int!,$skip:Int!){
4295
+ subDAOLibraryPointers(
4296
+ ${whereClause}
4297
+ first:$first,
4298
+ skip:$skip,
4299
+ orderBy: updatedAt,
4300
+ orderDirection: desc
4301
+ ){
4302
+ id
4303
+ subdao
4304
+ libraryId
4305
+ manifestCID
4306
+ previousCID
4307
+ promptCount
4308
+ updatedAt
4309
+ }
4310
+ }
4311
+ `;
4312
+ const variables = {
4313
+ first: Math.min(Math.max(1, Number(first || 20)), 100),
4314
+ skip
4315
+ };
4316
+ if (hasFilter) {
4317
+ const addr = safeGetAddress(subdao2);
4318
+ if (!addr) throw new Error("invalid subdao address");
4319
+ variables.subdao = addr.toLowerCase();
4320
+ }
4321
+ const data = await query(url, doc, variables);
4322
+ return mapSafe(data?.subDAOLibraryPointers, (row) => {
4323
+ const id2 = row?.id;
4324
+ const manifestCID = row?.manifestCID;
4325
+ const sub = safeGetAddress(row?.subdao);
4326
+ if (!id2 || !manifestCID || !sub) return null;
4327
+ return {
4328
+ id: String(id2),
4329
+ subdao: sub,
4330
+ libraryId: String(row.libraryId || "main"),
4331
+ manifestCID: String(manifestCID),
4332
+ previousCID: row.previousCID || null,
4333
+ promptCount: row.promptCount != null ? Number(row.promptCount) : null,
4334
+ updatedAt: row.updatedAt != null ? Number(row.updatedAt) : null
4335
+ };
4336
+ });
4337
+ }
4338
+ async function getSubdaoPrompts({ url, registry, first = 50, skip = 0, orderBy = "updatedAt", orderDirection = "desc" }) {
4339
+ if (!url) throw new Error("subgraph url required");
4340
+ const reg = safeGetAddress(registry);
4341
+ if (!reg) throw new Error("invalid registry address");
4342
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["updatedAt"], "updatedAt");
4343
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
4344
+ const doc = `
4345
+ query($registry:Bytes!,$first:Int!,$skip:Int!){
4346
+ prompts(
4347
+ where:{ registry:$registry },
4348
+ first:$first,
4349
+ skip:$skip,
4350
+ orderBy: ${safeOrderBy},
4351
+ orderDirection: ${safeOrderDirection}
4352
+ ){
4353
+ id
4354
+ key
4355
+ cid
4356
+ version
4357
+ author
4358
+ registry
4359
+ updatedAt
4360
+ }
4361
+ }
4362
+ `;
4363
+ const data = await query(url, doc, {
4364
+ registry: reg.toLowerCase(),
4365
+ first: Math.min(Math.max(1, Number(first || 50)), 100),
4366
+ skip
4367
+ });
4368
+ return mapSafe(data?.prompts, (p) => {
4369
+ const author = safeGetAddress(p.author);
4370
+ const regAddr = safeGetAddress(p.registry);
4371
+ if (!author || !regAddr) return null;
4372
+ return {
4373
+ id: String(p.id),
4374
+ key: String(p.key),
4375
+ cid: String(p.cid),
4376
+ version: BigInt(p.version || "0"),
4377
+ author,
4378
+ registry: regAddr,
4379
+ updatedAt: Number(p.updatedAt || 0)
4380
+ };
4381
+ });
4382
+ }
4383
+ module2.exports = {
4384
+ query,
4385
+ listProposals,
4386
+ listProposalsFiltered,
4387
+ listLibraries,
4388
+ getSubdaoLibraries,
4389
+ getSubdaoPrompts,
4390
+ /**
4391
+ * Canonical proposal timeline. Tries common fields first, then event-style fallbacks.
4392
+ * Returns { id, createdAt, queuedAt, executedAt, canceledAt, eta, state } (numbers/strings may be null when unavailable).
4393
+ */
4394
+ async getProposalTimeline({ url, id: id2 }) {
4395
+ if (!url) throw new Error("subgraph url required");
4396
+ const pid = typeof id2 === "bigint" ? id2.toString() : String(id2);
4397
+ try {
4398
+ const data = await query(url, `
4399
+ query($id: ID!) {
4400
+ proposal(id: $id) {
4401
+ id
4402
+ createdAt
4403
+ updatedAt
4404
+ state
4405
+ eta
4406
+ queuedAt
4407
+ executedAt
4408
+ canceledAt
4409
+ }
4410
+ }
4411
+ `, { id: pid });
4412
+ if (data && data.proposal) {
4413
+ const p = data.proposal;
4414
+ return {
4415
+ id: p.id,
4416
+ createdAt: Number(p.createdAt || 0),
4417
+ queuedAt: p.queuedAt != null ? Number(p.queuedAt) : null,
4418
+ executedAt: p.executedAt != null ? Number(p.executedAt) : null,
4419
+ canceledAt: p.canceledAt != null ? Number(p.canceledAt) : null,
4420
+ eta: p.eta != null ? BigInt(String(p.eta)) : null,
4421
+ state: String(p.state || "")
4422
+ };
4423
+ }
4424
+ } catch (_) {
4425
+ }
4426
+ try {
4427
+ const data = await query(url, `
4428
+ query($id: String!) {
4429
+ proposalEvents(where: { proposal: $id }, orderBy: timestamp, orderDirection: asc) {
4430
+ type
4431
+ timestamp
4432
+ }
4433
+ proposals(where: { id: $id }, first:1) { id createdAt state eta }
4434
+ }
4435
+ `, { id: pid });
4436
+ const events = (data?.proposalEvents || []).map((e) => ({ type: String(e.type || ""), timestamp: Number(e.timestamp || 0) }));
4437
+ const base = data?.proposals?.[0] || {};
4438
+ const find = (t) => events.find((e) => e.type.toLowerCase() === t)?.timestamp || null;
4439
+ return {
4440
+ id: base.id || pid,
4441
+ createdAt: Number(base.createdAt || 0),
4442
+ queuedAt: find("queued"),
4443
+ executedAt: find("executed"),
4444
+ canceledAt: find("canceled") || find("cancelled") || null,
4445
+ eta: base.eta != null ? BigInt(String(base.eta)) : null,
4446
+ state: String(base.state || "")
4447
+ };
4448
+ } catch (_) {
4449
+ }
4450
+ return { id: pid, createdAt: 0, queuedAt: null, executedAt: null, canceledAt: null, eta: null, state: "" };
4451
+ },
4452
+ async listLiquidityAddPlans({ url, subdao: subdao2 = null, first = 50, skip = 0, orderBy = "blockTimestamp", orderDirection = "desc" }) {
4453
+ if (!url) throw new Error("subgraph url required");
4454
+ const filters = [];
4455
+ if (subdao2) {
4456
+ const addr = safeGetAddress(subdao2);
4457
+ if (!addr) throw new Error("invalid subdao address");
4458
+ filters.push(`subdao: "${addr.toLowerCase()}"`);
4459
+ }
4460
+ const where = filters.length ? `where: { ${filters.join(", ")} }` : "";
4461
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["blockTimestamp", "blockNumber"], "blockTimestamp");
4462
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
4463
+ const doc = `
4464
+ query($first:Int!,$skip:Int!){
4465
+ liquidityAddPlans(${where} first:$first, skip:$skip, orderBy: ${safeOrderBy}, orderDirection: ${safeOrderDirection}){
4466
+ id subdao pool sxxxToken stableToken sxxxAmount stableAmount lpRecipient blockNumber blockTimestamp transactionHash
4467
+ }
4468
+ }
4469
+ `;
4470
+ const data = await query(url, doc, { first, skip });
4471
+ return mapSafe(data?.liquidityAddPlans, (e) => {
4472
+ const sub = safeGetAddress(e.subdao);
4473
+ const pool = safeGetAddress(e.pool);
4474
+ const sxxxToken = safeGetAddress(e.sxxxToken);
4475
+ const stableToken = safeGetAddress(e.stableToken);
4476
+ const lpRecipient = safeGetAddress(e.lpRecipient);
4477
+ if (!sub || !pool || !sxxxToken || !stableToken || !lpRecipient) return null;
4478
+ return {
4479
+ id: String(e.id),
4480
+ subdao: sub,
4481
+ pool,
4482
+ sxxxToken,
4483
+ stableToken,
4484
+ sxxxAmount: BigInt(String(e.sxxxAmount)),
4485
+ stableAmount: BigInt(String(e.stableAmount)),
4486
+ lpRecipient,
4487
+ blockNumber: Number(e.blockNumber || 0),
4488
+ blockTimestamp: Number(e.blockTimestamp || 0),
4489
+ transactionHash: e.transactionHash
4490
+ };
4491
+ });
4492
+ },
4493
+ async listLiquidityRemovePlans({ url, subdao: subdao2 = null, first = 50, skip = 0, orderBy = "blockTimestamp", orderDirection = "desc" }) {
4494
+ if (!url) throw new Error("subgraph url required");
4495
+ const filters = [];
4496
+ if (subdao2) {
4497
+ const addr = safeGetAddress(subdao2);
4498
+ if (!addr) throw new Error("invalid subdao address");
4499
+ filters.push(`subdao: "${addr.toLowerCase()}"`);
4500
+ }
4501
+ const where = filters.length ? `where: { ${filters.join(", ")} }` : "";
4502
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["blockTimestamp", "blockNumber"], "blockTimestamp");
4503
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
4504
+ const doc = `
4505
+ query($first:Int!,$skip:Int!){
4506
+ liquidityRemovePlans(${where} first:$first, skip:$skip, orderBy: ${safeOrderBy}, orderDirection: ${safeOrderDirection}){
4507
+ id subdao pool lpToken lpAmount recipient blockNumber blockTimestamp transactionHash
4508
+ }
4509
+ }
4510
+ `;
4511
+ const data = await query(url, doc, { first, skip });
4512
+ return mapSafe(data?.liquidityRemovePlans, (e) => {
4513
+ const sub = safeGetAddress(e.subdao);
4514
+ const pool = safeGetAddress(e.pool);
4515
+ const lpToken = safeGetAddress(e.lpToken);
4516
+ const recipient = safeGetAddress(e.recipient);
4517
+ if (!sub || !pool || !lpToken || !recipient) return null;
4518
+ return {
4519
+ id: String(e.id),
4520
+ subdao: sub,
4521
+ pool,
4522
+ lpToken,
4523
+ lpAmount: BigInt(String(e.lpAmount)),
4524
+ recipient,
4525
+ blockNumber: Number(e.blockNumber || 0),
4526
+ blockTimestamp: Number(e.blockTimestamp || 0),
4527
+ transactionHash: e.transactionHash
4528
+ };
4529
+ });
4530
+ },
4531
+ async listPromptsByTag({ url, tagsHash, registry = null, first = 50, skip = 0, orderBy = "updatedAt", orderDirection = "desc" }) {
4532
+ if (!url) throw new Error("subgraph url required");
4533
+ const clauses = [`tagsHash: "${String(tagsHash)}"`];
4534
+ if (registry) {
4535
+ const addr = safeGetAddress(registry);
4536
+ if (!addr) throw new Error("invalid registry address");
4537
+ clauses.push(`registry: "${addr.toLowerCase()}"`);
4538
+ }
4539
+ const where = `where: { ${clauses.join(", ")} }`;
4540
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["updatedAt"], "updatedAt");
4541
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
4542
+ const doc = `
4543
+ query($first:Int!,$skip:Int!) {
4544
+ prompts(${where} first:$first, skip:$skip, orderBy: ${safeOrderBy}, orderDirection: ${safeOrderDirection}) {
4545
+ id key cid version author registry updatedAt tagsHash
4546
+ }
4547
+ }
4548
+ `;
4549
+ const data = await query(url, doc, { first, skip });
4550
+ return mapSafe(data?.prompts, (p) => {
4551
+ const author = safeGetAddress(p.author);
4552
+ const regAddr = safeGetAddress(p.registry);
4553
+ if (!author || !regAddr) return null;
4554
+ return {
4555
+ id: String(p.id),
4556
+ key: String(p.key),
4557
+ cid: String(p.cid),
4558
+ version: BigInt(p.version || "0"),
4559
+ author,
4560
+ registry: regAddr,
4561
+ updatedAt: Number(p.updatedAt || 0),
4562
+ tagsHash: String(p.tagsHash || "")
4563
+ };
4564
+ });
4565
+ },
4566
+ // Prompt helpers (registry scoped)
4567
+ async listRegistryPrompts({ url, registry, first = 50, skip = 0, orderBy = "updatedAt", orderDirection = "desc" }) {
4568
+ if (!url) throw new Error("subgraph url required");
4569
+ const reg = safeGetAddress(registry);
4570
+ if (!reg) throw new Error("invalid registry address");
4571
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["updatedAt"], "updatedAt");
4572
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
4573
+ const doc = `
4574
+ query($first:Int!,$skip:Int!,$registry:Bytes!) {
4575
+ prompts(where:{ registry: $registry }, first:$first, skip:$skip, orderBy: ${safeOrderBy}, orderDirection: ${safeOrderDirection}) {
4576
+ id
4577
+ key
4578
+ cid
4579
+ version
4580
+ author
4581
+ registry
4582
+ updatedAt
4583
+ }
4584
+ }
4585
+ `;
4586
+ const data = await query(url, doc, { first, skip, registry: reg.toLowerCase() });
4587
+ return mapSafe(data?.prompts, (p) => {
4588
+ const author = safeGetAddress(p.author);
4589
+ const regAddr = safeGetAddress(p.registry);
4590
+ if (!author || !regAddr) return null;
4591
+ return {
4592
+ id: String(p.id),
4593
+ key: String(p.key),
4594
+ cid: String(p.cid),
4595
+ version: BigInt(p.version || "0"),
4596
+ author,
4597
+ registry: regAddr,
4598
+ updatedAt: Number(p.updatedAt || 0)
4599
+ };
4600
+ });
4601
+ },
4602
+ async getPromptByKey({ url, registry, key }) {
4603
+ if (!url) throw new Error("subgraph url required");
4604
+ const reg = safeGetAddress(registry);
4605
+ if (!reg) throw new Error("invalid registry address");
4606
+ const doc = `
4607
+ query($registry:Bytes!,$key:String!) {
4608
+ prompts(where:{ registry: $registry, key: $key }, first:1) {
4609
+ id
4610
+ key
4611
+ cid
4612
+ version
4613
+ author
4614
+ registry
4615
+ updatedAt
4616
+ }
4617
+ }
4618
+ `;
4619
+ const data = await query(url, doc, { registry: reg.toLowerCase(), key: String(key) });
4620
+ const p = (data?.prompts || [])[0];
4621
+ if (!p) return null;
4622
+ const author = safeGetAddress(p.author);
4623
+ const regAddr = safeGetAddress(p.registry);
4624
+ if (!author || !regAddr) return null;
4625
+ return {
4626
+ id: String(p.id),
4627
+ key: String(p.key),
4628
+ cid: String(p.cid),
4629
+ version: BigInt(p.version || "0"),
4630
+ author,
4631
+ registry: regAddr,
4632
+ updatedAt: Number(p.updatedAt || 0)
4633
+ };
4634
+ },
4635
+ async getProposalById({ url, id: id2 }) {
4636
+ if (!url) throw new Error("subgraph url required");
4637
+ const doc = `query($id: ID!){ proposal(id:$id){ id proposer description createdAt updatedAt state eta targets values calldatas } }`;
4638
+ const data = await query(url, doc, { id: String(id2) });
4639
+ const p = data?.proposal;
4640
+ if (!p) return null;
4641
+ try {
4642
+ const proposer = safeGetAddress(p.proposer);
4643
+ if (!proposer) return null;
4644
+ const targets = (p.targets || []).map((t) => safeGetAddress(t)).filter(Boolean);
4645
+ if (!targets.length && (p.targets || []).length) return null;
4646
+ return {
4647
+ id: BigInt(p.id),
4648
+ proposer,
4649
+ description: p.description || "",
4650
+ createdAt: Number(p.createdAt || 0),
4651
+ updatedAt: Number(p.updatedAt || 0),
4652
+ state: String(p.state || ""),
4653
+ eta: p.eta ? BigInt(String(p.eta)) : null,
4654
+ targets,
4655
+ values: (p.values || []).map((v) => BigInt(String(v))),
4656
+ calldatas: p.calldatas || []
4657
+ };
4658
+ } catch {
4659
+ return null;
4660
+ }
4661
+ }
4662
+ };
4663
+ }
4664
+ });
4665
+
3218
4666
  // src/adapters/governance/openzeppelin.js
3219
4667
  var require_openzeppelin = __commonJS({
3220
4668
  "src/adapters/governance/openzeppelin.js"(exports2, module2) {
@@ -3569,6 +5017,7 @@ var require_operations = __commonJS({
3569
5017
  cache = null,
3570
5018
  fromBlock = 0,
3571
5019
  helperAddress = null,
5020
+ subgraphUrl = null,
3572
5021
  hints = {},
3573
5022
  chunkSizeBlocks = 1e4,
3574
5023
  lookBackBlocks = 2e3,
@@ -3582,6 +5031,27 @@ var require_operations = __commonJS({
3582
5031
  const cached = await cacheAdapter.load(govAddr, id2);
3583
5032
  if (cached) return cached;
3584
5033
  }
5034
+ if (subgraphUrl) {
5035
+ try {
5036
+ const subgraph2 = require_subgraph2();
5037
+ const sgProposal = await subgraph2.getProposalById({ url: subgraphUrl, id: String(id2) });
5038
+ if (sgProposal && sgProposal.targets && sgProposal.targets.length > 0) {
5039
+ const tuple2 = {
5040
+ id: id2,
5041
+ governor: govAddr,
5042
+ targets: sgProposal.targets,
5043
+ values: sgProposal.values || [],
5044
+ calldatas: sgProposal.calldatas || [],
5045
+ description: sgProposal.description || "",
5046
+ descriptionHash: sgProposal.description ? keccak256(toUtf8Bytes(sgProposal.description)) : null,
5047
+ createdBlock: sgProposal.createdAt || null
5048
+ };
5049
+ if (cacheAdapter) await cacheAdapter.save(govAddr, id2, tuple2);
5050
+ return tuple2;
5051
+ }
5052
+ } catch (_) {
5053
+ }
5054
+ }
3585
5055
  if (helperAddress) {
3586
5056
  try {
3587
5057
  const helperAbi = [
@@ -3795,8 +5265,14 @@ var require_operations = __commonJS({
3795
5265
  ]);
3796
5266
  let resolvedSubDAO = subdao2;
3797
5267
  if (!resolvedSubDAO) {
3798
- resolvedSubDAO = await governorContract.subDAO().catch(() => null);
3799
- if (resolvedSubDAO === ZeroAddress) resolvedSubDAO = null;
5268
+ try {
5269
+ const subDAOInterface = new Interface(["function subDAO() view returns (address)"]);
5270
+ const subdaoContract = new Contract(govAddr, subDAOInterface, provider);
5271
+ resolvedSubDAO = await subdaoContract.subDAO().catch(() => null);
5272
+ if (resolvedSubDAO === ZeroAddress) resolvedSubDAO = null;
5273
+ } catch {
5274
+ resolvedSubDAO = null;
5275
+ }
3800
5276
  }
3801
5277
  let mode = null;
3802
5278
  let eligible = null;
@@ -3871,10 +5347,11 @@ var require_operations = __commonJS({
3871
5347
  refresh = false,
3872
5348
  cache = null,
3873
5349
  includeTimeline = false,
3874
- helperAddress = null
5350
+ helperAddress = null,
5351
+ subgraphUrl = null
3875
5352
  }) {
3876
5353
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3877
- const tuple = await resolveProposalTuple({ provider, governor, proposalId, refresh, cache, helperAddress });
5354
+ const tuple = await resolveProposalTuple({ provider, governor, proposalId, refresh, cache, helperAddress, subgraphUrl });
3878
5355
  let proposal = null;
3879
5356
  try {
3880
5357
  proposal = await governance2.getProposal({ provider, governor: tuple.governor, id: tuple.id });
@@ -4212,8 +5689,6 @@ var require_factory = __commonJS({
4212
5689
  stableCreationFee,
4213
5690
  feeReceiver,
4214
5691
  allowStableFee,
4215
- stablePromptForkFee,
4216
- allowStablePromptForkFee,
4217
5692
  stableForkFee,
4218
5693
  allowStableForkFee,
4219
5694
  timelockMinDelay,
@@ -4237,8 +5712,6 @@ var require_factory = __commonJS({
4237
5712
  }
4238
5713
  })(),
4239
5714
  contract.allowStableFee().catch(() => null),
4240
- contract.stablePromptForkFee().catch(() => null),
4241
- contract.allowStablePromptForkFee().catch(() => null),
4242
5715
  contract.stableForkFee().catch(() => null),
4243
5716
  contract.allowStableForkFee().catch(() => null),
4244
5717
  contract.timelockMinDelay().catch(() => null),
@@ -4254,8 +5727,6 @@ var require_factory = __commonJS({
4254
5727
  stableCreationFee,
4255
5728
  feeReceiver: feeReceiver && feeReceiver !== "0x0000000000000000000000000000000000000000" ? getAddress(feeReceiver) : null,
4256
5729
  allowStableFee,
4257
- stablePromptForkFee,
4258
- allowStablePromptForkFee,
4259
5730
  stableForkFee,
4260
5731
  allowStableForkFee,
4261
5732
  timelockMinDelay,
@@ -4587,6 +6058,113 @@ var require_factory = __commonJS({
4587
6058
  }
4588
6059
  });
4589
6060
 
6061
+ // src/lineage/index.js
6062
+ var require_lineage = __commonJS({
6063
+ "src/lineage/index.js"(exports2, module2) {
6064
+ var { Contract, getAddress } = require("ethers");
6065
+ var { SageSDKError, CODES } = require_errors();
6066
+ var LINEAGE_ABI = [
6067
+ "function libraryByDAO(address) view returns (string manifestCID, address lastUpdater, uint256 lastUpdated, string version, address forkedFromDAO, uint256 sxxxForkFee)",
6068
+ "function getLibraryForkFee(address) view returns (uint256)"
6069
+ ];
6070
+ var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
6071
+ function normalise(address, label) {
6072
+ if (!address) throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
6073
+ try {
6074
+ return getAddress(address);
6075
+ } catch (err) {
6076
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
6077
+ }
6078
+ }
6079
+ async function getParentLibrary({ provider, registry, subdao: subdao2 }) {
6080
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6081
+ if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
6082
+ if (!subdao2) throw new SageSDKError(CODES.INVALID_ARGS, "subdao required");
6083
+ try {
6084
+ const contract = new Contract(normalise(registry, "registry"), LINEAGE_ABI, provider);
6085
+ const info = await contract.libraryByDAO(normalise(subdao2, "subdao"));
6086
+ const parent = info.forkedFromDAO;
6087
+ if (!parent || parent === ZERO_ADDRESS) {
6088
+ return null;
6089
+ }
6090
+ return getAddress(parent).toLowerCase();
6091
+ } catch (err) {
6092
+ throw new SageSDKError(CODES.CONTRACT_ERROR, "Failed to fetch parent library", { cause: err });
6093
+ }
6094
+ }
6095
+ async function getLineageChain({ provider, registry, subdao: subdao2 }) {
6096
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6097
+ if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
6098
+ if (!subdao2) throw new SageSDKError(CODES.INVALID_ARGS, "subdao required");
6099
+ try {
6100
+ const contract = new Contract(normalise(registry, "registry"), LINEAGE_ABI, provider);
6101
+ const chain = [];
6102
+ let current = normalise(subdao2, "subdao");
6103
+ const MAX_DEPTH = 100;
6104
+ let iterations = 0;
6105
+ while (current && iterations < MAX_DEPTH) {
6106
+ chain.unshift(getAddress(current).toLowerCase());
6107
+ const info = await contract.libraryByDAO(current);
6108
+ const parent = info.forkedFromDAO;
6109
+ if (!parent || parent === ZERO_ADDRESS) {
6110
+ break;
6111
+ }
6112
+ current = parent;
6113
+ iterations++;
6114
+ }
6115
+ return {
6116
+ chain,
6117
+ depth: chain.length - 1,
6118
+ root: chain[0]
6119
+ };
6120
+ } catch (err) {
6121
+ throw new SageSDKError(CODES.CONTRACT_ERROR, "Failed to fetch lineage chain", { cause: err });
6122
+ }
6123
+ }
6124
+ async function isFork({ provider, registry, subdao: subdao2 }) {
6125
+ const parent = await getParentLibrary({ provider, registry, subdao: subdao2 });
6126
+ return parent !== null;
6127
+ }
6128
+ async function getLibraryForkFee({ provider, registry, subdao: subdao2 }) {
6129
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6130
+ if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
6131
+ if (!subdao2) throw new SageSDKError(CODES.INVALID_ARGS, "subdao required");
6132
+ try {
6133
+ const contract = new Contract(normalise(registry, "registry"), LINEAGE_ABI, provider);
6134
+ const fee = await contract.getLibraryForkFee(normalise(subdao2, "subdao"));
6135
+ return BigInt(fee.toString());
6136
+ } catch (err) {
6137
+ throw new SageSDKError(CODES.CONTRACT_ERROR, "Failed to fetch library fork fee", { cause: err });
6138
+ }
6139
+ }
6140
+ async function getLibraryInfo({ provider, registry, subdao: subdao2 }) {
6141
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6142
+ if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
6143
+ if (!subdao2) throw new SageSDKError(CODES.INVALID_ARGS, "subdao required");
6144
+ try {
6145
+ const contract = new Contract(normalise(registry, "registry"), LINEAGE_ABI, provider);
6146
+ const info = await contract.libraryByDAO(normalise(subdao2, "subdao"));
6147
+ const parent = info.forkedFromDAO;
6148
+ return {
6149
+ parentDAO: !parent || parent === ZERO_ADDRESS ? null : getAddress(parent).toLowerCase(),
6150
+ forkFee: BigInt(info.sxxxForkFee.toString()),
6151
+ manifestCID: info.manifestCID,
6152
+ version: info.version
6153
+ };
6154
+ } catch (err) {
6155
+ throw new SageSDKError(CODES.CONTRACT_ERROR, "Failed to fetch library info", { cause: err });
6156
+ }
6157
+ }
6158
+ module2.exports = {
6159
+ getParentLibrary,
6160
+ getLineageChain,
6161
+ isFork,
6162
+ getLibraryForkFee,
6163
+ getLibraryInfo
6164
+ };
6165
+ }
6166
+ });
6167
+
4590
6168
  // src/prompt/execute.js
4591
6169
  var require_execute = __commonJS({
4592
6170
  "src/prompt/execute.js"(exports2, module2) {
@@ -5259,7 +6837,6 @@ var require_ipns = __commonJS({
5259
6837
  headers["X-Wallet-Address"] = auth.address;
5260
6838
  headers["X-Wallet-Signature"] = auth.signature;
5261
6839
  headers["X-Wallet-Nonce"] = auth.nonce;
5262
- headers["X-Wallet-Message"] = auth.message;
5263
6840
  }
5264
6841
  return { headers, auth };
5265
6842
  }
@@ -5281,8 +6858,7 @@ var require_ipns = __commonJS({
5281
6858
  ...extraHeaders,
5282
6859
  "X-Wallet-Address": auth.address,
5283
6860
  "X-Wallet-Signature": auth.signature,
5284
- "X-Wallet-Nonce": auth.nonce,
5285
- "X-Wallet-Message": auth.message
6861
+ "X-Wallet-Nonce": auth.nonce
5286
6862
  };
5287
6863
  return { headers, auth };
5288
6864
  }
@@ -5919,8 +7495,34 @@ var require_time = __commonJS({
5919
7495
  var require_treasury = __commonJS({
5920
7496
  "src/treasury/index.js"(exports2, module2) {
5921
7497
  var { Contract, Interface, getAddress } = require("ethers");
5922
- var ABI = require_abi();
5923
7498
  var { SageSDKError, CODES } = require_errors();
7499
+ var SAGE_TREASURY_ABI = [
7500
+ // Aggregated views
7501
+ "function totalReserves() view returns (uint256)",
7502
+ "function totalPOL() view returns (uint256)",
7503
+ "function totalDebt() view returns (uint256)",
7504
+ // Canonical liquidity config
7505
+ "function canonicalPool() view returns (address)",
7506
+ "function routerOrVault() view returns (address)",
7507
+ // Withdrawal rate limits
7508
+ "function maxWithdrawalRate() view returns (uint256)",
7509
+ "function emergencyWithdrawalLimit() view returns (uint256)",
7510
+ // Reserve tokens
7511
+ "function getReserveTokens() view returns (address[])",
7512
+ "function getReserve(address token) view returns (tuple(uint256 amount, uint256 value, bool isLP, bool isActive))",
7513
+ // Withdrawal queue
7514
+ "function nextWithdrawalId() view returns (uint256)",
7515
+ "function pendingWithdrawals(uint256 id) view returns (tuple(bool exists, address token, address recipient, uint256 amount, uint256 value, address requester, uint256 balanceBefore, uint256 recipientBalanceBefore, uint256 depositSnapshot, bool isLP, bool isEmergency))",
7516
+ "function withdraw(address token, uint256 amount, address recipient)",
7517
+ "function confirmWithdrawal(uint256 id)",
7518
+ "function cancelWithdrawal(uint256 id)",
7519
+ // Manual price overrides
7520
+ "function manualPrices(address token) view returns (tuple(uint256 price, uint256 expiresAt, bool active))",
7521
+ "function setPriceOverride(address token, uint256 price, uint256 ttlSeconds)",
7522
+ "function clearPriceOverride(address token)",
7523
+ // Events
7524
+ "event WithdrawalScheduled(uint256 indexed id, address indexed token, address indexed recipient, uint256 amount)"
7525
+ ];
5924
7526
  var LiquidityEvents = new Interface([
5925
7527
  "event CanonicalLiquidityUpdated(address indexed pool, address indexed routerOrVault)",
5926
7528
  "event LiquidityAddPlanned(address indexed subdao, address indexed pool, address sxxxToken, address stableToken, uint256 sxxxAmount, uint256 stableAmount, address lpRecipient)",
@@ -5965,7 +7567,7 @@ var require_treasury = __commonJS({
5965
7567
  async function getTreasuryInfo({ provider, treasury: treasury2 }) {
5966
7568
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
5967
7569
  const addr = normalise(treasury2, "treasury");
5968
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7570
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
5969
7571
  const [totalReserves, totalPOL, totalDebt, canonicalPool, routerOrVault, maxWithdrawalRate, emergencyWithdrawalLimit] = await Promise.all([
5970
7572
  contract.totalReserves().catch(() => 0n),
5971
7573
  contract.totalPOL().catch(() => 0n),
@@ -5989,7 +7591,7 @@ var require_treasury = __commonJS({
5989
7591
  async function getPendingWithdrawals({ provider, treasury: treasury2, ids, limit = 50 }) {
5990
7592
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
5991
7593
  const addr = normalise(treasury2, "treasury");
5992
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7594
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
5993
7595
  let idList = ids;
5994
7596
  if (!Array.isArray(idList)) {
5995
7597
  const nextId = await contract.nextWithdrawalId().catch(() => 0n);
@@ -6021,14 +7623,14 @@ var require_treasury = __commonJS({
6021
7623
  async function getReserveTokens({ provider, treasury: treasury2 }) {
6022
7624
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6023
7625
  const addr = normalise(treasury2, "treasury");
6024
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7626
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6025
7627
  const tokens = await contract.getReserveTokens().catch(() => []);
6026
7628
  return tokens.map((token2) => getAddress(token2));
6027
7629
  }
6028
7630
  async function getReserves({ provider, treasury: treasury2, tokens, fetchMetadata = true }) {
6029
7631
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6030
7632
  const addr = normalise(treasury2, "treasury");
6031
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7633
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6032
7634
  const tokenList = Array.isArray(tokens) && tokens.length ? tokens.map((token2) => getAddress(token2)) : await contract.getReserveTokens().catch(() => []);
6033
7635
  const reserves = [];
6034
7636
  for (const token2 of tokenList) {
@@ -6058,7 +7660,7 @@ var require_treasury = __commonJS({
6058
7660
  async function getManualPriceOverrides({ provider, treasury: treasury2, tokens }) {
6059
7661
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6060
7662
  const addr = normalise(treasury2, "treasury");
6061
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7663
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6062
7664
  const tokenList = Array.isArray(tokens) && tokens.length ? tokens.map((token2) => getAddress(token2)) : await contract.getReserveTokens().catch(() => []);
6063
7665
  const overrides = [];
6064
7666
  for (const token2 of tokenList) {
@@ -6163,7 +7765,7 @@ var require_treasury = __commonJS({
6163
7765
  async function getLPContribution({ provider, treasury: treasury2, subdao: subdao2, token: token2 }) {
6164
7766
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6165
7767
  const addr = normalise(treasury2, "treasury");
6166
- const c = new Contract(addr, ABI.SageTreasury, provider);
7768
+ const c = new Contract(addr, SAGE_TREASURY_ABI, provider);
6167
7769
  const amount = await c.lpContributions(normalise(subdao2, "subdao"), normalise(token2, "token")).catch(() => 0n);
6168
7770
  return amount;
6169
7771
  }
@@ -6205,7 +7807,7 @@ var require_treasury = __commonJS({
6205
7807
  function createWriteContract({ signer, treasury: treasury2 }) {
6206
7808
  if (!signer) throw new SageSDKError(CODES.INVALID_ARGS, "signer required");
6207
7809
  const addr = normalise(treasury2, "treasury");
6208
- return new Contract(addr, ABI.SageTreasury, signer);
7810
+ return new Contract(addr, SAGE_TREASURY_ABI, signer);
6209
7811
  }
6210
7812
  async function waitForReceipt({ signer, tx, waitMs }) {
6211
7813
  const provider = signer.provider;
@@ -6509,6 +8111,350 @@ var require_bounty = __commonJS({
6509
8111
  }
6510
8112
  });
6511
8113
 
8114
+ // src/votingMultiplier/index.js
8115
+ var require_votingMultiplier = __commonJS({
8116
+ "src/votingMultiplier/index.js"(exports2, module2) {
8117
+ var { Contract, Interface, getAddress } = require("ethers");
8118
+ var ABI = require_abi();
8119
+ var { SageSDKError, CODES } = require_errors();
8120
+ function normaliseAddress(address, label) {
8121
+ if (!address) throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
8122
+ try {
8123
+ return getAddress(address);
8124
+ } catch (err) {
8125
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
8126
+ }
8127
+ }
8128
+ function toBigInt(value, label) {
8129
+ if (value === void 0 || value === null) {
8130
+ throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
8131
+ }
8132
+ try {
8133
+ return BigInt(value.toString());
8134
+ } catch (err) {
8135
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
8136
+ }
8137
+ }
8138
+ function getNftContract(provider, nft) {
8139
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
8140
+ const addr = normaliseAddress(nft, "nft");
8141
+ return new Contract(addr, ABI.VotingMultiplierNFT, provider);
8142
+ }
8143
+ function getWrapperContract(provider, wrapper) {
8144
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
8145
+ const addr = normaliseAddress(wrapper, "wrapper");
8146
+ return new Contract(addr, ABI.MultipliedVotes, provider);
8147
+ }
8148
+ async function getTier({ provider, nft, tierId }) {
8149
+ const c = getNftContract(provider, nft);
8150
+ const id2 = toBigInt(tierId, "tierId");
8151
+ let tier;
8152
+ if (typeof c.getTier === "function") {
8153
+ tier = await c.getTier(id2);
8154
+ } else {
8155
+ tier = await c.tiers(id2);
8156
+ }
8157
+ const name = String(tier.name ?? tier[0]);
8158
+ const multiplier = BigInt((tier.multiplier ?? tier[1]).toString());
8159
+ const maxSupply = BigInt((tier.maxSupply ?? tier[2]).toString());
8160
+ const minted = BigInt((tier.minted ?? tier[3]).toString());
8161
+ const price = BigInt((tier.price ?? tier[4]).toString());
8162
+ const dao = getAddress(tier.dao ?? tier[5]);
8163
+ return { name, multiplier, maxSupply, minted, price, dao };
8164
+ }
8165
+ async function getTierCount({ provider, nft }) {
8166
+ const c = getNftContract(provider, nft);
8167
+ const count = await c.tierCount();
8168
+ return BigInt(count.toString());
8169
+ }
8170
+ function buildCreateTierTx({ nft, dao, name, multiplier, maxSupply, price }) {
8171
+ const addr = normaliseAddress(nft, "nft");
8172
+ const iface = new Interface(ABI.VotingMultiplierNFT);
8173
+ const data = iface.encodeFunctionData("createTier", [
8174
+ normaliseAddress(dao, "dao"),
8175
+ String(name ?? ""),
8176
+ toBigInt(multiplier, "multiplier"),
8177
+ toBigInt(maxSupply, "maxSupply"),
8178
+ toBigInt(price, "price")
8179
+ ]);
8180
+ return { to: addr, data, value: 0n };
8181
+ }
8182
+ function buildMintTx({ nft, to, tierId, uri }) {
8183
+ const addr = normaliseAddress(nft, "nft");
8184
+ const iface = new Interface(ABI.VotingMultiplierNFT);
8185
+ const data = iface.encodeFunctionData("mint", [
8186
+ normaliseAddress(to, "to"),
8187
+ toBigInt(tierId, "tierId"),
8188
+ String(uri ?? "")
8189
+ ]);
8190
+ return { to: addr, data, value: 0n };
8191
+ }
8192
+ function buildPublicMintTx({ nft, tierId, uri, value }) {
8193
+ const addr = normaliseAddress(nft, "nft");
8194
+ const iface = new Interface(ABI.VotingMultiplierNFT);
8195
+ const data = iface.encodeFunctionData("publicMint", [
8196
+ toBigInt(tierId, "tierId"),
8197
+ String(uri ?? "")
8198
+ ]);
8199
+ return { to: addr, data, value: toBigInt(value ?? 0n, "value") };
8200
+ }
8201
+ async function getMultiplier({ provider, nft, account, dao }) {
8202
+ const c = getNftContract(provider, nft);
8203
+ const res = await c.getMultiplier(normaliseAddress(account, "account"), normaliseAddress(dao, "dao"));
8204
+ return BigInt(res.toString());
8205
+ }
8206
+ async function getPastMultiplier({ provider, nft, account, dao, timepoint }) {
8207
+ const c = getNftContract(provider, nft);
8208
+ const res = await c.getPastMultiplier(
8209
+ normaliseAddress(account, "account"),
8210
+ normaliseAddress(dao, "dao"),
8211
+ toBigInt(timepoint, "timepoint")
8212
+ );
8213
+ return BigInt(res.toString());
8214
+ }
8215
+ async function getTokenMultiplier({ provider, nft, tokenId }) {
8216
+ const c = getNftContract(provider, nft);
8217
+ const res = await c.getTokenMultiplier(toBigInt(tokenId, "tokenId"));
8218
+ return BigInt(res.toString());
8219
+ }
8220
+ async function getTokenDAO({ provider, nft, tokenId }) {
8221
+ const c = getNftContract(provider, nft);
8222
+ const res = await c.getTokenDAO(toBigInt(tokenId, "tokenId"));
8223
+ return getAddress(res);
8224
+ }
8225
+ async function getTokenInfo({ provider, nft, tokenId }) {
8226
+ const c = getNftContract(provider, nft);
8227
+ const id2 = toBigInt(tokenId, "tokenId");
8228
+ const info = await c.getTokenInfo(id2);
8229
+ const owner = getAddress(info.owner ?? info[0]);
8230
+ const tierId = BigInt((info.tierId ?? info[1]).toString());
8231
+ const multiplier = BigInt((info.multiplier ?? info[2]).toString());
8232
+ const uri = String(info.uri ?? info[3]);
8233
+ return { owner, tierId, multiplier, uri };
8234
+ }
8235
+ async function getVotes({ provider, wrapper, account }) {
8236
+ const c = getWrapperContract(provider, wrapper);
8237
+ const res = await c.getVotes(normaliseAddress(account, "account"));
8238
+ return BigInt(res.toString());
8239
+ }
8240
+ async function getPastVotes({ provider, wrapper, account, timepoint }) {
8241
+ const c = getWrapperContract(provider, wrapper);
8242
+ const res = await c.getPastVotes(
8243
+ normaliseAddress(account, "account"),
8244
+ toBigInt(timepoint, "timepoint")
8245
+ );
8246
+ return BigInt(res.toString());
8247
+ }
8248
+ async function getVotingBreakdown({ provider, wrapper, account }) {
8249
+ const c = getWrapperContract(provider, wrapper);
8250
+ const [baseVotes, multiplier, effectiveVotes] = await c.getVotingBreakdown(normaliseAddress(account, "account"));
8251
+ return {
8252
+ baseVotes: BigInt(baseVotes.toString()),
8253
+ multiplier: BigInt(multiplier.toString()),
8254
+ effectiveVotes: BigInt(effectiveVotes.toString())
8255
+ };
8256
+ }
8257
+ async function getPastVotingBreakdown({ provider, wrapper, account, timepoint }) {
8258
+ const c = getWrapperContract(provider, wrapper);
8259
+ const [baseVotes, multiplier, effectiveVotes] = await c.getPastVotingBreakdown(
8260
+ normaliseAddress(account, "account"),
8261
+ toBigInt(timepoint, "timepoint")
8262
+ );
8263
+ return {
8264
+ baseVotes: BigInt(baseVotes.toString()),
8265
+ multiplier: BigInt(multiplier.toString()),
8266
+ effectiveVotes: BigInt(effectiveVotes.toString())
8267
+ };
8268
+ }
8269
+ async function hasMultiplierBonus({ provider, wrapper, account }) {
8270
+ const c = getWrapperContract(provider, wrapper);
8271
+ const res = await c.hasMultiplierBonus(normaliseAddress(account, "account"));
8272
+ return !!res;
8273
+ }
8274
+ module2.exports = {
8275
+ // Tier management
8276
+ getTier,
8277
+ getTierCount,
8278
+ buildCreateTierTx,
8279
+ // Minting
8280
+ buildMintTx,
8281
+ buildPublicMintTx,
8282
+ // Multiplier queries
8283
+ getMultiplier,
8284
+ getPastMultiplier,
8285
+ getTokenMultiplier,
8286
+ getTokenDAO,
8287
+ getTokenInfo,
8288
+ // Wrapper queries
8289
+ getVotes,
8290
+ getPastVotes,
8291
+ getVotingBreakdown,
8292
+ getPastVotingBreakdown,
8293
+ hasMultiplierBonus
8294
+ };
8295
+ }
8296
+ });
8297
+
8298
+ // src/auction/index.js
8299
+ var require_auction = __commonJS({
8300
+ "src/auction/index.js"(exports2, module2) {
8301
+ var { Contract, Interface, getAddress } = require("ethers");
8302
+ var ABI = require_abi();
8303
+ var { SageSDKError, CODES } = require_errors();
8304
+ function normaliseAddress(address, label) {
8305
+ if (!address) throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
8306
+ try {
8307
+ return getAddress(address);
8308
+ } catch (err) {
8309
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
8310
+ }
8311
+ }
8312
+ function toBigInt(value, label) {
8313
+ if (value === void 0 || value === null) {
8314
+ throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
8315
+ }
8316
+ try {
8317
+ return BigInt(value.toString());
8318
+ } catch (err) {
8319
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
8320
+ }
8321
+ }
8322
+ function getAuctionContract(provider, auctionHouse) {
8323
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
8324
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8325
+ return new Contract(addr, ABI.SageAuctionHouse, provider);
8326
+ }
8327
+ async function getAuction({ provider, auctionHouse }) {
8328
+ const c = getAuctionContract(provider, auctionHouse);
8329
+ const res = await c.auction();
8330
+ const nftId = BigInt(res.nftId.toString());
8331
+ const amount = BigInt(res.amount.toString());
8332
+ const startTime = BigInt(res.startTime.toString());
8333
+ const endTime = BigInt(res.endTime.toString());
8334
+ const bidder = getAddress(res.bidder);
8335
+ const settled = !!res.settled;
8336
+ return { nftId, amount, startTime, endTime, bidder, settled };
8337
+ }
8338
+ async function getConfig({ provider, auctionHouse }) {
8339
+ const c = getAuctionContract(provider, auctionHouse);
8340
+ const [nft, treasury2, weth, timeBuffer, reservePrice, minBidIncrementPercentage, duration, mintTierId, defaultTokenURI, paused, owner] = await Promise.all([
8341
+ c.nft(),
8342
+ c.treasury(),
8343
+ c.weth(),
8344
+ c.timeBuffer(),
8345
+ c.reservePrice(),
8346
+ c.minBidIncrementPercentage(),
8347
+ c.duration(),
8348
+ c.mintTierId(),
8349
+ c.defaultTokenURI(),
8350
+ c.paused(),
8351
+ c.owner()
8352
+ ]);
8353
+ return {
8354
+ nft: getAddress(nft),
8355
+ treasury: getAddress(treasury2),
8356
+ weth: getAddress(weth),
8357
+ timeBuffer: BigInt(timeBuffer.toString()),
8358
+ reservePrice: BigInt(reservePrice.toString()),
8359
+ minBidIncrementPercentage: BigInt(minBidIncrementPercentage.toString()),
8360
+ duration: BigInt(duration.toString()),
8361
+ mintTierId: BigInt(mintTierId.toString()),
8362
+ defaultTokenURI: String(defaultTokenURI),
8363
+ paused: !!paused,
8364
+ owner: getAddress(owner)
8365
+ };
8366
+ }
8367
+ function buildCreateBidTx({ auctionHouse, nftId, value }) {
8368
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8369
+ const iface = new Interface(ABI.SageAuctionHouse);
8370
+ const data = iface.encodeFunctionData("createBid", [toBigInt(nftId, "nftId")]);
8371
+ return { to: addr, data, value: toBigInt(value, "value") };
8372
+ }
8373
+ function buildSettleAndCreateTx({ auctionHouse }) {
8374
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8375
+ const iface = new Interface(ABI.SageAuctionHouse);
8376
+ const data = iface.encodeFunctionData("settleCurrentAndCreateNewAuction", []);
8377
+ return { to: addr, data, value: 0n };
8378
+ }
8379
+ function buildSettleTx({ auctionHouse }) {
8380
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8381
+ const iface = new Interface(ABI.SageAuctionHouse);
8382
+ const data = iface.encodeFunctionData("settleAuction", []);
8383
+ return { to: addr, data, value: 0n };
8384
+ }
8385
+ function buildCreateAuctionTx({ auctionHouse }) {
8386
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8387
+ const iface = new Interface(ABI.SageAuctionHouse);
8388
+ const data = iface.encodeFunctionData("createAuction", []);
8389
+ return { to: addr, data, value: 0n };
8390
+ }
8391
+ function buildPauseTx({ auctionHouse }) {
8392
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8393
+ const iface = new Interface(ABI.SageAuctionHouse);
8394
+ const data = iface.encodeFunctionData("pause", []);
8395
+ return { to: addr, data, value: 0n };
8396
+ }
8397
+ function buildUnpauseTx({ auctionHouse }) {
8398
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8399
+ const iface = new Interface(ABI.SageAuctionHouse);
8400
+ const data = iface.encodeFunctionData("unpause", []);
8401
+ return { to: addr, data, value: 0n };
8402
+ }
8403
+ function buildSetTimeBufferTx({ auctionHouse, timeBuffer }) {
8404
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8405
+ const iface = new Interface(ABI.SageAuctionHouse);
8406
+ const data = iface.encodeFunctionData("setTimeBuffer", [toBigInt(timeBuffer, "timeBuffer")]);
8407
+ return { to: addr, data, value: 0n };
8408
+ }
8409
+ function buildSetReservePriceTx({ auctionHouse, reservePrice }) {
8410
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8411
+ const iface = new Interface(ABI.SageAuctionHouse);
8412
+ const data = iface.encodeFunctionData("setReservePrice", [toBigInt(reservePrice, "reservePrice")]);
8413
+ return { to: addr, data, value: 0n };
8414
+ }
8415
+ function buildSetMinBidIncrementTx({ auctionHouse, percentage }) {
8416
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8417
+ const iface = new Interface(ABI.SageAuctionHouse);
8418
+ const data = iface.encodeFunctionData("setMinBidIncrementPercentage", [toBigInt(percentage, "percentage")]);
8419
+ return { to: addr, data, value: 0n };
8420
+ }
8421
+ function buildSetDurationTx({ auctionHouse, duration }) {
8422
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8423
+ const iface = new Interface(ABI.SageAuctionHouse);
8424
+ const data = iface.encodeFunctionData("setDuration", [toBigInt(duration, "duration")]);
8425
+ return { to: addr, data, value: 0n };
8426
+ }
8427
+ function buildSetMintTierIdTx({ auctionHouse, tierId }) {
8428
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8429
+ const iface = new Interface(ABI.SageAuctionHouse);
8430
+ const data = iface.encodeFunctionData("setMintTierId", [toBigInt(tierId, "tierId")]);
8431
+ return { to: addr, data, value: 0n };
8432
+ }
8433
+ function buildSetDefaultTokenURITx({ auctionHouse, uri }) {
8434
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8435
+ const iface = new Interface(ABI.SageAuctionHouse);
8436
+ const data = iface.encodeFunctionData("setDefaultTokenURI", [String(uri ?? "")]);
8437
+ return { to: addr, data, value: 0n };
8438
+ }
8439
+ module2.exports = {
8440
+ getAuction,
8441
+ getConfig,
8442
+ buildCreateBidTx,
8443
+ buildSettleAndCreateTx,
8444
+ buildSettleTx,
8445
+ buildCreateAuctionTx,
8446
+ buildPauseTx,
8447
+ buildUnpauseTx,
8448
+ buildSetTimeBufferTx,
8449
+ buildSetReservePriceTx,
8450
+ buildSetMinBidIncrementTx,
8451
+ buildSetDurationTx,
8452
+ buildSetMintTierIdTx,
8453
+ buildSetDefaultTokenURITx
8454
+ };
8455
+ }
8456
+ });
8457
+
6512
8458
  // src/utils/provider.js
6513
8459
  var require_provider = __commonJS({
6514
8460
  "src/utils/provider.js"(exports2, module2) {
@@ -8372,8 +10318,8 @@ var require_doppler = __commonJS({
8372
10318
  return res;
8373
10319
  };
8374
10320
  module2.exports.getStaticPoolInfo = async function getStaticPoolInfo(sdk, poolAddress) {
8375
- const auction = await sdk.getStaticAuction(poolAddress);
8376
- return auction.getPoolInfo();
10321
+ const auction2 = await sdk.getStaticAuction(poolAddress);
10322
+ return auction2.getPoolInfo();
8377
10323
  };
8378
10324
  module2.exports.quoteV3ExactIn = async function quoteV3ExactIn(sdk, { tokenIn, tokenOut, amountIn, fee, sqrtPriceLimitX96 = 0n }) {
8379
10325
  return sdk.quoter.quoteExactInputV3({ tokenIn, tokenOut, amountIn, fee, sqrtPriceLimitX96 });
@@ -8396,8 +10342,8 @@ var require_doppler = __commonJS({
8396
10342
  return { deposited: needed, hash };
8397
10343
  };
8398
10344
  module2.exports.getDynamicHookInfo = async function getDynamicHookInfo(sdk, hookAddress) {
8399
- const auction = await sdk.getDynamicAuction(hookAddress);
8400
- return auction.getHookInfo();
10345
+ const auction2 = await sdk.getDynamicAuction(hookAddress);
10346
+ return auction2.getHookInfo();
8401
10347
  };
8402
10348
  module2.exports.quoteV4ExactIn = async function quoteV4ExactIn(sdk, { poolKey, zeroForOne, exactAmount, hookData }) {
8403
10349
  return sdk.quoter.quoteExactInputV4({ poolKey, zeroForOne, exactAmount, hookData });
@@ -8510,6 +10456,60 @@ var require_doppler = __commonJS({
8510
10456
  }
8511
10457
  });
8512
10458
 
10459
+ // src/points.js
10460
+ var require_points = __commonJS({
10461
+ "src/points.js"(exports2, module2) {
10462
+ var axios = require("axios");
10463
+ function resolveBaseUrl(baseUrl) {
10464
+ const fromEnv = process.env.SAGE_POINTS_BASE_URL;
10465
+ const base = baseUrl || fromEnv;
10466
+ if (!base) {
10467
+ throw new Error(
10468
+ "SAGE_POINTS_BASE_URL not set and no baseUrl provided. Provide the Sage web app base URL, e.g. https://app.sage.xyz"
10469
+ );
10470
+ }
10471
+ return base.replace(/\/+$/, "");
10472
+ }
10473
+ async function fetchSeasonSnapshot({ baseUrl, season = "season-1" } = {}) {
10474
+ const base = resolveBaseUrl(baseUrl);
10475
+ const url = `${base}/airdrop/${season}/points.json`;
10476
+ const resp = await axios.get(url, { timeout: 15e3 });
10477
+ if (!resp || !resp.data) {
10478
+ throw new Error(`No data returned from ${url}`);
10479
+ }
10480
+ return resp.data;
10481
+ }
10482
+ async function getSeasonPoints({ address, season = "season-1", baseUrl } = {}) {
10483
+ if (!address) throw new Error("address is required");
10484
+ const snapshot = await fetchSeasonSnapshot({ baseUrl, season });
10485
+ const totals = snapshot.totals || {};
10486
+ const key = address.toLowerCase();
10487
+ const entry = totals[key] || null;
10488
+ return {
10489
+ season: snapshot.season || season,
10490
+ chainId: snapshot.chainId,
10491
+ address: key,
10492
+ totalPoints: entry ? entry.points || 0 : 0,
10493
+ breakdown: entry ? entry.breakdown || {} : {}
10494
+ };
10495
+ }
10496
+ async function getSeasonLeaderboard({ limit = 100, season = "season-1", baseUrl } = {}) {
10497
+ const snapshot = await fetchSeasonSnapshot({ baseUrl, season });
10498
+ const totals = snapshot.totals || {};
10499
+ const entries = Object.entries(totals).map(([addr, v]) => ({
10500
+ address: addr,
10501
+ points: v.points || 0
10502
+ })).sort((a, b) => b.points - a.points);
10503
+ return entries.slice(0, limit);
10504
+ }
10505
+ module2.exports = {
10506
+ fetchSeasonSnapshot,
10507
+ getSeasonPoints,
10508
+ getSeasonLeaderboard
10509
+ };
10510
+ }
10511
+ });
10512
+
8513
10513
  // src/services/utils/cache.js
8514
10514
  var require_cache = __commonJS({
8515
10515
  "src/services/utils/cache.js"(exports2, module2) {
@@ -9260,6 +11260,273 @@ var require_client2 = __commonJS({
9260
11260
  }
9261
11261
  });
9262
11262
 
11263
+ // src/clients/discovery-client.js
11264
+ var require_discovery_client = __commonJS({
11265
+ "src/clients/discovery-client.js"(exports2, module2) {
11266
+ var DiscoveryClient2 = class {
11267
+ /**
11268
+ * @param {string} baseUrl - Base URL of the discovery API
11269
+ * @param {object} [options] - Client options
11270
+ * @param {number} [options.timeout=10000] - Request timeout in milliseconds
11271
+ * @param {Record<string, string>} [options.headers] - Custom headers
11272
+ */
11273
+ constructor(baseUrl, options = {}) {
11274
+ this.baseUrl = baseUrl.replace(/\/$/, "");
11275
+ this.timeout = options.timeout || 1e4;
11276
+ this.headers = options.headers || {};
11277
+ }
11278
+ /**
11279
+ * Search prompts with keyword matching and trend ranking
11280
+ * @param {string} query - Search query
11281
+ * @param {object} [options] - Search options
11282
+ * @param {string} [options.category] - Filter by category
11283
+ * @param {string[]} [options.tags] - Filter by tags
11284
+ * @param {string} [options.author] - Filter by author
11285
+ * @param {number} [options.limit] - Max results to return
11286
+ * @param {number} [options.offset] - Number of results to skip
11287
+ * @param {boolean} [options.useVector] - Use vector search
11288
+ * @returns {Promise<{results: Array, total: number}>}
11289
+ */
11290
+ async search(query, options = {}) {
11291
+ const params = new URLSearchParams();
11292
+ if (query) params.set("q", query);
11293
+ if (options.category) params.set("category", options.category);
11294
+ if (options.author) params.set("author", options.author);
11295
+ if (options.tags) {
11296
+ options.tags.forEach((tag) => params.append("tags", tag));
11297
+ }
11298
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11299
+ if (options.offset !== void 0) params.set("offset", String(options.offset));
11300
+ if (options.useVector !== void 0) params.set("useVector", String(options.useVector));
11301
+ return this._get(`/discover/search?${params}`);
11302
+ }
11303
+ /**
11304
+ * Get trending prompts by time window
11305
+ * @param {object} [options] - Trending options
11306
+ * @param {'1h'|'24h'|'7d'|'30d'|'all'} [options.window] - Time window
11307
+ * @param {string} [options.category] - Filter by category
11308
+ * @param {number} [options.limit] - Max results to return
11309
+ * @param {number} [options.offset] - Number of results to skip
11310
+ * @returns {Promise<{results: Array}>}
11311
+ */
11312
+ async trending(options = {}) {
11313
+ const params = new URLSearchParams();
11314
+ if (options.window) params.set("window", options.window);
11315
+ if (options.category) params.set("category", options.category);
11316
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11317
+ if (options.offset !== void 0) params.set("offset", String(options.offset));
11318
+ return this._get(`/discover/trending?${params}`);
11319
+ }
11320
+ /**
11321
+ * Get trending prompts (alias for /trends/top endpoint)
11322
+ * @param {object} [options] - Trending options
11323
+ * @param {'1h'|'24h'|'7d'|'30d'|'all'} [options.window] - Time window
11324
+ * @param {number} [options.limit] - Max results to return
11325
+ * @param {number} [options.offset] - Number of results to skip
11326
+ * @returns {Promise<{results: Array}>}
11327
+ */
11328
+ async trendingTop(options = {}) {
11329
+ const params = new URLSearchParams();
11330
+ if (options.window) params.set("window", options.window);
11331
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11332
+ if (options.offset !== void 0) params.set("offset", String(options.offset));
11333
+ return this._get(`/trends/top?${params}`);
11334
+ }
11335
+ /**
11336
+ * Find prompts matching user preferences
11337
+ *
11338
+ * Note: This endpoint is not yet implemented in the backend.
11339
+ * This is a placeholder for future implementation.
11340
+ * @param {object} preferences - User preferences
11341
+ * @param {string[]} [preferences.recentPrompts] - Recent prompt CIDs
11342
+ * @param {string[]} [preferences.preferredTags] - Preferred tags
11343
+ * @param {string[]} [preferences.preferredCategories] - Preferred categories
11344
+ * @param {string[]} [preferences.excludeAuthors] - Authors to exclude
11345
+ * @param {number} [preferences.limit] - Max results
11346
+ * @param {boolean} [preferences.diversify] - Diversify results
11347
+ * @returns {Promise<{results: Array, total: number}>}
11348
+ */
11349
+ async match(preferences) {
11350
+ return this._post("/discover/match", preferences);
11351
+ }
11352
+ /**
11353
+ * Find prompts similar to a given prompt
11354
+ * @param {string} cid - Prompt CID to find similar prompts for
11355
+ * @param {object} [options] - Similar options
11356
+ * @param {number} [options.limit] - Max results to return
11357
+ * @param {'vector'|'keyword'|'hybrid'} [options.method] - Similarity method
11358
+ * @returns {Promise<{similar: Array}>}
11359
+ */
11360
+ async similar(cid, options = {}) {
11361
+ const params = new URLSearchParams();
11362
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11363
+ if (options.method) params.set("method", options.method);
11364
+ return this._get(`/discover/similar/${cid}?${params}`);
11365
+ }
11366
+ /**
11367
+ * Get popular tags with optional clustering
11368
+ * @param {object} [options] - Tags options
11369
+ * @param {number} [options.limit] - Max tags to return
11370
+ * @param {string} [options.category] - Filter by category
11371
+ * @param {boolean} [options.clusters] - Enable tag clustering
11372
+ * @returns {Promise<{tags: Array}>}
11373
+ */
11374
+ async tags(options = {}) {
11375
+ const params = new URLSearchParams();
11376
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11377
+ if (options.category) params.set("category", options.category);
11378
+ if (options.clusters !== void 0) params.set("clusters", String(options.clusters));
11379
+ return this._get(`/discover/tags?${params}`);
11380
+ }
11381
+ /**
11382
+ * Get category statistics
11383
+ *
11384
+ * Note: This endpoint is not yet implemented in the backend.
11385
+ * This is a placeholder for future implementation.
11386
+ * @returns {Promise<{categories: Array}>}
11387
+ */
11388
+ async categories() {
11389
+ return this._get("/discover/categories");
11390
+ }
11391
+ /**
11392
+ * Get prompts by tag
11393
+ * @param {string} tag - Tag to search for
11394
+ * @param {number} [limit] - Max results to return
11395
+ * @returns {Promise<{results: Array}>}
11396
+ */
11397
+ async promptsByTag(tag, limit) {
11398
+ const params = new URLSearchParams();
11399
+ if (limit !== void 0) params.set("limit", String(limit));
11400
+ const encodedTag = encodeURIComponent(tag);
11401
+ return this._get(`/discover/by-tag/${encodedTag}?${params}`);
11402
+ }
11403
+ /**
11404
+ * Get index statistics
11405
+ * @returns {Promise<{totalPrompts: number, totalTags: number, avgTrendScore: number}>}
11406
+ */
11407
+ async stats() {
11408
+ return this._get("/discover/stats");
11409
+ }
11410
+ /**
11411
+ * Get trend signals for a specific CID
11412
+ * @param {string} cid - Prompt CID
11413
+ * @returns {Promise<{usageCount: number, forkCount: number, purchaseCount: number, uniqueBuyers: number, governanceVotes: number, lastActivityAt: number}>}
11414
+ */
11415
+ async trendSignals(cid) {
11416
+ return this._get(`/trends/signals/${cid}`);
11417
+ }
11418
+ /**
11419
+ * Get trend history for a specific CID
11420
+ * @param {string} cid - Prompt CID
11421
+ * @param {object} [options] - History options
11422
+ * @param {number} [options.limit] - Max history entries
11423
+ * @param {number} [options.since] - Timestamp to start from
11424
+ * @returns {Promise<{history: Array}>}
11425
+ */
11426
+ async trendHistory(cid, options = {}) {
11427
+ const params = new URLSearchParams();
11428
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11429
+ if (options.since !== void 0) params.set("since", String(options.since));
11430
+ return this._get(`/trends/history/${cid}?${params}`);
11431
+ }
11432
+ /**
11433
+ * Get trend statistics
11434
+ * @returns {Promise<{totalTracked: number, avgScore: number, maxScore: number, recentlyActive: number}>}
11435
+ */
11436
+ async trendStats() {
11437
+ return this._get("/trends/stats");
11438
+ }
11439
+ /**
11440
+ * Record a usage event for a prompt (requires authentication)
11441
+ * @param {string} cid - Prompt CID
11442
+ * @returns {Promise<{ok: boolean}>}
11443
+ */
11444
+ async recordUsage(cid) {
11445
+ return this._post("/trends/usage", { cid });
11446
+ }
11447
+ // Private fetch helpers
11448
+ /**
11449
+ * Perform a GET request
11450
+ * @private
11451
+ * @param {string} path - API path
11452
+ * @returns {Promise<any>}
11453
+ */
11454
+ async _get(path2) {
11455
+ const controller = new AbortController();
11456
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
11457
+ try {
11458
+ const response = await fetch(`${this.baseUrl}${path2}`, {
11459
+ method: "GET",
11460
+ headers: {
11461
+ "Accept": "application/json",
11462
+ ...this.headers
11463
+ },
11464
+ signal: controller.signal
11465
+ });
11466
+ clearTimeout(timeoutId);
11467
+ if (!response.ok) {
11468
+ const errorBody = await response.text().catch(() => "Unknown error");
11469
+ throw new Error(`HTTP ${response.status}: ${errorBody}`);
11470
+ }
11471
+ return await response.json();
11472
+ } catch (error) {
11473
+ clearTimeout(timeoutId);
11474
+ if (error.name === "AbortError") {
11475
+ throw new Error(`Request timeout after ${this.timeout}ms`);
11476
+ }
11477
+ throw error;
11478
+ }
11479
+ }
11480
+ /**
11481
+ * Perform a POST request
11482
+ * @private
11483
+ * @param {string} path - API path
11484
+ * @param {any} body - Request body
11485
+ * @returns {Promise<any>}
11486
+ */
11487
+ async _post(path2, body) {
11488
+ const controller = new AbortController();
11489
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
11490
+ try {
11491
+ const response = await fetch(`${this.baseUrl}${path2}`, {
11492
+ method: "POST",
11493
+ headers: {
11494
+ "Accept": "application/json",
11495
+ "Content-Type": "application/json",
11496
+ ...this.headers
11497
+ },
11498
+ body: JSON.stringify(body),
11499
+ signal: controller.signal
11500
+ });
11501
+ clearTimeout(timeoutId);
11502
+ if (!response.ok) {
11503
+ const errorBody = await response.text().catch(() => "Unknown error");
11504
+ throw new Error(`HTTP ${response.status}: ${errorBody}`);
11505
+ }
11506
+ return await response.json();
11507
+ } catch (error) {
11508
+ clearTimeout(timeoutId);
11509
+ if (error.name === "AbortError") {
11510
+ throw new Error(`Request timeout after ${this.timeout}ms`);
11511
+ }
11512
+ throw error;
11513
+ }
11514
+ }
11515
+ };
11516
+ module2.exports = { DiscoveryClient: DiscoveryClient2 };
11517
+ }
11518
+ });
11519
+
11520
+ // src/clients/index.js
11521
+ var require_clients = __commonJS({
11522
+ "src/clients/index.js"(exports2, module2) {
11523
+ var { DiscoveryClient: DiscoveryClient2 } = require_discovery_client();
11524
+ module2.exports = {
11525
+ DiscoveryClient: DiscoveryClient2
11526
+ };
11527
+ }
11528
+ });
11529
+
9263
11530
  // src/hooks/useSubDAOs.js
9264
11531
  var require_useSubDAOs = __commonJS({
9265
11532
  "src/hooks/useSubDAOs.js"(exports2, module2) {
@@ -9468,6 +11735,7 @@ var subdao = require_subdao();
9468
11735
  var timelock = require_timelock();
9469
11736
  var factory = require_factory();
9470
11737
  var library = require_library();
11738
+ var lineage = require_lineage();
9471
11739
  var prompt = require_prompt();
9472
11740
  var { SageEchoExecutor } = require_execute();
9473
11741
  var ipfs = require_ipfs();
@@ -9481,6 +11749,8 @@ var time = require_time();
9481
11749
  var treasury = require_treasury();
9482
11750
  var boost = require_boost();
9483
11751
  var bounty = require_bounty();
11752
+ var votingMultiplier = require_votingMultiplier();
11753
+ var auction = require_auction();
9484
11754
  var wallet = require_wallet();
9485
11755
  wallet.session = require_session();
9486
11756
  var walletCastManager = require_cast_manager();
@@ -9495,11 +11765,13 @@ var adapters = {
9495
11765
  openzeppelin: require_openzeppelin()
9496
11766
  }
9497
11767
  };
11768
+ var points = require_points();
9498
11769
  var { SubgraphService } = require_client();
9499
11770
  var { IPFSService } = require_client2();
9500
11771
  var serviceErrors = require_errors2();
9501
11772
  var { SimpleCache } = require_cache();
9502
11773
  var { retryWithBackoff } = require_retry();
11774
+ var { DiscoveryClient } = require_clients();
9503
11775
  var hooks = null;
9504
11776
  try {
9505
11777
  hooks = require_hooks();
@@ -9515,6 +11787,7 @@ module.exports = {
9515
11787
  timelock,
9516
11788
  factory,
9517
11789
  library,
11790
+ lineage,
9518
11791
  prompt,
9519
11792
  ipfs,
9520
11793
  ipns,
@@ -9527,6 +11800,8 @@ module.exports = {
9527
11800
  subgraph,
9528
11801
  utils: { ...utils, privateTx, safe, time },
9529
11802
  bounty,
11803
+ votingMultiplier,
11804
+ auction,
9530
11805
  wallet: Object.assign(wallet, {
9531
11806
  cast: walletCastManager,
9532
11807
  cdp: walletCdpManager
@@ -9535,6 +11810,8 @@ module.exports = {
9535
11810
  errors,
9536
11811
  doppler,
9537
11812
  adapters,
11813
+ // Season points helpers (airdrops/testnet)
11814
+ points,
9538
11815
  // New service layer exports
9539
11816
  services: {
9540
11817
  SubgraphService,
@@ -9545,6 +11822,11 @@ module.exports = {
9545
11822
  SimpleCache,
9546
11823
  retryWithBackoff
9547
11824
  },
11825
+ // Client exports
11826
+ clients: {
11827
+ DiscoveryClient
11828
+ },
11829
+ DiscoveryClient,
9548
11830
  // React hooks (optional - requires react + swr peer dependencies)
9549
11831
  hooks,
9550
11832
  // Legacy exports (deprecated): maintain compatibility while consumers migrate