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