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