@continuumdao/ctm-mpc-defi 0.2.50 → 0.2.52
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/agent/catalog.cjs +829 -55
- package/dist/agent/catalog.cjs.map +1 -1
- package/dist/agent/catalog.d.ts +93 -22
- package/dist/agent/catalog.js +829 -55
- package/dist/agent/catalog.js.map +1 -1
- package/dist/agent/skills/continuum-dao/SKILL.md +9 -6
- package/dist/agent/skills/continuum-dao-marketplace/SKILL.md +58 -0
- package/dist/agent/skills/hyperliquidOutcome/SKILL.md +47 -0
- package/dist/core/index.cjs +2 -1
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.js +2 -1
- package/dist/core/index.js.map +1 -1
- package/dist/index.cjs +2 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/protocols/evm/aerodrome/index.cjs.map +1 -1
- package/dist/protocols/evm/aerodrome/index.js.map +1 -1
- package/dist/protocols/evm/continuum-dao/index.cjs +2311 -62
- package/dist/protocols/evm/continuum-dao/index.cjs.map +1 -1
- package/dist/protocols/evm/continuum-dao/index.d.ts +697 -2
- package/dist/protocols/evm/continuum-dao/index.js +2255 -64
- package/dist/protocols/evm/continuum-dao/index.js.map +1 -1
- package/dist/protocols/evm/hyperliquidOutcome/index.cjs +1294 -0
- package/dist/protocols/evm/hyperliquidOutcome/index.cjs.map +1 -0
- package/dist/protocols/evm/hyperliquidOutcome/index.d.ts +465 -0
- package/dist/protocols/evm/hyperliquidOutcome/index.js +1247 -0
- package/dist/protocols/evm/hyperliquidOutcome/index.js.map +1 -0
- package/dist/protocols/evm/pendle/index.cjs +2 -1
- package/dist/protocols/evm/pendle/index.cjs.map +1 -1
- package/dist/protocols/evm/pendle/index.js +2 -1
- package/dist/protocols/evm/pendle/index.js.map +1 -1
- package/dist/protocols/evm/trueo/index.cjs +569 -9
- package/dist/protocols/evm/trueo/index.cjs.map +1 -1
- package/dist/protocols/evm/trueo/index.d.ts +42 -1
- package/dist/protocols/evm/trueo/index.js +569 -9
- package/dist/protocols/evm/trueo/index.js.map +1 -1
- package/package.json +6 -1
|
@@ -40,19 +40,19 @@ var init_chainIdParse = __esm({
|
|
|
40
40
|
"src/chains/evm/chainIdParse.ts"() {
|
|
41
41
|
}
|
|
42
42
|
});
|
|
43
|
-
function isContinuumDaoCommitteeProposer(
|
|
44
|
-
if (!
|
|
43
|
+
function isContinuumDaoCommitteeProposer(addr2) {
|
|
44
|
+
if (!addr2 || !isConfiguredAddress(addr2)) return false;
|
|
45
45
|
try {
|
|
46
|
-
const a = viem.getAddress(
|
|
46
|
+
const a = viem.getAddress(addr2);
|
|
47
47
|
return exports.CONTINUUM_DAO_COMMITTEE_PROPOSERS.some((c) => c === a);
|
|
48
48
|
} catch {
|
|
49
49
|
return false;
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
-
function isConfiguredAddress(
|
|
53
|
-
if (!
|
|
52
|
+
function isConfiguredAddress(addr2) {
|
|
53
|
+
if (!addr2?.trim()) return false;
|
|
54
54
|
try {
|
|
55
|
-
return viem.getAddress(
|
|
55
|
+
return viem.getAddress(addr2) !== viem.zeroAddress;
|
|
56
56
|
} catch {
|
|
57
57
|
return false;
|
|
58
58
|
}
|
|
@@ -74,6 +74,10 @@ function votingEscrowAddressOnEvmChain(chainId) {
|
|
|
74
74
|
const ve = continuumDaoDeployment(chainId)?.votingEscrow;
|
|
75
75
|
return ve && isConfiguredAddress(ve) ? viem.getAddress(ve) : null;
|
|
76
76
|
}
|
|
77
|
+
function votingEscrowMarketplaceAddressOnEvmChain(chainId) {
|
|
78
|
+
if (chainId !== exports.CONTINUUM_DAO_LINEA_CHAIN_ID) return null;
|
|
79
|
+
return exports.VOTING_ESCROW_MARKETPLACE_LINEA_ADDRESS;
|
|
80
|
+
}
|
|
77
81
|
function governorAddressOnEvmChain(chainId) {
|
|
78
82
|
const gov = continuumDaoDeployment(chainId)?.governor;
|
|
79
83
|
return gov && isConfiguredAddress(gov) ? viem.getAddress(gov) : null;
|
|
@@ -136,7 +140,7 @@ function listContinuumDaoDefaultAssets() {
|
|
|
136
140
|
}
|
|
137
141
|
return out;
|
|
138
142
|
}
|
|
139
|
-
exports.CONTINUUM_DAO_PROTOCOL_ID = void 0; exports.CONTINUUM_DAO_ETHEREUM_CHAIN_ID = void 0; exports.CONTINUUM_DAO_LINEA_CHAIN_ID = void 0; exports.CONTINUUM_DAO_LINEA_SEPOLIA_CHAIN_ID = void 0; exports.CTM_TOKEN_NAME = void 0; exports.CTM_TOKEN_SYMBOL = void 0; exports.VECTM_TOKEN_NAME = void 0; exports.VECTM_TOKEN_SYMBOL = void 0; exports.CTM_TOKEN_DECIMALS = void 0; exports.WEEK_SECONDS = void 0; exports.MAXTIME_SECONDS = void 0; exports.VECTM_MAX_LOCK_WEEKS = void 0; exports.VECTM_DEFAULT_MINIMUM_LOCK_WEI = void 0; exports.VECTM_LIQ_MIN_LOCKED_WEI = void 0; exports.VECTM_LIQ_PENALTY_NUM = void 0; exports.VECTM_LIQ_PENALTY_DEN = void 0; var UNSET; exports.CTM_TOKEN_ADDRESS = void 0; exports.VOTING_ESCROW_LINEA_ADDRESS = void 0; exports.CONTINUUM_DAO_LINEA_GOVERNOR_ADDRESS = void 0; exports.CONTINUUM_DAO_LINEA_GOVERNOR_LEGACY_ADDRESS = void 0; exports.CONTINUUM_DAO_COMMITTEE_PROPOSERS = void 0; exports.CONTINUUM_DAO_DEPLOYMENTS = void 0; exports.CONTINUUM_DAO_GOVERNANCE_API = void 0;
|
|
143
|
+
exports.CONTINUUM_DAO_PROTOCOL_ID = void 0; exports.CONTINUUM_DAO_ETHEREUM_CHAIN_ID = void 0; exports.CONTINUUM_DAO_LINEA_CHAIN_ID = void 0; exports.CONTINUUM_DAO_LINEA_SEPOLIA_CHAIN_ID = void 0; exports.CTM_TOKEN_NAME = void 0; exports.CTM_TOKEN_SYMBOL = void 0; exports.VECTM_TOKEN_NAME = void 0; exports.VECTM_TOKEN_SYMBOL = void 0; exports.CTM_TOKEN_DECIMALS = void 0; exports.WEEK_SECONDS = void 0; exports.MAXTIME_SECONDS = void 0; exports.VECTM_MAX_LOCK_WEEKS = void 0; exports.VECTM_DEFAULT_MINIMUM_LOCK_WEI = void 0; exports.VECTM_LIQ_MIN_LOCKED_WEI = void 0; exports.VECTM_LIQ_PENALTY_NUM = void 0; exports.VECTM_LIQ_PENALTY_DEN = void 0; var UNSET; exports.CTM_TOKEN_ADDRESS = void 0; exports.VOTING_ESCROW_LINEA_ADDRESS = void 0; exports.MULTISIGN_AGENT_WALLET_LINEA_ADDRESS = void 0; exports.CTM_FEE_RATE_SCALE = void 0; exports.VOTING_ESCROW_MARKETPLACE_LINEA_ADDRESS = void 0; exports.VOTING_ESCROW_MARKETPLACE_START_BLOCK = void 0; exports.MARKETPLACE_WETH_LINEA_ADDRESS = void 0; exports.MARKETPLACE_USDC_LINEA_ADDRESS = void 0; exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID = void 0; exports.CONTINUUM_DAO_LINEA_GOVERNOR_ADDRESS = void 0; exports.CONTINUUM_DAO_LINEA_GOVERNOR_LEGACY_ADDRESS = void 0; exports.CONTINUUM_DAO_COMMITTEE_PROPOSERS = void 0; exports.CONTINUUM_DAO_DEPLOYMENTS = void 0; exports.CONTINUUM_DAO_GOVERNANCE_API = void 0; exports.CONTINUUM_DAO_MARKETPLACE_API = void 0;
|
|
140
144
|
var init_constants = __esm({
|
|
141
145
|
"src/protocols/evm/continuum-dao/constants.ts"() {
|
|
142
146
|
init_chainIdParse();
|
|
@@ -165,6 +169,13 @@ var init_constants = __esm({
|
|
|
165
169
|
};
|
|
166
170
|
exports.CTM_TOKEN_ADDRESS = viem.getAddress("0x2026027054F5beBCEB650aBD62dC623e327658e7");
|
|
167
171
|
exports.VOTING_ESCROW_LINEA_ADDRESS = viem.getAddress("0x221EC90B3B083A8501A37bdeb7035CeaedF3C31f");
|
|
172
|
+
exports.MULTISIGN_AGENT_WALLET_LINEA_ADDRESS = viem.getAddress("0x4ebd7cCBe32a51d1638cFE90E8eD1c4BdF42f729");
|
|
173
|
+
exports.CTM_FEE_RATE_SCALE = 1000n;
|
|
174
|
+
exports.VOTING_ESCROW_MARKETPLACE_LINEA_ADDRESS = viem.getAddress("0x92557d38beAe4658d3c03A02F349FFB60c3bfFA5");
|
|
175
|
+
exports.VOTING_ESCROW_MARKETPLACE_START_BLOCK = 32100001n;
|
|
176
|
+
exports.MARKETPLACE_WETH_LINEA_ADDRESS = viem.getAddress("0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f");
|
|
177
|
+
exports.MARKETPLACE_USDC_LINEA_ADDRESS = viem.getAddress("0x176211869cA2b568f2A7D4EE941E073a821EE1ff");
|
|
178
|
+
exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID = "continuum-dao-marketplace";
|
|
168
179
|
exports.CONTINUUM_DAO_LINEA_GOVERNOR_ADDRESS = viem.getAddress("0x76FF2CB03175900F1D83328C82D27EA9aeaF2355");
|
|
169
180
|
exports.CONTINUUM_DAO_LINEA_GOVERNOR_LEGACY_ADDRESS = viem.getAddress("0x4800F9f1dC1b6daCA841B71E0531F547D374168E");
|
|
170
181
|
exports.CONTINUUM_DAO_COMMITTEE_PROPOSERS = [
|
|
@@ -185,6 +196,7 @@ var init_constants = __esm({
|
|
|
185
196
|
}
|
|
186
197
|
};
|
|
187
198
|
exports.CONTINUUM_DAO_GOVERNANCE_API = "https://app-api.continuumdao.org";
|
|
199
|
+
exports.CONTINUUM_DAO_MARKETPLACE_API = exports.CONTINUUM_DAO_GOVERNANCE_API;
|
|
188
200
|
}
|
|
189
201
|
});
|
|
190
202
|
function defiEvmTransport(rpcUrl, opts) {
|
|
@@ -606,25 +618,25 @@ async function forumFetch(path, init = {}) {
|
|
|
606
618
|
return body;
|
|
607
619
|
}
|
|
608
620
|
async function continuumDaoForumResolve(args) {
|
|
609
|
-
const
|
|
610
|
-
if (args.url)
|
|
611
|
-
if (args.tid != null)
|
|
612
|
-
return forumFetch(`/api/continuum/forum/resolve?${
|
|
621
|
+
const qs2 = new URLSearchParams();
|
|
622
|
+
if (args.url) qs2.set("url", String(args.url));
|
|
623
|
+
if (args.tid != null) qs2.set("tid", String(args.tid));
|
|
624
|
+
return forumFetch(`/api/continuum/forum/resolve?${qs2}`, { forumUrl: args.forumUrl });
|
|
613
625
|
}
|
|
614
626
|
async function continuumDaoForumFetchThread(args) {
|
|
615
|
-
const
|
|
616
|
-
if (args.url)
|
|
617
|
-
if (args.tid != null)
|
|
618
|
-
if (args.index != null)
|
|
619
|
-
if (args.start != null)
|
|
620
|
-
if (args.limit != null)
|
|
621
|
-
return forumFetch(`/api/continuum/forum/thread?${
|
|
627
|
+
const qs2 = new URLSearchParams();
|
|
628
|
+
if (args.url) qs2.set("url", String(args.url));
|
|
629
|
+
if (args.tid != null) qs2.set("tid", String(args.tid));
|
|
630
|
+
if (args.index != null) qs2.set("index", String(args.index));
|
|
631
|
+
if (args.start != null) qs2.set("start", String(args.start));
|
|
632
|
+
if (args.limit != null) qs2.set("limit", String(args.limit));
|
|
633
|
+
return forumFetch(`/api/continuum/forum/thread?${qs2}`, { forumUrl: args.forumUrl });
|
|
622
634
|
}
|
|
623
635
|
async function continuumDaoForumReplyCount(args) {
|
|
624
|
-
const
|
|
625
|
-
if (args.url)
|
|
626
|
-
if (args.tid != null)
|
|
627
|
-
return forumFetch(`/api/continuum/forum/thread/replies?${
|
|
636
|
+
const qs2 = new URLSearchParams();
|
|
637
|
+
if (args.url) qs2.set("url", String(args.url));
|
|
638
|
+
if (args.tid != null) qs2.set("tid", String(args.tid));
|
|
639
|
+
return forumFetch(`/api/continuum/forum/thread/replies?${qs2}`, { forumUrl: args.forumUrl });
|
|
628
640
|
}
|
|
629
641
|
async function continuumDaoForumFetchPost(args) {
|
|
630
642
|
return forumFetch(`/api/continuum/forum/post?pid=${encodeURIComponent(String(args.pid))}`, {
|
|
@@ -650,22 +662,22 @@ function assertContinuumDaoForumRecentInput(args) {
|
|
|
650
662
|
}
|
|
651
663
|
async function continuumDaoForumSearch(args) {
|
|
652
664
|
assertContinuumDaoForumSearchInput(args);
|
|
653
|
-
const
|
|
654
|
-
if (args.query?.trim())
|
|
655
|
-
if (args.hours != null)
|
|
656
|
-
if (args.since?.trim())
|
|
657
|
-
if (args.start != null)
|
|
658
|
-
if (args.limit != null)
|
|
659
|
-
return forumFetch(`/api/continuum/forum/search?${
|
|
665
|
+
const qs2 = new URLSearchParams();
|
|
666
|
+
if (args.query?.trim()) qs2.set("query", args.query.trim());
|
|
667
|
+
if (args.hours != null) qs2.set("hours", String(args.hours));
|
|
668
|
+
if (args.since?.trim()) qs2.set("since", args.since.trim());
|
|
669
|
+
if (args.start != null) qs2.set("start", String(args.start));
|
|
670
|
+
if (args.limit != null) qs2.set("limit", String(args.limit));
|
|
671
|
+
return forumFetch(`/api/continuum/forum/search?${qs2}`, { forumUrl: args.forumUrl });
|
|
660
672
|
}
|
|
661
673
|
async function continuumDaoForumRecent(args) {
|
|
662
674
|
assertContinuumDaoForumRecentInput(args);
|
|
663
|
-
const
|
|
664
|
-
if (args.hours != null)
|
|
665
|
-
if (args.since?.trim())
|
|
666
|
-
if (args.start != null)
|
|
667
|
-
if (args.limit != null)
|
|
668
|
-
return forumFetch(`/api/continuum/forum/recent?${
|
|
675
|
+
const qs2 = new URLSearchParams();
|
|
676
|
+
if (args.hours != null) qs2.set("hours", String(args.hours));
|
|
677
|
+
if (args.since?.trim()) qs2.set("since", args.since.trim());
|
|
678
|
+
if (args.start != null) qs2.set("start", String(args.start));
|
|
679
|
+
if (args.limit != null) qs2.set("limit", String(args.limit));
|
|
680
|
+
return forumFetch(`/api/continuum/forum/recent?${qs2}`, {
|
|
669
681
|
forumUrl: args.forumUrl,
|
|
670
682
|
ticket: args.ticket
|
|
671
683
|
});
|
|
@@ -699,10 +711,10 @@ async function continuumDaoForumDelete(args) {
|
|
|
699
711
|
});
|
|
700
712
|
}
|
|
701
713
|
async function continuumDaoForumUserPostIds(args) {
|
|
702
|
-
const
|
|
703
|
-
if (args.start != null)
|
|
704
|
-
if (args.limit != null)
|
|
705
|
-
return forumFetch(`/api/continuum/forum/user/posts?${
|
|
714
|
+
const qs2 = new URLSearchParams({ username: args.username });
|
|
715
|
+
if (args.start != null) qs2.set("start", String(args.start));
|
|
716
|
+
if (args.limit != null) qs2.set("limit", String(args.limit));
|
|
717
|
+
return forumFetch(`/api/continuum/forum/user/posts?${qs2}`, { forumUrl: args.forumUrl });
|
|
706
718
|
}
|
|
707
719
|
async function continuumDaoForumReply(args) {
|
|
708
720
|
return forumFetch("/api/continuum/forum/reply", {
|
|
@@ -773,11 +785,11 @@ async function continuumDaoForumUnread(args) {
|
|
|
773
785
|
if (!args.ticket?.trim()) {
|
|
774
786
|
throw new Error("ticket is required to list unread forum topics");
|
|
775
787
|
}
|
|
776
|
-
const
|
|
777
|
-
if (args.filter?.trim())
|
|
778
|
-
if (args.start != null)
|
|
779
|
-
if (args.limit != null)
|
|
780
|
-
const suffix =
|
|
788
|
+
const qs2 = new URLSearchParams();
|
|
789
|
+
if (args.filter?.trim()) qs2.set("filter", args.filter.trim());
|
|
790
|
+
if (args.start != null) qs2.set("start", String(args.start));
|
|
791
|
+
if (args.limit != null) qs2.set("limit", String(args.limit));
|
|
792
|
+
const suffix = qs2.toString() ? `?${qs2}` : "";
|
|
781
793
|
return forumFetch(`/api/continuum/forum/unread${suffix}`, {
|
|
782
794
|
forumUrl: args.forumUrl,
|
|
783
795
|
ticket: args.ticket
|
|
@@ -918,20 +930,52 @@ async function continuumDaoForumSignInEligible(args) {
|
|
|
918
930
|
const st = body.status && typeof body.status === "object" ? body.status : null;
|
|
919
931
|
const reason = typeof body.reason === "string" && body.reason || st && typeof st.message === "string" && st.message || void 0;
|
|
920
932
|
const ok = res.ok && Boolean(body.ok ?? body.eligible);
|
|
933
|
+
const votingPower = typeof body.votingPower === "string" ? body.votingPower : void 0;
|
|
934
|
+
const threshold = typeof body.threshold === "string" ? body.threshold : void 0;
|
|
935
|
+
const tokenId = typeof body.tokenId === "string" ? body.tokenId : void 0;
|
|
921
936
|
return {
|
|
922
937
|
ok,
|
|
923
938
|
eligible: ok,
|
|
924
939
|
address: typeof body.address === "string" ? body.address : address,
|
|
925
|
-
reason: ok ? void 0 : reason || "Address does not meet the veCTM threshold"
|
|
940
|
+
reason: ok ? void 0 : reason || "Address does not meet the veCTM threshold",
|
|
941
|
+
votingPower,
|
|
942
|
+
threshold,
|
|
943
|
+
tokenId
|
|
926
944
|
};
|
|
927
945
|
}
|
|
946
|
+
function assertForumSignInUsernameChoice(args) {
|
|
947
|
+
const nodeKey = args.nodeKey?.trim() || "";
|
|
948
|
+
const username = args.username?.trim() || "";
|
|
949
|
+
if (username && !FORUM_USERNAME_RE.test(username)) {
|
|
950
|
+
throw new Error(
|
|
951
|
+
"Ask the operator for a forum username of 2\u201316 letters, numbers, periods, underscores, or hyphens. If they want the node-key name, call again with useNodeKeyUsername true and nodeKey set."
|
|
952
|
+
);
|
|
953
|
+
}
|
|
954
|
+
if (!username && !(args.useNodeKeyUsername && nodeKey)) {
|
|
955
|
+
throw new Error(
|
|
956
|
+
"Ask the operator for a custom forum username (2\u201316 letters, numbers, . _ -). If they want the default, call again with useNodeKeyUsername true and nodeKey set. The username will be the first 16 characters of the node key."
|
|
957
|
+
);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
928
960
|
async function continuumDaoForumSignInNonce(args) {
|
|
929
|
-
const
|
|
961
|
+
const qs2 = new URLSearchParams({
|
|
930
962
|
address: args.address,
|
|
931
963
|
nodeKey: args.nodeKey || "",
|
|
932
964
|
username: args.username || ""
|
|
933
965
|
});
|
|
934
|
-
return forumFetch(`/api/continuum/eip712/nonce?${
|
|
966
|
+
return forumFetch(`/api/continuum/eip712/nonce?${qs2}`, { forumUrl: args.forumUrl });
|
|
967
|
+
}
|
|
968
|
+
function forumSignInTypedExpiryUnix(message) {
|
|
969
|
+
const raw = message.expiresAt;
|
|
970
|
+
const n = typeof raw === "number" ? raw : typeof raw === "string" && raw.trim() !== "" ? Number(raw) : NaN;
|
|
971
|
+
if (!Number.isFinite(n) || n <= 0) return void 0;
|
|
972
|
+
return Math.floor(n > 1e12 ? n / 1e3 : n);
|
|
973
|
+
}
|
|
974
|
+
function forumSignInRequestExpiryUnix(message, explicit) {
|
|
975
|
+
const typed = forumSignInTypedExpiryUnix(message);
|
|
976
|
+
const caller = explicit != null && explicit > 0 ? Math.floor(explicit) : void 0;
|
|
977
|
+
if (typed != null && caller != null) return Math.min(typed, caller);
|
|
978
|
+
return typed ?? caller;
|
|
935
979
|
}
|
|
936
980
|
async function buildEvmMultisignBodyContinuumDaoForumSignIn(args) {
|
|
937
981
|
const owner = viem.getAddress(args.executorAddress);
|
|
@@ -941,6 +985,7 @@ async function buildEvmMultisignBodyContinuumDaoForumSignIn(args) {
|
|
|
941
985
|
`${gate.reason || "Address does not meet the veCTM threshold"}. Do not start a multi-sign request.`
|
|
942
986
|
);
|
|
943
987
|
}
|
|
988
|
+
assertForumSignInUsernameChoice(args);
|
|
944
989
|
const typed = await continuumDaoForumSignInNonce({
|
|
945
990
|
address: owner,
|
|
946
991
|
nodeKey: args.nodeKey,
|
|
@@ -969,10 +1014,10 @@ async function buildEvmMultisignBodyContinuumDaoForumSignIn(args) {
|
|
|
969
1014
|
}
|
|
970
1015
|
}
|
|
971
1016
|
],
|
|
972
|
-
expiryDate: args.expiryDate
|
|
1017
|
+
expiryDate: forumSignInRequestExpiryUnix(typed.message, args.expiryDate)
|
|
973
1018
|
});
|
|
974
1019
|
}
|
|
975
|
-
var DEFAULT_FORUM_URL; exports.FORUM_GOVERNANCE_SECTIONS = void 0; exports.FORUM_IDEA_SECTION = void 0; exports.PROPOSAL_TYPE_TO_FORUM_SECTION = void 0; var IDEA_SECTION_ALIASES; exports.FORUM_LOGIN_DELIVERY_KIND = void 0;
|
|
1020
|
+
var DEFAULT_FORUM_URL; exports.FORUM_GOVERNANCE_SECTIONS = void 0; exports.FORUM_IDEA_SECTION = void 0; exports.PROPOSAL_TYPE_TO_FORUM_SECTION = void 0; var IDEA_SECTION_ALIASES; exports.FORUM_LOGIN_DELIVERY_KIND = void 0; var FORUM_USERNAME_RE;
|
|
976
1021
|
var init_forum = __esm({
|
|
977
1022
|
"src/protocols/evm/continuum-dao/forum.ts"() {
|
|
978
1023
|
init_eip712Multisign();
|
|
@@ -994,6 +1039,7 @@ var init_forum = __esm({
|
|
|
994
1039
|
};
|
|
995
1040
|
IDEA_SECTION_ALIASES = /* @__PURE__ */ new Set(["ideas", "ideas-suggestions", "suggestions"]);
|
|
996
1041
|
exports.FORUM_LOGIN_DELIVERY_KIND = "forumLogin";
|
|
1042
|
+
FORUM_USERNAME_RE = /^[A-Za-z0-9._-]{2,16}$/;
|
|
997
1043
|
}
|
|
998
1044
|
});
|
|
999
1045
|
|
|
@@ -2295,9 +2341,9 @@ function parseBackendProposal(raw) {
|
|
|
2295
2341
|
committeeProposer: proposer ? isContinuumDaoCommitteeProposer(proposer) : void 0
|
|
2296
2342
|
};
|
|
2297
2343
|
}
|
|
2298
|
-
function isLegacyContinuumDaoGovernor(
|
|
2299
|
-
if (!
|
|
2300
|
-
return viem.getAddress(
|
|
2344
|
+
function isLegacyContinuumDaoGovernor(addr2) {
|
|
2345
|
+
if (!addr2 || !isConfiguredAddress(addr2)) return false;
|
|
2346
|
+
return viem.getAddress(addr2) === exports.CONTINUUM_DAO_LINEA_GOVERNOR_LEGACY_ADDRESS;
|
|
2301
2347
|
}
|
|
2302
2348
|
function summarizeLiveProposals(result) {
|
|
2303
2349
|
if (result.overlay === "backend-only") {
|
|
@@ -2474,6 +2520,45 @@ function registerProtocolModule(mod) {
|
|
|
2474
2520
|
|
|
2475
2521
|
// src/protocols/evm/continuum-dao/index.ts
|
|
2476
2522
|
init_constants();
|
|
2523
|
+
|
|
2524
|
+
// src/protocols/evm/continuum-dao/marketplaceModule.ts
|
|
2525
|
+
init_constants();
|
|
2526
|
+
var common = ["keyGen", "purposeText", "useCustomGas"];
|
|
2527
|
+
var continuumDaoMarketplaceProtocolModule = {
|
|
2528
|
+
id: exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID,
|
|
2529
|
+
chainCategory: "evm",
|
|
2530
|
+
isChainSupported(ctx) {
|
|
2531
|
+
if (ctx.chainCategory !== "evm") return false;
|
|
2532
|
+
const n = typeof ctx.chainId === "number" ? ctx.chainId : Number.parseInt(String(ctx.chainId), 10);
|
|
2533
|
+
return n === exports.CONTINUUM_DAO_LINEA_CHAIN_ID;
|
|
2534
|
+
},
|
|
2535
|
+
isTokenSupported(token) {
|
|
2536
|
+
return token.category === "evm" && (token.kind === "erc20" || token.kind === "erc721");
|
|
2537
|
+
},
|
|
2538
|
+
actions: [
|
|
2539
|
+
{ id: "continuum-dao-marketplace.fetch-config", protocolId: exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID, chainCategory: "evm", description: "Marketplace payment tokens, durations, and fees", commonParams: [], params: {} },
|
|
2540
|
+
{ id: "continuum-dao-marketplace.search", protocolId: exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID, chainCategory: "evm", description: "Rank veCTMs for sale by price, locked CTM, or unlock time", commonParams: [], params: {} },
|
|
2541
|
+
{ id: "continuum-dao-marketplace.fee-alternative", protocolId: exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID, chainCategory: "evm", description: "One qualifying direct listing beside 12 times the KeyGen monthly fee", commonParams: [], params: {} },
|
|
2542
|
+
{ id: "continuum-dao-marketplace.fetch-listings", protocolId: exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID, chainCategory: "evm", description: "Open listings, or past sales when includeInactive is set", commonParams: [], params: {} },
|
|
2543
|
+
{ id: "continuum-dao-marketplace.fetch-offerings", protocolId: exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID, chainCategory: "evm", description: "Open offerings, or closed offers when includeInactive is set", commonParams: [], params: {} },
|
|
2544
|
+
{ id: "continuum-dao-marketplace.fetch-auctions", protocolId: exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID, chainCategory: "evm", description: "Live auctions, or settled auctions when includeInactive is set. Each row includes bids.", commonParams: [], params: {} },
|
|
2545
|
+
{ id: "continuum-dao-marketplace.fetch-token", protocolId: exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID, chainCategory: "evm", description: "One veCTM: live orders plus history of sales and auctions", commonParams: [], params: { tokenId: { type: "string", required: true, description: "veCTM token id" } } },
|
|
2546
|
+
{ id: "continuum-dao-marketplace.fetch-activity", protocolId: exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID, chainCategory: "evm", description: "An address\u2019s sales, buys, and auctions including bids", commonParams: [], params: { address: { type: "string", required: true, description: "KeyGen or wallet" } } },
|
|
2547
|
+
{ id: "continuum-dao-marketplace.fetch-fee-preview", protocolId: exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID, chainCategory: "evm", description: "Protocol fee for a price and veCTM", commonParams: [], params: {} },
|
|
2548
|
+
{ id: "continuum-dao-marketplace.create-listing", protocolId: exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID, chainCategory: "evm", description: "Approve veCTM if needed and create a listing", commonParams: [...common], params: { tokenId: { type: "string", required: true, description: "veCTM token id" }, askWei: { type: "string", required: true, description: "Ask in payment-token wei" } } },
|
|
2549
|
+
{ id: "continuum-dao-marketplace.delist", protocolId: exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID, chainCategory: "evm", description: "Delist an open listing", commonParams: [...common], params: { tokenId: { type: "string", required: true, description: "veCTM token id" } } },
|
|
2550
|
+
{ id: "continuum-dao-marketplace.fulfill-listing", protocolId: exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID, chainCategory: "evm", description: "Buy a listed veCTM", commonParams: [...common], params: { tokenId: { type: "string", required: true, description: "veCTM token id" } } },
|
|
2551
|
+
{ id: "continuum-dao-marketplace.create-offering", protocolId: exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID, chainCategory: "evm", description: "Make an offering on a veCTM", commonParams: [...common], params: { tokenId: { type: "string", required: true, description: "veCTM token id" } } },
|
|
2552
|
+
{ id: "continuum-dao-marketplace.rescind", protocolId: exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID, chainCategory: "evm", description: "Rescind an open offering", commonParams: [...common], params: { tokenId: { type: "string", required: true, description: "veCTM token id" } } },
|
|
2553
|
+
{ id: "continuum-dao-marketplace.fulfill-offering", protocolId: exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID, chainCategory: "evm", description: "Accept an offering on a veCTM you own", commonParams: [...common], params: { tokenId: { type: "string", required: true, description: "veCTM token id" } } },
|
|
2554
|
+
{ id: "continuum-dao-marketplace.create-auction", protocolId: exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID, chainCategory: "evm", description: "Escrow a veCTM into an auction", commonParams: [...common], params: { tokenId: { type: "string", required: true, description: "veCTM token id" } } },
|
|
2555
|
+
{ id: "continuum-dao-marketplace.cancel-auction", protocolId: exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID, chainCategory: "evm", description: "Cancel a pending auction with no bids", commonParams: [...common], params: { tokenId: { type: "string", required: true, description: "veCTM token id" } } },
|
|
2556
|
+
{ id: "continuum-dao-marketplace.auction-bid", protocolId: exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID, chainCategory: "evm", description: "Bid on a live auction", commonParams: [...common], params: { tokenId: { type: "string", required: true, description: "veCTM token id" } } },
|
|
2557
|
+
{ id: "continuum-dao-marketplace.settle-auction", protocolId: exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID, chainCategory: "evm", description: "Settle a completed or expired auction", commonParams: [...common], params: { tokenId: { type: "string", required: true, description: "veCTM token id" } } }
|
|
2558
|
+
]
|
|
2559
|
+
};
|
|
2560
|
+
|
|
2561
|
+
// src/protocols/evm/continuum-dao/index.ts
|
|
2477
2562
|
init_constants();
|
|
2478
2563
|
|
|
2479
2564
|
// src/protocols/evm/continuum-dao/escrowRules.ts
|
|
@@ -2769,13 +2854,13 @@ async function readVeCtmLockState(args) {
|
|
|
2769
2854
|
let attached = false;
|
|
2770
2855
|
if (isConfiguredAddress(nodeProperties)) {
|
|
2771
2856
|
try {
|
|
2772
|
-
const
|
|
2857
|
+
const attachedKey2 = await client.readContract({
|
|
2773
2858
|
address: viem.getAddress(nodeProperties),
|
|
2774
2859
|
abi: nodePropsAbi,
|
|
2775
2860
|
functionName: "attachedKeyGen",
|
|
2776
2861
|
args: [args.tokenId]
|
|
2777
2862
|
});
|
|
2778
|
-
attached =
|
|
2863
|
+
attached = attachedKey2 !== viem.zeroAddress;
|
|
2779
2864
|
} catch {
|
|
2780
2865
|
attached = false;
|
|
2781
2866
|
}
|
|
@@ -2943,7 +3028,7 @@ async function preflightAttachVeCtm(args) {
|
|
|
2943
3028
|
}
|
|
2944
3029
|
if (isConfiguredAddress(nodeProperties)) {
|
|
2945
3030
|
const np = viem.getAddress(nodeProperties);
|
|
2946
|
-
const [
|
|
3031
|
+
const [attachedKey2, attachedForKey] = await Promise.all([
|
|
2947
3032
|
client.readContract({
|
|
2948
3033
|
address: np,
|
|
2949
3034
|
abi: nodePropsAbi,
|
|
@@ -2957,7 +3042,7 @@ async function preflightAttachVeCtm(args) {
|
|
|
2957
3042
|
args: [executor]
|
|
2958
3043
|
})
|
|
2959
3044
|
]);
|
|
2960
|
-
if (
|
|
3045
|
+
if (attachedKey2 !== viem.zeroAddress) {
|
|
2961
3046
|
throw new Error(`veCTM #${args.tokenId} is already attached. You cannot replace an attached NFT.`);
|
|
2962
3047
|
}
|
|
2963
3048
|
if (attachedForKey !== 0n) {
|
|
@@ -2974,7 +3059,7 @@ async function preflightAttachVeCtm(args) {
|
|
|
2974
3059
|
}
|
|
2975
3060
|
async function preflightRequestDetach(args) {
|
|
2976
3061
|
const client = publicClient(args.rpcUrl, args.chainId);
|
|
2977
|
-
const [
|
|
3062
|
+
const [attachedKey2, alreadyRequested] = await Promise.all([
|
|
2978
3063
|
client.readContract({
|
|
2979
3064
|
address: args.nodeProperties,
|
|
2980
3065
|
abi: nodePropsAbi,
|
|
@@ -2988,7 +3073,7 @@ async function preflightRequestDetach(args) {
|
|
|
2988
3073
|
args: [args.tokenId]
|
|
2989
3074
|
})
|
|
2990
3075
|
]);
|
|
2991
|
-
if (
|
|
3076
|
+
if (attachedKey2 === viem.zeroAddress) {
|
|
2992
3077
|
throw new Error(`veCTM #${args.tokenId} is not attached to a node.`);
|
|
2993
3078
|
}
|
|
2994
3079
|
if (alreadyRequested) {
|
|
@@ -2996,9 +3081,9 @@ async function preflightRequestDetach(args) {
|
|
|
2996
3081
|
`Detach already requested for veCTM #${args.tokenId}. The NFT stays attached until governance executes detach.`
|
|
2997
3082
|
);
|
|
2998
3083
|
}
|
|
2999
|
-
if (viem.getAddress(
|
|
3084
|
+
if (viem.getAddress(attachedKey2) !== viem.getAddress(args.owner)) {
|
|
3000
3085
|
throw new Error(
|
|
3001
|
-
`Request detach from the attached KeyGen (${viem.getAddress(
|
|
3086
|
+
`Request detach from the attached KeyGen (${viem.getAddress(attachedKey2)}).`
|
|
3002
3087
|
);
|
|
3003
3088
|
}
|
|
3004
3089
|
}
|
|
@@ -3852,8 +3937,8 @@ function extractAbiFromSourcifyFiles(data) {
|
|
|
3852
3937
|
if (!label.includes("metadata.json") && f.name !== "metadata.json") continue;
|
|
3853
3938
|
if (typeof f.content !== "string") continue;
|
|
3854
3939
|
try {
|
|
3855
|
-
const
|
|
3856
|
-
const abi = extractAbiFromUnknown(
|
|
3940
|
+
const meta4 = JSON.parse(f.content);
|
|
3941
|
+
const abi = extractAbiFromUnknown(meta4);
|
|
3857
3942
|
if (abi) return abi;
|
|
3858
3943
|
} catch {
|
|
3859
3944
|
continue;
|
|
@@ -4713,6 +4798,2112 @@ async function continuumDaoFetchProposalVotes(args, deps) {
|
|
|
4713
4798
|
|
|
4714
4799
|
// src/protocols/evm/continuum-dao/index.ts
|
|
4715
4800
|
init_forum();
|
|
4801
|
+
|
|
4802
|
+
// src/protocols/evm/continuum-dao/marketplaceTypes.ts
|
|
4803
|
+
var MARKET_ORDER_STATUS = [
|
|
4804
|
+
"NonExistent",
|
|
4805
|
+
"Open",
|
|
4806
|
+
"Fulfilled",
|
|
4807
|
+
"Expired",
|
|
4808
|
+
"DelistedOrRescinded",
|
|
4809
|
+
"LockAmountDecreased",
|
|
4810
|
+
"LockEndIncreased",
|
|
4811
|
+
"TokenApprovalRequired",
|
|
4812
|
+
"PaymentApprovalRequired",
|
|
4813
|
+
"KeyGenAttached"
|
|
4814
|
+
];
|
|
4815
|
+
var AUCTION_STATUS = [
|
|
4816
|
+
"NonExistent",
|
|
4817
|
+
"Pending",
|
|
4818
|
+
"Active",
|
|
4819
|
+
"Complete",
|
|
4820
|
+
"Sold",
|
|
4821
|
+
"Canceled",
|
|
4822
|
+
"Expired"
|
|
4823
|
+
];
|
|
4824
|
+
var FEE_TIER_NAMES = ["Black", "Gold", "Silver", "Bronze", "Blue"];
|
|
4825
|
+
function orderStatusName(code) {
|
|
4826
|
+
return MARKET_ORDER_STATUS[code] ?? "NonExistent";
|
|
4827
|
+
}
|
|
4828
|
+
function auctionStatusName(code) {
|
|
4829
|
+
return AUCTION_STATUS[code] ?? "NonExistent";
|
|
4830
|
+
}
|
|
4831
|
+
function addr(value) {
|
|
4832
|
+
try {
|
|
4833
|
+
return viem.getAddress(value);
|
|
4834
|
+
} catch {
|
|
4835
|
+
return value;
|
|
4836
|
+
}
|
|
4837
|
+
}
|
|
4838
|
+
function same(a, b) {
|
|
4839
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
4840
|
+
}
|
|
4841
|
+
function deadlineAt(unix) {
|
|
4842
|
+
const n = Number(unix);
|
|
4843
|
+
if (!Number.isFinite(n) || n <= 0) return "";
|
|
4844
|
+
return new Date(n * 1e3).toISOString();
|
|
4845
|
+
}
|
|
4846
|
+
function blankOrder(kind, tokenId, creator, index) {
|
|
4847
|
+
return {
|
|
4848
|
+
kind,
|
|
4849
|
+
tokenId,
|
|
4850
|
+
onchainIndex: index,
|
|
4851
|
+
creator: addr(creator),
|
|
4852
|
+
paymentToken: viem.zeroAddress,
|
|
4853
|
+
price: "0",
|
|
4854
|
+
deadlineUnix: "0",
|
|
4855
|
+
deadlineAt: "",
|
|
4856
|
+
snapshotAmount: "0",
|
|
4857
|
+
snapshotEnd: "0",
|
|
4858
|
+
storedStatus: "Open",
|
|
4859
|
+
protocolStatus: "Open"
|
|
4860
|
+
};
|
|
4861
|
+
}
|
|
4862
|
+
function blankAuction(tokenId, seller, index) {
|
|
4863
|
+
return {
|
|
4864
|
+
tokenId,
|
|
4865
|
+
onchainIndex: index,
|
|
4866
|
+
seller: addr(seller),
|
|
4867
|
+
paymentToken: viem.zeroAddress,
|
|
4868
|
+
reservePrice: "0",
|
|
4869
|
+
minimumBidIncrement: "0",
|
|
4870
|
+
highestBid: "0",
|
|
4871
|
+
highestBidder: null,
|
|
4872
|
+
deadlineUnix: "0",
|
|
4873
|
+
deadlineAt: "",
|
|
4874
|
+
storedStatus: "Pending",
|
|
4875
|
+
derivedStatus: "Pending",
|
|
4876
|
+
needsSettle: false,
|
|
4877
|
+
bids: []
|
|
4878
|
+
};
|
|
4879
|
+
}
|
|
4880
|
+
function latestOpenOrder(rows, kind, tokenId, creator) {
|
|
4881
|
+
for (let i = rows.length - 1; i >= 0; i--) {
|
|
4882
|
+
const row = rows[i];
|
|
4883
|
+
if (row.kind === kind && row.tokenId === tokenId && same(row.creator, creator) && row.storedStatus === "Open") {
|
|
4884
|
+
return row;
|
|
4885
|
+
}
|
|
4886
|
+
}
|
|
4887
|
+
return void 0;
|
|
4888
|
+
}
|
|
4889
|
+
function latestAuction(rows, tokenId, seller) {
|
|
4890
|
+
for (let i = rows.length - 1; i >= 0; i--) {
|
|
4891
|
+
const row = rows[i];
|
|
4892
|
+
if (row.tokenId === tokenId && same(row.seller, seller)) return row;
|
|
4893
|
+
}
|
|
4894
|
+
return void 0;
|
|
4895
|
+
}
|
|
4896
|
+
function applyMarketplaceEvent(book, ev) {
|
|
4897
|
+
const listingSeq = book.listings.reduce((max, row) => Math.max(max, Number(row.onchainIndex) || 0), 0);
|
|
4898
|
+
const offeringSeq = book.offerings.reduce((max, row) => Math.max(max, Number(row.onchainIndex) || 0), 0);
|
|
4899
|
+
const auctionSeq = book.auctions.reduce((max, row) => Math.max(max, Number(row.onchainIndex) || 0), 0);
|
|
4900
|
+
const next = (seq) => String(seq + 1);
|
|
4901
|
+
if (ev.name === "ListingCreated" || ev.name === "OfferingCreated") {
|
|
4902
|
+
const kind = ev.name === "ListingCreated" ? "Listing" : "Offering";
|
|
4903
|
+
const rows = kind === "Listing" ? book.listings : book.offerings;
|
|
4904
|
+
const prev = latestOpenOrder(rows, kind, ev.tokenId, ev.actor);
|
|
4905
|
+
if (prev) {
|
|
4906
|
+
prev.storedStatus = "DelistedOrRescinded";
|
|
4907
|
+
prev.protocolStatus = "DelistedOrRescinded";
|
|
4908
|
+
prev.closedTx = ev.tx;
|
|
4909
|
+
prev.closedBlock = ev.block;
|
|
4910
|
+
}
|
|
4911
|
+
const row = blankOrder(kind, ev.tokenId, ev.actor, next(kind === "Listing" ? listingSeq : offeringSeq));
|
|
4912
|
+
row.paymentToken = addr(ev.paymentToken);
|
|
4913
|
+
row.price = ev.amount;
|
|
4914
|
+
row.deadlineUnix = ev.deadline;
|
|
4915
|
+
row.deadlineAt = deadlineAt(ev.deadline);
|
|
4916
|
+
row.createdTx = ev.tx;
|
|
4917
|
+
row.createdBlock = ev.block;
|
|
4918
|
+
if (kind === "Listing") row.seller = addr(ev.actor);
|
|
4919
|
+
else row.buyer = addr(ev.actor);
|
|
4920
|
+
rows.push(row);
|
|
4921
|
+
return;
|
|
4922
|
+
}
|
|
4923
|
+
if (ev.name === "Delisted" || ev.name === "Rescinded") {
|
|
4924
|
+
const kind = ev.name === "Delisted" ? "Listing" : "Offering";
|
|
4925
|
+
const row = latestOpenOrder(kind === "Listing" ? book.listings : book.offerings, kind, ev.tokenId, ev.actor);
|
|
4926
|
+
if (row) {
|
|
4927
|
+
row.storedStatus = "DelistedOrRescinded";
|
|
4928
|
+
row.protocolStatus = "DelistedOrRescinded";
|
|
4929
|
+
row.closedTx = ev.tx;
|
|
4930
|
+
row.closedBlock = ev.block;
|
|
4931
|
+
}
|
|
4932
|
+
return;
|
|
4933
|
+
}
|
|
4934
|
+
if (ev.name === "ListingFulfilled" || ev.name === "OfferingFulfilled") {
|
|
4935
|
+
const kind = ev.name === "ListingFulfilled" ? "Listing" : "Offering";
|
|
4936
|
+
const actor = kind === "Listing" ? ev.seller : ev.buyer;
|
|
4937
|
+
const row = latestOpenOrder(kind === "Listing" ? book.listings : book.offerings, kind, ev.tokenId, actor);
|
|
4938
|
+
if (row) {
|
|
4939
|
+
row.storedStatus = "Fulfilled";
|
|
4940
|
+
row.protocolStatus = "Fulfilled";
|
|
4941
|
+
row.counterparty = addr(kind === "Listing" ? ev.buyer : ev.seller);
|
|
4942
|
+
row.seller = addr(ev.seller);
|
|
4943
|
+
row.buyer = addr(ev.buyer);
|
|
4944
|
+
row.fee = ev.fee;
|
|
4945
|
+
row.net = ev.net;
|
|
4946
|
+
row.closedTx = ev.tx;
|
|
4947
|
+
row.closedBlock = ev.block;
|
|
4948
|
+
}
|
|
4949
|
+
return;
|
|
4950
|
+
}
|
|
4951
|
+
if (ev.name === "AuctionCreated") {
|
|
4952
|
+
const prev = latestAuction(book.auctions, ev.tokenId, ev.actor);
|
|
4953
|
+
if (prev && (prev.storedStatus === "Pending" || prev.storedStatus === "Active")) {
|
|
4954
|
+
prev.storedStatus = "Canceled";
|
|
4955
|
+
prev.derivedStatus = "Canceled";
|
|
4956
|
+
prev.closedTx = ev.tx;
|
|
4957
|
+
prev.closedBlock = ev.block;
|
|
4958
|
+
}
|
|
4959
|
+
const row = blankAuction(ev.tokenId, ev.actor, next(auctionSeq));
|
|
4960
|
+
row.paymentToken = addr(ev.paymentToken);
|
|
4961
|
+
row.reservePrice = ev.amount;
|
|
4962
|
+
row.minimumBidIncrement = ev.minIncrement;
|
|
4963
|
+
row.deadlineUnix = ev.deadline;
|
|
4964
|
+
row.deadlineAt = deadlineAt(ev.deadline);
|
|
4965
|
+
row.createdTx = ev.tx;
|
|
4966
|
+
row.createdBlock = ev.block;
|
|
4967
|
+
book.auctions.push(row);
|
|
4968
|
+
return;
|
|
4969
|
+
}
|
|
4970
|
+
if (ev.name === "AuctionCanceled") {
|
|
4971
|
+
const row = latestAuction(book.auctions, ev.tokenId, ev.actor);
|
|
4972
|
+
if (row && row.storedStatus === "Pending") {
|
|
4973
|
+
row.storedStatus = "Canceled";
|
|
4974
|
+
row.derivedStatus = "Canceled";
|
|
4975
|
+
row.closedTx = ev.tx;
|
|
4976
|
+
row.closedBlock = ev.block;
|
|
4977
|
+
}
|
|
4978
|
+
return;
|
|
4979
|
+
}
|
|
4980
|
+
if (ev.name === "AuctionBid") {
|
|
4981
|
+
const row = latestAuction(book.auctions, ev.tokenId, ev.seller);
|
|
4982
|
+
if (!row || row.storedStatus !== "Pending" && row.storedStatus !== "Active") return;
|
|
4983
|
+
row.bids = [
|
|
4984
|
+
...row.bids,
|
|
4985
|
+
{
|
|
4986
|
+
bidder: addr(ev.buyer),
|
|
4987
|
+
price: ev.price,
|
|
4988
|
+
tx: ev.tx,
|
|
4989
|
+
timestamp: ev.timestamp ?? "0",
|
|
4990
|
+
logIndex: String(ev.logIndex),
|
|
4991
|
+
block: ev.block
|
|
4992
|
+
}
|
|
4993
|
+
];
|
|
4994
|
+
row.highestBid = ev.price;
|
|
4995
|
+
row.highestBidder = addr(ev.buyer);
|
|
4996
|
+
row.storedStatus = "Active";
|
|
4997
|
+
row.derivedStatus = "Active";
|
|
4998
|
+
return;
|
|
4999
|
+
}
|
|
5000
|
+
if (ev.name === "AuctionSettled") {
|
|
5001
|
+
const row = latestAuction(book.auctions, ev.tokenId, ev.seller);
|
|
5002
|
+
if (!row) return;
|
|
5003
|
+
const name = auctionStatusName(ev.finalStatus);
|
|
5004
|
+
row.storedStatus = name;
|
|
5005
|
+
row.derivedStatus = name;
|
|
5006
|
+
row.needsSettle = false;
|
|
5007
|
+
row.closedTx = ev.tx;
|
|
5008
|
+
row.closedBlock = ev.block;
|
|
5009
|
+
return;
|
|
5010
|
+
}
|
|
5011
|
+
if (ev.name === "AuctionSuccessful") {
|
|
5012
|
+
const row = latestAuction(book.auctions, ev.tokenId, ev.seller);
|
|
5013
|
+
if (!row) return;
|
|
5014
|
+
row.storedStatus = "Sold";
|
|
5015
|
+
row.derivedStatus = "Sold";
|
|
5016
|
+
row.buyer = addr(ev.buyer);
|
|
5017
|
+
row.highestBidder = addr(ev.buyer);
|
|
5018
|
+
row.highestBid = ev.price;
|
|
5019
|
+
row.fee = ev.fee;
|
|
5020
|
+
row.net = ev.net;
|
|
5021
|
+
row.needsSettle = false;
|
|
5022
|
+
row.closedTx = ev.tx;
|
|
5023
|
+
row.closedBlock = ev.block;
|
|
5024
|
+
}
|
|
5025
|
+
}
|
|
5026
|
+
function foldMarketplaceEvents(events, initial) {
|
|
5027
|
+
const book = {
|
|
5028
|
+
listings: [...initial?.listings ?? []],
|
|
5029
|
+
offerings: [...initial?.offerings ?? []],
|
|
5030
|
+
auctions: (initial?.auctions ?? []).map((row) => ({ ...row, bids: [...row.bids] }))
|
|
5031
|
+
};
|
|
5032
|
+
for (const ev of events) applyMarketplaceEvent(book, ev);
|
|
5033
|
+
return book;
|
|
5034
|
+
}
|
|
5035
|
+
function deriveAuctionStatus(auction, nowUnix) {
|
|
5036
|
+
const deadline = Number(auction.deadlineUnix);
|
|
5037
|
+
if (auction.storedStatus === "Pending" && Number.isFinite(deadline) && nowUnix >= deadline) return "Expired";
|
|
5038
|
+
if (auction.storedStatus === "Active" && Number.isFinite(deadline) && nowUnix >= deadline) return "Complete";
|
|
5039
|
+
return auction.derivedStatus || auction.storedStatus;
|
|
5040
|
+
}
|
|
5041
|
+
function applyDerivedStatuses(book, nowUnix) {
|
|
5042
|
+
return {
|
|
5043
|
+
listings: book.listings.map((row) => {
|
|
5044
|
+
const deadline = Number(row.deadlineUnix);
|
|
5045
|
+
if (row.storedStatus === "Open" && Number.isFinite(deadline) && nowUnix >= deadline) {
|
|
5046
|
+
return { ...row, protocolStatus: "Expired" };
|
|
5047
|
+
}
|
|
5048
|
+
return row;
|
|
5049
|
+
}),
|
|
5050
|
+
offerings: book.offerings.map((row) => {
|
|
5051
|
+
const deadline = Number(row.deadlineUnix);
|
|
5052
|
+
if (row.storedStatus === "Open" && Number.isFinite(deadline) && nowUnix >= deadline) {
|
|
5053
|
+
return { ...row, protocolStatus: "Expired" };
|
|
5054
|
+
}
|
|
5055
|
+
return row;
|
|
5056
|
+
}),
|
|
5057
|
+
auctions: book.auctions.map((row) => {
|
|
5058
|
+
const derived = deriveAuctionStatus(row, nowUnix);
|
|
5059
|
+
const needsSettle = derived === "Complete" || derived === "Expired";
|
|
5060
|
+
return { ...row, derivedStatus: derived, needsSettle };
|
|
5061
|
+
})
|
|
5062
|
+
};
|
|
5063
|
+
}
|
|
5064
|
+
function isLiveAuctionStatus(status) {
|
|
5065
|
+
return status === "Pending" || status === "Active" || status === "Complete";
|
|
5066
|
+
}
|
|
5067
|
+
function isOpenOrder(row) {
|
|
5068
|
+
return row.storedStatus === "Open" && row.protocolStatus === "Open";
|
|
5069
|
+
}
|
|
5070
|
+
var marketplaceAbi = viem.parseAbi([
|
|
5071
|
+
"function weth() view returns (address)",
|
|
5072
|
+
"function ve() view returns (address)",
|
|
5073
|
+
"function np() view returns (address)",
|
|
5074
|
+
"function gov() view returns (address)",
|
|
5075
|
+
"function minimumDuration() view returns (uint256)",
|
|
5076
|
+
"function maximumDuration() view returns (uint256)",
|
|
5077
|
+
"function isValidPaymentToken(address) view returns (bool)",
|
|
5078
|
+
"function feeLimitByTier(uint8) view returns (uint256)",
|
|
5079
|
+
"function feeRateByTier(uint8) view returns (uint256)",
|
|
5080
|
+
"function listingIndexByTokenSeller(uint256,address) view returns (uint256)",
|
|
5081
|
+
"function listingsByToken(uint256,uint256) view returns (uint256 price, uint256 deadline, uint256 snapshotAmount, uint256 snapshotEnd, address creator, address paymentToken, uint8 status, uint8 kind)",
|
|
5082
|
+
"function offeringIndexByTokenBuyer(uint256,address) view returns (uint256)",
|
|
5083
|
+
"function offeringsByToken(uint256,uint256) view returns (uint256 price, uint256 deadline, uint256 snapshotAmount, uint256 snapshotEnd, address creator, address paymentToken, uint8 status, uint8 kind)",
|
|
5084
|
+
"function auctionIndexByTokenSeller(uint256,address) view returns (uint256)",
|
|
5085
|
+
"function auctionsByToken(uint256,uint256) view returns (uint256 reservePrice, uint256 minimumBidIncrement, uint256 deadline, address seller, address paymentToken, address highestBidder, uint256 highestBid, uint8 status)",
|
|
5086
|
+
"function marketOrderStatus((uint256,uint256,uint256,uint256,address,address,uint8,uint8),uint256,uint256,address,uint256) view returns (uint8)",
|
|
5087
|
+
"function auctionStatus((uint256,uint256,uint256,address,address,address,uint256,uint8)) view returns (uint8)",
|
|
5088
|
+
"function createListing(uint256,address,uint256,uint256)",
|
|
5089
|
+
"function delist(uint256)",
|
|
5090
|
+
"function fulfillListing(uint256,address,address,uint256) payable",
|
|
5091
|
+
"function createOffering(uint256,address,uint256,uint256) payable",
|
|
5092
|
+
"function rescind(uint256)",
|
|
5093
|
+
"function fulfillOffering(uint256,address,address,uint256)",
|
|
5094
|
+
"function createAuction(uint256,address,uint256,uint256,uint256)",
|
|
5095
|
+
"function cancelAuction(uint256)",
|
|
5096
|
+
"function auctionBid(uint256,address,uint256) payable",
|
|
5097
|
+
"function settleAuction(uint256,address)",
|
|
5098
|
+
"event ListingCreated(uint256 indexed _tokenId, address indexed _listedBy, address indexed _paymentToken, uint256 _ask, uint256 _deadline)",
|
|
5099
|
+
"event ListingFulfilled(uint256 indexed _tokenId, address indexed _buyer, address indexed _seller, uint256 _ask, uint256 _netPrice, uint256 _fee)",
|
|
5100
|
+
"event Delisted(uint256 indexed _tokenId, address indexed _seller)",
|
|
5101
|
+
"event OfferingCreated(uint256 indexed _tokenId, address indexed _offeredBy, address indexed _paymentToken, uint256 _bid, uint256 _deadline)",
|
|
5102
|
+
"event OfferingFulfilled(uint256 indexed _tokenId, address indexed _buyer, address indexed _seller, uint256 _bid, uint256 _netPrice, uint256 _fee)",
|
|
5103
|
+
"event Rescinded(uint256 indexed _tokenId, address indexed _buyer)",
|
|
5104
|
+
"event AuctionCreated(uint256 indexed _tokenId, address indexed _createdBy, address indexed _paymentToken, uint256 _reservePrice, uint256 _minimumBidIncrement, uint256 _deadline)",
|
|
5105
|
+
"event AuctionCanceled(uint256 indexed _tokenId, address indexed _seller)",
|
|
5106
|
+
"event AuctionBid(uint256 indexed _tokenId, address indexed _seller, address indexed _buyer, uint256 _price)",
|
|
5107
|
+
"event AuctionSettled(uint256 indexed _tokenId, address indexed _seller, uint8 indexed _finalStatus)",
|
|
5108
|
+
"event AuctionSuccessful(uint256 indexed _tokenId, address indexed _seller, address indexed _buyer, uint256 _price, uint256 _fee, uint256 _net)"
|
|
5109
|
+
]);
|
|
5110
|
+
var marketplaceReadAbi = viem.parseAbi([
|
|
5111
|
+
"function ownerOf(uint256) view returns (address)",
|
|
5112
|
+
"function getApproved(uint256) view returns (address)",
|
|
5113
|
+
"function isApprovedForAll(address,address) view returns (bool)",
|
|
5114
|
+
"function approve(address,uint256)",
|
|
5115
|
+
"function locked(uint256) view returns (int128 amount, uint256 end)",
|
|
5116
|
+
"function allowance(address,address) view returns (uint256)",
|
|
5117
|
+
"function decimals() view returns (uint8)",
|
|
5118
|
+
"function symbol() view returns (string)",
|
|
5119
|
+
"function attachedKeyGen(uint256) view returns (address)"
|
|
5120
|
+
]);
|
|
5121
|
+
|
|
5122
|
+
// src/protocols/evm/continuum-dao/marketplacePlan.ts
|
|
5123
|
+
var MARKETPLACE_APPROVE_FALLBACK = 80000n;
|
|
5124
|
+
var MARKETPLACE_LISTING_FALLBACK = 280000n;
|
|
5125
|
+
var MARKETPLACE_FULFILL_FALLBACK = 450000n;
|
|
5126
|
+
var MARKETPLACE_OFFERING_FALLBACK = 320000n;
|
|
5127
|
+
var MARKETPLACE_AUCTION_CREATE_FALLBACK = 380000n;
|
|
5128
|
+
var MARKETPLACE_BID_FALLBACK = 280000n;
|
|
5129
|
+
var MARKETPLACE_SETTLE_FALLBACK = 400000n;
|
|
5130
|
+
function same2(a, b) {
|
|
5131
|
+
try {
|
|
5132
|
+
return viem.getAddress(a) === viem.getAddress(b);
|
|
5133
|
+
} catch {
|
|
5134
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
5135
|
+
}
|
|
5136
|
+
}
|
|
5137
|
+
function isWeth(snap, token) {
|
|
5138
|
+
return same2(token, snap.weth);
|
|
5139
|
+
}
|
|
5140
|
+
function keyGenOwnsVeCtm(snap, seller) {
|
|
5141
|
+
if (same2(snap.owner, snap.executor)) return true;
|
|
5142
|
+
if (seller && same2(seller, snap.executor)) return true;
|
|
5143
|
+
if (snap.executorOpenListing && same2(snap.owner, snap.executor)) return true;
|
|
5144
|
+
if (snap.executorLiveAuction) return true;
|
|
5145
|
+
return false;
|
|
5146
|
+
}
|
|
5147
|
+
function assertNotOwn(snap, seller, tokenId) {
|
|
5148
|
+
if (same2(snap.owner, snap.executor) || seller && same2(seller, snap.executor) || snap.executorLiveAuction) {
|
|
5149
|
+
throw new Error(`This KeyGen already owns veCTM #${tokenId.toString()} and cannot buy or bid on it.`);
|
|
5150
|
+
}
|
|
5151
|
+
}
|
|
5152
|
+
function assertDeadline(snap, deadline) {
|
|
5153
|
+
const min = snap.now + snap.minimumDuration;
|
|
5154
|
+
const max = snap.now + snap.maximumDuration;
|
|
5155
|
+
if (deadline < min || deadline > max) {
|
|
5156
|
+
throw new Error(`Deadline must be between ${min.toString()} and ${max.toString()} (unix seconds).`);
|
|
5157
|
+
}
|
|
5158
|
+
}
|
|
5159
|
+
function assertPayment(snap) {
|
|
5160
|
+
if (!snap.paymentTokenValid) throw new Error("This payment token is not accepted by the marketplace.");
|
|
5161
|
+
}
|
|
5162
|
+
function assertNotAttached(snap, tokenId) {
|
|
5163
|
+
if (snap.attachedKeyGen !== viem.zeroAddress) {
|
|
5164
|
+
throw new Error(`veCTM #${tokenId.toString()} has a KeyGen attached.`);
|
|
5165
|
+
}
|
|
5166
|
+
}
|
|
5167
|
+
function nftApproveStep(snap, tokenId) {
|
|
5168
|
+
if (snap.nftApproved) return null;
|
|
5169
|
+
return {
|
|
5170
|
+
to: snap.votingEscrow,
|
|
5171
|
+
data: viem.encodeFunctionData({
|
|
5172
|
+
abi: marketplaceReadAbi,
|
|
5173
|
+
functionName: "approve",
|
|
5174
|
+
args: [snap.marketplace, tokenId]
|
|
5175
|
+
}),
|
|
5176
|
+
value: 0n,
|
|
5177
|
+
fallbackGas: MARKETPLACE_APPROVE_FALLBACK,
|
|
5178
|
+
evmType: "continuum_dao_marketplace_nft_approve",
|
|
5179
|
+
name: "VotingEscrow.approve",
|
|
5180
|
+
extra: { tokenId: tokenId.toString(), operator: snap.marketplace }
|
|
5181
|
+
};
|
|
5182
|
+
}
|
|
5183
|
+
function parseApproveAbi() {
|
|
5184
|
+
return [
|
|
5185
|
+
{
|
|
5186
|
+
type: "function",
|
|
5187
|
+
name: "approve",
|
|
5188
|
+
stateMutability: "nonpayable",
|
|
5189
|
+
inputs: [
|
|
5190
|
+
{ name: "spender", type: "address" },
|
|
5191
|
+
{ name: "amount", type: "uint256" }
|
|
5192
|
+
],
|
|
5193
|
+
outputs: [{ name: "", type: "bool" }]
|
|
5194
|
+
}
|
|
5195
|
+
];
|
|
5196
|
+
}
|
|
5197
|
+
function erc20Approve(snap, token, amount) {
|
|
5198
|
+
if (snap.allowance >= amount) return null;
|
|
5199
|
+
return {
|
|
5200
|
+
to: token,
|
|
5201
|
+
data: viem.encodeFunctionData({
|
|
5202
|
+
abi: parseApproveAbi(),
|
|
5203
|
+
functionName: "approve",
|
|
5204
|
+
args: [snap.marketplace, amount]
|
|
5205
|
+
}),
|
|
5206
|
+
value: 0n,
|
|
5207
|
+
fallbackGas: MARKETPLACE_APPROVE_FALLBACK,
|
|
5208
|
+
evmType: "continuum_dao_marketplace_approve",
|
|
5209
|
+
name: "ERC20.approve",
|
|
5210
|
+
extra: { spender: snap.marketplace, amountWei: amount.toString(), token }
|
|
5211
|
+
};
|
|
5212
|
+
}
|
|
5213
|
+
function withApprovals(steps) {
|
|
5214
|
+
return steps.filter((s) => s != null);
|
|
5215
|
+
}
|
|
5216
|
+
function planMarketplaceSteps(input, snap) {
|
|
5217
|
+
const m = snap.marketplace;
|
|
5218
|
+
switch (input.action) {
|
|
5219
|
+
case "createListing": {
|
|
5220
|
+
assertPayment(snap);
|
|
5221
|
+
assertDeadline(snap, input.deadline);
|
|
5222
|
+
if (!same2(snap.owner, snap.executor)) throw new Error("Only the veCTM owner can create a listing.");
|
|
5223
|
+
return withApprovals([
|
|
5224
|
+
nftApproveStep(snap, input.tokenId),
|
|
5225
|
+
{
|
|
5226
|
+
to: m,
|
|
5227
|
+
data: viem.encodeFunctionData({
|
|
5228
|
+
abi: marketplaceAbi,
|
|
5229
|
+
functionName: "createListing",
|
|
5230
|
+
args: [input.tokenId, input.paymentToken, input.askWei, input.deadline]
|
|
5231
|
+
}),
|
|
5232
|
+
value: 0n,
|
|
5233
|
+
fallbackGas: MARKETPLACE_LISTING_FALLBACK,
|
|
5234
|
+
evmType: "continuum_dao_marketplace_create_listing",
|
|
5235
|
+
name: "VotingEscrowMarketplace.createListing",
|
|
5236
|
+
extra: {
|
|
5237
|
+
tokenId: input.tokenId.toString(),
|
|
5238
|
+
paymentToken: input.paymentToken,
|
|
5239
|
+
askWei: input.askWei.toString(),
|
|
5240
|
+
deadline: input.deadline.toString()
|
|
5241
|
+
}
|
|
5242
|
+
}
|
|
5243
|
+
]);
|
|
5244
|
+
}
|
|
5245
|
+
case "delist": {
|
|
5246
|
+
if (!snap.listing || snap.listing.status !== 1) throw new Error("No open listing for this KeyGen.");
|
|
5247
|
+
return [
|
|
5248
|
+
{
|
|
5249
|
+
to: m,
|
|
5250
|
+
data: viem.encodeFunctionData({ abi: marketplaceAbi, functionName: "delist", args: [input.tokenId] }),
|
|
5251
|
+
value: 0n,
|
|
5252
|
+
fallbackGas: MARKETPLACE_LISTING_FALLBACK,
|
|
5253
|
+
evmType: "continuum_dao_marketplace_delist",
|
|
5254
|
+
name: "VotingEscrowMarketplace.delist",
|
|
5255
|
+
extra: { tokenId: input.tokenId.toString() }
|
|
5256
|
+
}
|
|
5257
|
+
];
|
|
5258
|
+
}
|
|
5259
|
+
case "fulfillListing": {
|
|
5260
|
+
assertNotOwn(snap, input.seller, input.tokenId);
|
|
5261
|
+
const listing = snap.listing;
|
|
5262
|
+
if (!listing || !same2(listing.creator, input.seller)) throw new Error("No open listing for this seller.");
|
|
5263
|
+
if (!same2(listing.paymentToken, input.paymentToken) || listing.price !== input.priceWei) {
|
|
5264
|
+
throw new Error("Listing price or payment token changed. Refresh and try again.");
|
|
5265
|
+
}
|
|
5266
|
+
const weth = isWeth(snap, listing.paymentToken);
|
|
5267
|
+
return withApprovals([
|
|
5268
|
+
weth ? null : erc20Approve(snap, listing.paymentToken, listing.price),
|
|
5269
|
+
{
|
|
5270
|
+
to: m,
|
|
5271
|
+
data: viem.encodeFunctionData({
|
|
5272
|
+
abi: marketplaceAbi,
|
|
5273
|
+
functionName: "fulfillListing",
|
|
5274
|
+
args: [input.tokenId, input.seller, listing.paymentToken, listing.price]
|
|
5275
|
+
}),
|
|
5276
|
+
value: weth ? listing.price : 0n,
|
|
5277
|
+
fallbackGas: MARKETPLACE_FULFILL_FALLBACK,
|
|
5278
|
+
evmType: "continuum_dao_marketplace_fulfill_listing",
|
|
5279
|
+
name: "VotingEscrowMarketplace.fulfillListing",
|
|
5280
|
+
extra: {
|
|
5281
|
+
tokenId: input.tokenId.toString(),
|
|
5282
|
+
seller: input.seller,
|
|
5283
|
+
paymentToken: listing.paymentToken,
|
|
5284
|
+
priceWei: listing.price.toString(),
|
|
5285
|
+
recipient: snap.executor
|
|
5286
|
+
}
|
|
5287
|
+
}
|
|
5288
|
+
]);
|
|
5289
|
+
}
|
|
5290
|
+
case "createOffering": {
|
|
5291
|
+
assertNotOwn(snap, void 0, input.tokenId);
|
|
5292
|
+
assertPayment(snap);
|
|
5293
|
+
assertDeadline(snap, input.deadline);
|
|
5294
|
+
const weth = isWeth(snap, input.paymentToken);
|
|
5295
|
+
return withApprovals([
|
|
5296
|
+
erc20Approve(snap, input.paymentToken, input.bidWei),
|
|
5297
|
+
{
|
|
5298
|
+
to: m,
|
|
5299
|
+
data: viem.encodeFunctionData({
|
|
5300
|
+
abi: marketplaceAbi,
|
|
5301
|
+
functionName: "createOffering",
|
|
5302
|
+
args: [input.tokenId, input.paymentToken, input.bidWei, input.deadline]
|
|
5303
|
+
}),
|
|
5304
|
+
value: weth ? input.bidWei : 0n,
|
|
5305
|
+
fallbackGas: MARKETPLACE_OFFERING_FALLBACK,
|
|
5306
|
+
evmType: "continuum_dao_marketplace_create_offering",
|
|
5307
|
+
name: "VotingEscrowMarketplace.createOffering",
|
|
5308
|
+
extra: {
|
|
5309
|
+
tokenId: input.tokenId.toString(),
|
|
5310
|
+
paymentToken: input.paymentToken,
|
|
5311
|
+
bidWei: input.bidWei.toString(),
|
|
5312
|
+
deadline: input.deadline.toString()
|
|
5313
|
+
}
|
|
5314
|
+
}
|
|
5315
|
+
]);
|
|
5316
|
+
}
|
|
5317
|
+
case "rescind": {
|
|
5318
|
+
if (!snap.offering || snap.offering.status !== 1) throw new Error("No open offering for this KeyGen.");
|
|
5319
|
+
return [
|
|
5320
|
+
{
|
|
5321
|
+
to: m,
|
|
5322
|
+
data: viem.encodeFunctionData({ abi: marketplaceAbi, functionName: "rescind", args: [input.tokenId] }),
|
|
5323
|
+
value: 0n,
|
|
5324
|
+
fallbackGas: MARKETPLACE_OFFERING_FALLBACK,
|
|
5325
|
+
evmType: "continuum_dao_marketplace_rescind",
|
|
5326
|
+
name: "VotingEscrowMarketplace.rescind",
|
|
5327
|
+
extra: { tokenId: input.tokenId.toString() }
|
|
5328
|
+
}
|
|
5329
|
+
];
|
|
5330
|
+
}
|
|
5331
|
+
case "fulfillOffering": {
|
|
5332
|
+
assertNotAttached(snap, input.tokenId);
|
|
5333
|
+
if (!same2(snap.owner, snap.executor)) throw new Error("Only the veCTM owner can accept an offering.");
|
|
5334
|
+
const offering = snap.offering;
|
|
5335
|
+
if (!offering || !same2(offering.creator, input.buyer)) throw new Error("No open offering for this buyer.");
|
|
5336
|
+
if (!same2(offering.paymentToken, input.paymentToken) || offering.price !== input.priceWei) {
|
|
5337
|
+
throw new Error("Offering price or payment token changed. Refresh and try again.");
|
|
5338
|
+
}
|
|
5339
|
+
return withApprovals([
|
|
5340
|
+
nftApproveStep(snap, input.tokenId),
|
|
5341
|
+
{
|
|
5342
|
+
to: m,
|
|
5343
|
+
data: viem.encodeFunctionData({
|
|
5344
|
+
abi: marketplaceAbi,
|
|
5345
|
+
functionName: "fulfillOffering",
|
|
5346
|
+
args: [input.tokenId, input.buyer, offering.paymentToken, offering.price]
|
|
5347
|
+
}),
|
|
5348
|
+
value: 0n,
|
|
5349
|
+
fallbackGas: MARKETPLACE_FULFILL_FALLBACK,
|
|
5350
|
+
evmType: "continuum_dao_marketplace_fulfill_offering",
|
|
5351
|
+
name: "VotingEscrowMarketplace.fulfillOffering",
|
|
5352
|
+
extra: {
|
|
5353
|
+
tokenId: input.tokenId.toString(),
|
|
5354
|
+
buyer: input.buyer,
|
|
5355
|
+
paymentToken: offering.paymentToken,
|
|
5356
|
+
priceWei: offering.price.toString()
|
|
5357
|
+
}
|
|
5358
|
+
}
|
|
5359
|
+
]);
|
|
5360
|
+
}
|
|
5361
|
+
case "createAuction": {
|
|
5362
|
+
assertNotAttached(snap, input.tokenId);
|
|
5363
|
+
assertPayment(snap);
|
|
5364
|
+
assertDeadline(snap, input.deadline);
|
|
5365
|
+
if (input.reserveWei <= 0n) throw new Error("Reserve price must be greater than zero.");
|
|
5366
|
+
if (!same2(snap.owner, snap.executor)) throw new Error("Only the veCTM owner can start an auction.");
|
|
5367
|
+
if (snap.executorLiveAuction) throw new Error("A live auction already exists for this token.");
|
|
5368
|
+
return withApprovals([
|
|
5369
|
+
nftApproveStep(snap, input.tokenId),
|
|
5370
|
+
{
|
|
5371
|
+
to: m,
|
|
5372
|
+
data: viem.encodeFunctionData({
|
|
5373
|
+
abi: marketplaceAbi,
|
|
5374
|
+
functionName: "createAuction",
|
|
5375
|
+
args: [input.tokenId, input.paymentToken, input.deadline, input.reserveWei, input.minIncrementWei]
|
|
5376
|
+
}),
|
|
5377
|
+
value: 0n,
|
|
5378
|
+
fallbackGas: MARKETPLACE_AUCTION_CREATE_FALLBACK,
|
|
5379
|
+
evmType: "continuum_dao_marketplace_create_auction",
|
|
5380
|
+
name: "VotingEscrowMarketplace.createAuction",
|
|
5381
|
+
extra: {
|
|
5382
|
+
tokenId: input.tokenId.toString(),
|
|
5383
|
+
paymentToken: input.paymentToken,
|
|
5384
|
+
reserveWei: input.reserveWei.toString(),
|
|
5385
|
+
minIncrementWei: input.minIncrementWei.toString(),
|
|
5386
|
+
deadline: input.deadline.toString()
|
|
5387
|
+
}
|
|
5388
|
+
}
|
|
5389
|
+
]);
|
|
5390
|
+
}
|
|
5391
|
+
case "cancelAuction": {
|
|
5392
|
+
const auction = snap.auction;
|
|
5393
|
+
if (!auction || !same2(auction.seller, snap.executor)) throw new Error("No auction for this KeyGen.");
|
|
5394
|
+
if (auction.status !== 1) throw new Error("Only a pending auction with no bids can be canceled.");
|
|
5395
|
+
return [
|
|
5396
|
+
{
|
|
5397
|
+
to: m,
|
|
5398
|
+
data: viem.encodeFunctionData({ abi: marketplaceAbi, functionName: "cancelAuction", args: [input.tokenId] }),
|
|
5399
|
+
value: 0n,
|
|
5400
|
+
fallbackGas: MARKETPLACE_AUCTION_CREATE_FALLBACK,
|
|
5401
|
+
evmType: "continuum_dao_marketplace_cancel_auction",
|
|
5402
|
+
name: "VotingEscrowMarketplace.cancelAuction",
|
|
5403
|
+
extra: { tokenId: input.tokenId.toString(), recipient: snap.executor }
|
|
5404
|
+
}
|
|
5405
|
+
];
|
|
5406
|
+
}
|
|
5407
|
+
case "auctionBid": {
|
|
5408
|
+
assertNotOwn(snap, input.seller, input.tokenId);
|
|
5409
|
+
const auction = snap.auction;
|
|
5410
|
+
if (!auction || !same2(auction.seller, input.seller)) throw new Error("No live auction for this seller.");
|
|
5411
|
+
if (auction.status !== 1 && auction.status !== 2) throw new Error("This auction is not accepting bids.");
|
|
5412
|
+
if (input.priceWei < auction.reservePrice) throw new Error("Bid is below the reserve price.");
|
|
5413
|
+
if (auction.highestBidder !== viem.zeroAddress && input.priceWei < auction.highestBid + auction.minimumBidIncrement) {
|
|
5414
|
+
throw new Error("Bid is below the highest bid plus the minimum increment.");
|
|
5415
|
+
}
|
|
5416
|
+
const weth = isWeth(snap, auction.paymentToken);
|
|
5417
|
+
return withApprovals([
|
|
5418
|
+
weth ? null : erc20Approve(snap, auction.paymentToken, input.priceWei),
|
|
5419
|
+
{
|
|
5420
|
+
to: m,
|
|
5421
|
+
data: viem.encodeFunctionData({
|
|
5422
|
+
abi: marketplaceAbi,
|
|
5423
|
+
functionName: "auctionBid",
|
|
5424
|
+
args: [input.tokenId, input.seller, input.priceWei]
|
|
5425
|
+
}),
|
|
5426
|
+
value: weth ? input.priceWei : 0n,
|
|
5427
|
+
fallbackGas: MARKETPLACE_BID_FALLBACK,
|
|
5428
|
+
evmType: "continuum_dao_marketplace_auction_bid",
|
|
5429
|
+
name: "VotingEscrowMarketplace.auctionBid",
|
|
5430
|
+
extra: {
|
|
5431
|
+
tokenId: input.tokenId.toString(),
|
|
5432
|
+
seller: input.seller,
|
|
5433
|
+
priceWei: input.priceWei.toString(),
|
|
5434
|
+
paymentToken: auction.paymentToken
|
|
5435
|
+
}
|
|
5436
|
+
}
|
|
5437
|
+
]);
|
|
5438
|
+
}
|
|
5439
|
+
case "settleAuction": {
|
|
5440
|
+
const auction = snap.auction;
|
|
5441
|
+
if (!auction || !same2(auction.seller, input.seller)) throw new Error("Auction not found.");
|
|
5442
|
+
const derived = auction.status === 2 && snap.now >= auction.deadline ? 3 : auction.status === 1 && snap.now >= auction.deadline ? 6 : auction.status;
|
|
5443
|
+
if (derived !== 3 && derived !== 6) throw new Error("This auction is not ready to settle.");
|
|
5444
|
+
const winner = auction.highestBidder;
|
|
5445
|
+
return [
|
|
5446
|
+
{
|
|
5447
|
+
to: m,
|
|
5448
|
+
data: viem.encodeFunctionData({
|
|
5449
|
+
abi: marketplaceAbi,
|
|
5450
|
+
functionName: "settleAuction",
|
|
5451
|
+
args: [input.tokenId, input.seller]
|
|
5452
|
+
}),
|
|
5453
|
+
value: 0n,
|
|
5454
|
+
fallbackGas: MARKETPLACE_SETTLE_FALLBACK,
|
|
5455
|
+
evmType: "continuum_dao_marketplace_settle_auction",
|
|
5456
|
+
name: "VotingEscrowMarketplace.settleAuction",
|
|
5457
|
+
extra: {
|
|
5458
|
+
tokenId: input.tokenId.toString(),
|
|
5459
|
+
seller: input.seller,
|
|
5460
|
+
highestBidder: winner,
|
|
5461
|
+
recipient: derived === 3 ? winner : input.seller
|
|
5462
|
+
}
|
|
5463
|
+
}
|
|
5464
|
+
];
|
|
5465
|
+
}
|
|
5466
|
+
default:
|
|
5467
|
+
throw new Error("Unknown marketplace action.");
|
|
5468
|
+
}
|
|
5469
|
+
}
|
|
5470
|
+
|
|
5471
|
+
// src/protocols/evm/continuum-dao/marketplaceChain.ts
|
|
5472
|
+
init_defiEvmClient();
|
|
5473
|
+
init_constants();
|
|
5474
|
+
function marketplacePublicClient(chainId, rpcUrl) {
|
|
5475
|
+
const ch = viem.defineChain({
|
|
5476
|
+
id: chainId,
|
|
5477
|
+
name: "Linea",
|
|
5478
|
+
nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
|
|
5479
|
+
rpcUrls: { default: { http: [rpcUrl] } }
|
|
5480
|
+
});
|
|
5481
|
+
return viem.createPublicClient({ chain: ch, transport: defiEvmTransport(rpcUrl) });
|
|
5482
|
+
}
|
|
5483
|
+
var KNOWN_PAYMENT_TOKENS = [
|
|
5484
|
+
{ address: viem.getAddress(exports.CTM_TOKEN_ADDRESS), symbol: "CTM", decimals: 18 },
|
|
5485
|
+
{ address: exports.MARKETPLACE_WETH_LINEA_ADDRESS, symbol: "WETH", decimals: 18 },
|
|
5486
|
+
{ address: exports.MARKETPLACE_USDC_LINEA_ADDRESS, symbol: "USDC", decimals: 6 }
|
|
5487
|
+
];
|
|
5488
|
+
function calculateMarketplaceFee(price, lockedAmount, limits, rates) {
|
|
5489
|
+
for (let i = 0; i < 5; i++) {
|
|
5490
|
+
const limit = limits[i] ?? 0n;
|
|
5491
|
+
if (lockedAmount >= limit) {
|
|
5492
|
+
const rateBps = rates[i] ?? 0n;
|
|
5493
|
+
const fee = price * rateBps / 10000n;
|
|
5494
|
+
return {
|
|
5495
|
+
tier: FEE_TIER_NAMES[i] ?? "Blue",
|
|
5496
|
+
tierIndex: i,
|
|
5497
|
+
limit,
|
|
5498
|
+
rateBps,
|
|
5499
|
+
fee,
|
|
5500
|
+
net: price - fee
|
|
5501
|
+
};
|
|
5502
|
+
}
|
|
5503
|
+
}
|
|
5504
|
+
return null;
|
|
5505
|
+
}
|
|
5506
|
+
async function readMarketplaceConfigFromChain(args) {
|
|
5507
|
+
const marketplace = args.marketplace ?? exports.VOTING_ESCROW_MARKETPLACE_LINEA_ADDRESS;
|
|
5508
|
+
const client = marketplacePublicClient(args.chainId, args.rpcUrl);
|
|
5509
|
+
const [weth, ve, gov, np, minimumDuration, maximumDuration] = await Promise.all([
|
|
5510
|
+
client.readContract({ address: marketplace, abi: marketplaceAbi, functionName: "weth" }),
|
|
5511
|
+
client.readContract({ address: marketplace, abi: marketplaceAbi, functionName: "ve" }),
|
|
5512
|
+
client.readContract({ address: marketplace, abi: marketplaceAbi, functionName: "gov" }),
|
|
5513
|
+
client.readContract({ address: marketplace, abi: marketplaceAbi, functionName: "np" }),
|
|
5514
|
+
client.readContract({ address: marketplace, abi: marketplaceAbi, functionName: "minimumDuration" }),
|
|
5515
|
+
client.readContract({ address: marketplace, abi: marketplaceAbi, functionName: "maximumDuration" })
|
|
5516
|
+
]);
|
|
5517
|
+
const feeLimits = [];
|
|
5518
|
+
const feeRates = [];
|
|
5519
|
+
for (let i = 0; i < 5; i++) {
|
|
5520
|
+
const [limit, rate] = await Promise.all([
|
|
5521
|
+
client.readContract({
|
|
5522
|
+
address: marketplace,
|
|
5523
|
+
abi: marketplaceAbi,
|
|
5524
|
+
functionName: "feeLimitByTier",
|
|
5525
|
+
args: [i]
|
|
5526
|
+
}),
|
|
5527
|
+
client.readContract({
|
|
5528
|
+
address: marketplace,
|
|
5529
|
+
abi: marketplaceAbi,
|
|
5530
|
+
functionName: "feeRateByTier",
|
|
5531
|
+
args: [i]
|
|
5532
|
+
})
|
|
5533
|
+
]);
|
|
5534
|
+
feeLimits.push(limit);
|
|
5535
|
+
feeRates.push(rate);
|
|
5536
|
+
}
|
|
5537
|
+
const paymentTokens = [];
|
|
5538
|
+
for (const token of KNOWN_PAYMENT_TOKENS) {
|
|
5539
|
+
let isValid = false;
|
|
5540
|
+
try {
|
|
5541
|
+
isValid = await client.readContract({
|
|
5542
|
+
address: marketplace,
|
|
5543
|
+
abi: marketplaceAbi,
|
|
5544
|
+
functionName: "isValidPaymentToken",
|
|
5545
|
+
args: [token.address]
|
|
5546
|
+
});
|
|
5547
|
+
} catch {
|
|
5548
|
+
isValid = false;
|
|
5549
|
+
}
|
|
5550
|
+
if (isValid) paymentTokens.push({ ...token, address: token.address, isValid: true });
|
|
5551
|
+
}
|
|
5552
|
+
return {
|
|
5553
|
+
chainId: args.chainId,
|
|
5554
|
+
marketplace,
|
|
5555
|
+
ve,
|
|
5556
|
+
gov,
|
|
5557
|
+
np,
|
|
5558
|
+
weth,
|
|
5559
|
+
minimumDuration: minimumDuration.toString(),
|
|
5560
|
+
maximumDuration: maximumDuration.toString(),
|
|
5561
|
+
feeLimits: feeLimits.map((n) => n.toString()),
|
|
5562
|
+
feeRates: feeRates.map((n) => n.toString()),
|
|
5563
|
+
feeTiers: FEE_TIER_NAMES.map((name, index) => ({
|
|
5564
|
+
name,
|
|
5565
|
+
index,
|
|
5566
|
+
limit: feeLimits[index].toString(),
|
|
5567
|
+
rateBps: feeRates[index].toString()
|
|
5568
|
+
})),
|
|
5569
|
+
paymentTokens,
|
|
5570
|
+
source: "logs"
|
|
5571
|
+
};
|
|
5572
|
+
}
|
|
5573
|
+
async function readMarketplaceFeePreviewFromChain(args) {
|
|
5574
|
+
const marketplace = args.marketplace ?? exports.VOTING_ESCROW_MARKETPLACE_LINEA_ADDRESS;
|
|
5575
|
+
const ve = args.votingEscrow ?? exports.VOTING_ESCROW_LINEA_ADDRESS;
|
|
5576
|
+
const client = marketplacePublicClient(args.chainId, args.rpcUrl);
|
|
5577
|
+
const locked = await client.readContract({
|
|
5578
|
+
address: ve,
|
|
5579
|
+
abi: marketplaceReadAbi,
|
|
5580
|
+
functionName: "locked",
|
|
5581
|
+
args: [args.tokenId]
|
|
5582
|
+
});
|
|
5583
|
+
const lockedAmount = BigInt(locked[0]);
|
|
5584
|
+
const limits = [];
|
|
5585
|
+
const rates = [];
|
|
5586
|
+
for (let i = 0; i < 5; i++) {
|
|
5587
|
+
limits.push(
|
|
5588
|
+
await client.readContract({
|
|
5589
|
+
address: marketplace,
|
|
5590
|
+
abi: marketplaceAbi,
|
|
5591
|
+
functionName: "feeLimitByTier",
|
|
5592
|
+
args: [i]
|
|
5593
|
+
})
|
|
5594
|
+
);
|
|
5595
|
+
rates.push(
|
|
5596
|
+
await client.readContract({
|
|
5597
|
+
address: marketplace,
|
|
5598
|
+
abi: marketplaceAbi,
|
|
5599
|
+
functionName: "feeRateByTier",
|
|
5600
|
+
args: [i]
|
|
5601
|
+
})
|
|
5602
|
+
);
|
|
5603
|
+
}
|
|
5604
|
+
const fee = calculateMarketplaceFee(args.price, lockedAmount < 0n ? 0n : lockedAmount, limits, rates);
|
|
5605
|
+
if (!fee) throw new Error("Locked CTM is below the minimum fee tier.");
|
|
5606
|
+
return {
|
|
5607
|
+
tokenId: args.tokenId.toString(),
|
|
5608
|
+
lockedAmount: (lockedAmount < 0n ? 0n : lockedAmount).toString(),
|
|
5609
|
+
tier: fee.tier,
|
|
5610
|
+
tierIndex: fee.tierIndex,
|
|
5611
|
+
limit: fee.limit.toString(),
|
|
5612
|
+
rateBps: fee.rateBps.toString(),
|
|
5613
|
+
price: args.price.toString(),
|
|
5614
|
+
fee: fee.fee.toString(),
|
|
5615
|
+
net: fee.net.toString(),
|
|
5616
|
+
source: "logs"
|
|
5617
|
+
};
|
|
5618
|
+
}
|
|
5619
|
+
async function readOrder(client, marketplace, tokenId, index, kind) {
|
|
5620
|
+
if (index === 0n) return null;
|
|
5621
|
+
const row = kind === "listing" ? await client.readContract({
|
|
5622
|
+
address: marketplace,
|
|
5623
|
+
abi: marketplaceAbi,
|
|
5624
|
+
functionName: "listingsByToken",
|
|
5625
|
+
args: [tokenId, index]
|
|
5626
|
+
}) : await client.readContract({
|
|
5627
|
+
address: marketplace,
|
|
5628
|
+
abi: marketplaceAbi,
|
|
5629
|
+
functionName: "offeringsByToken",
|
|
5630
|
+
args: [tokenId, index]
|
|
5631
|
+
});
|
|
5632
|
+
return {
|
|
5633
|
+
price: row[0],
|
|
5634
|
+
deadline: row[1],
|
|
5635
|
+
snapshotAmount: row[2],
|
|
5636
|
+
snapshotEnd: row[3],
|
|
5637
|
+
creator: row[4],
|
|
5638
|
+
paymentToken: row[5],
|
|
5639
|
+
status: Number(row[6])
|
|
5640
|
+
};
|
|
5641
|
+
}
|
|
5642
|
+
async function readAuction(client, marketplace, tokenId, index) {
|
|
5643
|
+
if (index === 0n) return null;
|
|
5644
|
+
const row = await client.readContract({
|
|
5645
|
+
address: marketplace,
|
|
5646
|
+
abi: marketplaceAbi,
|
|
5647
|
+
functionName: "auctionsByToken",
|
|
5648
|
+
args: [tokenId, index]
|
|
5649
|
+
});
|
|
5650
|
+
return {
|
|
5651
|
+
reservePrice: row[0],
|
|
5652
|
+
minimumBidIncrement: row[1],
|
|
5653
|
+
deadline: row[2],
|
|
5654
|
+
seller: row[3],
|
|
5655
|
+
paymentToken: row[4],
|
|
5656
|
+
highestBidder: row[5],
|
|
5657
|
+
highestBid: row[6],
|
|
5658
|
+
status: Number(row[7])
|
|
5659
|
+
};
|
|
5660
|
+
}
|
|
5661
|
+
async function loadMarketplacePlanSnapshot(args) {
|
|
5662
|
+
const marketplace = exports.VOTING_ESCROW_MARKETPLACE_LINEA_ADDRESS;
|
|
5663
|
+
const client = marketplacePublicClient(args.chainId, args.rpcUrl);
|
|
5664
|
+
const [weth, ve, np, minimumDuration, maximumDuration, block] = await Promise.all([
|
|
5665
|
+
client.readContract({ address: marketplace, abi: marketplaceAbi, functionName: "weth" }),
|
|
5666
|
+
client.readContract({ address: marketplace, abi: marketplaceAbi, functionName: "ve" }),
|
|
5667
|
+
client.readContract({ address: marketplace, abi: marketplaceAbi, functionName: "np" }),
|
|
5668
|
+
client.readContract({ address: marketplace, abi: marketplaceAbi, functionName: "minimumDuration" }),
|
|
5669
|
+
client.readContract({ address: marketplace, abi: marketplaceAbi, functionName: "maximumDuration" }),
|
|
5670
|
+
client.getBlock({ blockTag: "latest" })
|
|
5671
|
+
]);
|
|
5672
|
+
let owner = viem.zeroAddress;
|
|
5673
|
+
try {
|
|
5674
|
+
owner = await client.readContract({
|
|
5675
|
+
address: ve,
|
|
5676
|
+
abi: marketplaceReadAbi,
|
|
5677
|
+
functionName: "ownerOf",
|
|
5678
|
+
args: [args.tokenId]
|
|
5679
|
+
});
|
|
5680
|
+
} catch {
|
|
5681
|
+
owner = viem.zeroAddress;
|
|
5682
|
+
}
|
|
5683
|
+
const [approved, approvedForAll, attachedKeyGen, listingIndex, offeringIndex, auctionIndex] = await Promise.all([
|
|
5684
|
+
client.readContract({ address: ve, abi: marketplaceReadAbi, functionName: "getApproved", args: [args.tokenId] }).catch(() => viem.zeroAddress),
|
|
5685
|
+
owner === viem.zeroAddress ? Promise.resolve(false) : client.readContract({
|
|
5686
|
+
address: ve,
|
|
5687
|
+
abi: marketplaceReadAbi,
|
|
5688
|
+
functionName: "isApprovedForAll",
|
|
5689
|
+
args: [owner, marketplace]
|
|
5690
|
+
}).catch(() => false),
|
|
5691
|
+
client.readContract({ address: np, abi: marketplaceReadAbi, functionName: "attachedKeyGen", args: [args.tokenId] }).catch(() => viem.zeroAddress),
|
|
5692
|
+
client.readContract({
|
|
5693
|
+
address: marketplace,
|
|
5694
|
+
abi: marketplaceAbi,
|
|
5695
|
+
functionName: "listingIndexByTokenSeller",
|
|
5696
|
+
args: [args.tokenId, args.seller ?? args.executor]
|
|
5697
|
+
}),
|
|
5698
|
+
client.readContract({
|
|
5699
|
+
address: marketplace,
|
|
5700
|
+
abi: marketplaceAbi,
|
|
5701
|
+
functionName: "offeringIndexByTokenBuyer",
|
|
5702
|
+
args: [args.tokenId, args.buyer ?? args.executor]
|
|
5703
|
+
}),
|
|
5704
|
+
client.readContract({
|
|
5705
|
+
address: marketplace,
|
|
5706
|
+
abi: marketplaceAbi,
|
|
5707
|
+
functionName: "auctionIndexByTokenSeller",
|
|
5708
|
+
args: [args.tokenId, args.seller ?? args.executor]
|
|
5709
|
+
})
|
|
5710
|
+
]);
|
|
5711
|
+
const [listing, offering, auction, executorListingIndex, executorAuctionIndex] = await Promise.all([
|
|
5712
|
+
readOrder(client, marketplace, args.tokenId, listingIndex, "listing"),
|
|
5713
|
+
readOrder(client, marketplace, args.tokenId, offeringIndex, "offering"),
|
|
5714
|
+
readAuction(client, marketplace, args.tokenId, auctionIndex),
|
|
5715
|
+
args.seller && args.seller !== args.executor ? client.readContract({
|
|
5716
|
+
address: marketplace,
|
|
5717
|
+
abi: marketplaceAbi,
|
|
5718
|
+
functionName: "listingIndexByTokenSeller",
|
|
5719
|
+
args: [args.tokenId, args.executor]
|
|
5720
|
+
}) : Promise.resolve(0n),
|
|
5721
|
+
args.seller && args.seller !== args.executor ? client.readContract({
|
|
5722
|
+
address: marketplace,
|
|
5723
|
+
abi: marketplaceAbi,
|
|
5724
|
+
functionName: "auctionIndexByTokenSeller",
|
|
5725
|
+
args: [args.tokenId, args.executor]
|
|
5726
|
+
}) : Promise.resolve(auctionIndex)
|
|
5727
|
+
]);
|
|
5728
|
+
const executorAuction = executorAuctionIndex === auctionIndex ? auction : await readAuction(client, marketplace, args.tokenId, executorAuctionIndex);
|
|
5729
|
+
const liveAuction = executorAuction != null && (executorAuction.status === 1 || executorAuction.status === 2 || executorAuction.status === 3) && executorAuction.seller.toLowerCase() === args.executor.toLowerCase();
|
|
5730
|
+
let executorOpenListing = false;
|
|
5731
|
+
if (executorListingIndex > 0n) {
|
|
5732
|
+
const row = await readOrder(client, marketplace, args.tokenId, executorListingIndex, "listing");
|
|
5733
|
+
executorOpenListing = row?.status === 1;
|
|
5734
|
+
} else if (!args.seller || args.seller === args.executor) {
|
|
5735
|
+
executorOpenListing = listing?.status === 1 && listing.creator.toLowerCase() === args.executor.toLowerCase();
|
|
5736
|
+
}
|
|
5737
|
+
const paymentToken = args.paymentToken ?? listing?.paymentToken ?? offering?.paymentToken ?? auction?.paymentToken;
|
|
5738
|
+
let paymentTokenValid = true;
|
|
5739
|
+
if (paymentToken) {
|
|
5740
|
+
paymentTokenValid = await client.readContract({
|
|
5741
|
+
address: marketplace,
|
|
5742
|
+
abi: marketplaceAbi,
|
|
5743
|
+
functionName: "isValidPaymentToken",
|
|
5744
|
+
args: [paymentToken]
|
|
5745
|
+
});
|
|
5746
|
+
}
|
|
5747
|
+
const spendToken = paymentToken ?? viem.zeroAddress;
|
|
5748
|
+
const spendFrom = args.buyer && args.buyer !== args.executor ? args.buyer : args.executor;
|
|
5749
|
+
let allowance = 0n;
|
|
5750
|
+
if (spendToken !== viem.zeroAddress && spendToken.toLowerCase() !== weth.toLowerCase()) {
|
|
5751
|
+
allowance = await client.readContract({
|
|
5752
|
+
address: spendToken,
|
|
5753
|
+
abi: marketplaceReadAbi,
|
|
5754
|
+
functionName: "allowance",
|
|
5755
|
+
args: [spendFrom, marketplace]
|
|
5756
|
+
}).catch(() => 0n);
|
|
5757
|
+
} else if (spendToken.toLowerCase() === weth.toLowerCase()) {
|
|
5758
|
+
allowance = await client.readContract({
|
|
5759
|
+
address: spendToken,
|
|
5760
|
+
abi: marketplaceReadAbi,
|
|
5761
|
+
functionName: "allowance",
|
|
5762
|
+
args: [args.executor, marketplace]
|
|
5763
|
+
}).catch(() => 0n);
|
|
5764
|
+
}
|
|
5765
|
+
return {
|
|
5766
|
+
marketplace,
|
|
5767
|
+
votingEscrow: ve,
|
|
5768
|
+
weth,
|
|
5769
|
+
now: block.timestamp,
|
|
5770
|
+
minimumDuration,
|
|
5771
|
+
maximumDuration,
|
|
5772
|
+
executor: args.executor,
|
|
5773
|
+
owner,
|
|
5774
|
+
nftApproved: approvedForAll || approved !== viem.zeroAddress && approved.toLowerCase() === marketplace.toLowerCase(),
|
|
5775
|
+
allowance,
|
|
5776
|
+
attachedKeyGen,
|
|
5777
|
+
paymentTokenValid,
|
|
5778
|
+
executorOpenListing,
|
|
5779
|
+
executorLiveAuction: liveAuction,
|
|
5780
|
+
listing: listing && listing.status === 1 ? listing : listing,
|
|
5781
|
+
offering: offering && offering.status === 1 ? offering : offering,
|
|
5782
|
+
auction
|
|
5783
|
+
};
|
|
5784
|
+
}
|
|
5785
|
+
init_constants();
|
|
5786
|
+
var memoryCache = /* @__PURE__ */ new Map();
|
|
5787
|
+
function emptyMarketplaceIndexCache() {
|
|
5788
|
+
return { lastScannedBlock: "0", listings: [], offerings: [], auctions: [] };
|
|
5789
|
+
}
|
|
5790
|
+
function getMarketplaceIndexMemoryCache(chainId) {
|
|
5791
|
+
return memoryCache.get(chainId) ?? null;
|
|
5792
|
+
}
|
|
5793
|
+
function setMarketplaceIndexMemoryCache(chainId, cache) {
|
|
5794
|
+
memoryCache.set(chainId, cache);
|
|
5795
|
+
}
|
|
5796
|
+
function arg(args, key, index) {
|
|
5797
|
+
const value = args[key] ?? args[index];
|
|
5798
|
+
if (typeof value === "bigint") return value.toString();
|
|
5799
|
+
return String(value ?? "");
|
|
5800
|
+
}
|
|
5801
|
+
function toFoldEvent(log, timestamp) {
|
|
5802
|
+
try {
|
|
5803
|
+
const decoded = viem.decodeEventLog({
|
|
5804
|
+
abi: marketplaceAbi,
|
|
5805
|
+
data: log.data,
|
|
5806
|
+
topics: log.topics
|
|
5807
|
+
});
|
|
5808
|
+
const args = decoded.args;
|
|
5809
|
+
const ref = {
|
|
5810
|
+
tx: log.transactionHash ?? "",
|
|
5811
|
+
block: log.blockNumber != null ? log.blockNumber.toString() : "0",
|
|
5812
|
+
logIndex: log.logIndex ?? 0,
|
|
5813
|
+
timestamp
|
|
5814
|
+
};
|
|
5815
|
+
switch (decoded.eventName) {
|
|
5816
|
+
case "ListingCreated":
|
|
5817
|
+
return {
|
|
5818
|
+
name: "ListingCreated",
|
|
5819
|
+
tokenId: arg(args, "_tokenId", 0),
|
|
5820
|
+
actor: arg(args, "_listedBy", 1),
|
|
5821
|
+
paymentToken: arg(args, "_paymentToken", 2),
|
|
5822
|
+
amount: arg(args, "_ask", 3),
|
|
5823
|
+
deadline: arg(args, "_deadline", 4),
|
|
5824
|
+
...ref
|
|
5825
|
+
};
|
|
5826
|
+
case "OfferingCreated":
|
|
5827
|
+
return {
|
|
5828
|
+
name: "OfferingCreated",
|
|
5829
|
+
tokenId: arg(args, "_tokenId", 0),
|
|
5830
|
+
actor: arg(args, "_offeredBy", 1),
|
|
5831
|
+
paymentToken: arg(args, "_paymentToken", 2),
|
|
5832
|
+
amount: arg(args, "_bid", 3),
|
|
5833
|
+
deadline: arg(args, "_deadline", 4),
|
|
5834
|
+
...ref
|
|
5835
|
+
};
|
|
5836
|
+
case "ListingFulfilled":
|
|
5837
|
+
return {
|
|
5838
|
+
name: "ListingFulfilled",
|
|
5839
|
+
tokenId: arg(args, "_tokenId", 0),
|
|
5840
|
+
buyer: arg(args, "_buyer", 1),
|
|
5841
|
+
seller: arg(args, "_seller", 2),
|
|
5842
|
+
price: arg(args, "_ask", 3),
|
|
5843
|
+
net: arg(args, "_netPrice", 4),
|
|
5844
|
+
fee: arg(args, "_fee", 5),
|
|
5845
|
+
...ref
|
|
5846
|
+
};
|
|
5847
|
+
case "OfferingFulfilled":
|
|
5848
|
+
return {
|
|
5849
|
+
name: "OfferingFulfilled",
|
|
5850
|
+
tokenId: arg(args, "_tokenId", 0),
|
|
5851
|
+
buyer: arg(args, "_buyer", 1),
|
|
5852
|
+
seller: arg(args, "_seller", 2),
|
|
5853
|
+
price: arg(args, "_bid", 3),
|
|
5854
|
+
net: arg(args, "_netPrice", 4),
|
|
5855
|
+
fee: arg(args, "_fee", 5),
|
|
5856
|
+
...ref
|
|
5857
|
+
};
|
|
5858
|
+
case "Delisted":
|
|
5859
|
+
return { name: "Delisted", tokenId: arg(args, "_tokenId", 0), actor: arg(args, "_seller", 1), ...ref };
|
|
5860
|
+
case "Rescinded":
|
|
5861
|
+
return { name: "Rescinded", tokenId: arg(args, "_tokenId", 0), actor: arg(args, "_buyer", 1), ...ref };
|
|
5862
|
+
case "AuctionCreated":
|
|
5863
|
+
return {
|
|
5864
|
+
name: "AuctionCreated",
|
|
5865
|
+
tokenId: arg(args, "_tokenId", 0),
|
|
5866
|
+
actor: arg(args, "_createdBy", 1),
|
|
5867
|
+
paymentToken: arg(args, "_paymentToken", 2),
|
|
5868
|
+
amount: arg(args, "_reservePrice", 3),
|
|
5869
|
+
minIncrement: arg(args, "_minimumBidIncrement", 4),
|
|
5870
|
+
deadline: arg(args, "_deadline", 5),
|
|
5871
|
+
...ref
|
|
5872
|
+
};
|
|
5873
|
+
case "AuctionCanceled":
|
|
5874
|
+
return { name: "AuctionCanceled", tokenId: arg(args, "_tokenId", 0), actor: arg(args, "_seller", 1), ...ref };
|
|
5875
|
+
case "AuctionBid":
|
|
5876
|
+
return {
|
|
5877
|
+
name: "AuctionBid",
|
|
5878
|
+
tokenId: arg(args, "_tokenId", 0),
|
|
5879
|
+
seller: arg(args, "_seller", 1),
|
|
5880
|
+
buyer: arg(args, "_buyer", 2),
|
|
5881
|
+
price: arg(args, "_price", 3),
|
|
5882
|
+
...ref
|
|
5883
|
+
};
|
|
5884
|
+
case "AuctionSettled":
|
|
5885
|
+
return {
|
|
5886
|
+
name: "AuctionSettled",
|
|
5887
|
+
tokenId: arg(args, "_tokenId", 0),
|
|
5888
|
+
seller: arg(args, "_seller", 1),
|
|
5889
|
+
finalStatus: Number(args._finalStatus ?? args[2] ?? 0),
|
|
5890
|
+
...ref
|
|
5891
|
+
};
|
|
5892
|
+
case "AuctionSuccessful":
|
|
5893
|
+
return {
|
|
5894
|
+
name: "AuctionSuccessful",
|
|
5895
|
+
tokenId: arg(args, "_tokenId", 0),
|
|
5896
|
+
seller: arg(args, "_seller", 1),
|
|
5897
|
+
buyer: arg(args, "_buyer", 2),
|
|
5898
|
+
price: arg(args, "_price", 3),
|
|
5899
|
+
fee: arg(args, "_fee", 4),
|
|
5900
|
+
net: arg(args, "_net", 5),
|
|
5901
|
+
...ref
|
|
5902
|
+
};
|
|
5903
|
+
default:
|
|
5904
|
+
return null;
|
|
5905
|
+
}
|
|
5906
|
+
} catch {
|
|
5907
|
+
return null;
|
|
5908
|
+
}
|
|
5909
|
+
}
|
|
5910
|
+
async function getLogsChunked(args) {
|
|
5911
|
+
const logs = [];
|
|
5912
|
+
let chunk = 5000n;
|
|
5913
|
+
let start = args.fromBlock;
|
|
5914
|
+
while (start <= args.toBlock) {
|
|
5915
|
+
const end = start + chunk - 1n > args.toBlock ? args.toBlock : start + chunk - 1n;
|
|
5916
|
+
try {
|
|
5917
|
+
const part = await args.client.getLogs({
|
|
5918
|
+
address: args.address,
|
|
5919
|
+
fromBlock: start,
|
|
5920
|
+
toBlock: end
|
|
5921
|
+
});
|
|
5922
|
+
logs.push(...part);
|
|
5923
|
+
args.onProgress?.(end, args.toBlock);
|
|
5924
|
+
start = end + 1n;
|
|
5925
|
+
} catch (err) {
|
|
5926
|
+
if (chunk <= 200n) throw err;
|
|
5927
|
+
chunk = chunk / 2n < 200n ? 200n : chunk / 2n;
|
|
5928
|
+
}
|
|
5929
|
+
}
|
|
5930
|
+
return logs;
|
|
5931
|
+
}
|
|
5932
|
+
async function scanMarketplaceLogs(args) {
|
|
5933
|
+
const client = marketplacePublicClient(args.chainId, args.rpcUrl);
|
|
5934
|
+
const head = await client.getBlockNumber();
|
|
5935
|
+
const prior = args.cache ?? getMarketplaceIndexMemoryCache(args.chainId) ?? emptyMarketplaceIndexCache();
|
|
5936
|
+
const scanned = BigInt(prior.lastScannedBlock || "0");
|
|
5937
|
+
const fromBlock = scanned > 0n ? scanned + 1n : exports.VOTING_ESCROW_MARKETPLACE_START_BLOCK;
|
|
5938
|
+
if (fromBlock > head) {
|
|
5939
|
+
const now2 = Number((await client.getBlock({ blockTag: "latest" })).timestamp);
|
|
5940
|
+
const derived2 = applyDerivedStatuses(
|
|
5941
|
+
{ listings: prior.listings, offerings: prior.offerings, auctions: prior.auctions },
|
|
5942
|
+
now2
|
|
5943
|
+
);
|
|
5944
|
+
const cache2 = { lastScannedBlock: head.toString(), ...derived2 };
|
|
5945
|
+
setMarketplaceIndexMemoryCache(args.chainId, cache2);
|
|
5946
|
+
return cache2;
|
|
5947
|
+
}
|
|
5948
|
+
const logs = await getLogsChunked({
|
|
5949
|
+
client,
|
|
5950
|
+
address: exports.VOTING_ESCROW_MARKETPLACE_LINEA_ADDRESS,
|
|
5951
|
+
fromBlock,
|
|
5952
|
+
toBlock: head,
|
|
5953
|
+
onProgress: args.onProgress
|
|
5954
|
+
});
|
|
5955
|
+
const events = logs.map((log) => toFoldEvent(log)).filter((ev) => ev != null);
|
|
5956
|
+
const folded = foldMarketplaceEvents(events, {
|
|
5957
|
+
listings: prior.listings,
|
|
5958
|
+
offerings: prior.offerings,
|
|
5959
|
+
auctions: prior.auctions
|
|
5960
|
+
});
|
|
5961
|
+
const now = Number((await client.getBlock({ blockTag: "latest" })).timestamp);
|
|
5962
|
+
const derived = applyDerivedStatuses(folded, now);
|
|
5963
|
+
const cache = { lastScannedBlock: head.toString(), ...derived };
|
|
5964
|
+
setMarketplaceIndexMemoryCache(args.chainId, cache);
|
|
5965
|
+
return cache;
|
|
5966
|
+
}
|
|
5967
|
+
|
|
5968
|
+
// src/protocols/evm/continuum-dao/marketplaceCatalog.ts
|
|
5969
|
+
init_constants();
|
|
5970
|
+
function apiBase(args) {
|
|
5971
|
+
return (args.apiBase ?? exports.CONTINUUM_DAO_MARKETPLACE_API).replace(/\/$/, "");
|
|
5972
|
+
}
|
|
5973
|
+
function isOffline(status) {
|
|
5974
|
+
if (status == null || status === 0 || status >= 500) return true;
|
|
5975
|
+
return false;
|
|
5976
|
+
}
|
|
5977
|
+
async function getJson(url) {
|
|
5978
|
+
try {
|
|
5979
|
+
const res = await fetch(url);
|
|
5980
|
+
if (!res.ok) {
|
|
5981
|
+
const text = await res.text().catch(() => "");
|
|
5982
|
+
return { ok: false, status: res.status, error: new Error(`${url}: ${res.status} ${text}`.trim()) };
|
|
5983
|
+
}
|
|
5984
|
+
return { ok: true, body: await res.json() };
|
|
5985
|
+
} catch (err) {
|
|
5986
|
+
return { ok: false, status: 0, error: err instanceof Error ? err : new Error(String(err)) };
|
|
5987
|
+
}
|
|
5988
|
+
}
|
|
5989
|
+
function qs(params) {
|
|
5990
|
+
const search = new URLSearchParams();
|
|
5991
|
+
for (const [key, value] of Object.entries(params)) {
|
|
5992
|
+
if (value === void 0 || value === "") continue;
|
|
5993
|
+
search.set(key, String(value));
|
|
5994
|
+
}
|
|
5995
|
+
const encoded = search.toString();
|
|
5996
|
+
return encoded ? `?${encoded}` : "";
|
|
5997
|
+
}
|
|
5998
|
+
async function logsBook(args) {
|
|
5999
|
+
if (!args.rpcUrl?.trim()) throw new Error("Linea RPC is required to index the marketplace while the API is offline.");
|
|
6000
|
+
return scanMarketplaceLogs({
|
|
6001
|
+
chainId: args.chainId ?? exports.CONTINUUM_DAO_LINEA_CHAIN_ID,
|
|
6002
|
+
rpcUrl: args.rpcUrl.trim(),
|
|
6003
|
+
cache: args.cache,
|
|
6004
|
+
onProgress: args.onProgress
|
|
6005
|
+
});
|
|
6006
|
+
}
|
|
6007
|
+
function matchOrder(row, args, includeInactive) {
|
|
6008
|
+
if (!includeInactive && !isOpenOrder(row)) return false;
|
|
6009
|
+
if (args.tokenId && row.tokenId !== args.tokenId) return false;
|
|
6010
|
+
if (args.paymentToken && row.paymentToken.toLowerCase() !== args.paymentToken.toLowerCase()) return false;
|
|
6011
|
+
if (args.creator && row.creator.toLowerCase() !== args.creator.toLowerCase()) return false;
|
|
6012
|
+
if (args.seller && (row.seller ?? row.creator).toLowerCase() !== args.seller.toLowerCase()) return false;
|
|
6013
|
+
return true;
|
|
6014
|
+
}
|
|
6015
|
+
function matchAuction(row, args, includeInactive) {
|
|
6016
|
+
if (!includeInactive && !isLiveAuctionStatus(row.derivedStatus)) return false;
|
|
6017
|
+
if (args.tokenId && row.tokenId !== args.tokenId) return false;
|
|
6018
|
+
if (args.paymentToken && row.paymentToken.toLowerCase() !== args.paymentToken.toLowerCase()) return false;
|
|
6019
|
+
if (args.seller && row.seller.toLowerCase() !== args.seller.toLowerCase()) return false;
|
|
6020
|
+
return true;
|
|
6021
|
+
}
|
|
6022
|
+
function listFrom(items, source) {
|
|
6023
|
+
return { items, nextCursor: null, source };
|
|
6024
|
+
}
|
|
6025
|
+
async function fetchContinuumDaoMarketplaceConfig(args = {}) {
|
|
6026
|
+
const url = `${apiBase(args)}/marketplace/config`;
|
|
6027
|
+
const res = await getJson(url);
|
|
6028
|
+
if (res.ok && res.body && typeof res.body === "object") {
|
|
6029
|
+
return { ...res.body, source: "api" };
|
|
6030
|
+
}
|
|
6031
|
+
if (!res.ok && !isOffline(res.status)) throw res.error;
|
|
6032
|
+
return readMarketplaceConfigFromChain({
|
|
6033
|
+
chainId: args.chainId ?? exports.CONTINUUM_DAO_LINEA_CHAIN_ID,
|
|
6034
|
+
rpcUrl: args.rpcUrl ?? ""
|
|
6035
|
+
});
|
|
6036
|
+
}
|
|
6037
|
+
async function fetchContinuumDaoMarketplaceListings(args = {}) {
|
|
6038
|
+
const includeInactive = Boolean(args.includeInactive);
|
|
6039
|
+
const url = `${apiBase(args)}/marketplace/listings${qs({
|
|
6040
|
+
includeInactive,
|
|
6041
|
+
paymentToken: args.paymentToken,
|
|
6042
|
+
tokenId: args.tokenId,
|
|
6043
|
+
creator: args.creator,
|
|
6044
|
+
limit: args.limit ?? 100,
|
|
6045
|
+
cursor: args.cursor,
|
|
6046
|
+
viewer: args.viewer
|
|
6047
|
+
})}`;
|
|
6048
|
+
const res = await getJson(url);
|
|
6049
|
+
if (res.ok) {
|
|
6050
|
+
const body = res.body;
|
|
6051
|
+
return { items: body.items ?? [], nextCursor: body.nextCursor ?? null, source: "api" };
|
|
6052
|
+
}
|
|
6053
|
+
if (args.cursor || !isOffline(res.status)) throw res.error;
|
|
6054
|
+
const book = await logsBook(args);
|
|
6055
|
+
return listFrom(book.listings.filter((row) => matchOrder(row, args, includeInactive)), "logs");
|
|
6056
|
+
}
|
|
6057
|
+
async function fetchContinuumDaoMarketplaceOfferings(args = {}) {
|
|
6058
|
+
const includeInactive = Boolean(args.includeInactive);
|
|
6059
|
+
const url = `${apiBase(args)}/marketplace/offerings${qs({
|
|
6060
|
+
includeInactive,
|
|
6061
|
+
paymentToken: args.paymentToken,
|
|
6062
|
+
tokenId: args.tokenId,
|
|
6063
|
+
creator: args.creator,
|
|
6064
|
+
limit: args.limit ?? 100,
|
|
6065
|
+
cursor: args.cursor,
|
|
6066
|
+
viewer: args.viewer
|
|
6067
|
+
})}`;
|
|
6068
|
+
const res = await getJson(url);
|
|
6069
|
+
if (res.ok) {
|
|
6070
|
+
const body = res.body;
|
|
6071
|
+
return { items: body.items ?? [], nextCursor: body.nextCursor ?? null, source: "api" };
|
|
6072
|
+
}
|
|
6073
|
+
if (args.cursor || !isOffline(res.status)) throw res.error;
|
|
6074
|
+
const book = await logsBook(args);
|
|
6075
|
+
return listFrom(book.offerings.filter((row) => matchOrder(row, args, includeInactive)), "logs");
|
|
6076
|
+
}
|
|
6077
|
+
async function fetchContinuumDaoMarketplaceAuctions(args = {}) {
|
|
6078
|
+
const includeInactive = Boolean(args.includeInactive);
|
|
6079
|
+
const url = `${apiBase(args)}/marketplace/auctions${qs({
|
|
6080
|
+
includeInactive,
|
|
6081
|
+
paymentToken: args.paymentToken,
|
|
6082
|
+
tokenId: args.tokenId,
|
|
6083
|
+
seller: args.seller,
|
|
6084
|
+
limit: args.limit ?? 100,
|
|
6085
|
+
cursor: args.cursor,
|
|
6086
|
+
viewer: args.viewer
|
|
6087
|
+
})}`;
|
|
6088
|
+
const res = await getJson(url);
|
|
6089
|
+
if (res.ok) {
|
|
6090
|
+
const body = res.body;
|
|
6091
|
+
return {
|
|
6092
|
+
items: (body.items ?? []).map((row) => ({ ...row, bids: row.bids ?? [] })),
|
|
6093
|
+
nextCursor: body.nextCursor ?? null,
|
|
6094
|
+
source: "api"
|
|
6095
|
+
};
|
|
6096
|
+
}
|
|
6097
|
+
if (args.cursor || !isOffline(res.status)) throw res.error;
|
|
6098
|
+
const book = await logsBook(args);
|
|
6099
|
+
return listFrom(book.auctions.filter((row) => matchAuction(row, args, includeInactive)), "logs");
|
|
6100
|
+
}
|
|
6101
|
+
async function fetchContinuumDaoMarketplaceToken(args) {
|
|
6102
|
+
const url = `${apiBase(args)}/marketplace/tokens/${encodeURIComponent(args.tokenId)}${qs({ viewer: args.viewer })}`;
|
|
6103
|
+
const res = await getJson(url);
|
|
6104
|
+
if (res.ok && res.body && typeof res.body === "object") {
|
|
6105
|
+
return { ...res.body, source: "api" };
|
|
6106
|
+
}
|
|
6107
|
+
if (!res.ok && !isOffline(res.status)) throw res.error;
|
|
6108
|
+
const book = await logsBook(args);
|
|
6109
|
+
const listings = book.listings.filter((row) => row.tokenId === args.tokenId);
|
|
6110
|
+
const offerings = book.offerings.filter((row) => row.tokenId === args.tokenId);
|
|
6111
|
+
const auctions = book.auctions.filter((row) => row.tokenId === args.tokenId);
|
|
6112
|
+
return {
|
|
6113
|
+
token: { tokenId: args.tokenId },
|
|
6114
|
+
listing: listings.find((row) => isOpenOrder(row)) ?? null,
|
|
6115
|
+
offerings: offerings.filter((row) => isOpenOrder(row)),
|
|
6116
|
+
auction: auctions.find((row) => isLiveAuctionStatus(row.derivedStatus)) ?? null,
|
|
6117
|
+
history: {
|
|
6118
|
+
listings: listings.filter((row) => !isOpenOrder(row)),
|
|
6119
|
+
offerings: offerings.filter((row) => !isOpenOrder(row)),
|
|
6120
|
+
auctions: auctions.filter((row) => !isLiveAuctionStatus(row.derivedStatus))
|
|
6121
|
+
},
|
|
6122
|
+
source: "logs"
|
|
6123
|
+
};
|
|
6124
|
+
}
|
|
6125
|
+
async function fetchContinuumDaoMarketplaceFeePreview(args) {
|
|
6126
|
+
const url = `${apiBase(args)}/marketplace/fee-preview${qs({ tokenId: args.tokenId, price: args.price })}`;
|
|
6127
|
+
const res = await getJson(url);
|
|
6128
|
+
if (res.ok && res.body && typeof res.body === "object") {
|
|
6129
|
+
return { ...res.body, source: "api" };
|
|
6130
|
+
}
|
|
6131
|
+
if (!res.ok && !isOffline(res.status)) throw res.error;
|
|
6132
|
+
return readMarketplaceFeePreviewFromChain({
|
|
6133
|
+
chainId: args.chainId ?? exports.CONTINUUM_DAO_LINEA_CHAIN_ID,
|
|
6134
|
+
rpcUrl: args.rpcUrl ?? "",
|
|
6135
|
+
tokenId: BigInt(args.tokenId),
|
|
6136
|
+
price: BigInt(args.price)
|
|
6137
|
+
});
|
|
6138
|
+
}
|
|
6139
|
+
async function fetchContinuumDaoMarketplaceActivity(args) {
|
|
6140
|
+
const url = `${apiBase(args)}/marketplace/users/${encodeURIComponent(args.address)}/activity${qs({ limit: args.limit ?? 50 })}`;
|
|
6141
|
+
const res = await getJson(url);
|
|
6142
|
+
if (res.ok && res.body && typeof res.body === "object") {
|
|
6143
|
+
const body = res.body;
|
|
6144
|
+
return {
|
|
6145
|
+
address: args.address,
|
|
6146
|
+
orders: body.orders ?? [],
|
|
6147
|
+
auctions: (body.auctions ?? []).map((row) => ({ ...row, bids: row.bids ?? [] })),
|
|
6148
|
+
source: "api"
|
|
6149
|
+
};
|
|
6150
|
+
}
|
|
6151
|
+
if (!res.ok && !isOffline(res.status)) throw res.error;
|
|
6152
|
+
const book = await logsBook(args);
|
|
6153
|
+
const address = args.address.toLowerCase();
|
|
6154
|
+
const orders = [...book.listings, ...book.offerings].filter((row) => {
|
|
6155
|
+
return row.creator.toLowerCase() === address || (row.counterparty ?? "").toLowerCase() === address || (row.seller ?? "").toLowerCase() === address || (row.buyer ?? "").toLowerCase() === address;
|
|
6156
|
+
});
|
|
6157
|
+
const auctions = book.auctions.filter((row) => {
|
|
6158
|
+
return row.seller.toLowerCase() === address || (row.buyer ?? "").toLowerCase() === address || (row.highestBidder ?? "").toLowerCase() === address || row.bids.some((bid) => bid.bidder.toLowerCase() === address);
|
|
6159
|
+
});
|
|
6160
|
+
return { address: args.address, orders, auctions, source: "logs" };
|
|
6161
|
+
}
|
|
6162
|
+
|
|
6163
|
+
// src/protocols/evm/continuum-dao/marketplaceSearch.ts
|
|
6164
|
+
init_constants();
|
|
6165
|
+
var LOCKED_ABI = [viem.parseAbiItem("function locked(uint256 tokenId) view returns (int128 amount, uint256 end)")];
|
|
6166
|
+
var MONTH_SECONDS = 30 * 24 * 60 * 60;
|
|
6167
|
+
var PAGE_SIZE = 100;
|
|
6168
|
+
var MAX_PAGES = 20;
|
|
6169
|
+
var DEFAULT_LIMIT = 10;
|
|
6170
|
+
var MAX_LIMIT = 25;
|
|
6171
|
+
var DEFAULT_DIRECTION = {
|
|
6172
|
+
pricePerLockedCtm: "asc",
|
|
6173
|
+
price: "asc",
|
|
6174
|
+
locked: "desc",
|
|
6175
|
+
unlock: "asc",
|
|
6176
|
+
deadline: "asc"
|
|
6177
|
+
};
|
|
6178
|
+
function same3(a, b) {
|
|
6179
|
+
if (!a || !b) return false;
|
|
6180
|
+
try {
|
|
6181
|
+
return viem.getAddress(a) === viem.getAddress(b);
|
|
6182
|
+
} catch {
|
|
6183
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
6184
|
+
}
|
|
6185
|
+
}
|
|
6186
|
+
function attachedKey(keygen, protocolStatus) {
|
|
6187
|
+
if (protocolStatus === "KeyGenAttached") return true;
|
|
6188
|
+
const value = (keygen ?? "").trim().toLowerCase();
|
|
6189
|
+
return Boolean(value && value !== "0" && !/^0x0+$/.test(value));
|
|
6190
|
+
}
|
|
6191
|
+
function asBig(value) {
|
|
6192
|
+
try {
|
|
6193
|
+
return BigInt(value || "0");
|
|
6194
|
+
} catch {
|
|
6195
|
+
return 0n;
|
|
6196
|
+
}
|
|
6197
|
+
}
|
|
6198
|
+
function parseCtm(raw) {
|
|
6199
|
+
const trimmed = raw?.trim();
|
|
6200
|
+
if (!trimmed) return null;
|
|
6201
|
+
return viem.parseUnits(trimmed, 18);
|
|
6202
|
+
}
|
|
6203
|
+
function parseTime(raw) {
|
|
6204
|
+
const trimmed = raw?.trim();
|
|
6205
|
+
if (!trimmed) return null;
|
|
6206
|
+
if (/^\d+$/.test(trimmed)) {
|
|
6207
|
+
const n = Number(trimmed);
|
|
6208
|
+
if (!Number.isFinite(n)) throw new Error("Unlock bound must be an ISO date or unix seconds.");
|
|
6209
|
+
return n > 1e12 ? Math.floor(n / 1e3) : n;
|
|
6210
|
+
}
|
|
6211
|
+
const ms = Date.parse(trimmed);
|
|
6212
|
+
if (Number.isNaN(ms)) throw new Error("Unlock bound must be an ISO date or unix seconds.");
|
|
6213
|
+
return Math.floor(ms / 1e3);
|
|
6214
|
+
}
|
|
6215
|
+
function paymentMeta(address) {
|
|
6216
|
+
const lower = address.toLowerCase();
|
|
6217
|
+
if (lower === exports.MARKETPLACE_USDC_LINEA_ADDRESS.toLowerCase()) return { symbol: "USDC", decimals: 6 };
|
|
6218
|
+
if (lower === exports.MARKETPLACE_WETH_LINEA_ADDRESS.toLowerCase()) return { symbol: "WETH", decimals: 18 };
|
|
6219
|
+
if (lower === exports.CTM_TOKEN_ADDRESS.toLowerCase()) return { symbol: "CTM", decimals: 18 };
|
|
6220
|
+
return { symbol: "token", decimals: 18 };
|
|
6221
|
+
}
|
|
6222
|
+
function trimDecimal(value) {
|
|
6223
|
+
return value.replace(/(\.\d*?[1-9])0+$/, "$1").replace(/\.0+$/, "");
|
|
6224
|
+
}
|
|
6225
|
+
function humanAmount(wei, decimals) {
|
|
6226
|
+
return trimDecimal(viem.formatUnits(wei, decimals));
|
|
6227
|
+
}
|
|
6228
|
+
function positive(value) {
|
|
6229
|
+
const trimmed = (value ?? "").trim();
|
|
6230
|
+
return trimmed && trimmed !== "0" ? trimmed : "";
|
|
6231
|
+
}
|
|
6232
|
+
function unlockUnixFrom(row) {
|
|
6233
|
+
const iso2 = positive(row.unlockTimeAt);
|
|
6234
|
+
if (iso2) {
|
|
6235
|
+
const ms = Date.parse(iso2);
|
|
6236
|
+
if (!Number.isNaN(ms)) return Math.floor(ms / 1e3);
|
|
6237
|
+
}
|
|
6238
|
+
const unix = positive(row.unlockTime) || positive(row.snapshotEnd);
|
|
6239
|
+
return unix ? Number(unix) : 0;
|
|
6240
|
+
}
|
|
6241
|
+
function lockedFrom(row) {
|
|
6242
|
+
return asBig(positive(row.lockedCTM) || positive(row.currentLockedAmount) || positive(row.snapshotAmount));
|
|
6243
|
+
}
|
|
6244
|
+
function listingCandidate(row) {
|
|
6245
|
+
const attached = attachedKey(row.keygen, row.protocolStatus);
|
|
6246
|
+
const open = row.protocolStatus === "Open" || row.storedStatus === "Open";
|
|
6247
|
+
return {
|
|
6248
|
+
kind: "listing",
|
|
6249
|
+
tokenId: row.tokenId,
|
|
6250
|
+
onchainIndex: row.onchainIndex,
|
|
6251
|
+
seller: row.seller ?? row.creator,
|
|
6252
|
+
paymentToken: row.paymentToken,
|
|
6253
|
+
price: asBig(row.price),
|
|
6254
|
+
priceBasis: "ask",
|
|
6255
|
+
locked: lockedFrom(row),
|
|
6256
|
+
unlockUnix: unlockUnixFrom(row),
|
|
6257
|
+
deadlineUnix: Number(row.deadlineUnix || "0") || 0,
|
|
6258
|
+
attached,
|
|
6259
|
+
fillable: open && !attached,
|
|
6260
|
+
protocolStatus: row.protocolStatus,
|
|
6261
|
+
storedStatus: row.storedStatus,
|
|
6262
|
+
keygen: row.keygen
|
|
6263
|
+
};
|
|
6264
|
+
}
|
|
6265
|
+
function auctionCandidate(row) {
|
|
6266
|
+
const attached = attachedKey(row.keygen, row.storedStatus);
|
|
6267
|
+
const bid = asBig(row.highestBid);
|
|
6268
|
+
const reserve = asBig(row.reservePrice);
|
|
6269
|
+
const live = row.derivedStatus === "Pending" || row.derivedStatus === "Active";
|
|
6270
|
+
return {
|
|
6271
|
+
kind: "auction",
|
|
6272
|
+
tokenId: row.tokenId,
|
|
6273
|
+
onchainIndex: row.onchainIndex,
|
|
6274
|
+
seller: row.seller,
|
|
6275
|
+
paymentToken: row.paymentToken,
|
|
6276
|
+
price: bid > 0n ? bid : reserve,
|
|
6277
|
+
priceBasis: bid > 0n ? "highestBid" : "reserve",
|
|
6278
|
+
locked: lockedFrom(row),
|
|
6279
|
+
unlockUnix: unlockUnixFrom(row),
|
|
6280
|
+
deadlineUnix: Number(row.deadlineUnix || "0") || 0,
|
|
6281
|
+
attached,
|
|
6282
|
+
fillable: live && !attached,
|
|
6283
|
+
protocolStatus: row.derivedStatus,
|
|
6284
|
+
storedStatus: row.storedStatus,
|
|
6285
|
+
keygen: row.keygen
|
|
6286
|
+
};
|
|
6287
|
+
}
|
|
6288
|
+
function applyLock(row, lock) {
|
|
6289
|
+
if (row.locked > 0n && row.unlockUnix > 0) return row;
|
|
6290
|
+
if (!lock) return row;
|
|
6291
|
+
return {
|
|
6292
|
+
...row,
|
|
6293
|
+
locked: row.locked > 0n ? row.locked : lock.amount,
|
|
6294
|
+
unlockUnix: row.unlockUnix > 0 ? row.unlockUnix : lock.end
|
|
6295
|
+
};
|
|
6296
|
+
}
|
|
6297
|
+
function rankMarketplaceSearchHits(rows, query, nowUnix = Math.floor(Date.now() / 1e3)) {
|
|
6298
|
+
const sort = query.sort ?? "pricePerLockedCtm";
|
|
6299
|
+
const direction = query.sortDirection ?? DEFAULT_DIRECTION[sort];
|
|
6300
|
+
const minLocked = parseCtm(query.minLockedCtm);
|
|
6301
|
+
const maxLocked = parseCtm(query.maxLockedCtm);
|
|
6302
|
+
const unlockAfter = parseTime(query.unlockAfter);
|
|
6303
|
+
const unlockBefore = parseTime(query.unlockBefore);
|
|
6304
|
+
const monthCap = query.maxUnlockMonths != null && Number.isFinite(query.maxUnlockMonths) ? nowUnix + Math.floor(query.maxUnlockMonths * MONTH_SECONDS) : null;
|
|
6305
|
+
const executor = query.executor?.trim();
|
|
6306
|
+
const excludeOwned = query.excludeOwned !== false && Boolean(executor);
|
|
6307
|
+
let matched = rows.filter((row) => {
|
|
6308
|
+
if (query.paymentToken && !same3(row.paymentToken, query.paymentToken)) return false;
|
|
6309
|
+
if (excludeOwned && same3(row.seller, executor)) return false;
|
|
6310
|
+
if (minLocked != null && row.locked < minLocked) return false;
|
|
6311
|
+
if (maxLocked != null && row.locked > maxLocked) return false;
|
|
6312
|
+
if (unlockAfter != null && row.unlockUnix < unlockAfter) return false;
|
|
6313
|
+
if (unlockBefore != null && (row.unlockUnix <= 0 || row.unlockUnix > unlockBefore)) return false;
|
|
6314
|
+
if (monthCap != null && (row.unlockUnix <= nowUnix || row.unlockUnix > monthCap)) return false;
|
|
6315
|
+
return true;
|
|
6316
|
+
});
|
|
6317
|
+
const priceSort = sort === "price" || sort === "pricePerLockedCtm";
|
|
6318
|
+
if (priceSort && !query.paymentToken) {
|
|
6319
|
+
const tokens = new Set(matched.map((row) => row.paymentToken.toLowerCase()));
|
|
6320
|
+
if (tokens.size > 1) {
|
|
6321
|
+
const symbols = [...tokens].map((token) => paymentMeta(token).symbol).join(", ");
|
|
6322
|
+
throw new Error(`Pass paymentToken to rank by price. These rows use ${symbols}.`);
|
|
6323
|
+
}
|
|
6324
|
+
}
|
|
6325
|
+
const asc = direction === "asc";
|
|
6326
|
+
const key = (row) => {
|
|
6327
|
+
if (sort === "locked") return row.locked;
|
|
6328
|
+
if (sort === "unlock") return BigInt(row.unlockUnix || 0);
|
|
6329
|
+
if (sort === "deadline") return BigInt(row.deadlineUnix || 0);
|
|
6330
|
+
if (sort === "pricePerLockedCtm") return row.locked > 0n ? row.price * 10n ** 18n / row.locked : 2n ** 255n - 1n;
|
|
6331
|
+
return row.price;
|
|
6332
|
+
};
|
|
6333
|
+
matched = [...matched].sort((a, b) => {
|
|
6334
|
+
if (a.fillable !== b.fillable) return a.fillable ? -1 : 1;
|
|
6335
|
+
if (sort === "pricePerLockedCtm" && a.locked <= 0n !== b.locked <= 0n) return a.locked <= 0n ? 1 : -1;
|
|
6336
|
+
const cmp = key(a) === key(b) ? 0 : key(a) < key(b) ? -1 : 1;
|
|
6337
|
+
if (cmp !== 0) return asc ? cmp : -cmp;
|
|
6338
|
+
return a.tokenId.localeCompare(b.tokenId);
|
|
6339
|
+
});
|
|
6340
|
+
const limit = Math.min(MAX_LIMIT, Math.max(1, query.limit ?? DEFAULT_LIMIT));
|
|
6341
|
+
return matched.slice(0, limit).map((row) => toHit(row, nowUnix));
|
|
6342
|
+
}
|
|
6343
|
+
function toHit(row, nowUnix) {
|
|
6344
|
+
const meta4 = paymentMeta(row.paymentToken);
|
|
6345
|
+
const perCtm = row.locked > 0n ? row.price * 10n ** 18n / row.locked : 0n;
|
|
6346
|
+
const months = row.unlockUnix > nowUnix ? ((row.unlockUnix - nowUnix) / MONTH_SECONDS).toFixed(1) : row.unlockUnix > 0 ? "0" : "";
|
|
6347
|
+
return {
|
|
6348
|
+
kind: row.kind,
|
|
6349
|
+
tokenId: row.tokenId,
|
|
6350
|
+
onchainIndex: row.onchainIndex,
|
|
6351
|
+
seller: row.seller,
|
|
6352
|
+
paymentToken: row.paymentToken,
|
|
6353
|
+
paymentSymbol: meta4.symbol,
|
|
6354
|
+
price: row.price.toString(),
|
|
6355
|
+
priceHuman: humanAmount(row.price, meta4.decimals),
|
|
6356
|
+
priceBasis: row.priceBasis,
|
|
6357
|
+
lockedCtm: row.locked.toString(),
|
|
6358
|
+
lockedCtmHuman: humanAmount(row.locked, 18),
|
|
6359
|
+
unlockAt: row.unlockUnix > 0 ? new Date(row.unlockUnix * 1e3).toISOString() : "",
|
|
6360
|
+
monthsToUnlock: months,
|
|
6361
|
+
pricePerLockedCtm: row.locked > 0n ? humanAmount(perCtm, meta4.decimals) : "",
|
|
6362
|
+
deadlineAt: row.deadlineUnix > 0 ? new Date(row.deadlineUnix * 1e3).toISOString() : "",
|
|
6363
|
+
attached: row.attached,
|
|
6364
|
+
fillable: row.fillable
|
|
6365
|
+
};
|
|
6366
|
+
}
|
|
6367
|
+
async function fillMissingLocks(rows, rpcUrl, chainId) {
|
|
6368
|
+
const missing = [...new Set(rows.filter((row) => row.locked <= 0n || row.unlockUnix <= 0).map((row) => row.tokenId))];
|
|
6369
|
+
if (missing.length === 0 || !rpcUrl?.trim()) return rows;
|
|
6370
|
+
const client = marketplacePublicClient(chainId, rpcUrl.trim());
|
|
6371
|
+
const locks = /* @__PURE__ */ new Map();
|
|
6372
|
+
for (let i = 0; i < missing.length; i += 40) {
|
|
6373
|
+
const chunk = missing.slice(i, i + 40);
|
|
6374
|
+
const results = await client.multicall({
|
|
6375
|
+
contracts: chunk.map((id) => ({
|
|
6376
|
+
address: exports.VOTING_ESCROW_LINEA_ADDRESS,
|
|
6377
|
+
abi: LOCKED_ABI,
|
|
6378
|
+
functionName: "locked",
|
|
6379
|
+
args: [BigInt(id)]
|
|
6380
|
+
})),
|
|
6381
|
+
allowFailure: true
|
|
6382
|
+
});
|
|
6383
|
+
results.forEach((result, index) => {
|
|
6384
|
+
if (result.status !== "success" || !result.result) return;
|
|
6385
|
+
const [amount, end] = result.result;
|
|
6386
|
+
const id = chunk[index];
|
|
6387
|
+
if (!id) return;
|
|
6388
|
+
locks.set(id, { amount: amount < 0n ? 0n : amount, end: Number(end) });
|
|
6389
|
+
});
|
|
6390
|
+
}
|
|
6391
|
+
return rows.map((row) => applyLock(row, locks.get(row.tokenId)));
|
|
6392
|
+
}
|
|
6393
|
+
async function collectKind(kind, args) {
|
|
6394
|
+
const rows = [];
|
|
6395
|
+
let cursor;
|
|
6396
|
+
let scanned = 0;
|
|
6397
|
+
let source = "api";
|
|
6398
|
+
let truncated = false;
|
|
6399
|
+
for (let page = 0; page < MAX_PAGES; page += 1) {
|
|
6400
|
+
const query = { ...args, includeInactive: false, limit: PAGE_SIZE, cursor };
|
|
6401
|
+
const res = kind === "listing" ? await fetchContinuumDaoMarketplaceListings(query) : await fetchContinuumDaoMarketplaceAuctions(query);
|
|
6402
|
+
source = res.source;
|
|
6403
|
+
scanned += res.items.length;
|
|
6404
|
+
for (const item of res.items) {
|
|
6405
|
+
rows.push(kind === "listing" ? listingCandidate(item) : auctionCandidate(item));
|
|
6406
|
+
}
|
|
6407
|
+
if (res.source === "logs" || !res.nextCursor) return { rows, scanned, truncated, source };
|
|
6408
|
+
cursor = res.nextCursor;
|
|
6409
|
+
}
|
|
6410
|
+
truncated = true;
|
|
6411
|
+
return { rows, scanned, truncated, source };
|
|
6412
|
+
}
|
|
6413
|
+
async function searchContinuumDaoMarketplace(args = {}) {
|
|
6414
|
+
const kind = args.kind ?? "listing";
|
|
6415
|
+
const chainId = args.chainId ?? exports.CONTINUUM_DAO_LINEA_CHAIN_ID;
|
|
6416
|
+
const parts = await Promise.all([
|
|
6417
|
+
kind !== "auction" ? collectKind("listing", args) : Promise.resolve(null),
|
|
6418
|
+
kind !== "listing" ? collectKind("auction", args) : Promise.resolve(null)
|
|
6419
|
+
]);
|
|
6420
|
+
const collected = parts.flatMap((part) => part?.rows ?? []);
|
|
6421
|
+
const withLocks = await fillMissingLocks(collected, args.rpcUrl, chainId);
|
|
6422
|
+
const sort = args.sort ?? "pricePerLockedCtm";
|
|
6423
|
+
const items = rankMarketplaceSearchHits(withLocks, args);
|
|
6424
|
+
return {
|
|
6425
|
+
sort,
|
|
6426
|
+
sortDirection: args.sortDirection ?? DEFAULT_DIRECTION[sort],
|
|
6427
|
+
paymentToken: args.paymentToken ?? null,
|
|
6428
|
+
scanned: parts.reduce((sum, part) => sum + (part?.scanned ?? 0), 0),
|
|
6429
|
+
truncated: parts.some((part) => part?.truncated),
|
|
6430
|
+
items,
|
|
6431
|
+
source: parts.some((part) => part?.source === "logs") ? "logs" : "api"
|
|
6432
|
+
};
|
|
6433
|
+
}
|
|
6434
|
+
|
|
6435
|
+
// src/protocols/evm/continuum-dao/marketplaceFeeAlternative.ts
|
|
6436
|
+
init_constants();
|
|
6437
|
+
var PAGE_SIZE2 = 100;
|
|
6438
|
+
var MAX_PAGES2 = 20;
|
|
6439
|
+
var feeAbi = viem.parseAbi([
|
|
6440
|
+
"function veCtmThresholdPower() view returns (uint256)",
|
|
6441
|
+
"function getActiveRates() view returns (uint256 monthlyFee, uint256 freeSignaturesPerMonth, uint256 overageFeePerSignature)",
|
|
6442
|
+
"function FEE_TOKEN() view returns (address)",
|
|
6443
|
+
"function ctmPerFeeToken() view returns (uint256)",
|
|
6444
|
+
"function locked(uint256 tokenId) view returns (int128 amount, uint256 end)",
|
|
6445
|
+
"function balanceOfNFT(uint256 tokenId) view returns (uint256)"
|
|
6446
|
+
]);
|
|
6447
|
+
function trimDecimal2(value) {
|
|
6448
|
+
return value.replace(/(\.\d*?[1-9])0+$/, "$1").replace(/\.0+$/, "");
|
|
6449
|
+
}
|
|
6450
|
+
function human(wei, decimals) {
|
|
6451
|
+
return trimDecimal2(viem.formatUnits(wei, decimals));
|
|
6452
|
+
}
|
|
6453
|
+
function paymentMeta2(address) {
|
|
6454
|
+
const lower = address.toLowerCase();
|
|
6455
|
+
if (lower === exports.MARKETPLACE_USDC_LINEA_ADDRESS.toLowerCase()) return { symbol: "USDC", decimals: 6 };
|
|
6456
|
+
if (lower === exports.MARKETPLACE_WETH_LINEA_ADDRESS.toLowerCase()) return { symbol: "WETH", decimals: 18 };
|
|
6457
|
+
if (lower === exports.CTM_TOKEN_ADDRESS.toLowerCase()) return { symbol: "CTM", decimals: 18 };
|
|
6458
|
+
return { symbol: "token", decimals: 18 };
|
|
6459
|
+
}
|
|
6460
|
+
function monthsOfFees(price, monthly) {
|
|
6461
|
+
if (monthly <= 0n || price < 0n) return null;
|
|
6462
|
+
const tenths = price * 10n / monthly;
|
|
6463
|
+
const whole = tenths / 10n;
|
|
6464
|
+
const frac = tenths % 10n;
|
|
6465
|
+
return frac === 0n ? whole.toString() : `${whole}.${frac}`;
|
|
6466
|
+
}
|
|
6467
|
+
function votingPowerAboveUntil(args) {
|
|
6468
|
+
if (args.votingPower <= args.threshold) return null;
|
|
6469
|
+
if (args.unlockUnix <= args.nowUnix) return null;
|
|
6470
|
+
if (args.threshold <= 0n) return args.unlockUnix;
|
|
6471
|
+
const remaining = BigInt(args.unlockUnix - args.nowUnix);
|
|
6472
|
+
const drop = remaining * args.threshold / args.votingPower;
|
|
6473
|
+
return args.unlockUnix - Number(drop);
|
|
6474
|
+
}
|
|
6475
|
+
function pickFeeAlternativeExample(rows, preferredToken) {
|
|
6476
|
+
const fillable = rows.filter((row) => row.fillable && row.locked > 0n && row.votingPower > 0n);
|
|
6477
|
+
const preferred = preferredToken ? fillable.filter((row) => row.paymentToken.toLowerCase() === preferredToken.toLowerCase()) : [];
|
|
6478
|
+
const pool = preferred.length > 0 ? preferred : fillable;
|
|
6479
|
+
const perCtm = (row) => row.price * 10n ** 18n / row.locked;
|
|
6480
|
+
return [...pool].sort((a, b) => {
|
|
6481
|
+
const left = perCtm(a);
|
|
6482
|
+
const right = perCtm(b);
|
|
6483
|
+
if (left === right) return a.tokenId.localeCompare(b.tokenId);
|
|
6484
|
+
return left < right ? -1 : 1;
|
|
6485
|
+
})[0] ?? null;
|
|
6486
|
+
}
|
|
6487
|
+
function iso(unix) {
|
|
6488
|
+
return unix > 0 ? new Date(unix * 1e3).toISOString() : "";
|
|
6489
|
+
}
|
|
6490
|
+
function buildFeeAlternativeSummary(args) {
|
|
6491
|
+
const fee = `${args.monthlyFeeHuman} ${args.monthlyFeeSymbol}`;
|
|
6492
|
+
const year = `${args.annualFeeHuman} ${args.monthlyFeeSymbol} (${args.annualFeeCtmHuman} CTM)`;
|
|
6493
|
+
const lead = `Paying this month is ${fee}. A year for one KeyGen is ${year}. As an alternative, buy a veCTM and attach it. Locked CTM and voting power both have to be above ${args.thresholdHuman}. One attached veCTM waives the monthly fee for KeyGens in that group, and VPN follows a qualifying group on the node. Voting power decays, so a lock sitting on the line can miss a later month.`;
|
|
6494
|
+
if (!args.example) {
|
|
6495
|
+
return `${lead} No live direct listing is above that threshold right now.`;
|
|
6496
|
+
}
|
|
6497
|
+
const row = args.example;
|
|
6498
|
+
const compare = row.monthsOfFees ? ` That ask is about ${row.monthsOfFees} months of fees. The ask buys a lock you still hold; the monthly fee is spent.` : ` The listing is priced in ${row.paymentSymbol}, which is a different token from the fee.`;
|
|
6499
|
+
return `${lead} Example direct listing #${row.tokenId}: ${row.priceHuman} ${row.paymentSymbol} for ${row.lockedCtmHuman} CTM, unlocks ${row.unlockAt}. Voting power stays above the threshold until ${row.staysAboveThresholdUntil}.${compare}`;
|
|
6500
|
+
}
|
|
6501
|
+
async function readFeeSide(rpcUrl, chainId) {
|
|
6502
|
+
const client = marketplacePublicClient(chainId, rpcUrl);
|
|
6503
|
+
const wallet = exports.MULTISIGN_AGENT_WALLET_LINEA_ADDRESS;
|
|
6504
|
+
const [threshold, rates, feeToken, ctmPerFeeToken] = await Promise.all([
|
|
6505
|
+
client.readContract({ address: wallet, abi: feeAbi, functionName: "veCtmThresholdPower" }),
|
|
6506
|
+
client.readContract({ address: wallet, abi: feeAbi, functionName: "getActiveRates" }),
|
|
6507
|
+
client.readContract({ address: wallet, abi: feeAbi, functionName: "FEE_TOKEN" }),
|
|
6508
|
+
client.readContract({ address: wallet, abi: feeAbi, functionName: "ctmPerFeeToken" })
|
|
6509
|
+
]);
|
|
6510
|
+
const monthlyFee = rates[0];
|
|
6511
|
+
const monthlyFeeCtm = ctmPerFeeToken > 0n ? monthlyFee * ctmPerFeeToken / exports.CTM_FEE_RATE_SCALE : 0n;
|
|
6512
|
+
return { threshold, monthlyFee, monthlyFeeCtm, feeToken: viem.getAddress(feeToken) };
|
|
6513
|
+
}
|
|
6514
|
+
async function collectListings(args) {
|
|
6515
|
+
const rows = [];
|
|
6516
|
+
let cursor;
|
|
6517
|
+
let scanned = 0;
|
|
6518
|
+
let source = "api";
|
|
6519
|
+
let truncated = false;
|
|
6520
|
+
for (let page = 0; page < MAX_PAGES2; page += 1) {
|
|
6521
|
+
const res = await fetchContinuumDaoMarketplaceListings({ ...args, includeInactive: false, limit: PAGE_SIZE2, cursor });
|
|
6522
|
+
source = res.source;
|
|
6523
|
+
scanned += res.items.length;
|
|
6524
|
+
rows.push(...res.items.map(listingCandidate));
|
|
6525
|
+
if (res.source === "logs" || !res.nextCursor) return { rows, scanned, truncated, source };
|
|
6526
|
+
cursor = res.nextCursor;
|
|
6527
|
+
}
|
|
6528
|
+
return { rows, scanned, truncated: true, source };
|
|
6529
|
+
}
|
|
6530
|
+
async function fillLocks(rows, rpcUrl, chainId) {
|
|
6531
|
+
const missing = [...new Set(rows.filter((row) => row.locked <= 0n || row.unlockUnix <= 0).map((row) => row.tokenId))];
|
|
6532
|
+
if (missing.length === 0) return rows;
|
|
6533
|
+
const client = marketplacePublicClient(chainId, rpcUrl);
|
|
6534
|
+
const locks = /* @__PURE__ */ new Map();
|
|
6535
|
+
for (let i = 0; i < missing.length; i += 40) {
|
|
6536
|
+
const chunk = missing.slice(i, i + 40);
|
|
6537
|
+
const results = await client.multicall({
|
|
6538
|
+
contracts: chunk.map((id) => ({
|
|
6539
|
+
address: exports.VOTING_ESCROW_LINEA_ADDRESS,
|
|
6540
|
+
abi: feeAbi,
|
|
6541
|
+
functionName: "locked",
|
|
6542
|
+
args: [BigInt(id)]
|
|
6543
|
+
})),
|
|
6544
|
+
allowFailure: true
|
|
6545
|
+
});
|
|
6546
|
+
results.forEach((result, index) => {
|
|
6547
|
+
if (result.status !== "success" || !result.result) return;
|
|
6548
|
+
const id = chunk[index];
|
|
6549
|
+
if (!id) return;
|
|
6550
|
+
const [amount, end] = result.result;
|
|
6551
|
+
locks.set(id, { amount: amount < 0n ? 0n : amount, end: Number(end) });
|
|
6552
|
+
});
|
|
6553
|
+
}
|
|
6554
|
+
return rows.map((row) => {
|
|
6555
|
+
const lock = locks.get(row.tokenId);
|
|
6556
|
+
if (!lock) return row;
|
|
6557
|
+
return { ...row, locked: row.locked > 0n ? row.locked : lock.amount, unlockUnix: row.unlockUnix > 0 ? row.unlockUnix : lock.end };
|
|
6558
|
+
});
|
|
6559
|
+
}
|
|
6560
|
+
async function readVotingPower(tokenIds, rpcUrl, chainId) {
|
|
6561
|
+
const client = marketplacePublicClient(chainId, rpcUrl);
|
|
6562
|
+
const power = /* @__PURE__ */ new Map();
|
|
6563
|
+
for (let i = 0; i < tokenIds.length; i += 40) {
|
|
6564
|
+
const chunk = tokenIds.slice(i, i + 40);
|
|
6565
|
+
const results = await client.multicall({
|
|
6566
|
+
contracts: chunk.map((id) => ({
|
|
6567
|
+
address: exports.VOTING_ESCROW_LINEA_ADDRESS,
|
|
6568
|
+
abi: feeAbi,
|
|
6569
|
+
functionName: "balanceOfNFT",
|
|
6570
|
+
args: [BigInt(id)]
|
|
6571
|
+
})),
|
|
6572
|
+
allowFailure: true
|
|
6573
|
+
});
|
|
6574
|
+
results.forEach((result, index) => {
|
|
6575
|
+
const id = chunk[index];
|
|
6576
|
+
if (!id || result.status !== "success") return;
|
|
6577
|
+
power.set(id, result.result);
|
|
6578
|
+
});
|
|
6579
|
+
}
|
|
6580
|
+
return power;
|
|
6581
|
+
}
|
|
6582
|
+
async function quoteContinuumDaoMarketplaceFeeAlternative(args) {
|
|
6583
|
+
const rpcUrl = args.rpcUrl?.trim();
|
|
6584
|
+
if (!rpcUrl) throw new Error("Linea RPC is required to read the monthly fee and veCTM threshold.");
|
|
6585
|
+
const chainId = args.chainId ?? exports.CONTINUUM_DAO_LINEA_CHAIN_ID;
|
|
6586
|
+
const payment = args.payment ?? "fee";
|
|
6587
|
+
const nowUnix = Math.floor(Date.now() / 1e3);
|
|
6588
|
+
const fee = await readFeeSide(rpcUrl, chainId);
|
|
6589
|
+
const collected = await collectListings(args);
|
|
6590
|
+
const withLocks = await fillLocks(collected.rows, rpcUrl, chainId);
|
|
6591
|
+
const executor = args.executor?.trim();
|
|
6592
|
+
const visible = executor ? withLocks.filter((row) => {
|
|
6593
|
+
try {
|
|
6594
|
+
return viem.getAddress(row.seller) !== viem.getAddress(executor);
|
|
6595
|
+
} catch {
|
|
6596
|
+
return row.seller.toLowerCase() !== executor.toLowerCase();
|
|
6597
|
+
}
|
|
6598
|
+
}) : withLocks;
|
|
6599
|
+
const aboveLock = visible.filter((row) => row.fillable && row.locked > fee.threshold);
|
|
6600
|
+
const power = await readVotingPower(aboveLock.map((row) => row.tokenId), rpcUrl, chainId);
|
|
6601
|
+
const qualified = aboveLock.flatMap((row) => {
|
|
6602
|
+
const votingPower = power.get(row.tokenId);
|
|
6603
|
+
if (votingPower == null || votingPower <= fee.threshold) return [];
|
|
6604
|
+
return [
|
|
6605
|
+
{
|
|
6606
|
+
tokenId: row.tokenId,
|
|
6607
|
+
paymentToken: row.paymentToken,
|
|
6608
|
+
price: row.price,
|
|
6609
|
+
locked: row.locked,
|
|
6610
|
+
unlockUnix: row.unlockUnix,
|
|
6611
|
+
votingPower,
|
|
6612
|
+
fillable: row.fillable
|
|
6613
|
+
}
|
|
6614
|
+
];
|
|
6615
|
+
});
|
|
6616
|
+
const preferred = payment === "ctm" ? exports.CTM_TOKEN_ADDRESS : fee.feeToken;
|
|
6617
|
+
const picked = pickFeeAlternativeExample(qualified, preferred);
|
|
6618
|
+
const feeMeta = paymentMeta2(fee.feeToken);
|
|
6619
|
+
const example = picked ? toExample(picked, fee, payment, preferred, nowUnix) : null;
|
|
6620
|
+
const quoteBase = {
|
|
6621
|
+
payment,
|
|
6622
|
+
threshold: fee.threshold.toString(),
|
|
6623
|
+
thresholdHuman: human(fee.threshold, 18),
|
|
6624
|
+
monthlyFee: fee.monthlyFee.toString(),
|
|
6625
|
+
monthlyFeeHuman: human(fee.monthlyFee, feeMeta.decimals),
|
|
6626
|
+
monthlyFeeSymbol: feeMeta.symbol,
|
|
6627
|
+
annualFee: (fee.monthlyFee * 12n).toString(),
|
|
6628
|
+
annualFeeHuman: human(fee.monthlyFee * 12n, feeMeta.decimals),
|
|
6629
|
+
monthlyFeeCtm: fee.monthlyFeeCtm.toString(),
|
|
6630
|
+
monthlyFeeCtmHuman: human(fee.monthlyFeeCtm, 18),
|
|
6631
|
+
annualFeeCtm: (fee.monthlyFeeCtm * 12n).toString(),
|
|
6632
|
+
annualFeeCtmHuman: human(fee.monthlyFeeCtm * 12n, 18),
|
|
6633
|
+
feeToken: fee.feeToken,
|
|
6634
|
+
example,
|
|
6635
|
+
scanned: collected.scanned,
|
|
6636
|
+
truncated: collected.truncated,
|
|
6637
|
+
source: collected.source
|
|
6638
|
+
};
|
|
6639
|
+
return {
|
|
6640
|
+
...quoteBase,
|
|
6641
|
+
summary: buildFeeAlternativeSummary({
|
|
6642
|
+
thresholdHuman: quoteBase.thresholdHuman,
|
|
6643
|
+
monthlyFeeHuman: quoteBase.monthlyFeeHuman,
|
|
6644
|
+
monthlyFeeSymbol: quoteBase.monthlyFeeSymbol,
|
|
6645
|
+
annualFeeHuman: quoteBase.annualFeeHuman,
|
|
6646
|
+
annualFeeCtmHuman: quoteBase.annualFeeCtmHuman,
|
|
6647
|
+
example
|
|
6648
|
+
})
|
|
6649
|
+
};
|
|
6650
|
+
}
|
|
6651
|
+
function toExample(row, fee, payment, preferred, nowUnix) {
|
|
6652
|
+
const meta4 = paymentMeta2(row.paymentToken);
|
|
6653
|
+
const same5 = row.paymentToken.toLowerCase() === preferred.toLowerCase();
|
|
6654
|
+
const monthly = payment === "ctm" ? fee.monthlyFeeCtm : fee.monthlyFee;
|
|
6655
|
+
const until = votingPowerAboveUntil({
|
|
6656
|
+
votingPower: row.votingPower,
|
|
6657
|
+
threshold: fee.threshold,
|
|
6658
|
+
nowUnix,
|
|
6659
|
+
unlockUnix: row.unlockUnix
|
|
6660
|
+
});
|
|
6661
|
+
const perCtm = row.price * 10n ** 18n / row.locked;
|
|
6662
|
+
return {
|
|
6663
|
+
tokenId: row.tokenId,
|
|
6664
|
+
price: row.price.toString(),
|
|
6665
|
+
priceHuman: human(row.price, meta4.decimals),
|
|
6666
|
+
paymentToken: row.paymentToken,
|
|
6667
|
+
paymentSymbol: meta4.symbol,
|
|
6668
|
+
lockedCtm: row.locked.toString(),
|
|
6669
|
+
lockedCtmHuman: human(row.locked, 18),
|
|
6670
|
+
unlockAt: iso(row.unlockUnix),
|
|
6671
|
+
votingPower: row.votingPower.toString(),
|
|
6672
|
+
votingPowerHuman: human(row.votingPower, 18),
|
|
6673
|
+
staysAboveThresholdUntil: iso(until ?? 0),
|
|
6674
|
+
pricePerLockedCtm: human(perCtm, meta4.decimals),
|
|
6675
|
+
monthsOfFees: same5 ? monthsOfFees(row.price, monthly) : null,
|
|
6676
|
+
comparedTo: same5 ? payment : null,
|
|
6677
|
+
fillable: row.fillable
|
|
6678
|
+
};
|
|
6679
|
+
}
|
|
6680
|
+
|
|
6681
|
+
// src/protocols/evm/continuum-dao/marketplaceMultisign.ts
|
|
6682
|
+
init_buildBatch();
|
|
6683
|
+
init_constants();
|
|
6684
|
+
function parseWei(raw, label) {
|
|
6685
|
+
const value = typeof raw === "bigint" ? raw : BigInt(String(raw).trim());
|
|
6686
|
+
if (value < 0n) throw new Error(`${label} must be zero or greater.`);
|
|
6687
|
+
return value;
|
|
6688
|
+
}
|
|
6689
|
+
function parseTokenId2(raw) {
|
|
6690
|
+
const id = typeof raw === "bigint" ? raw : BigInt(String(raw).trim());
|
|
6691
|
+
if (id <= 0n) throw new Error("veCTM token id must be greater than zero.");
|
|
6692
|
+
return id;
|
|
6693
|
+
}
|
|
6694
|
+
function requireLinea(chainId) {
|
|
6695
|
+
if (chainId !== exports.CONTINUUM_DAO_LINEA_CHAIN_ID) {
|
|
6696
|
+
throw new Error("veCTM marketplace actions are Linea mainnet only.");
|
|
6697
|
+
}
|
|
6698
|
+
}
|
|
6699
|
+
function meta3(step, chainId, gasLimit) {
|
|
6700
|
+
return {
|
|
6701
|
+
destinationAddress: step.to,
|
|
6702
|
+
signatureText: continuumDaoSignatureText({ name: step.name, ...step.extra }, chainId),
|
|
6703
|
+
evm: {
|
|
6704
|
+
type: step.evmType,
|
|
6705
|
+
version: 1,
|
|
6706
|
+
chainId: String(chainId),
|
|
6707
|
+
protocolId: exports.CONTINUUM_DAO_MARKETPLACE_PROTOCOL_ID
|
|
6708
|
+
},
|
|
6709
|
+
continuumDaoMarketplace: { ...step.extra, name: step.name, gas: { baseGasUnits: gasLimit.toString() } }
|
|
6710
|
+
};
|
|
6711
|
+
}
|
|
6712
|
+
async function finalize2(steps, args, purposeSuffix) {
|
|
6713
|
+
const evmSteps = steps.map((s) => ({
|
|
6714
|
+
to: s.to,
|
|
6715
|
+
data: s.data,
|
|
6716
|
+
value: s.value,
|
|
6717
|
+
fallbackGas: s.fallbackGas
|
|
6718
|
+
}));
|
|
6719
|
+
const firstDataNo0x = evmSteps[0].data.startsWith("0x") ? evmSteps[0].data.slice(2) : evmSteps[0].data;
|
|
6720
|
+
return buildEvmMultisignBatch({
|
|
6721
|
+
context: {
|
|
6722
|
+
chainCategory: "evm",
|
|
6723
|
+
keyGen: args.keyGen,
|
|
6724
|
+
purposeText: args.purposeText,
|
|
6725
|
+
chainId: args.chainId,
|
|
6726
|
+
rpcUrl: args.rpcUrl.trim(),
|
|
6727
|
+
executorAddress: args.executorAddress,
|
|
6728
|
+
chainDetail: args.chainDetail,
|
|
6729
|
+
useCustomGas: args.useCustomGas,
|
|
6730
|
+
customGasChainDetails: args.customGasChainDetails
|
|
6731
|
+
},
|
|
6732
|
+
steps: evmSteps,
|
|
6733
|
+
purposeSuffix,
|
|
6734
|
+
firstMsgRawNo0x: firstDataNo0x,
|
|
6735
|
+
destinationAddress: steps[0].to,
|
|
6736
|
+
buildBatchMeta: ({ index, gasLimit }) => meta3(steps[index], args.chainId, gasLimit)
|
|
6737
|
+
});
|
|
6738
|
+
}
|
|
6739
|
+
async function build(args, input, purposeSuffix, snapshotArgs) {
|
|
6740
|
+
requireLinea(args.chainId);
|
|
6741
|
+
const executor = viem.getAddress(args.executorAddress);
|
|
6742
|
+
const tokenId = "tokenId" in input ? input.tokenId : 0n;
|
|
6743
|
+
const snap = await loadMarketplacePlanSnapshot({
|
|
6744
|
+
chainId: args.chainId,
|
|
6745
|
+
rpcUrl: args.rpcUrl,
|
|
6746
|
+
executor,
|
|
6747
|
+
tokenId,
|
|
6748
|
+
...snapshotArgs
|
|
6749
|
+
});
|
|
6750
|
+
const steps = planMarketplaceSteps(input, snap);
|
|
6751
|
+
return finalize2(steps, args, purposeSuffix);
|
|
6752
|
+
}
|
|
6753
|
+
async function buildEvmMultisignBodyContinuumDaoMarketplaceCreateListing(args) {
|
|
6754
|
+
const tokenId = parseTokenId2(args.tokenId);
|
|
6755
|
+
const paymentToken = viem.getAddress(args.paymentToken);
|
|
6756
|
+
const askWei = parseWei(args.askWei, "Ask");
|
|
6757
|
+
const deadline = parseWei(args.deadline, "Deadline");
|
|
6758
|
+
return build(
|
|
6759
|
+
args,
|
|
6760
|
+
{ action: "createListing", tokenId, paymentToken, askWei, deadline },
|
|
6761
|
+
`ContinuumDAO marketplace: list veCTM #${tokenId.toString()}.`,
|
|
6762
|
+
{ paymentToken }
|
|
6763
|
+
);
|
|
6764
|
+
}
|
|
6765
|
+
async function buildEvmMultisignBodyContinuumDaoMarketplaceDelist(args) {
|
|
6766
|
+
const tokenId = parseTokenId2(args.tokenId);
|
|
6767
|
+
return build(args, { action: "delist", tokenId }, `ContinuumDAO marketplace: delist veCTM #${tokenId.toString()}.`, {});
|
|
6768
|
+
}
|
|
6769
|
+
async function buildEvmMultisignBodyContinuumDaoMarketplaceFulfillListing(args) {
|
|
6770
|
+
const tokenId = parseTokenId2(args.tokenId);
|
|
6771
|
+
const seller = viem.getAddress(args.seller);
|
|
6772
|
+
const paymentToken = viem.getAddress(args.paymentToken);
|
|
6773
|
+
const priceWei = parseWei(args.priceWei, "Price");
|
|
6774
|
+
return build(
|
|
6775
|
+
args,
|
|
6776
|
+
{ action: "fulfillListing", tokenId, seller, paymentToken, priceWei },
|
|
6777
|
+
`ContinuumDAO marketplace: buy veCTM #${tokenId.toString()}.`,
|
|
6778
|
+
{ seller, paymentToken }
|
|
6779
|
+
);
|
|
6780
|
+
}
|
|
6781
|
+
async function buildEvmMultisignBodyContinuumDaoMarketplaceCreateOffering(args) {
|
|
6782
|
+
const tokenId = parseTokenId2(args.tokenId);
|
|
6783
|
+
const paymentToken = viem.getAddress(args.paymentToken);
|
|
6784
|
+
const bidWei = parseWei(args.bidWei, "Bid");
|
|
6785
|
+
const deadline = parseWei(args.deadline, "Deadline");
|
|
6786
|
+
return build(
|
|
6787
|
+
args,
|
|
6788
|
+
{ action: "createOffering", tokenId, paymentToken, bidWei, deadline },
|
|
6789
|
+
`ContinuumDAO marketplace: offer on veCTM #${tokenId.toString()}.`,
|
|
6790
|
+
{ paymentToken }
|
|
6791
|
+
);
|
|
6792
|
+
}
|
|
6793
|
+
async function buildEvmMultisignBodyContinuumDaoMarketplaceRescind(args) {
|
|
6794
|
+
const tokenId = parseTokenId2(args.tokenId);
|
|
6795
|
+
return build(
|
|
6796
|
+
args,
|
|
6797
|
+
{ action: "rescind", tokenId },
|
|
6798
|
+
`ContinuumDAO marketplace: rescind offer on veCTM #${tokenId.toString()}.`,
|
|
6799
|
+
{}
|
|
6800
|
+
);
|
|
6801
|
+
}
|
|
6802
|
+
async function buildEvmMultisignBodyContinuumDaoMarketplaceFulfillOffering(args) {
|
|
6803
|
+
const tokenId = parseTokenId2(args.tokenId);
|
|
6804
|
+
const buyer = viem.getAddress(args.buyer);
|
|
6805
|
+
const paymentToken = viem.getAddress(args.paymentToken);
|
|
6806
|
+
const priceWei = parseWei(args.priceWei, "Price");
|
|
6807
|
+
return build(
|
|
6808
|
+
args,
|
|
6809
|
+
{ action: "fulfillOffering", tokenId, buyer, paymentToken, priceWei },
|
|
6810
|
+
`ContinuumDAO marketplace: accept offer on veCTM #${tokenId.toString()}.`,
|
|
6811
|
+
{ buyer, paymentToken }
|
|
6812
|
+
);
|
|
6813
|
+
}
|
|
6814
|
+
async function buildEvmMultisignBodyContinuumDaoMarketplaceCreateAuction(args) {
|
|
6815
|
+
const tokenId = parseTokenId2(args.tokenId);
|
|
6816
|
+
const paymentToken = viem.getAddress(args.paymentToken);
|
|
6817
|
+
const deadline = parseWei(args.deadline, "Deadline");
|
|
6818
|
+
const reserveWei = parseWei(args.reserveWei, "Reserve");
|
|
6819
|
+
const minIncrementWei = parseWei(args.minIncrementWei, "Minimum increment");
|
|
6820
|
+
return build(
|
|
6821
|
+
args,
|
|
6822
|
+
{ action: "createAuction", tokenId, paymentToken, deadline, reserveWei, minIncrementWei },
|
|
6823
|
+
`ContinuumDAO marketplace: auction veCTM #${tokenId.toString()}.`,
|
|
6824
|
+
{ paymentToken }
|
|
6825
|
+
);
|
|
6826
|
+
}
|
|
6827
|
+
async function buildEvmMultisignBodyContinuumDaoMarketplaceCancelAuction(args) {
|
|
6828
|
+
const tokenId = parseTokenId2(args.tokenId);
|
|
6829
|
+
return build(
|
|
6830
|
+
args,
|
|
6831
|
+
{ action: "cancelAuction", tokenId },
|
|
6832
|
+
`ContinuumDAO marketplace: cancel auction for veCTM #${tokenId.toString()}.`,
|
|
6833
|
+
{}
|
|
6834
|
+
);
|
|
6835
|
+
}
|
|
6836
|
+
async function buildEvmMultisignBodyContinuumDaoMarketplaceAuctionBid(args) {
|
|
6837
|
+
const tokenId = parseTokenId2(args.tokenId);
|
|
6838
|
+
const seller = viem.getAddress(args.seller);
|
|
6839
|
+
const priceWei = parseWei(args.priceWei, "Bid");
|
|
6840
|
+
return build(
|
|
6841
|
+
args,
|
|
6842
|
+
{ action: "auctionBid", tokenId, seller, priceWei },
|
|
6843
|
+
`ContinuumDAO marketplace: bid on veCTM #${tokenId.toString()}.`,
|
|
6844
|
+
{ seller }
|
|
6845
|
+
);
|
|
6846
|
+
}
|
|
6847
|
+
async function buildEvmMultisignBodyContinuumDaoMarketplaceSettleAuction(args) {
|
|
6848
|
+
const tokenId = parseTokenId2(args.tokenId);
|
|
6849
|
+
const seller = viem.getAddress(args.seller);
|
|
6850
|
+
return build(
|
|
6851
|
+
args,
|
|
6852
|
+
{ action: "settleAuction", tokenId, seller },
|
|
6853
|
+
`ContinuumDAO marketplace: settle auction for veCTM #${tokenId.toString()}.`,
|
|
6854
|
+
{ seller }
|
|
6855
|
+
);
|
|
6856
|
+
}
|
|
6857
|
+
function parseExtra(detail) {
|
|
6858
|
+
const raw = detail?.ExtraJSON ?? detail?.extraJSON;
|
|
6859
|
+
if (raw == null) return null;
|
|
6860
|
+
if (typeof raw === "object" && !Array.isArray(raw)) return raw;
|
|
6861
|
+
if (typeof raw === "string" && raw.trim()) {
|
|
6862
|
+
try {
|
|
6863
|
+
const parsed = JSON.parse(raw);
|
|
6864
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
|
|
6865
|
+
} catch {
|
|
6866
|
+
return null;
|
|
6867
|
+
}
|
|
6868
|
+
}
|
|
6869
|
+
return null;
|
|
6870
|
+
}
|
|
6871
|
+
function same4(a, b) {
|
|
6872
|
+
try {
|
|
6873
|
+
return viem.getAddress(a) === viem.getAddress(b);
|
|
6874
|
+
} catch {
|
|
6875
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
6876
|
+
}
|
|
6877
|
+
}
|
|
6878
|
+
function marketplaceVeCtmReceivedBy(detail, executor) {
|
|
6879
|
+
const extra = parseExtra(detail);
|
|
6880
|
+
const batch = extra?.batchMeta;
|
|
6881
|
+
if (!Array.isArray(batch) || !executor.trim()) return null;
|
|
6882
|
+
for (const entry of batch) {
|
|
6883
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
|
|
6884
|
+
const row = entry;
|
|
6885
|
+
const evm = row.evm;
|
|
6886
|
+
const type = evm && typeof evm === "object" ? String(evm.type ?? "") : "";
|
|
6887
|
+
const meta4 = row.continuumDaoMarketplace;
|
|
6888
|
+
if (!meta4 || typeof meta4 !== "object" || Array.isArray(meta4)) continue;
|
|
6889
|
+
const info = meta4;
|
|
6890
|
+
const tokenId = String(info.tokenId ?? "").trim();
|
|
6891
|
+
if (!tokenId) continue;
|
|
6892
|
+
if (type === "continuum_dao_marketplace_fulfill_listing") {
|
|
6893
|
+
const recipient = String(info.recipient ?? "");
|
|
6894
|
+
if (!recipient || same4(recipient, executor)) return { tokenId };
|
|
6895
|
+
}
|
|
6896
|
+
if (type === "continuum_dao_marketplace_settle_auction") {
|
|
6897
|
+
const highest = String(info.highestBidder ?? "");
|
|
6898
|
+
const recipient = String(info.recipient ?? "");
|
|
6899
|
+
if (highest && same4(highest, executor) && same4(recipient, executor)) return { tokenId };
|
|
6900
|
+
}
|
|
6901
|
+
}
|
|
6902
|
+
return null;
|
|
6903
|
+
}
|
|
6904
|
+
|
|
6905
|
+
// src/protocols/evm/continuum-dao/index.ts
|
|
6906
|
+
registerProtocolModule(continuumDaoMarketplaceProtocolModule);
|
|
4716
6907
|
var continuumDaoProtocolModule = {
|
|
4717
6908
|
id: exports.CONTINUUM_DAO_PROTOCOL_ID,
|
|
4718
6909
|
chainCategory: "evm",
|
|
@@ -4765,6 +6956,7 @@ var continuumDaoProtocolModule = {
|
|
|
4765
6956
|
registerProtocolModule(continuumDaoProtocolModule);
|
|
4766
6957
|
|
|
4767
6958
|
exports.ATTACH_VECTM_SIGNATURE = ATTACH_VECTM_SIGNATURE;
|
|
6959
|
+
exports.AUCTION_STATUS = AUCTION_STATUS;
|
|
4768
6960
|
exports.BRAVO_SUPPORT_LABELS = BRAVO_SUPPORT_LABELS;
|
|
4769
6961
|
exports.CONTINUUM_DAO_APPROVE_FALLBACK = CONTINUUM_DAO_APPROVE_FALLBACK;
|
|
4770
6962
|
exports.CONTINUUM_DAO_ATTACH_FALLBACK = CONTINUUM_DAO_ATTACH_FALLBACK;
|
|
@@ -4779,11 +6971,22 @@ exports.CONTINUUM_DAO_MERGE_FALLBACK = CONTINUUM_DAO_MERGE_FALLBACK;
|
|
|
4779
6971
|
exports.CONTINUUM_DAO_SPLIT_FALLBACK = CONTINUUM_DAO_SPLIT_FALLBACK;
|
|
4780
6972
|
exports.CONTINUUM_DAO_TRANSFER_FALLBACK = CONTINUUM_DAO_TRANSFER_FALLBACK;
|
|
4781
6973
|
exports.CONTINUUM_DAO_WITHDRAW_FALLBACK = CONTINUUM_DAO_WITHDRAW_FALLBACK;
|
|
6974
|
+
exports.FEE_TIER_NAMES = FEE_TIER_NAMES;
|
|
4782
6975
|
exports.INCREASE_UNLOCK_TIME_SIGNATURE = INCREASE_UNLOCK_TIME_SIGNATURE;
|
|
6976
|
+
exports.MARKETPLACE_APPROVE_FALLBACK = MARKETPLACE_APPROVE_FALLBACK;
|
|
6977
|
+
exports.MARKETPLACE_AUCTION_CREATE_FALLBACK = MARKETPLACE_AUCTION_CREATE_FALLBACK;
|
|
6978
|
+
exports.MARKETPLACE_BID_FALLBACK = MARKETPLACE_BID_FALLBACK;
|
|
6979
|
+
exports.MARKETPLACE_FULFILL_FALLBACK = MARKETPLACE_FULFILL_FALLBACK;
|
|
6980
|
+
exports.MARKETPLACE_LISTING_FALLBACK = MARKETPLACE_LISTING_FALLBACK;
|
|
6981
|
+
exports.MARKETPLACE_OFFERING_FALLBACK = MARKETPLACE_OFFERING_FALLBACK;
|
|
6982
|
+
exports.MARKETPLACE_SETTLE_FALLBACK = MARKETPLACE_SETTLE_FALLBACK;
|
|
6983
|
+
exports.MARKET_ORDER_STATUS = MARKET_ORDER_STATUS;
|
|
4783
6984
|
exports.VECTM_NODE_INFO_TUPLE = VECTM_NODE_INFO_TUPLE;
|
|
4784
6985
|
exports.VOTE_CAST_EVENT = VOTE_CAST_EVENT;
|
|
4785
6986
|
exports.VOTE_CAST_WITH_PARAMS_EVENT = VOTE_CAST_WITH_PARAMS_EVENT;
|
|
6987
|
+
exports.applyDerivedStatuses = applyDerivedStatuses;
|
|
4786
6988
|
exports.applyForumSectionCheck = applyForumSectionCheck;
|
|
6989
|
+
exports.applyMarketplaceEvent = applyMarketplaceEvent;
|
|
4787
6990
|
exports.applyNodeAttachments = applyNodeAttachments;
|
|
4788
6991
|
exports.assertContinuumDaoForumDeleteInput = assertContinuumDaoForumDeleteInput;
|
|
4789
6992
|
exports.assertContinuumDaoForumMarkReadInput = assertContinuumDaoForumMarkReadInput;
|
|
@@ -4804,6 +7007,8 @@ exports.assertSplitExtracted = assertSplitExtracted;
|
|
|
4804
7007
|
exports.assertTransfer = assertTransfer;
|
|
4805
7008
|
exports.assertUndelegateNotAlreadySelf = assertUndelegateNotAlreadySelf;
|
|
4806
7009
|
exports.assertWithdraw = assertWithdraw;
|
|
7010
|
+
exports.auctionCandidate = auctionCandidate;
|
|
7011
|
+
exports.auctionStatusName = auctionStatusName;
|
|
4807
7012
|
exports.bravoSupportLabel = bravoSupportLabel;
|
|
4808
7013
|
exports.bucketGovernorState = bucketGovernorState;
|
|
4809
7014
|
exports.buildBravoProposalArgs = buildBravoProposalArgs;
|
|
@@ -4821,6 +7026,16 @@ exports.buildEvmMultisignBodyContinuumDaoForumSignIn = buildEvmMultisignBodyCont
|
|
|
4821
7026
|
exports.buildEvmMultisignBodyContinuumDaoIncreaseAmount = buildEvmMultisignBodyContinuumDaoIncreaseAmount;
|
|
4822
7027
|
exports.buildEvmMultisignBodyContinuumDaoIncreaseUnlockTime = buildEvmMultisignBodyContinuumDaoIncreaseUnlockTime;
|
|
4823
7028
|
exports.buildEvmMultisignBodyContinuumDaoLiquidate = buildEvmMultisignBodyContinuumDaoLiquidate;
|
|
7029
|
+
exports.buildEvmMultisignBodyContinuumDaoMarketplaceAuctionBid = buildEvmMultisignBodyContinuumDaoMarketplaceAuctionBid;
|
|
7030
|
+
exports.buildEvmMultisignBodyContinuumDaoMarketplaceCancelAuction = buildEvmMultisignBodyContinuumDaoMarketplaceCancelAuction;
|
|
7031
|
+
exports.buildEvmMultisignBodyContinuumDaoMarketplaceCreateAuction = buildEvmMultisignBodyContinuumDaoMarketplaceCreateAuction;
|
|
7032
|
+
exports.buildEvmMultisignBodyContinuumDaoMarketplaceCreateListing = buildEvmMultisignBodyContinuumDaoMarketplaceCreateListing;
|
|
7033
|
+
exports.buildEvmMultisignBodyContinuumDaoMarketplaceCreateOffering = buildEvmMultisignBodyContinuumDaoMarketplaceCreateOffering;
|
|
7034
|
+
exports.buildEvmMultisignBodyContinuumDaoMarketplaceDelist = buildEvmMultisignBodyContinuumDaoMarketplaceDelist;
|
|
7035
|
+
exports.buildEvmMultisignBodyContinuumDaoMarketplaceFulfillListing = buildEvmMultisignBodyContinuumDaoMarketplaceFulfillListing;
|
|
7036
|
+
exports.buildEvmMultisignBodyContinuumDaoMarketplaceFulfillOffering = buildEvmMultisignBodyContinuumDaoMarketplaceFulfillOffering;
|
|
7037
|
+
exports.buildEvmMultisignBodyContinuumDaoMarketplaceRescind = buildEvmMultisignBodyContinuumDaoMarketplaceRescind;
|
|
7038
|
+
exports.buildEvmMultisignBodyContinuumDaoMarketplaceSettleAuction = buildEvmMultisignBodyContinuumDaoMarketplaceSettleAuction;
|
|
4824
7039
|
exports.buildEvmMultisignBodyContinuumDaoMerge = buildEvmMultisignBodyContinuumDaoMerge;
|
|
4825
7040
|
exports.buildEvmMultisignBodyContinuumDaoProposeBravo = buildEvmMultisignBodyContinuumDaoProposeBravo;
|
|
4826
7041
|
exports.buildEvmMultisignBodyContinuumDaoProposeDelta = buildEvmMultisignBodyContinuumDaoProposeDelta;
|
|
@@ -4830,7 +7045,9 @@ exports.buildEvmMultisignBodyContinuumDaoSplit = buildEvmMultisignBodyContinuumD
|
|
|
4830
7045
|
exports.buildEvmMultisignBodyContinuumDaoTransfer = buildEvmMultisignBodyContinuumDaoTransfer;
|
|
4831
7046
|
exports.buildEvmMultisignBodyContinuumDaoUndelegate = buildEvmMultisignBodyContinuumDaoUndelegate;
|
|
4832
7047
|
exports.buildEvmMultisignBodyContinuumDaoWithdraw = buildEvmMultisignBodyContinuumDaoWithdraw;
|
|
7048
|
+
exports.buildFeeAlternativeSummary = buildFeeAlternativeSummary;
|
|
4833
7049
|
exports.buildFoundryProposalSimulatePlan = buildFoundryProposalSimulatePlan;
|
|
7050
|
+
exports.calculateMarketplaceFee = calculateMarketplaceFee;
|
|
4834
7051
|
exports.collectVotesFromLogs = collectVotesFromLogs;
|
|
4835
7052
|
exports.computeLiquidationAmounts = computeLiquidationAmounts;
|
|
4836
7053
|
exports.continuumDaoComposeProposalAction = continuumDaoComposeProposalAction;
|
|
@@ -4867,6 +7084,7 @@ exports.continuumDaoForumUnread = continuumDaoForumUnread;
|
|
|
4867
7084
|
exports.continuumDaoForumUrl = continuumDaoForumUrl;
|
|
4868
7085
|
exports.continuumDaoForumUserPostIds = continuumDaoForumUserPostIds;
|
|
4869
7086
|
exports.continuumDaoHashProposal = continuumDaoHashProposal;
|
|
7087
|
+
exports.continuumDaoMarketplaceProtocolModule = continuumDaoMarketplaceProtocolModule;
|
|
4870
7088
|
exports.continuumDaoMpaFlag = continuumDaoMpaFlag;
|
|
4871
7089
|
exports.continuumDaoMpaListing = continuumDaoMpaListing;
|
|
4872
7090
|
exports.continuumDaoMpaMailboxList = continuumDaoMpaMailboxList;
|
|
@@ -4880,6 +7098,8 @@ exports.continuumDaoSimulateProposal = continuumDaoSimulateProposal;
|
|
|
4880
7098
|
exports.continuumDaoTechnocoreBind = continuumDaoTechnocoreBind;
|
|
4881
7099
|
exports.ctmTokenAddressOnEvmChain = ctmTokenAddressOnEvmChain;
|
|
4882
7100
|
exports.decodeDeltaVoteParams = decodeDeltaVoteParams;
|
|
7101
|
+
exports.deriveAuctionStatus = deriveAuctionStatus;
|
|
7102
|
+
exports.emptyMarketplaceIndexCache = emptyMarketplaceIndexCache;
|
|
4883
7103
|
exports.encodeContinuumDaoNodeInfo = encodeContinuumDaoNodeInfo;
|
|
4884
7104
|
exports.encodeDeltaMetadata = encodeDeltaMetadata;
|
|
4885
7105
|
exports.encodeDeltaVoteParams = encodeDeltaVoteParams;
|
|
@@ -4890,10 +7110,19 @@ exports.expectedForumSectionForProposalType = expectedForumSectionForProposalTyp
|
|
|
4890
7110
|
exports.explainGovAction = explainGovAction;
|
|
4891
7111
|
exports.explainProposalRecord = explainProposalRecord;
|
|
4892
7112
|
exports.explorerBase = explorerBase;
|
|
7113
|
+
exports.fetchContinuumDaoMarketplaceActivity = fetchContinuumDaoMarketplaceActivity;
|
|
7114
|
+
exports.fetchContinuumDaoMarketplaceAuctions = fetchContinuumDaoMarketplaceAuctions;
|
|
7115
|
+
exports.fetchContinuumDaoMarketplaceConfig = fetchContinuumDaoMarketplaceConfig;
|
|
7116
|
+
exports.fetchContinuumDaoMarketplaceFeePreview = fetchContinuumDaoMarketplaceFeePreview;
|
|
7117
|
+
exports.fetchContinuumDaoMarketplaceListings = fetchContinuumDaoMarketplaceListings;
|
|
7118
|
+
exports.fetchContinuumDaoMarketplaceOfferings = fetchContinuumDaoMarketplaceOfferings;
|
|
7119
|
+
exports.fetchContinuumDaoMarketplaceToken = fetchContinuumDaoMarketplaceToken;
|
|
4893
7120
|
exports.floorUnlockTimeSeconds = floorUnlockTimeSeconds;
|
|
7121
|
+
exports.foldMarketplaceEvents = foldMarketplaceEvents;
|
|
4894
7122
|
exports.formatProposalSimulationFailure = formatProposalSimulationFailure;
|
|
4895
7123
|
exports.foundryPlanHasSequentialExecute = foundryPlanHasSequentialExecute;
|
|
4896
7124
|
exports.foundryScriptContainsCall = foundryScriptContainsCall;
|
|
7125
|
+
exports.getMarketplaceIndexMemoryCache = getMarketplaceIndexMemoryCache;
|
|
4897
7126
|
exports.governorAddressOnEvmChain = governorAddressOnEvmChain;
|
|
4898
7127
|
exports.howVoted = howVoted;
|
|
4899
7128
|
exports.isConfiguredAddress = isConfiguredAddress;
|
|
@@ -4907,14 +7136,25 @@ exports.isForumIdeaSection = isForumIdeaSection;
|
|
|
4907
7136
|
exports.isGovNoOpAction = isGovNoOpAction;
|
|
4908
7137
|
exports.isLegacyContinuumDaoGovernor = isLegacyContinuumDaoGovernor;
|
|
4909
7138
|
exports.isLineaHomeNetwork = isLineaHomeNetwork;
|
|
7139
|
+
exports.isLiveAuctionStatus = isLiveAuctionStatus;
|
|
7140
|
+
exports.isOpenOrder = isOpenOrder;
|
|
4910
7141
|
exports.isRemoteC3Action = isRemoteC3Action;
|
|
4911
7142
|
exports.isVotingEscrowContinuumName = isVotingEscrowContinuumName;
|
|
7143
|
+
exports.keyGenOwnsVeCtm = keyGenOwnsVeCtm;
|
|
4912
7144
|
exports.listContinuumDaoDefaultAssets = listContinuumDaoDefaultAssets;
|
|
7145
|
+
exports.listingCandidate = listingCandidate;
|
|
7146
|
+
exports.loadMarketplacePlanSnapshot = loadMarketplacePlanSnapshot;
|
|
4913
7147
|
exports.looksLikeProposalCatalogId = looksLikeProposalCatalogId;
|
|
4914
7148
|
exports.looksLikeUnixSeconds = looksLikeUnixSeconds;
|
|
7149
|
+
exports.marketplacePublicClient = marketplacePublicClient;
|
|
7150
|
+
exports.marketplaceVeCtmReceivedBy = marketplaceVeCtmReceivedBy;
|
|
4915
7151
|
exports.maxLockDurationSeconds = maxLockDurationSeconds;
|
|
7152
|
+
exports.monthsOfFees = monthsOfFees;
|
|
4916
7153
|
exports.normalizeGovConfiguration = normalizeGovConfiguration;
|
|
4917
7154
|
exports.normalizeNodeInfo = normalizeNodeInfo;
|
|
7155
|
+
exports.orderStatusName = orderStatusName;
|
|
7156
|
+
exports.pickFeeAlternativeExample = pickFeeAlternativeExample;
|
|
7157
|
+
exports.planMarketplaceSteps = planMarketplaceSteps;
|
|
4918
7158
|
exports.preflightAttachVeCtm = preflightAttachVeCtm;
|
|
4919
7159
|
exports.preflightCreateLock = preflightCreateLock;
|
|
4920
7160
|
exports.preflightDelegate = preflightDelegate;
|
|
@@ -4929,18 +7169,27 @@ exports.preflightUndelegate = preflightUndelegate;
|
|
|
4929
7169
|
exports.preflightWithdraw = preflightWithdraw;
|
|
4930
7170
|
exports.proposalDescriptionHash = proposalDescriptionHash;
|
|
4931
7171
|
exports.publicClient = publicClient2;
|
|
7172
|
+
exports.quoteContinuumDaoMarketplaceFeeAlternative = quoteContinuumDaoMarketplaceFeeAlternative;
|
|
7173
|
+
exports.rankMarketplaceSearchHits = rankMarketplaceSearchHits;
|
|
4932
7174
|
exports.readCtmBalanceWei = readCtmBalanceWei;
|
|
7175
|
+
exports.readMarketplaceConfigFromChain = readMarketplaceConfigFromChain;
|
|
7176
|
+
exports.readMarketplaceFeePreviewFromChain = readMarketplaceFeePreviewFromChain;
|
|
4933
7177
|
exports.readMinimumLockWei = readMinimumLockWei;
|
|
4934
7178
|
exports.readVeCtmLockState = readVeCtmLockState;
|
|
4935
7179
|
exports.requireGovernor = requireGovernor;
|
|
4936
7180
|
exports.resolveAttachGroupId = resolveAttachGroupId;
|
|
4937
7181
|
exports.resolveGovernorProposalRef = resolveGovernorProposalRef;
|
|
4938
7182
|
exports.resolveProposalCatalogRange = resolveProposalCatalogRange;
|
|
7183
|
+
exports.scanMarketplaceLogs = scanMarketplaceLogs;
|
|
7184
|
+
exports.searchContinuumDaoMarketplace = searchContinuumDaoMarketplace;
|
|
7185
|
+
exports.setMarketplaceIndexMemoryCache = setMarketplaceIndexMemoryCache;
|
|
4939
7186
|
exports.summarizeLiveProposals = summarizeLiveProposals;
|
|
4940
7187
|
exports.summarizeProposalVotes = summarizeProposalVotes;
|
|
4941
7188
|
exports.throwIfProposalSimulationFailed = throwIfProposalSimulationFailed;
|
|
4942
7189
|
exports.validateAbiParameter = validateAbiParameter;
|
|
4943
7190
|
exports.votingEscrowAddressOnEvmChain = votingEscrowAddressOnEvmChain;
|
|
7191
|
+
exports.votingEscrowMarketplaceAddressOnEvmChain = votingEscrowMarketplaceAddressOnEvmChain;
|
|
7192
|
+
exports.votingPowerAboveUntil = votingPowerAboveUntil;
|
|
4944
7193
|
exports.votingPowerRefuse = votingPowerRefuse;
|
|
4945
7194
|
exports.votingPowerWarning = votingPowerWarning;
|
|
4946
7195
|
//# sourceMappingURL=index.cjs.map
|