@sage-protocol/sdk 0.1.16 → 0.1.18

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.
@@ -14,7 +14,7 @@ var require_package = __commonJS({
14
14
  "package.json"(exports2, module2) {
15
15
  module2.exports = {
16
16
  name: "@sage-protocol/sdk",
17
- version: "0.1.16",
17
+ version: "0.1.18",
18
18
  description: "Backend-agnostic SDK for interacting with the Sage Protocol (governance, SubDAOs, tokens).",
19
19
  main: "dist/index.cjs",
20
20
  module: "dist/index.mjs",
@@ -70,11 +70,11 @@ var require_package = __commonJS({
70
70
  release: "yarn build && npm publish --workspace @sage-protocol/sdk"
71
71
  },
72
72
  dependencies: {
73
- "content-hash": "^2.5.2",
74
73
  "@merit-systems/echo-typescript-sdk": "^1.0.17",
75
74
  "@whetstone-research/doppler-sdk": "^0.0.1-alpha.40",
76
75
  ai: "^3.2.3",
77
76
  axios: "^1.11.0",
77
+ "content-hash": "^2.5.2",
78
78
  ethers: "^6.15.0",
79
79
  viem: "^2.33.2"
80
80
  },
@@ -293,6 +293,186 @@ var require_abi = __commonJS({
293
293
  "function create(uint256 proposalId, address token, uint256 perVoter, uint256 maxVoters)",
294
294
  "function fund(uint256 proposalId, uint256 amount)"
295
295
  ];
296
+ var VotingMultiplierNFT = [
297
+ // Constants
298
+ "function MINTER_ROLE() view returns (bytes32)",
299
+ "function MAX_NFTS_PER_ACCOUNT() view returns (uint256)",
300
+ // Tier Management
301
+ "function createTier(address dao, string name, uint256 multiplier, uint256 maxSupply, uint256 price) returns (uint256 tierId)",
302
+ "function getTier(uint256 tierId) view returns (tuple(string name, uint256 multiplier, uint256 maxSupply, uint256 minted, uint256 price, address dao))",
303
+ "function tierCount() view returns (uint256)",
304
+ "function tiers(uint256) view returns (string name, uint256 multiplier, uint256 maxSupply, uint256 minted, uint256 price, address dao)",
305
+ // Minting
306
+ "function mint(address to, uint256 tierId, string uri) returns (uint256 tokenId)",
307
+ "function publicMint(uint256 tierId, string uri) payable returns (uint256 tokenId)",
308
+ // Multiplier Functions
309
+ "function getMultiplier(address account, address dao) view returns (uint256)",
310
+ "function getPastMultiplier(address account, address dao, uint256 timepoint) view returns (uint256)",
311
+ "function getTokenMultiplier(uint256 tokenId) view returns (uint256)",
312
+ "function getTokenDAO(uint256 tokenId) view returns (address)",
313
+ // Token Info
314
+ "function tokenMultiplier(uint256) view returns (uint256)",
315
+ "function tokenDAO(uint256) view returns (address)",
316
+ "function tokenTier(uint256) view returns (uint256)",
317
+ "function getTokenInfo(uint256 tokenId) view returns (address owner, uint256 tierId, uint256 multiplier, string uri)",
318
+ // ERC721 Standard
319
+ "function balanceOf(address owner) view returns (uint256)",
320
+ "function ownerOf(uint256 tokenId) view returns (address)",
321
+ "function tokenOfOwnerByIndex(address owner, uint256 index) view returns (uint256)",
322
+ "function tokenURI(uint256 tokenId) view returns (string)",
323
+ "function transferFrom(address from, address to, uint256 tokenId)",
324
+ "function safeTransferFrom(address from, address to, uint256 tokenId)",
325
+ "function approve(address to, uint256 tokenId)",
326
+ "function setApprovalForAll(address operator, bool approved)",
327
+ "function getApproved(uint256 tokenId) view returns (address)",
328
+ "function isApprovedForAll(address owner, address operator) view returns (bool)",
329
+ // Admin
330
+ "function withdrawFunds(address to)",
331
+ "function grantRole(bytes32 role, address account)",
332
+ "function revokeRole(bytes32 role, address account)",
333
+ "function hasRole(bytes32 role, address account) view returns (bool)",
334
+ // Events
335
+ "event TierCreated(uint256 indexed tierId, address indexed dao, string name, uint256 multiplier, uint256 maxSupply, uint256 price)",
336
+ "event NFTMinted(address indexed to, uint256 indexed tokenId, address indexed dao, uint256 tierId, uint256 multiplier)",
337
+ "event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)"
338
+ ];
339
+ var MultipliedVotes = [
340
+ // Core IVotes Interface
341
+ "function getVotes(address account) view returns (uint256)",
342
+ "function getPastVotes(address account, uint256 timepoint) view returns (uint256)",
343
+ "function getPastTotalSupply(uint256 timepoint) view returns (uint256)",
344
+ "function delegates(address account) view returns (address)",
345
+ "function delegate(address delegatee)",
346
+ "function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s)",
347
+ // IERC6372 Clock Interface
348
+ "function clock() view returns (uint48)",
349
+ "function CLOCK_MODE() view returns (string)",
350
+ // View Helpers
351
+ "function getVotingBreakdown(address account) view returns (uint256 baseVotes, uint256 multiplier, uint256 effectiveVotes)",
352
+ "function getPastVotingBreakdown(address account, uint256 timepoint) view returns (uint256 baseVotes, uint256 multiplier, uint256 effectiveVotes)",
353
+ "function hasMultiplierBonus(address account) view returns (bool)",
354
+ // Immutable Config
355
+ "function baseToken() view returns (address)",
356
+ "function multiplierNFT() view returns (address)",
357
+ "function dao() view returns (address)",
358
+ "function BASIS() view returns (uint256)"
359
+ ];
360
+ var SageAuctionHouse = [
361
+ // Core Auction Functions
362
+ "function createBid(uint256 nftId) payable",
363
+ "function settleCurrentAndCreateNewAuction()",
364
+ "function settleAuction()",
365
+ "function createAuction()",
366
+ // Current Auction State
367
+ "function auction() view returns (uint256 nftId, uint256 amount, uint256 startTime, uint256 endTime, address bidder, bool settled)",
368
+ // Configuration
369
+ "function nft() view returns (address)",
370
+ "function treasury() view returns (address)",
371
+ "function weth() view returns (address)",
372
+ "function timeBuffer() view returns (uint256)",
373
+ "function reservePrice() view returns (uint256)",
374
+ "function minBidIncrementPercentage() view returns (uint256)",
375
+ "function duration() view returns (uint256)",
376
+ "function mintTierId() view returns (uint256)",
377
+ "function defaultTokenURI() view returns (string)",
378
+ // Admin Functions
379
+ "function pause()",
380
+ "function unpause()",
381
+ "function paused() view returns (bool)",
382
+ "function setTimeBuffer(uint256 _timeBuffer)",
383
+ "function setReservePrice(uint256 _reservePrice)",
384
+ "function setMinBidIncrementPercentage(uint256 _minBidIncrementPercentage)",
385
+ "function setDuration(uint256 _duration)",
386
+ "function setMintTierId(uint256 _tierId)",
387
+ "function setDefaultTokenURI(string _uri)",
388
+ "function owner() view returns (address)",
389
+ "function transferOwnership(address newOwner)",
390
+ // Events
391
+ "event AuctionCreated(uint256 indexed nftId, uint256 startTime, uint256 endTime)",
392
+ "event AuctionBid(uint256 indexed nftId, address sender, uint256 value, bool extended)",
393
+ "event AuctionExtended(uint256 indexed nftId, uint256 endTime)",
394
+ "event AuctionSettled(uint256 indexed nftId, address winner, uint256 amount)",
395
+ "event AuctionTimeBufferUpdated(uint256 timeBuffer)",
396
+ "event AuctionReservePriceUpdated(uint256 reservePrice)",
397
+ "event AuctionMinBidIncrementPercentageUpdated(uint256 minBidIncrementPercentage)",
398
+ "event AuctionDurationUpdated(uint256 duration)"
399
+ ];
400
+ var SimpleBountySystem = [
401
+ // Constants
402
+ "function GOVERNANCE_ROLE() view returns (bytes32)",
403
+ "function MAX_SUBMISSIONS_PER_BOUNTY() view returns (uint256)",
404
+ // Bounty Creation
405
+ "function createBounty(string title, string description, string ipfsCID, uint256 reward, uint256 deadline) returns (uint256)",
406
+ "function createBountyAdvanced(string title, string description, string ipfsCID, uint256 reward, uint256 deadline, uint256 votingDuration, uint8 mode, uint8 libraryAction, address assignee, string libraryKey) returns (uint256)",
407
+ // Submission & Claiming
408
+ "function claimBounty(uint256 bountyId)",
409
+ "function submitEntry(uint256 bountyId, string promptIPFS, string deliverableIPFS) returns (uint256)",
410
+ "function completeBounty(uint256 bountyId, string deliverableIPFS)",
411
+ // Voting (COMPETITIVE mode)
412
+ "function startVoting(uint256 bountyId)",
413
+ "function vote(uint256 bountyId, uint256 submissionId)",
414
+ "function finalizeCompetitive(uint256 bountyId)",
415
+ // Approval
416
+ "function approveSubmission(uint256 bountyId, uint256 submissionId)",
417
+ "function approveBountyCompletion(uint256 bountyId, string)",
418
+ // Cancellation & Expiry
419
+ "function cancelBounty(uint256 bountyId)",
420
+ "function expireBounty(uint256 bountyId)",
421
+ // Reward Management
422
+ "function increaseReward(uint256 bountyId, uint256 additionalReward)",
423
+ "function slashCreator(uint256 bountyId, uint256 amount, address to)",
424
+ // Gate Management
425
+ "function setGates(uint256 bountyId, uint256 minTokenBalance, uint256 requiredBadgeId)",
426
+ "function addToWhitelist(uint256 bountyId, address[] addresses)",
427
+ "function removeFromWhitelist(uint256 bountyId, address[] addresses)",
428
+ "function canSubmit(uint256 bountyId, address submitter) view returns (bool)",
429
+ // View Functions
430
+ "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))",
431
+ "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))",
432
+ "function getSubmissionCount(uint256 bountyId) view returns (uint256)",
433
+ "function getLeadingSubmission(uint256 bountyId) view returns (uint256 submissionId, uint256 votes)",
434
+ "function calculateStake(uint256 reward) view returns (uint256)",
435
+ // State Mappings
436
+ "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)",
437
+ "function nextBountyId() view returns (uint256)",
438
+ "function submissionCount(uint256) view returns (uint256)",
439
+ "function submitterToSubmission(uint256, address) view returns (uint256)",
440
+ "function hasVotedInBounty(uint256, address) view returns (bool)",
441
+ "function voterChosenSubmission(uint256, address) view returns (uint256)",
442
+ "function whitelist(uint256, address) view returns (bool)",
443
+ "function hasWhitelist(uint256) view returns (bool)",
444
+ // External Contracts
445
+ "function sxxxToken() view returns (address)",
446
+ "function contributorSystem() view returns (address)",
447
+ "function governanceConfig() view returns (address)",
448
+ "function communityTreasury() view returns (address)",
449
+ "function governanceContract() view returns (address)",
450
+ "function libraryRegistry() view returns (address)",
451
+ "function subdao() view returns (address)",
452
+ "function soulboundBadge() view returns (address)",
453
+ // Admin
454
+ "function setGovernanceContract(address _gov)",
455
+ "function setCommunityTreasury(address _treasury)",
456
+ "function setLibraryRegistry(address _registry)",
457
+ "function setSoulboundBadge(address _sbtAddress)",
458
+ "function grantRole(bytes32 role, address account)",
459
+ "function revokeRole(bytes32 role, address account)",
460
+ "function hasRole(bytes32 role, address account) view returns (bool)",
461
+ // Events
462
+ "event BountyCreated(uint256 indexed bountyId, address indexed creator, string title, uint256 reward, uint256 deposit, uint8 mode, address assignee)",
463
+ "event SubmissionReceived(uint256 indexed bountyId, uint256 indexed submissionId, address indexed submitter, string promptIPFS)",
464
+ "event BountyClaimed(uint256 indexed bountyId, address indexed claimant)",
465
+ "event BountyUnderReview(uint256 indexed bountyId, address indexed claimant, uint256 proposalId)",
466
+ "event VoteCast(uint256 indexed bountyId, uint256 indexed submissionId, address indexed voter, uint256 weight)",
467
+ "event VotingStarted(uint256 indexed bountyId, uint256 votingEndTime)",
468
+ "event BountyCompleted(uint256 indexed bountyId, address indexed winner, uint256 reward, string deliverable)",
469
+ "event BountyAutoApproved(uint256 indexed bountyId, address indexed winner)",
470
+ "event PromptAddedToLibrary(uint256 indexed bountyId, string libraryKey, string promptIPFS)",
471
+ "event BountyCancelled(uint256 indexed bountyId, address indexed creator)",
472
+ "event BountyExpired(uint256 indexed bountyId)",
473
+ "event BountyRewardIncreased(uint256 indexed bountyId, uint256 additionalReward, uint256 newTotal)",
474
+ "event CreatorSlashed(uint256 indexed bountyId, uint256 amount, address indexed to)"
475
+ ];
296
476
  var Events = {
297
477
  ProposalCreated: "event ProposalCreated(uint256 id, address proposer, address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, uint256 startBlock, uint256 endBlock, string description)"
298
478
  };
@@ -315,6 +495,13 @@ var require_abi = __commonJS({
315
495
  // Protocol treasury (replaces SageTreasury)
316
496
  GovernanceBoostMerkle,
317
497
  GovernanceBoostDirect,
498
+ // Voting Multiplier System
499
+ VotingMultiplierNFT,
500
+ MultipliedVotes,
501
+ // Auction House
502
+ SageAuctionHouse,
503
+ // Bounty System
504
+ SimpleBountySystem,
318
505
  Events
319
506
  };
320
507
  }
@@ -672,6 +859,409 @@ var require_subgraph = __commonJS({
672
859
  listLibraries,
673
860
  getSubdaoLibraries,
674
861
  getSubdaoPrompts,
862
+ /**
863
+ * Bounty dashboards (SimpleBountySystem)
864
+ */
865
+ async listBounties({ url, first = 50, skip = 0, status = null, creator = null }) {
866
+ if (!url) throw new Error("subgraph url required");
867
+ const filters = [];
868
+ if (status != null) filters.push(`status: ${Number(status)}`);
869
+ if (creator) {
870
+ const addr = safeGetAddress(creator);
871
+ if (!addr) throw new Error("invalid creator address");
872
+ filters.push(`creator: "${addr.toLowerCase()}"`);
873
+ }
874
+ const where = filters.length ? `where:{ ${filters.join(", ")} }` : "";
875
+ const doc = `
876
+ query($first:Int!,$skip:Int!){
877
+ bounties(
878
+ ${where}
879
+ first:$first
880
+ skip:$skip
881
+ orderBy: createdAt
882
+ orderDirection: desc
883
+ ){
884
+ id
885
+ contract
886
+ bountyId
887
+ creator
888
+ title
889
+ reward
890
+ creatorDeposit
891
+ mode
892
+ status
893
+ libraryAction
894
+ assignee
895
+ winner
896
+ winningSubmissionId
897
+ libraryKey
898
+ deadline
899
+ votingEndTime
900
+ createdAt
901
+ updatedAt
902
+ }
903
+ }
904
+ `;
905
+ const data = await query(url, doc, {
906
+ first: Math.min(Math.max(1, Number(first || 50)), 200),
907
+ skip: Number(skip || 0)
908
+ });
909
+ return mapSafe(data?.bounties, (row) => {
910
+ const contract = safeGetAddress(row.contract);
911
+ const creatorAddr = safeGetAddress(row.creator);
912
+ const assignee = row.assignee ? safeGetAddress(row.assignee) : null;
913
+ const winner = row.winner ? safeGetAddress(row.winner) : null;
914
+ if (!contract || !creatorAddr) return null;
915
+ return {
916
+ id: String(row.id),
917
+ contract,
918
+ bountyId: BigInt(String(row.bountyId || "0")),
919
+ creator: creatorAddr,
920
+ title: String(row.title || ""),
921
+ reward: BigInt(String(row.reward || "0")),
922
+ creatorDeposit: BigInt(String(row.creatorDeposit || "0")),
923
+ mode: Number(row.mode || 0),
924
+ status: Number(row.status || 0),
925
+ libraryAction: row.libraryAction != null ? Number(row.libraryAction) : null,
926
+ assignee,
927
+ winner,
928
+ winningSubmissionId: row.winningSubmissionId != null ? BigInt(String(row.winningSubmissionId)) : null,
929
+ libraryKey: row.libraryKey || null,
930
+ deadline: row.deadline != null ? Number(row.deadline) : null,
931
+ votingEndTime: row.votingEndTime != null ? Number(row.votingEndTime) : null,
932
+ createdAt: Number(row.createdAt || 0),
933
+ updatedAt: Number(row.updatedAt || 0)
934
+ };
935
+ });
936
+ },
937
+ async getBounty({ url, id: id2 }) {
938
+ if (!url) throw new Error("subgraph url required");
939
+ const doc = `
940
+ query($id:ID!){
941
+ bounty(id:$id){
942
+ id
943
+ contract
944
+ bountyId
945
+ creator
946
+ title
947
+ reward
948
+ creatorDeposit
949
+ mode
950
+ status
951
+ libraryAction
952
+ assignee
953
+ winner
954
+ winningSubmissionId
955
+ libraryKey
956
+ deadline
957
+ votingEndTime
958
+ snapshotBlock
959
+ governanceProposalId
960
+ createdAt
961
+ updatedAt
962
+ }
963
+ }
964
+ `;
965
+ const data = await query(url, doc, { id: String(id2) });
966
+ const row = data?.bounty;
967
+ if (!row) return null;
968
+ const contract = safeGetAddress(row.contract);
969
+ const creatorAddr = safeGetAddress(row.creator);
970
+ if (!contract || !creatorAddr) return null;
971
+ return {
972
+ id: String(row.id),
973
+ contract,
974
+ bountyId: BigInt(String(row.bountyId || "0")),
975
+ creator: creatorAddr,
976
+ title: String(row.title || ""),
977
+ reward: BigInt(String(row.reward || "0")),
978
+ creatorDeposit: BigInt(String(row.creatorDeposit || "0")),
979
+ mode: Number(row.mode || 0),
980
+ status: Number(row.status || 0),
981
+ libraryAction: row.libraryAction != null ? Number(row.libraryAction) : null,
982
+ assignee: row.assignee ? safeGetAddress(row.assignee) : null,
983
+ winner: row.winner ? safeGetAddress(row.winner) : null,
984
+ winningSubmissionId: row.winningSubmissionId != null ? BigInt(String(row.winningSubmissionId)) : null,
985
+ libraryKey: row.libraryKey || null,
986
+ deadline: row.deadline != null ? Number(row.deadline) : null,
987
+ votingEndTime: row.votingEndTime != null ? Number(row.votingEndTime) : null,
988
+ snapshotBlock: row.snapshotBlock != null ? Number(row.snapshotBlock) : null,
989
+ governanceProposalId: row.governanceProposalId != null ? BigInt(String(row.governanceProposalId)) : null,
990
+ createdAt: Number(row.createdAt || 0),
991
+ updatedAt: Number(row.updatedAt || 0)
992
+ };
993
+ },
994
+ async listBountySubmissions({ url, bountyId, first = 50, skip = 0 }) {
995
+ if (!url) throw new Error("subgraph url required");
996
+ const doc = `
997
+ query($bountyId:BigInt!,$first:Int!,$skip:Int!){
998
+ bountySubmissions(
999
+ where:{ bountyId:$bountyId }
1000
+ first:$first
1001
+ skip:$skip
1002
+ orderBy: timestamp
1003
+ orderDirection: asc
1004
+ ){
1005
+ id
1006
+ bountyId
1007
+ submissionId
1008
+ submitter
1009
+ promptIPFS
1010
+ deliverableIPFS
1011
+ timestamp
1012
+ voteCount
1013
+ }
1014
+ }
1015
+ `;
1016
+ const data = await query(url, doc, {
1017
+ bountyId: String(bountyId),
1018
+ first: Math.min(Math.max(1, Number(first || 50)), 200),
1019
+ skip: Number(skip || 0)
1020
+ });
1021
+ return mapSafe(data?.bountySubmissions, (row) => {
1022
+ const submitter = safeGetAddress(row.submitter);
1023
+ if (!submitter) return null;
1024
+ return {
1025
+ id: String(row.id),
1026
+ bountyId: BigInt(String(row.bountyId || "0")),
1027
+ submissionId: BigInt(String(row.submissionId || "0")),
1028
+ submitter,
1029
+ promptIPFS: String(row.promptIPFS || ""),
1030
+ deliverableIPFS: String(row.deliverableIPFS || ""),
1031
+ timestamp: Number(row.timestamp || 0),
1032
+ voteCount: BigInt(String(row.voteCount || "0"))
1033
+ };
1034
+ });
1035
+ },
1036
+ async listBountyVotes({ url, bountyId, first = 100, skip = 0 }) {
1037
+ if (!url) throw new Error("subgraph url required");
1038
+ const doc = `
1039
+ query($bountyId:BigInt!,$first:Int!,$skip:Int!){
1040
+ bountyVotes(
1041
+ where:{ bountyId:$bountyId }
1042
+ first:$first
1043
+ skip:$skip
1044
+ orderBy: blockTimestamp
1045
+ orderDirection: desc
1046
+ ){
1047
+ id
1048
+ bountyId
1049
+ submissionId
1050
+ voter
1051
+ weight
1052
+ blockNumber
1053
+ blockTimestamp
1054
+ transactionHash
1055
+ }
1056
+ }
1057
+ `;
1058
+ const data = await query(url, doc, {
1059
+ bountyId: String(bountyId),
1060
+ first: Math.min(Math.max(1, Number(first || 100)), 500),
1061
+ skip: Number(skip || 0)
1062
+ });
1063
+ return mapSafe(data?.bountyVotes, (row) => {
1064
+ const voter = safeGetAddress(row.voter);
1065
+ if (!voter) return null;
1066
+ return {
1067
+ id: String(row.id),
1068
+ bountyId: BigInt(String(row.bountyId || "0")),
1069
+ submissionId: BigInt(String(row.submissionId || "0")),
1070
+ voter,
1071
+ weight: BigInt(String(row.weight || "0")),
1072
+ blockNumber: Number(row.blockNumber || 0),
1073
+ blockTimestamp: Number(row.blockTimestamp || 0),
1074
+ transactionHash: row.transactionHash || null
1075
+ };
1076
+ });
1077
+ },
1078
+ /**
1079
+ * Multiplier dashboards (VotingMultiplierNFT + SageAuctionHouse)
1080
+ */
1081
+ async listMultiplierAccounts({ url, dao, first = 100, skip = 0 }) {
1082
+ if (!url) throw new Error("subgraph url required");
1083
+ const daoAddr = safeGetAddress(dao);
1084
+ if (!daoAddr) throw new Error("invalid dao address");
1085
+ const doc = `
1086
+ query($dao:Bytes!,$first:Int!,$skip:Int!){
1087
+ multiplierAccounts(
1088
+ where:{ dao: $dao }
1089
+ first:$first
1090
+ skip:$skip
1091
+ orderBy: currentMultiplierBps
1092
+ orderDirection: desc
1093
+ ){
1094
+ id
1095
+ dao
1096
+ account
1097
+ currentMultiplierBps
1098
+ tokenCount
1099
+ updatedAt
1100
+ }
1101
+ }
1102
+ `;
1103
+ const data = await query(url, doc, {
1104
+ dao: daoAddr.toLowerCase(),
1105
+ first: Math.min(Math.max(1, Number(first || 100)), 500),
1106
+ skip: Number(skip || 0)
1107
+ });
1108
+ return mapSafe(data?.multiplierAccounts, (row) => {
1109
+ const daoNorm = safeGetAddress(row.dao);
1110
+ const account = safeGetAddress(row.account);
1111
+ if (!daoNorm || !account) return null;
1112
+ return {
1113
+ id: String(row.id),
1114
+ dao: daoNorm,
1115
+ account,
1116
+ multiplierBps: BigInt(String(row.currentMultiplierBps || "0")),
1117
+ tokenCount: Number(row.tokenCount || 0),
1118
+ updatedAt: Number(row.updatedAt || 0)
1119
+ };
1120
+ });
1121
+ },
1122
+ async listMultiplierNFTs({ url, dao, owner = null, first = 100, skip = 0 }) {
1123
+ if (!url) throw new Error("subgraph url required");
1124
+ const daoAddr = safeGetAddress(dao);
1125
+ if (!daoAddr) throw new Error("invalid dao address");
1126
+ const ownerAddr = owner ? safeGetAddress(owner) : null;
1127
+ const filters = [`dao: $dao`];
1128
+ if (ownerAddr) filters.push(`owner: $owner`);
1129
+ const where = `where:{ ${filters.join(", ")} }`;
1130
+ const doc = `
1131
+ query($dao:Bytes!,$owner:Bytes,$first:Int!,$skip:Int!){
1132
+ multiplierNFTs(
1133
+ ${where}
1134
+ first:$first
1135
+ skip:$skip
1136
+ orderBy: mintedAt
1137
+ orderDirection: desc
1138
+ ){
1139
+ id
1140
+ owner
1141
+ dao
1142
+ tier { id name multiplier maxSupply minted price }
1143
+ multiplier
1144
+ tokenURI
1145
+ mintedAt
1146
+ transactionHash
1147
+ }
1148
+ }
1149
+ `;
1150
+ const variables = {
1151
+ dao: daoAddr.toLowerCase(),
1152
+ owner: ownerAddr ? ownerAddr.toLowerCase() : null,
1153
+ first: Math.min(Math.max(1, Number(first || 100)), 500),
1154
+ skip: Number(skip || 0)
1155
+ };
1156
+ const data = await query(url, doc, variables);
1157
+ return mapSafe(data?.multiplierNFTs, (row) => {
1158
+ const ownerNorm = safeGetAddress(row.owner);
1159
+ const daoNorm = safeGetAddress(row.dao);
1160
+ if (!ownerNorm || !daoNorm) return null;
1161
+ return {
1162
+ id: String(row.id),
1163
+ owner: ownerNorm,
1164
+ dao: daoNorm,
1165
+ tier: row.tier ? {
1166
+ id: String(row.tier.id),
1167
+ name: String(row.tier.name || ""),
1168
+ multiplier: Number(row.tier.multiplier || 0),
1169
+ maxSupply: BigInt(String(row.tier.maxSupply || "0")),
1170
+ minted: BigInt(String(row.tier.minted || "0")),
1171
+ price: BigInt(String(row.tier.price || "0"))
1172
+ } : null,
1173
+ multiplier: Number(row.multiplier || 0),
1174
+ tokenURI: row.tokenURI || null,
1175
+ mintedAt: Number(row.mintedAt || 0),
1176
+ transactionHash: row.transactionHash || null
1177
+ };
1178
+ });
1179
+ },
1180
+ async getCurrentAuction({ url, auctionHouse }) {
1181
+ if (!url) throw new Error("subgraph url required");
1182
+ const addr = safeGetAddress(auctionHouse);
1183
+ if (!addr) throw new Error("invalid auctionHouse address");
1184
+ const doc = `
1185
+ query($id:ID!){
1186
+ multiplierAuction(id:$id){
1187
+ id
1188
+ auctionHouse
1189
+ nft
1190
+ treasury
1191
+ currentNftId
1192
+ currentAmount
1193
+ currentBidder
1194
+ startTime
1195
+ endTime
1196
+ settled
1197
+ updatedAt
1198
+ }
1199
+ }
1200
+ `;
1201
+ const data = await query(url, doc, { id: addr.toLowerCase() });
1202
+ const row = data?.multiplierAuction;
1203
+ if (!row) return null;
1204
+ return {
1205
+ id: String(row.id),
1206
+ auctionHouse: safeGetAddress(row.auctionHouse) || addr,
1207
+ nft: safeGetAddress(row.nft),
1208
+ treasury: safeGetAddress(row.treasury),
1209
+ currentNftId: BigInt(String(row.currentNftId || "0")),
1210
+ currentAmount: BigInt(String(row.currentAmount || "0")),
1211
+ currentBidder: safeGetAddress(row.currentBidder || "0x0000000000000000000000000000000000000000"),
1212
+ startTime: Number(row.startTime || 0),
1213
+ endTime: Number(row.endTime || 0),
1214
+ settled: !!row.settled,
1215
+ updatedAt: Number(row.updatedAt || 0)
1216
+ };
1217
+ },
1218
+ async listAuctionBids({ url, auctionHouse, first = 100, skip = 0 }) {
1219
+ if (!url) throw new Error("subgraph url required");
1220
+ const addr = safeGetAddress(auctionHouse);
1221
+ if (!addr) throw new Error("invalid auctionHouse address");
1222
+ const doc = `
1223
+ query($auctionHouse:Bytes!,$first:Int!,$skip:Int!){
1224
+ multiplierAuctionBids(
1225
+ where:{ auctionHouse:$auctionHouse }
1226
+ first:$first
1227
+ skip:$skip
1228
+ orderBy: blockTimestamp
1229
+ orderDirection: desc
1230
+ ){
1231
+ id
1232
+ auctionHouse
1233
+ nftId
1234
+ bidder
1235
+ amount
1236
+ extended
1237
+ blockNumber
1238
+ blockTimestamp
1239
+ transactionHash
1240
+ }
1241
+ }
1242
+ `;
1243
+ const data = await query(url, doc, {
1244
+ auctionHouse: addr.toLowerCase(),
1245
+ first: Math.min(Math.max(1, Number(first || 100)), 500),
1246
+ skip: Number(skip || 0)
1247
+ });
1248
+ return mapSafe(data?.multiplierAuctionBids, (row) => {
1249
+ const bidder = safeGetAddress(row.bidder);
1250
+ const ah = safeGetAddress(row.auctionHouse);
1251
+ if (!ah || !bidder) return null;
1252
+ return {
1253
+ id: String(row.id),
1254
+ auctionHouse: ah,
1255
+ nftId: BigInt(String(row.nftId || "0")),
1256
+ bidder,
1257
+ amount: BigInt(String(row.amount || "0")),
1258
+ extended: !!row.extended,
1259
+ blockNumber: Number(row.blockNumber || 0),
1260
+ blockTimestamp: Number(row.blockTimestamp || 0),
1261
+ transactionHash: row.transactionHash || null
1262
+ };
1263
+ });
1264
+ },
675
1265
  /**
676
1266
  * Canonical proposal timeline. Tries common fields first, then event-style fallbacks.
677
1267
  * Returns { id, createdAt, queuedAt, executedAt, canceledAt, eta, state } (numbers/strings may be null when unavailable).
@@ -8510,6 +9100,60 @@ var require_doppler = __commonJS({
8510
9100
  }
8511
9101
  });
8512
9102
 
9103
+ // src/points.js
9104
+ var require_points = __commonJS({
9105
+ "src/points.js"(exports2, module2) {
9106
+ var axios = require("axios");
9107
+ function resolveBaseUrl(baseUrl) {
9108
+ const fromEnv = process.env.SAGE_POINTS_BASE_URL;
9109
+ const base = baseUrl || fromEnv;
9110
+ if (!base) {
9111
+ throw new Error(
9112
+ "SAGE_POINTS_BASE_URL not set and no baseUrl provided. Provide the Sage web app base URL, e.g. https://app.sage.xyz"
9113
+ );
9114
+ }
9115
+ return base.replace(/\/+$/, "");
9116
+ }
9117
+ async function fetchSeasonSnapshot({ baseUrl, season = "season-1" } = {}) {
9118
+ const base = resolveBaseUrl(baseUrl);
9119
+ const url = `${base}/airdrop/${season}/points.json`;
9120
+ const resp = await axios.get(url, { timeout: 15e3 });
9121
+ if (!resp || !resp.data) {
9122
+ throw new Error(`No data returned from ${url}`);
9123
+ }
9124
+ return resp.data;
9125
+ }
9126
+ async function getSeasonPoints({ address, season = "season-1", baseUrl } = {}) {
9127
+ if (!address) throw new Error("address is required");
9128
+ const snapshot = await fetchSeasonSnapshot({ baseUrl, season });
9129
+ const totals = snapshot.totals || {};
9130
+ const key = address.toLowerCase();
9131
+ const entry = totals[key] || null;
9132
+ return {
9133
+ season: snapshot.season || season,
9134
+ chainId: snapshot.chainId,
9135
+ address: key,
9136
+ totalPoints: entry ? entry.points || 0 : 0,
9137
+ breakdown: entry ? entry.breakdown || {} : {}
9138
+ };
9139
+ }
9140
+ async function getSeasonLeaderboard({ limit = 100, season = "season-1", baseUrl } = {}) {
9141
+ const snapshot = await fetchSeasonSnapshot({ baseUrl, season });
9142
+ const totals = snapshot.totals || {};
9143
+ const entries = Object.entries(totals).map(([addr, v]) => ({
9144
+ address: addr,
9145
+ points: v.points || 0
9146
+ })).sort((a, b) => b.points - a.points);
9147
+ return entries.slice(0, limit);
9148
+ }
9149
+ module2.exports = {
9150
+ fetchSeasonSnapshot,
9151
+ getSeasonPoints,
9152
+ getSeasonLeaderboard
9153
+ };
9154
+ }
9155
+ });
9156
+
8513
9157
  // src/services/utils/cache.js
8514
9158
  var require_cache = __commonJS({
8515
9159
  "src/services/utils/cache.js"(exports2, module2) {
@@ -9497,6 +10141,7 @@ var require_src = __commonJS({
9497
10141
  openzeppelin: require_openzeppelin()
9498
10142
  }
9499
10143
  };
10144
+ var points = require_points();
9500
10145
  var { SubgraphService } = require_client();
9501
10146
  var { IPFSService } = require_client2();
9502
10147
  var serviceErrors = require_errors2();
@@ -9537,6 +10182,8 @@ var require_src = __commonJS({
9537
10182
  errors,
9538
10183
  doppler,
9539
10184
  adapters,
10185
+ // Season points helpers (airdrops/testnet)
10186
+ points,
9540
10187
  // New service layer exports
9541
10188
  services: {
9542
10189
  SubgraphService,