@continuumdao/ctm-mpc-defi 0.2.37 → 0.2.38
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 +49 -38
- package/dist/agent/catalog.cjs.map +1 -1
- package/dist/agent/catalog.d.ts +722 -2
- package/dist/agent/catalog.js +49 -38
- package/dist/agent/catalog.js.map +1 -1
- package/dist/agent/skills/continuum-dao/SKILL.md +18 -2
- package/dist/{buildBatch-CngvebiD.d.ts → buildBatch-tsEUVn_a.d.ts} +3 -3
- package/dist/chains/evm/index.cjs +33 -22
- package/dist/chains/evm/index.cjs.map +1 -1
- package/dist/chains/evm/index.d.ts +10 -6
- package/dist/chains/evm/index.js +33 -22
- package/dist/chains/evm/index.js.map +1 -1
- package/dist/chains/near/index.d.ts +1 -1
- package/dist/chains/solana/index.d.ts +1 -1
- package/dist/core/index.d.ts +5 -5
- package/dist/{eip712Multisign-DCW7heqX.d.ts → eip712Multisign-6oNIlObj.d.ts} +1 -1
- package/dist/{envelope-C_bfuKab.d.ts → envelope-Cm-llShH.d.ts} +1 -1
- package/dist/index.cjs +33 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +33 -22
- package/dist/index.js.map +1 -1
- package/dist/protocols/evm/aave-v4/index.d.ts +1 -1
- package/dist/protocols/evm/aerodrome/index.d.ts +4 -4
- package/dist/protocols/evm/arcus/index.d.ts +2 -2
- package/dist/protocols/evm/circle-cctp/index.d.ts +2 -2
- package/dist/protocols/evm/compound-v3/index.d.ts +1 -1
- package/dist/protocols/evm/continuum-dao/index.cjs +797 -46
- package/dist/protocols/evm/continuum-dao/index.cjs.map +1 -1
- package/dist/protocols/evm/continuum-dao/index.d.ts +189 -5
- package/dist/protocols/evm/continuum-dao/index.js +759 -48
- package/dist/protocols/evm/continuum-dao/index.js.map +1 -1
- package/dist/protocols/evm/curve-dao/index.d.ts +2 -2
- package/dist/protocols/evm/ethena/index.d.ts +1 -1
- package/dist/protocols/evm/euler-v2/index.cjs +33 -22
- package/dist/protocols/evm/euler-v2/index.cjs.map +1 -1
- package/dist/protocols/evm/euler-v2/index.d.ts +1 -1
- package/dist/protocols/evm/euler-v2/index.js +33 -22
- package/dist/protocols/evm/euler-v2/index.js.map +1 -1
- package/dist/protocols/evm/gmx/index.d.ts +2 -2
- package/dist/protocols/evm/hyperliquid/index.d.ts +2 -2
- package/dist/protocols/evm/lido/index.d.ts +1 -1
- package/dist/protocols/evm/maple/index.d.ts +1 -1
- package/dist/protocols/evm/morpho/index.d.ts +1 -1
- package/dist/protocols/evm/pendle/index.d.ts +4 -4
- package/dist/protocols/evm/permit2/index.d.ts +1 -1
- package/dist/protocols/evm/sky/index.d.ts +1 -1
- package/dist/protocols/evm/uniswap-v4/index.d.ts +3 -3
- package/dist/protocols/evm/venice/index.d.ts +1 -1
- package/dist/{registry-DxDSPQ-p.d.ts → registry-BvsXh0-r.d.ts} +1 -1
- package/dist/{types-RZWOTm8c.d.ts → types-RJpoU4Pc.d.ts} +1 -1
- package/dist/{types-PZrvtjv8.d.ts → types-lIfv59N1.d.ts} +2 -0
- package/package.json +1 -1
|
@@ -50,6 +50,11 @@ var VECTM_TOKEN_SYMBOL = "veCTM";
|
|
|
50
50
|
var CTM_TOKEN_DECIMALS = 18;
|
|
51
51
|
var WEEK_SECONDS = 7 * 86400;
|
|
52
52
|
var MAXTIME_SECONDS = 4 * 365 * 86400;
|
|
53
|
+
var VECTM_MAX_LOCK_WEEKS = 208;
|
|
54
|
+
var VECTM_DEFAULT_MINIMUM_LOCK_WEI = 10n ** 18n;
|
|
55
|
+
var VECTM_LIQ_MIN_LOCKED_WEI = 100n;
|
|
56
|
+
var VECTM_LIQ_PENALTY_NUM = 50000n;
|
|
57
|
+
var VECTM_LIQ_PENALTY_DEN = 100000n;
|
|
53
58
|
var UNSET = {
|
|
54
59
|
ctm: viem.zeroAddress,
|
|
55
60
|
votingEscrow: viem.zeroAddress,
|
|
@@ -57,15 +62,18 @@ var UNSET = {
|
|
|
57
62
|
rewards: viem.zeroAddress,
|
|
58
63
|
governor: viem.zeroAddress
|
|
59
64
|
};
|
|
65
|
+
var CTM_TOKEN_ADDRESS = viem.getAddress("0x2026027054F5beBCEB650aBD62dC623e327658e7");
|
|
66
|
+
var VOTING_ESCROW_LINEA_ADDRESS = viem.getAddress("0x221EC90B3B083A8501A37bdeb7035CeaedF3C31f");
|
|
60
67
|
var CONTINUUM_DAO_DEPLOYMENTS = {
|
|
61
|
-
[CONTINUUM_DAO_LINEA_CHAIN_ID]: {
|
|
68
|
+
[CONTINUUM_DAO_LINEA_CHAIN_ID]: {
|
|
69
|
+
...UNSET,
|
|
70
|
+
ctm: CTM_TOKEN_ADDRESS,
|
|
71
|
+
votingEscrow: VOTING_ESCROW_LINEA_ADDRESS
|
|
72
|
+
},
|
|
62
73
|
[CONTINUUM_DAO_LINEA_SEPOLIA_CHAIN_ID]: { ...UNSET },
|
|
63
74
|
[CONTINUUM_DAO_ETHEREUM_CHAIN_ID]: {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
nodeProperties: viem.zeroAddress,
|
|
67
|
-
rewards: viem.zeroAddress,
|
|
68
|
-
governor: viem.zeroAddress
|
|
75
|
+
...UNSET,
|
|
76
|
+
ctm: CTM_TOKEN_ADDRESS
|
|
69
77
|
}
|
|
70
78
|
};
|
|
71
79
|
var CONTINUUM_DAO_GOVERNANCE_API = "https://app-api.continuumdao.org";
|
|
@@ -156,6 +164,544 @@ function listContinuumDaoDefaultAssets() {
|
|
|
156
164
|
}
|
|
157
165
|
return out;
|
|
158
166
|
}
|
|
167
|
+
function maxLockDurationSeconds() {
|
|
168
|
+
return Math.min(VECTM_MAX_LOCK_WEEKS * WEEK_SECONDS, MAXTIME_SECONDS);
|
|
169
|
+
}
|
|
170
|
+
function floorUnlockTimeSeconds(nowSec, durationSec) {
|
|
171
|
+
return (BigInt(nowSec) + durationSec) / BigInt(WEEK_SECONDS) * BigInt(WEEK_SECONDS);
|
|
172
|
+
}
|
|
173
|
+
function assertCtmAmountAtLeastMinimum(amountWei, minimumLockWei, label) {
|
|
174
|
+
const min = minimumLockWei > 0n ? minimumLockWei : VECTM_DEFAULT_MINIMUM_LOCK_WEI;
|
|
175
|
+
if (amountWei < min) {
|
|
176
|
+
throw new Error(`${label} must be at least ${formatCtmWei(min)} CTM (VotingEscrow.minimumLock).`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function assertCreateLockAmount(amountWei, minimumLockWei, balanceWei) {
|
|
180
|
+
if (amountWei <= 0n) throw new Error("CTM amount must be greater than zero.");
|
|
181
|
+
assertCtmAmountAtLeastMinimum(amountWei, minimumLockWei, "Create lock");
|
|
182
|
+
if (balanceWei != null && amountWei > balanceWei) {
|
|
183
|
+
throw new Error(`Create lock ${formatCtmWei(amountWei)} CTM exceeds KeyGen balance ${formatCtmWei(balanceWei)} CTM.`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function assertLockDurationSeconds(durationSec, nowSec, label) {
|
|
187
|
+
if (durationSec <= 0n) throw new Error(`${label} duration must be greater than zero.`);
|
|
188
|
+
if (durationSec < BigInt(WEEK_SECONDS)) {
|
|
189
|
+
throw new Error(`${label} duration must be at least 1 week (${WEEK_SECONDS} seconds).`);
|
|
190
|
+
}
|
|
191
|
+
if (durationSec > BigInt(maxLockDurationSeconds())) {
|
|
192
|
+
throw new Error(
|
|
193
|
+
`${label} duration cannot exceed ${VECTM_MAX_LOCK_WEEKS} weeks (VotingEscrow MAXTIME, week-aligned).`
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
const unlock = floorUnlockTimeSeconds(nowSec, durationSec);
|
|
197
|
+
if (unlock <= BigInt(nowSec)) {
|
|
198
|
+
throw new Error(`${label} unlock time must be after the current week boundary.`);
|
|
199
|
+
}
|
|
200
|
+
if (unlock > BigInt(nowSec) + BigInt(MAXTIME_SECONDS)) {
|
|
201
|
+
throw new Error(`${label} unlock time exceeds VotingEscrow MAXTIME (4 years).`);
|
|
202
|
+
}
|
|
203
|
+
return unlock;
|
|
204
|
+
}
|
|
205
|
+
function assertIncreaseAmount(amountWei, lock, nowSec, balanceWei) {
|
|
206
|
+
if (amountWei <= 0n) throw new Error("CTM amount must be greater than zero.");
|
|
207
|
+
if (lock.amountWei === 0n) throw new Error(`veCTM #${lock.tokenId} has no existing lock.`);
|
|
208
|
+
if (lock.endSec <= BigInt(nowSec)) {
|
|
209
|
+
throw new Error(`Cannot increase amount on expired veCTM #${lock.tokenId}. Withdraw or create a new lock.`);
|
|
210
|
+
}
|
|
211
|
+
if (balanceWei != null && amountWei > balanceWei) {
|
|
212
|
+
throw new Error(
|
|
213
|
+
`Increase amount ${formatCtmWei(amountWei)} CTM exceeds KeyGen balance ${formatCtmWei(balanceWei)} CTM.`
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
function assertIncreaseUnlockTime(durationSec, lock, nowSec) {
|
|
218
|
+
if (lock.amountWei === 0n) throw new Error(`veCTM #${lock.tokenId} has no existing lock.`);
|
|
219
|
+
if (lock.endSec <= BigInt(nowSec)) {
|
|
220
|
+
throw new Error(`Cannot increase unlock time on expired veCTM #${lock.tokenId}.`);
|
|
221
|
+
}
|
|
222
|
+
const unlock = assertLockDurationSeconds(durationSec, nowSec, "Increase unlock time");
|
|
223
|
+
if (unlock <= lock.endSec) {
|
|
224
|
+
throw new Error(
|
|
225
|
+
`New unlock time must be after the current lock end (${lock.endSec.toString()}). Pick a later week-aligned date.`
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
return unlock;
|
|
229
|
+
}
|
|
230
|
+
function assertSplitExtracted(extractedWei, lock, minimumLockWei, nowSec) {
|
|
231
|
+
if (lock.attached) {
|
|
232
|
+
throw new Error(`Split is blocked while veCTM #${lock.tokenId} is attached to a node. Request detach first.`);
|
|
233
|
+
}
|
|
234
|
+
if (lock.amountWei === 0n) throw new Error(`veCTM #${lock.tokenId} has no existing lock.`);
|
|
235
|
+
if (lock.endSec <= BigInt(nowSec)) {
|
|
236
|
+
throw new Error(`Cannot split expired veCTM #${lock.tokenId}.`);
|
|
237
|
+
}
|
|
238
|
+
const min = minimumLockWei > 0n ? minimumLockWei : VECTM_DEFAULT_MINIMUM_LOCK_WEI;
|
|
239
|
+
if (lock.amountWei < min * 2n) {
|
|
240
|
+
throw new Error("Split requires at least 2 CTM locked (1 CTM minimum per resulting lock).");
|
|
241
|
+
}
|
|
242
|
+
if (extractedWei < min) {
|
|
243
|
+
throw new Error(`Extract at least ${formatCtmWei(min)} CTM into the new lock.`);
|
|
244
|
+
}
|
|
245
|
+
if (extractedWei > lock.amountWei - min) {
|
|
246
|
+
throw new Error(`The original lock must keep at least ${formatCtmWei(min)} CTM after the split.`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function assertMerge(fromLock, toLock) {
|
|
250
|
+
if (fromLock.tokenId === toLock.tokenId) throw new Error("Merge requires two different token ids.");
|
|
251
|
+
if (fromLock.attached) {
|
|
252
|
+
throw new Error(`Merge is blocked while veCTM #${fromLock.tokenId} is attached to a node.`);
|
|
253
|
+
}
|
|
254
|
+
if (toLock.attached) {
|
|
255
|
+
throw new Error(`Merge is blocked while veCTM #${toLock.tokenId} is attached to a node.`);
|
|
256
|
+
}
|
|
257
|
+
if (fromLock.owner.toLowerCase() !== toLock.owner.toLowerCase()) {
|
|
258
|
+
throw new Error("Merge requires both veCTM locks to have the same owner.");
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
function assertWithdraw(lock, nowSec) {
|
|
262
|
+
if (lock.attached) {
|
|
263
|
+
throw new Error(`Withdraw is blocked while veCTM #${lock.tokenId} is attached to a node. Request detach first.`);
|
|
264
|
+
}
|
|
265
|
+
if (lock.endSec <= 0n) throw new Error(`Unlock time unavailable for veCTM #${lock.tokenId}.`);
|
|
266
|
+
if (lock.endSec > BigInt(nowSec)) {
|
|
267
|
+
throw new Error(`Withdraw is available after the lock expires (unlock ${lock.endSec.toString()}).`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function computeLiquidationAmounts(args) {
|
|
271
|
+
if (args.lockEndSec > 0n && BigInt(args.nowSec) >= args.lockEndSec) {
|
|
272
|
+
return {
|
|
273
|
+
userWei: args.lockedAmountWei,
|
|
274
|
+
treasuryWei: 0n,
|
|
275
|
+
lockExpired: true,
|
|
276
|
+
tooSmall: false,
|
|
277
|
+
zeroPenalty: false
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
if (args.lockedAmountWei <= VECTM_LIQ_MIN_LOCKED_WEI) {
|
|
281
|
+
return {
|
|
282
|
+
userWei: 0n,
|
|
283
|
+
treasuryWei: 0n,
|
|
284
|
+
lockExpired: false,
|
|
285
|
+
tooSmall: true,
|
|
286
|
+
zeroPenalty: false
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
const penalty = args.vePowerWei * VECTM_LIQ_PENALTY_NUM / VECTM_LIQ_PENALTY_DEN;
|
|
290
|
+
if (penalty === 0n) {
|
|
291
|
+
return {
|
|
292
|
+
userWei: 0n,
|
|
293
|
+
treasuryWei: 0n,
|
|
294
|
+
lockExpired: false,
|
|
295
|
+
tooSmall: false,
|
|
296
|
+
zeroPenalty: true
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
return {
|
|
300
|
+
userWei: args.lockedAmountWei - penalty,
|
|
301
|
+
treasuryWei: penalty,
|
|
302
|
+
lockExpired: false,
|
|
303
|
+
tooSmall: false,
|
|
304
|
+
zeroPenalty: false
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
function assertLiquidate(lock, liquidationsEnabled, nowSec) {
|
|
308
|
+
if (lock.attached) {
|
|
309
|
+
throw new Error(`Liquidate is blocked while veCTM #${lock.tokenId} is attached to a node. Request detach first.`);
|
|
310
|
+
}
|
|
311
|
+
if (liquidationsEnabled === false) {
|
|
312
|
+
throw new Error("Liquidations are currently disabled on-chain.");
|
|
313
|
+
}
|
|
314
|
+
const preview = computeLiquidationAmounts({
|
|
315
|
+
lockedAmountWei: lock.amountWei,
|
|
316
|
+
vePowerWei: lock.vePowerWei,
|
|
317
|
+
lockEndSec: lock.endSec,
|
|
318
|
+
nowSec
|
|
319
|
+
});
|
|
320
|
+
if (preview.tooSmall) throw new Error("Locked amount is too small to liquidate.");
|
|
321
|
+
if (preview.zeroPenalty) throw new Error("Voting power is too low to compute a liquidation penalty.");
|
|
322
|
+
}
|
|
323
|
+
function assertDelegatee(delegateeRaw, executor) {
|
|
324
|
+
const delegatee = viem.getAddress(delegateeRaw);
|
|
325
|
+
if (delegatee === viem.zeroAddress) {
|
|
326
|
+
throw new Error("Zero address is not allowed. Use undelegate to return power to this KeyGen.");
|
|
327
|
+
}
|
|
328
|
+
const self = viem.getAddress(executor);
|
|
329
|
+
if (delegatee === self) {
|
|
330
|
+
throw new Error("This is this KeyGen\u2019s address \u2014 use undelegate instead.");
|
|
331
|
+
}
|
|
332
|
+
return delegatee;
|
|
333
|
+
}
|
|
334
|
+
function assertUndelegateNotAlreadySelf(alreadySelf, account) {
|
|
335
|
+
if (alreadySelf) {
|
|
336
|
+
throw new Error(`Voting power is already at this KeyGen (${viem.getAddress(account)}).`);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function assertTransfer(lock, toRaw, fromRaw) {
|
|
340
|
+
if (lock.attached) {
|
|
341
|
+
throw new Error(`Transfer is blocked while veCTM #${lock.tokenId} is attached to a node.`);
|
|
342
|
+
}
|
|
343
|
+
const to = viem.getAddress(toRaw);
|
|
344
|
+
const from = viem.getAddress(fromRaw);
|
|
345
|
+
if (to === viem.zeroAddress) throw new Error("Cannot transfer veCTM to the zero address.");
|
|
346
|
+
if (to === from) throw new Error("Transfer recipient must be different from this KeyGen.");
|
|
347
|
+
return to;
|
|
348
|
+
}
|
|
349
|
+
function assertExecutorOwnsLock(lock, executor) {
|
|
350
|
+
if (lock.owner.toLowerCase() !== viem.getAddress(executor).toLowerCase()) {
|
|
351
|
+
throw new Error(`KeyGen ${viem.getAddress(executor)} does not own veCTM #${lock.tokenId} (owner ${lock.owner}).`);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
function formatCtmWei(wei) {
|
|
355
|
+
const whole = wei / 10n ** 18n;
|
|
356
|
+
const frac = wei % 10n ** 18n;
|
|
357
|
+
if (frac === 0n) return whole.toString();
|
|
358
|
+
const fracStr = frac.toString().padStart(18, "0").replace(/0+$/, "");
|
|
359
|
+
return `${whole.toString()}.${fracStr}`;
|
|
360
|
+
}
|
|
361
|
+
var veReadAbi = viem.parseAbi([
|
|
362
|
+
"function minimumLock() view returns (uint256)",
|
|
363
|
+
"function locked(uint256 tokenId) view returns (int128 amount, uint256 end)",
|
|
364
|
+
"function ownerOf(uint256 tokenId) view returns (address)",
|
|
365
|
+
"function balanceOfNFT(uint256 tokenId) view returns (uint256)",
|
|
366
|
+
"function liquidationsEnabled() view returns (bool)",
|
|
367
|
+
"function nodeProperties() view returns (address)",
|
|
368
|
+
"function rewards() view returns (address)",
|
|
369
|
+
"function delegates(address account) view returns (address)",
|
|
370
|
+
"function token() view returns (address)"
|
|
371
|
+
]);
|
|
372
|
+
var erc20Abi = viem.parseAbi(["function balanceOf(address owner) view returns (uint256)"]);
|
|
373
|
+
var nodePropsAbi = viem.parseAbi([
|
|
374
|
+
"function attachedKeyGen(uint256 tokenId) view returns (address)",
|
|
375
|
+
"function attachedTokenId(address keyGen) view returns (uint256)",
|
|
376
|
+
"function nodeRequestingDetachment(uint256 tokenId) view returns (bool)"
|
|
377
|
+
]);
|
|
378
|
+
var rewardsAbi = viem.parseAbi(["function unclaimedRewards(uint256 tokenId) view returns (uint256)"]);
|
|
379
|
+
var mpaReadAbi = viem.parseAbi([
|
|
380
|
+
"function getNodeWithdrawAuthority(string nodeKey) view returns (address)",
|
|
381
|
+
"function ve() view returns (address)",
|
|
382
|
+
"function veCtmThresholdPower() view returns (uint256)",
|
|
383
|
+
"function nodeProperties() view returns (address)"
|
|
384
|
+
]);
|
|
385
|
+
function publicClient(rpcUrl, chainId) {
|
|
386
|
+
return viem.createPublicClient({
|
|
387
|
+
chain: viem.defineChain({
|
|
388
|
+
id: chainId,
|
|
389
|
+
name: "ContinuumDAO escrow",
|
|
390
|
+
nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
|
|
391
|
+
rpcUrls: { default: { http: [rpcUrl.trim()] } }
|
|
392
|
+
}),
|
|
393
|
+
transport: viem.http(rpcUrl.trim())
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
async function readMinimumLockWei(args) {
|
|
397
|
+
const client = publicClient(args.rpcUrl, args.chainId);
|
|
398
|
+
try {
|
|
399
|
+
const min = await client.readContract({
|
|
400
|
+
address: args.votingEscrow,
|
|
401
|
+
abi: veReadAbi,
|
|
402
|
+
functionName: "minimumLock"
|
|
403
|
+
});
|
|
404
|
+
return min > 0n ? min : VECTM_DEFAULT_MINIMUM_LOCK_WEI;
|
|
405
|
+
} catch {
|
|
406
|
+
return VECTM_DEFAULT_MINIMUM_LOCK_WEI;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
async function readCtmBalanceWei(args) {
|
|
410
|
+
const client = publicClient(args.rpcUrl, args.chainId);
|
|
411
|
+
try {
|
|
412
|
+
return await client.readContract({
|
|
413
|
+
address: args.ctm,
|
|
414
|
+
abi: erc20Abi,
|
|
415
|
+
functionName: "balanceOf",
|
|
416
|
+
args: [args.owner]
|
|
417
|
+
});
|
|
418
|
+
} catch {
|
|
419
|
+
return void 0;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
async function readVeCtmLockState(args) {
|
|
423
|
+
const client = publicClient(args.rpcUrl, args.chainId);
|
|
424
|
+
const [lockedPair, owner, vePower, nodeProperties] = await Promise.all([
|
|
425
|
+
client.readContract({
|
|
426
|
+
address: args.votingEscrow,
|
|
427
|
+
abi: veReadAbi,
|
|
428
|
+
functionName: "locked",
|
|
429
|
+
args: [args.tokenId]
|
|
430
|
+
}),
|
|
431
|
+
client.readContract({
|
|
432
|
+
address: args.votingEscrow,
|
|
433
|
+
abi: veReadAbi,
|
|
434
|
+
functionName: "ownerOf",
|
|
435
|
+
args: [args.tokenId]
|
|
436
|
+
}),
|
|
437
|
+
client.readContract({
|
|
438
|
+
address: args.votingEscrow,
|
|
439
|
+
abi: veReadAbi,
|
|
440
|
+
functionName: "balanceOfNFT",
|
|
441
|
+
args: [args.tokenId]
|
|
442
|
+
}),
|
|
443
|
+
client.readContract({
|
|
444
|
+
address: args.votingEscrow,
|
|
445
|
+
abi: veReadAbi,
|
|
446
|
+
functionName: "nodeProperties"
|
|
447
|
+
})
|
|
448
|
+
]);
|
|
449
|
+
const amountRaw = lockedPair[0];
|
|
450
|
+
const amountWei = amountRaw < 0n ? 0n : BigInt(amountRaw);
|
|
451
|
+
let attached = false;
|
|
452
|
+
if (isConfiguredAddress(nodeProperties)) {
|
|
453
|
+
try {
|
|
454
|
+
const attachedKey = await client.readContract({
|
|
455
|
+
address: viem.getAddress(nodeProperties),
|
|
456
|
+
abi: nodePropsAbi,
|
|
457
|
+
functionName: "attachedKeyGen",
|
|
458
|
+
args: [args.tokenId]
|
|
459
|
+
});
|
|
460
|
+
attached = attachedKey !== viem.zeroAddress;
|
|
461
|
+
} catch {
|
|
462
|
+
attached = false;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return {
|
|
466
|
+
tokenId: args.tokenId,
|
|
467
|
+
amountWei,
|
|
468
|
+
endSec: lockedPair[1],
|
|
469
|
+
owner: viem.getAddress(owner),
|
|
470
|
+
attached,
|
|
471
|
+
vePowerWei: vePower
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
async function assertNoUnclaimedRewards(args) {
|
|
475
|
+
const client = publicClient(args.rpcUrl, args.chainId);
|
|
476
|
+
let rewards;
|
|
477
|
+
try {
|
|
478
|
+
rewards = await client.readContract({
|
|
479
|
+
address: args.votingEscrow,
|
|
480
|
+
abi: veReadAbi,
|
|
481
|
+
functionName: "rewards"
|
|
482
|
+
});
|
|
483
|
+
} catch {
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
if (!isConfiguredAddress(rewards)) return;
|
|
487
|
+
try {
|
|
488
|
+
const unclaimed = await client.readContract({
|
|
489
|
+
address: rewards,
|
|
490
|
+
abi: rewardsAbi,
|
|
491
|
+
functionName: "unclaimedRewards",
|
|
492
|
+
args: [args.tokenId]
|
|
493
|
+
});
|
|
494
|
+
if (unclaimed !== 0n) {
|
|
495
|
+
throw new Error(`veCTM #${args.tokenId} has unclaimed rewards. Claim them before this escrow action.`);
|
|
496
|
+
}
|
|
497
|
+
} catch (err) {
|
|
498
|
+
if (err instanceof Error && err.message.includes("unclaimed rewards")) throw err;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
async function preflightCreateLock(args) {
|
|
502
|
+
const nowSec = Math.floor(Date.now() / 1e3);
|
|
503
|
+
const [minimumLockWei, balanceWei] = await Promise.all([
|
|
504
|
+
readMinimumLockWei(args),
|
|
505
|
+
readCtmBalanceWei(args)
|
|
506
|
+
]);
|
|
507
|
+
assertCreateLockAmount(args.amountWei, minimumLockWei, balanceWei);
|
|
508
|
+
assertLockDurationSeconds(args.durationSec, nowSec, "Create lock");
|
|
509
|
+
}
|
|
510
|
+
async function preflightIncreaseAmount(args) {
|
|
511
|
+
const nowSec = Math.floor(Date.now() / 1e3);
|
|
512
|
+
const [lock, balanceWei] = await Promise.all([
|
|
513
|
+
readVeCtmLockState(args),
|
|
514
|
+
readCtmBalanceWei(args)
|
|
515
|
+
]);
|
|
516
|
+
assertExecutorOwnsLock(lock, args.owner);
|
|
517
|
+
assertIncreaseAmount(args.amountWei, lock, nowSec, balanceWei);
|
|
518
|
+
await assertNoUnclaimedRewards(args);
|
|
519
|
+
}
|
|
520
|
+
async function preflightIncreaseUnlockTime(args) {
|
|
521
|
+
const nowSec = Math.floor(Date.now() / 1e3);
|
|
522
|
+
const lock = await readVeCtmLockState(args);
|
|
523
|
+
assertExecutorOwnsLock(lock, args.owner);
|
|
524
|
+
assertIncreaseUnlockTime(args.durationSec, lock, nowSec);
|
|
525
|
+
await assertNoUnclaimedRewards(args);
|
|
526
|
+
}
|
|
527
|
+
async function preflightSplit(args) {
|
|
528
|
+
const nowSec = Math.floor(Date.now() / 1e3);
|
|
529
|
+
const [lock, minimumLockWei] = await Promise.all([
|
|
530
|
+
readVeCtmLockState(args),
|
|
531
|
+
readMinimumLockWei(args)
|
|
532
|
+
]);
|
|
533
|
+
assertExecutorOwnsLock(lock, args.owner);
|
|
534
|
+
assertSplitExtracted(args.extractedWei, lock, minimumLockWei, nowSec);
|
|
535
|
+
await assertNoUnclaimedRewards(args);
|
|
536
|
+
}
|
|
537
|
+
async function preflightMerge(args) {
|
|
538
|
+
const [fromLock, toLock] = await Promise.all([
|
|
539
|
+
readVeCtmLockState({ ...args, tokenId: args.fromTokenId }),
|
|
540
|
+
readVeCtmLockState({ ...args, tokenId: args.toTokenId })
|
|
541
|
+
]);
|
|
542
|
+
assertExecutorOwnsLock(fromLock, args.owner);
|
|
543
|
+
assertExecutorOwnsLock(toLock, args.owner);
|
|
544
|
+
assertMerge(fromLock, toLock);
|
|
545
|
+
await Promise.all([
|
|
546
|
+
assertNoUnclaimedRewards({ ...args, tokenId: args.fromTokenId }),
|
|
547
|
+
assertNoUnclaimedRewards({ ...args, tokenId: args.toTokenId })
|
|
548
|
+
]);
|
|
549
|
+
}
|
|
550
|
+
async function preflightWithdraw(args) {
|
|
551
|
+
const nowSec = Math.floor(Date.now() / 1e3);
|
|
552
|
+
const lock = await readVeCtmLockState(args);
|
|
553
|
+
assertExecutorOwnsLock(lock, args.owner);
|
|
554
|
+
assertWithdraw(lock, nowSec);
|
|
555
|
+
await assertNoUnclaimedRewards(args);
|
|
556
|
+
}
|
|
557
|
+
async function preflightLiquidate(args) {
|
|
558
|
+
const nowSec = Math.floor(Date.now() / 1e3);
|
|
559
|
+
const client = publicClient(args.rpcUrl, args.chainId);
|
|
560
|
+
const [lock, liquidationsEnabled] = await Promise.all([
|
|
561
|
+
readVeCtmLockState(args),
|
|
562
|
+
client.readContract({
|
|
563
|
+
address: args.votingEscrow,
|
|
564
|
+
abi: veReadAbi,
|
|
565
|
+
functionName: "liquidationsEnabled"
|
|
566
|
+
}).catch(() => null)
|
|
567
|
+
]);
|
|
568
|
+
assertExecutorOwnsLock(lock, args.owner);
|
|
569
|
+
assertLiquidate(lock, liquidationsEnabled, nowSec);
|
|
570
|
+
await assertNoUnclaimedRewards(args);
|
|
571
|
+
}
|
|
572
|
+
async function preflightDelegate(args) {
|
|
573
|
+
return assertDelegatee(args.delegatee, args.owner);
|
|
574
|
+
}
|
|
575
|
+
async function preflightUndelegate(args) {
|
|
576
|
+
const client = publicClient(args.rpcUrl, args.chainId);
|
|
577
|
+
const delegatee = await client.readContract({
|
|
578
|
+
address: args.votingEscrow,
|
|
579
|
+
abi: veReadAbi,
|
|
580
|
+
functionName: "delegates",
|
|
581
|
+
args: [args.owner]
|
|
582
|
+
});
|
|
583
|
+
assertUndelegateNotAlreadySelf(viem.getAddress(delegatee) === viem.getAddress(args.owner), args.owner);
|
|
584
|
+
}
|
|
585
|
+
async function preflightTransfer(args) {
|
|
586
|
+
const lock = await readVeCtmLockState(args);
|
|
587
|
+
assertExecutorOwnsLock(lock, args.owner);
|
|
588
|
+
return assertTransfer(lock, args.to, args.owner);
|
|
589
|
+
}
|
|
590
|
+
async function preflightAttachVeCtm(args) {
|
|
591
|
+
const client = publicClient(args.rpcUrl, args.chainId);
|
|
592
|
+
const [authority, veFromWallet, threshold, nodeProperties] = await Promise.all([
|
|
593
|
+
client.readContract({
|
|
594
|
+
address: args.mpaWallet,
|
|
595
|
+
abi: mpaReadAbi,
|
|
596
|
+
functionName: "getNodeWithdrawAuthority",
|
|
597
|
+
args: [args.nodeKey]
|
|
598
|
+
}),
|
|
599
|
+
client.readContract({ address: args.mpaWallet, abi: mpaReadAbi, functionName: "ve" }),
|
|
600
|
+
client.readContract({
|
|
601
|
+
address: args.mpaWallet,
|
|
602
|
+
abi: mpaReadAbi,
|
|
603
|
+
functionName: "veCtmThresholdPower"
|
|
604
|
+
}),
|
|
605
|
+
client.readContract({
|
|
606
|
+
address: args.mpaWallet,
|
|
607
|
+
abi: mpaReadAbi,
|
|
608
|
+
functionName: "nodeProperties"
|
|
609
|
+
})
|
|
610
|
+
]);
|
|
611
|
+
const ve = args.votingEscrow && isConfiguredAddress(args.votingEscrow) ? viem.getAddress(args.votingEscrow) : viem.getAddress(veFromWallet);
|
|
612
|
+
if (!isConfiguredAddress(ve)) throw new Error("veCTM is not live on the fee contract yet.");
|
|
613
|
+
const lock = await readVeCtmLockState({
|
|
614
|
+
rpcUrl: args.rpcUrl,
|
|
615
|
+
chainId: args.chainId,
|
|
616
|
+
votingEscrow: ve,
|
|
617
|
+
tokenId: args.tokenId
|
|
618
|
+
});
|
|
619
|
+
assertExecutorOwnsLock(lock, args.owner);
|
|
620
|
+
const executor = viem.getAddress(args.owner);
|
|
621
|
+
if (authority === viem.zeroAddress || viem.getAddress(authority) !== executor) {
|
|
622
|
+
throw new Error(
|
|
623
|
+
`Compose attachVeCtm from the claimed authority KeyGen (${authority}), which must own the NFT.`
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
if (isConfiguredAddress(nodeProperties)) {
|
|
627
|
+
const np = viem.getAddress(nodeProperties);
|
|
628
|
+
const [attachedKey, attachedForKey] = await Promise.all([
|
|
629
|
+
client.readContract({
|
|
630
|
+
address: np,
|
|
631
|
+
abi: nodePropsAbi,
|
|
632
|
+
functionName: "attachedKeyGen",
|
|
633
|
+
args: [args.tokenId]
|
|
634
|
+
}),
|
|
635
|
+
client.readContract({
|
|
636
|
+
address: np,
|
|
637
|
+
abi: nodePropsAbi,
|
|
638
|
+
functionName: "attachedTokenId",
|
|
639
|
+
args: [executor]
|
|
640
|
+
})
|
|
641
|
+
]);
|
|
642
|
+
if (attachedKey !== viem.zeroAddress) {
|
|
643
|
+
throw new Error(`veCTM #${args.tokenId} is already attached. You cannot replace an attached NFT.`);
|
|
644
|
+
}
|
|
645
|
+
if (attachedForKey !== 0n) {
|
|
646
|
+
throw new Error(
|
|
647
|
+
`This KeyGen already has veCTM #${attachedForKey} attached. Request detach and wait for governance. A second group on this node attaches after rotating nodeWithdrawAuthority to that group's secp256k1 KeyGen.`
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
if (threshold > 0n && lock.amountWei < threshold) {
|
|
652
|
+
throw new Error(
|
|
653
|
+
`Locked CTM on veCTM #${args.tokenId} is below MultiSignAgentWallet.veCtmThresholdPower (${threshold.toString()} wei).`
|
|
654
|
+
);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
async function preflightRequestDetach(args) {
|
|
658
|
+
const client = publicClient(args.rpcUrl, args.chainId);
|
|
659
|
+
const [attachedKey, alreadyRequested] = await Promise.all([
|
|
660
|
+
client.readContract({
|
|
661
|
+
address: args.nodeProperties,
|
|
662
|
+
abi: nodePropsAbi,
|
|
663
|
+
functionName: "attachedKeyGen",
|
|
664
|
+
args: [args.tokenId]
|
|
665
|
+
}),
|
|
666
|
+
client.readContract({
|
|
667
|
+
address: args.nodeProperties,
|
|
668
|
+
abi: nodePropsAbi,
|
|
669
|
+
functionName: "nodeRequestingDetachment",
|
|
670
|
+
args: [args.tokenId]
|
|
671
|
+
})
|
|
672
|
+
]);
|
|
673
|
+
if (attachedKey === viem.zeroAddress) {
|
|
674
|
+
throw new Error(`veCTM #${args.tokenId} is not attached to a node.`);
|
|
675
|
+
}
|
|
676
|
+
if (alreadyRequested) {
|
|
677
|
+
throw new Error(
|
|
678
|
+
`Detach already requested for veCTM #${args.tokenId}. The NFT stays attached until governance executes detach.`
|
|
679
|
+
);
|
|
680
|
+
}
|
|
681
|
+
if (viem.getAddress(attachedKey) !== viem.getAddress(args.owner)) {
|
|
682
|
+
throw new Error(
|
|
683
|
+
`Request detach from the attached KeyGen (${viem.getAddress(attachedKey)}).`
|
|
684
|
+
);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// src/protocols/evm/continuum-dao/attachGroup.ts
|
|
689
|
+
var VECTM_NODE_INFO_TUPLE = "(string,string,uint8[4],uint16[8],string,uint256,uint256,string,string,bytes)";
|
|
690
|
+
var ATTACH_VECTM_SIGNATURE = `attachVeCtm(string,uint256,${VECTM_NODE_INFO_TUPLE},string)`;
|
|
691
|
+
function resolveAttachGroupId(keyGen, explicit) {
|
|
692
|
+
const fromKg = (keyGen.groupId ?? keyGen.GroupId ?? "").trim();
|
|
693
|
+
const fromArg = (explicit ?? "").trim();
|
|
694
|
+
if (fromKg && fromArg && fromKg !== fromArg) {
|
|
695
|
+
throw new Error(
|
|
696
|
+
`groupId must be the attaching KeyGen's mpc-auth GroupId (${fromKg}), not a different group.`
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
if (fromKg) return fromKg;
|
|
700
|
+
if (fromArg) return fromArg;
|
|
701
|
+
throw new Error(
|
|
702
|
+
"groupId is required to attach veCTM (use the attaching KeyGen's mpc-auth GroupId)."
|
|
703
|
+
);
|
|
704
|
+
}
|
|
159
705
|
|
|
160
706
|
// src/core/purpose.ts
|
|
161
707
|
function mergePurposeText(purposeText, purposeSuffix) {
|
|
@@ -247,25 +793,25 @@ async function buildEvmMultisignBatch(args) {
|
|
|
247
793
|
nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
|
|
248
794
|
rpcUrls: { default: { http: [rpcUrl] } }
|
|
249
795
|
});
|
|
250
|
-
const
|
|
796
|
+
const publicClient3 = viem.createPublicClient({ chain: ch, transport: viem.http(rpcUrl) });
|
|
251
797
|
const feeParams = await continuumNodeSdk.fetchChainFeeParams(rpcUrl, chainId);
|
|
252
798
|
const legacy = Boolean(chainDetail?.legacy) || !feeParams.isEip1559;
|
|
253
|
-
const latestBaseFeeWei = !legacy ? (await
|
|
799
|
+
const latestBaseFeeWei = !legacy ? (await publicClient3.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
|
|
254
800
|
const gasLimitConfig = useCustomGas && chainDetail?.gasLimit != null ? Number(chainDetail.gasLimit) : void 0;
|
|
255
801
|
const chainGasLimitRouter = chainDetail?.gasLimit != null && Number.isFinite(Number(chainDetail.gasLimit)) && Number(chainDetail.gasLimit) > 0 ? Number(chainDetail.gasLimit) : void 0;
|
|
256
802
|
const gasFeeMultiplier = useCustomGas && chainDetail?.gasMultiplier != null ? Number(chainDetail.gasMultiplier) : void 0;
|
|
257
803
|
const executor = viem.getAddress(executorAddress);
|
|
258
|
-
const baseNonce = await
|
|
804
|
+
const baseNonce = await publicClient3.getTransactionCount({ address: executor, blockTag: "pending" });
|
|
259
805
|
const legs = [];
|
|
260
806
|
for (let i = 0; i < steps.length; i++) {
|
|
261
807
|
const step = steps[i];
|
|
262
808
|
const currentNonce = baseNonce + i;
|
|
263
809
|
let estimatedGas;
|
|
264
810
|
if (args.estimateGasForStep) {
|
|
265
|
-
estimatedGas = await args.estimateGasForStep({ step, index: i, publicClient:
|
|
811
|
+
estimatedGas = await args.estimateGasForStep({ step, index: i, publicClient: publicClient3, executor });
|
|
266
812
|
} else {
|
|
267
813
|
try {
|
|
268
|
-
estimatedGas = await
|
|
814
|
+
estimatedGas = await publicClient3.estimateGas({
|
|
269
815
|
to: step.to,
|
|
270
816
|
data: step.data,
|
|
271
817
|
value: step.value,
|
|
@@ -277,7 +823,7 @@ async function buildEvmMultisignBatch(args) {
|
|
|
277
823
|
}
|
|
278
824
|
let gasLimitI;
|
|
279
825
|
if (args.resolveGasLimit) {
|
|
280
|
-
gasLimitI = await args.resolveGasLimit({ step, index: i, estimatedGas, publicClient:
|
|
826
|
+
gasLimitI = await args.resolveGasLimit({ step, index: i, estimatedGas, publicClient: publicClient3 });
|
|
281
827
|
} else if (step.routerSwap) {
|
|
282
828
|
gasLimitI = routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimitRouter);
|
|
283
829
|
} else {
|
|
@@ -287,7 +833,7 @@ async function buildEvmMultisignBatch(args) {
|
|
|
287
833
|
let feeSnapshot;
|
|
288
834
|
let serialized;
|
|
289
835
|
if (legacy) {
|
|
290
|
-
let gasPriceWei = await
|
|
836
|
+
let gasPriceWei = await publicClient3.getGasPrice();
|
|
291
837
|
if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
|
|
292
838
|
gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
293
839
|
}
|
|
@@ -404,9 +950,7 @@ var CONTINUUM_DAO_DELEGATE_FALLBACK = 160000n;
|
|
|
404
950
|
var CONTINUUM_DAO_TRANSFER_FALLBACK = 160000n;
|
|
405
951
|
var CONTINUUM_DAO_ATTACH_FALLBACK = 450000n;
|
|
406
952
|
var CONTINUUM_DAO_DETACH_FALLBACK = 220000n;
|
|
407
|
-
var
|
|
408
|
-
var ATTACH_VECTM_SIGNATURE = `attachVeCtm(string,uint256,${VECTM_NODE_INFO_TUPLE})`;
|
|
409
|
-
var erc20Abi = viem.parseAbi([
|
|
953
|
+
var erc20Abi2 = viem.parseAbi([
|
|
410
954
|
"function allowance(address owner, address spender) view returns (uint256)",
|
|
411
955
|
"function approve(address spender, uint256 amount) returns (bool)"
|
|
412
956
|
]);
|
|
@@ -422,7 +966,7 @@ var veWriteAbi = viem.parseAbi([
|
|
|
422
966
|
"function transferFrom(address _from, address _to, uint256 _tokenId)"
|
|
423
967
|
]);
|
|
424
968
|
var attachAbi = viem.parseAbi([
|
|
425
|
-
`function attachVeCtm(string nodeKey, uint256 tokenId, ${VECTM_NODE_INFO_TUPLE} nodeInfo)`
|
|
969
|
+
`function attachVeCtm(string nodeKey, uint256 tokenId, ${VECTM_NODE_INFO_TUPLE} nodeInfo, string groupId)`
|
|
426
970
|
]);
|
|
427
971
|
var detachAbi = viem.parseAbi(["function setNodeRemovalStatus(uint256 tokenId, bool status)"]);
|
|
428
972
|
var CONTINUUM_DAO_EVM_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -513,7 +1057,7 @@ async function maybeApproveCtmStep(args) {
|
|
|
513
1057
|
try {
|
|
514
1058
|
allowance = await client.readContract({
|
|
515
1059
|
address: args.ctm,
|
|
516
|
-
abi:
|
|
1060
|
+
abi: erc20Abi2,
|
|
517
1061
|
functionName: "allowance",
|
|
518
1062
|
args: [args.owner, args.spender]
|
|
519
1063
|
});
|
|
@@ -522,7 +1066,7 @@ async function maybeApproveCtmStep(args) {
|
|
|
522
1066
|
}
|
|
523
1067
|
if (allowance >= args.amountWei) return null;
|
|
524
1068
|
const data = viem.encodeFunctionData({
|
|
525
|
-
abi:
|
|
1069
|
+
abi: erc20Abi2,
|
|
526
1070
|
functionName: "approve",
|
|
527
1071
|
args: [args.spender, args.amountWei]
|
|
528
1072
|
});
|
|
@@ -542,10 +1086,17 @@ async function buildEvmMultisignBodyContinuumDaoCreateLock(args) {
|
|
|
542
1086
|
const ve = args.votingEscrow && isConfiguredAddress(args.votingEscrow) ? viem.getAddress(args.votingEscrow) : requireVe(args.chainId);
|
|
543
1087
|
const ctm = args.ctm && isConfiguredAddress(args.ctm) ? viem.getAddress(args.ctm) : requireCtm(args.chainId);
|
|
544
1088
|
const amountWei = viem.parseUnits(String(args.amountHuman).trim().replace(/,/g, ""), CTM_TOKEN_DECIMALS);
|
|
545
|
-
if (amountWei <= 0n) throw new Error("CTM amount must be greater than zero.");
|
|
546
1089
|
const duration = BigInt(String(args.lockDurationSeconds).trim());
|
|
547
|
-
if (duration <= 0n) throw new Error("Lock duration must be greater than zero.");
|
|
548
1090
|
const owner = viem.getAddress(args.executorAddress);
|
|
1091
|
+
await preflightCreateLock({
|
|
1092
|
+
rpcUrl: args.rpcUrl,
|
|
1093
|
+
chainId: args.chainId,
|
|
1094
|
+
votingEscrow: ve,
|
|
1095
|
+
ctm,
|
|
1096
|
+
owner,
|
|
1097
|
+
amountWei,
|
|
1098
|
+
durationSec: duration
|
|
1099
|
+
});
|
|
549
1100
|
const approve = await maybeApproveCtmStep({
|
|
550
1101
|
rpcUrl: args.rpcUrl,
|
|
551
1102
|
chainId: args.chainId,
|
|
@@ -578,8 +1129,16 @@ async function buildEvmMultisignBodyContinuumDaoIncreaseAmount(args) {
|
|
|
578
1129
|
const ctm = args.ctm && isConfiguredAddress(args.ctm) ? viem.getAddress(args.ctm) : requireCtm(args.chainId);
|
|
579
1130
|
const tokenId = parseTokenId(args.tokenId);
|
|
580
1131
|
const amountWei = viem.parseUnits(String(args.amountHuman).trim().replace(/,/g, ""), CTM_TOKEN_DECIMALS);
|
|
581
|
-
if (amountWei <= 0n) throw new Error("CTM amount must be greater than zero.");
|
|
582
1132
|
const owner = viem.getAddress(args.executorAddress);
|
|
1133
|
+
await preflightIncreaseAmount({
|
|
1134
|
+
rpcUrl: args.rpcUrl,
|
|
1135
|
+
chainId: args.chainId,
|
|
1136
|
+
votingEscrow: ve,
|
|
1137
|
+
ctm,
|
|
1138
|
+
owner,
|
|
1139
|
+
tokenId,
|
|
1140
|
+
amountWei
|
|
1141
|
+
});
|
|
583
1142
|
const approve = await maybeApproveCtmStep({
|
|
584
1143
|
rpcUrl: args.rpcUrl,
|
|
585
1144
|
chainId: args.chainId,
|
|
@@ -611,7 +1170,15 @@ async function buildEvmMultisignBodyContinuumDaoIncreaseUnlockTime(args) {
|
|
|
611
1170
|
const ve = args.votingEscrow && isConfiguredAddress(args.votingEscrow) ? viem.getAddress(args.votingEscrow) : requireVe(args.chainId);
|
|
612
1171
|
const tokenId = parseTokenId(args.tokenId);
|
|
613
1172
|
const duration = BigInt(String(args.lockDurationSeconds).trim());
|
|
614
|
-
|
|
1173
|
+
const owner = viem.getAddress(args.executorAddress);
|
|
1174
|
+
await preflightIncreaseUnlockTime({
|
|
1175
|
+
rpcUrl: args.rpcUrl,
|
|
1176
|
+
chainId: args.chainId,
|
|
1177
|
+
votingEscrow: ve,
|
|
1178
|
+
owner,
|
|
1179
|
+
tokenId,
|
|
1180
|
+
durationSec: duration
|
|
1181
|
+
});
|
|
615
1182
|
const data = viem.encodeFunctionData({
|
|
616
1183
|
abi: veWriteAbi,
|
|
617
1184
|
functionName: "increase_unlock_time",
|
|
@@ -634,7 +1201,14 @@ async function buildEvmMultisignBodyContinuumDaoSplit(args) {
|
|
|
634
1201
|
const ve = args.votingEscrow && isConfiguredAddress(args.votingEscrow) ? viem.getAddress(args.votingEscrow) : requireVe(args.chainId);
|
|
635
1202
|
const tokenId = parseTokenId(args.tokenId);
|
|
636
1203
|
const extracted = viem.parseUnits(String(args.extractedHuman).trim().replace(/,/g, ""), CTM_TOKEN_DECIMALS);
|
|
637
|
-
|
|
1204
|
+
await preflightSplit({
|
|
1205
|
+
rpcUrl: args.rpcUrl,
|
|
1206
|
+
chainId: args.chainId,
|
|
1207
|
+
votingEscrow: ve,
|
|
1208
|
+
owner: viem.getAddress(args.executorAddress),
|
|
1209
|
+
tokenId,
|
|
1210
|
+
extractedWei: extracted
|
|
1211
|
+
});
|
|
638
1212
|
const data = viem.encodeFunctionData({
|
|
639
1213
|
abi: veWriteAbi,
|
|
640
1214
|
functionName: "split",
|
|
@@ -657,7 +1231,14 @@ async function buildEvmMultisignBodyContinuumDaoMerge(args) {
|
|
|
657
1231
|
const ve = args.votingEscrow && isConfiguredAddress(args.votingEscrow) ? viem.getAddress(args.votingEscrow) : requireVe(args.chainId);
|
|
658
1232
|
const fromId = parseTokenId(args.fromTokenId);
|
|
659
1233
|
const toId = parseTokenId(args.toTokenId);
|
|
660
|
-
|
|
1234
|
+
await preflightMerge({
|
|
1235
|
+
rpcUrl: args.rpcUrl,
|
|
1236
|
+
chainId: args.chainId,
|
|
1237
|
+
votingEscrow: ve,
|
|
1238
|
+
owner: viem.getAddress(args.executorAddress),
|
|
1239
|
+
fromTokenId: fromId,
|
|
1240
|
+
toTokenId: toId
|
|
1241
|
+
});
|
|
661
1242
|
const data = viem.encodeFunctionData({
|
|
662
1243
|
abi: veWriteAbi,
|
|
663
1244
|
functionName: "merge",
|
|
@@ -679,6 +1260,13 @@ async function buildEvmMultisignBodyContinuumDaoMerge(args) {
|
|
|
679
1260
|
async function buildEvmMultisignBodyContinuumDaoWithdraw(args) {
|
|
680
1261
|
const ve = args.votingEscrow && isConfiguredAddress(args.votingEscrow) ? viem.getAddress(args.votingEscrow) : requireVe(args.chainId);
|
|
681
1262
|
const tokenId = parseTokenId(args.tokenId);
|
|
1263
|
+
await preflightWithdraw({
|
|
1264
|
+
rpcUrl: args.rpcUrl,
|
|
1265
|
+
chainId: args.chainId,
|
|
1266
|
+
votingEscrow: ve,
|
|
1267
|
+
owner: viem.getAddress(args.executorAddress),
|
|
1268
|
+
tokenId
|
|
1269
|
+
});
|
|
682
1270
|
const data = viem.encodeFunctionData({ abi: veWriteAbi, functionName: "withdraw", args: [tokenId] });
|
|
683
1271
|
const step = {
|
|
684
1272
|
to: ve,
|
|
@@ -695,6 +1283,13 @@ async function buildEvmMultisignBodyContinuumDaoWithdraw(args) {
|
|
|
695
1283
|
async function buildEvmMultisignBodyContinuumDaoLiquidate(args) {
|
|
696
1284
|
const ve = args.votingEscrow && isConfiguredAddress(args.votingEscrow) ? viem.getAddress(args.votingEscrow) : requireVe(args.chainId);
|
|
697
1285
|
const tokenId = parseTokenId(args.tokenId);
|
|
1286
|
+
await preflightLiquidate({
|
|
1287
|
+
rpcUrl: args.rpcUrl,
|
|
1288
|
+
chainId: args.chainId,
|
|
1289
|
+
votingEscrow: ve,
|
|
1290
|
+
owner: viem.getAddress(args.executorAddress),
|
|
1291
|
+
tokenId
|
|
1292
|
+
});
|
|
698
1293
|
const data = viem.encodeFunctionData({ abi: veWriteAbi, functionName: "liquidate", args: [tokenId] });
|
|
699
1294
|
const step = {
|
|
700
1295
|
to: ve,
|
|
@@ -710,7 +1305,12 @@ async function buildEvmMultisignBodyContinuumDaoLiquidate(args) {
|
|
|
710
1305
|
}
|
|
711
1306
|
async function buildEvmMultisignBodyContinuumDaoDelegate(args) {
|
|
712
1307
|
const ve = args.votingEscrow && isConfiguredAddress(args.votingEscrow) ? viem.getAddress(args.votingEscrow) : requireVe(args.chainId);
|
|
713
|
-
const delegatee =
|
|
1308
|
+
const delegatee = await preflightDelegate({
|
|
1309
|
+
rpcUrl: args.rpcUrl,
|
|
1310
|
+
chainId: args.chainId,
|
|
1311
|
+
owner: viem.getAddress(args.executorAddress),
|
|
1312
|
+
delegatee: args.delegatee
|
|
1313
|
+
});
|
|
714
1314
|
const data = viem.encodeFunctionData({ abi: veWriteAbi, functionName: "delegate", args: [delegatee] });
|
|
715
1315
|
const step = {
|
|
716
1316
|
to: ve,
|
|
@@ -727,6 +1327,12 @@ async function buildEvmMultisignBodyContinuumDaoDelegate(args) {
|
|
|
727
1327
|
async function buildEvmMultisignBodyContinuumDaoUndelegate(args) {
|
|
728
1328
|
const ve = args.votingEscrow && isConfiguredAddress(args.votingEscrow) ? viem.getAddress(args.votingEscrow) : requireVe(args.chainId);
|
|
729
1329
|
const self = viem.getAddress(args.executorAddress);
|
|
1330
|
+
await preflightUndelegate({
|
|
1331
|
+
rpcUrl: args.rpcUrl,
|
|
1332
|
+
chainId: args.chainId,
|
|
1333
|
+
votingEscrow: ve,
|
|
1334
|
+
owner: self
|
|
1335
|
+
});
|
|
730
1336
|
const data = viem.encodeFunctionData({ abi: veWriteAbi, functionName: "delegate", args: [self] });
|
|
731
1337
|
const step = {
|
|
732
1338
|
to: ve,
|
|
@@ -741,7 +1347,7 @@ async function buildEvmMultisignBodyContinuumDaoUndelegate(args) {
|
|
|
741
1347
|
};
|
|
742
1348
|
return finalize([step], args, `ContinuumDAO: undelegate voting power (delegate back to ${self}).`);
|
|
743
1349
|
}
|
|
744
|
-
var
|
|
1350
|
+
var veReadAbi2 = viem.parseAbi(["function delegates(address account) view returns (address)"]);
|
|
745
1351
|
async function continuumDaoFetchDelegates(args) {
|
|
746
1352
|
const chainId = Number(args.chainId);
|
|
747
1353
|
requireLockChain(chainId);
|
|
@@ -757,15 +1363,22 @@ async function continuumDaoFetchDelegates(args) {
|
|
|
757
1363
|
transport: viem.http(args.rpcUrl.trim())
|
|
758
1364
|
});
|
|
759
1365
|
const delegatee = viem.getAddress(
|
|
760
|
-
await client.readContract({ address: ve, abi:
|
|
1366
|
+
await client.readContract({ address: ve, abi: veReadAbi2, functionName: "delegates", args: [account] })
|
|
761
1367
|
);
|
|
762
1368
|
return { account, delegatee, self: delegatee === account };
|
|
763
1369
|
}
|
|
764
1370
|
async function buildEvmMultisignBodyContinuumDaoTransfer(args) {
|
|
765
1371
|
const ve = args.votingEscrow && isConfiguredAddress(args.votingEscrow) ? viem.getAddress(args.votingEscrow) : requireVe(args.chainId);
|
|
766
1372
|
const tokenId = parseTokenId(args.tokenId);
|
|
767
|
-
const to = viem.getAddress(args.to);
|
|
768
1373
|
const from = viem.getAddress(args.executorAddress);
|
|
1374
|
+
const to = await preflightTransfer({
|
|
1375
|
+
rpcUrl: args.rpcUrl,
|
|
1376
|
+
chainId: args.chainId,
|
|
1377
|
+
votingEscrow: ve,
|
|
1378
|
+
owner: from,
|
|
1379
|
+
tokenId,
|
|
1380
|
+
to: args.to
|
|
1381
|
+
});
|
|
769
1382
|
const data = viem.encodeFunctionData({
|
|
770
1383
|
abi: veWriteAbi,
|
|
771
1384
|
functionName: "transferFrom",
|
|
@@ -826,11 +1439,20 @@ async function buildEvmMultisignBodyContinuumDaoAttachVeCtm(args) {
|
|
|
826
1439
|
const tokenId = parseTokenId(args.tokenId);
|
|
827
1440
|
const nodeKey = args.nodeKey.trim();
|
|
828
1441
|
if (!nodeKey) throw new Error("nodeKey is required to attach veCTM.");
|
|
1442
|
+
const groupId = resolveAttachGroupId(args.keyGen, args.groupId);
|
|
1443
|
+
await preflightAttachVeCtm({
|
|
1444
|
+
rpcUrl: args.rpcUrl,
|
|
1445
|
+
chainId: args.chainId,
|
|
1446
|
+
mpaWallet: wallet,
|
|
1447
|
+
nodeKey,
|
|
1448
|
+
tokenId,
|
|
1449
|
+
owner: viem.getAddress(args.executorAddress)
|
|
1450
|
+
});
|
|
829
1451
|
const tuple = args.nodeInfoTuple ?? encodeContinuumDaoNodeInfo(args.nodeInfo);
|
|
830
1452
|
const data = viem.encodeFunctionData({
|
|
831
1453
|
abi: attachAbi,
|
|
832
1454
|
functionName: "attachVeCtm",
|
|
833
|
-
args: [nodeKey, tokenId, tuple]
|
|
1455
|
+
args: [nodeKey, tokenId, tuple, groupId]
|
|
834
1456
|
});
|
|
835
1457
|
const step = {
|
|
836
1458
|
to: wallet,
|
|
@@ -840,16 +1462,24 @@ async function buildEvmMultisignBodyContinuumDaoAttachVeCtm(args) {
|
|
|
840
1462
|
buildBatchMeta: ({ gasLimit }) => meta("continuum_dao_attach", args.chainId, wallet, {
|
|
841
1463
|
name: "MultiSignAgentWallet.attachVeCtm",
|
|
842
1464
|
nodeKey,
|
|
843
|
-
tokenId: tokenId.toString()
|
|
1465
|
+
tokenId: tokenId.toString(),
|
|
1466
|
+
groupId
|
|
844
1467
|
}, gasLimit)
|
|
845
1468
|
};
|
|
846
|
-
return finalize([step], args, `ContinuumDAO: attach veCTM #${tokenId}.`);
|
|
1469
|
+
return finalize([step], args, `ContinuumDAO: attach veCTM #${tokenId} (group ${groupId}).`);
|
|
847
1470
|
}
|
|
848
1471
|
async function buildEvmMultisignBodyContinuumDaoRequestDetach(args) {
|
|
849
1472
|
requireLockChain(args.chainId);
|
|
850
1473
|
const np = viem.getAddress(args.nodeProperties);
|
|
851
1474
|
if (np === viem.zeroAddress) throw new Error("NodeProperties address is required to request detach.");
|
|
852
1475
|
const tokenId = parseTokenId(args.tokenId);
|
|
1476
|
+
await preflightRequestDetach({
|
|
1477
|
+
rpcUrl: args.rpcUrl,
|
|
1478
|
+
chainId: args.chainId,
|
|
1479
|
+
nodeProperties: np,
|
|
1480
|
+
owner: viem.getAddress(args.executorAddress),
|
|
1481
|
+
tokenId
|
|
1482
|
+
});
|
|
853
1483
|
const data = viem.encodeFunctionData({
|
|
854
1484
|
abi: detachAbi,
|
|
855
1485
|
functionName: "setNodeRemovalStatus",
|
|
@@ -1449,7 +2079,9 @@ var governorReadAbi = viem.parseAbi([
|
|
|
1449
2079
|
"function proposalThreshold() view returns (uint256)",
|
|
1450
2080
|
"function proposalCount() view returns (uint256)",
|
|
1451
2081
|
"function clock() view returns (uint48)",
|
|
1452
|
-
"function proposalVotes(uint256 proposalId) view returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes)"
|
|
2082
|
+
"function proposalVotes(uint256 proposalId) view returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes)",
|
|
2083
|
+
"function hasVoted(uint256 proposalId, address account) view returns (bool)",
|
|
2084
|
+
"function proposalSnapshot(uint256 proposalId) view returns (uint256)"
|
|
1453
2085
|
]);
|
|
1454
2086
|
function splitAbiParamList(inner) {
|
|
1455
2087
|
const out = [];
|
|
@@ -1701,9 +2333,32 @@ async function buildEvmMultisignBodyContinuumDaoProposeDelta(args) {
|
|
|
1701
2333
|
);
|
|
1702
2334
|
return { ...built, proposalArgs };
|
|
1703
2335
|
}
|
|
2336
|
+
async function requireVoteEligible(args) {
|
|
2337
|
+
const st = await continuumDaoFetchProposalState({
|
|
2338
|
+
chainId: args.chainId,
|
|
2339
|
+
rpcUrl: args.rpcUrl,
|
|
2340
|
+
proposalId: args.proposalId,
|
|
2341
|
+
governor: args.governor
|
|
2342
|
+
});
|
|
2343
|
+
if (st.state !== 1) {
|
|
2344
|
+
throw new Error(`Proposal is not Active (on-chain state ${st.state}).`);
|
|
2345
|
+
}
|
|
2346
|
+
const elig = await continuumDaoFetchProposalVoteEligibility({
|
|
2347
|
+
chainId: args.chainId,
|
|
2348
|
+
rpcUrl: args.rpcUrl,
|
|
2349
|
+
proposalId: args.proposalId,
|
|
2350
|
+
account: args.executorAddress,
|
|
2351
|
+
governor: args.governor
|
|
2352
|
+
});
|
|
2353
|
+
if (elig.hasVoted) throw new Error("This KeyGen has already voted on this proposal.");
|
|
2354
|
+
if (BigInt(elig.snapshotVotes) === 0n) {
|
|
2355
|
+
throw new Error("No veCTM voting power at snapshot for this KeyGen.");
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
1704
2358
|
async function buildEvmMultisignBodyContinuumDaoCastVoteBravo(args) {
|
|
1705
2359
|
const gov = requireGovernor(args.chainId, args.governor);
|
|
1706
2360
|
const proposalId = BigInt(String(args.proposalId).trim());
|
|
2361
|
+
await requireVoteEligible(args);
|
|
1707
2362
|
const data = viem.encodeFunctionData({
|
|
1708
2363
|
abi: governorWriteAbi,
|
|
1709
2364
|
functionName: "castVote",
|
|
@@ -1722,6 +2377,10 @@ async function buildEvmMultisignBodyContinuumDaoCastVoteBravo(args) {
|
|
|
1722
2377
|
async function buildEvmMultisignBodyContinuumDaoCastVoteDelta(args) {
|
|
1723
2378
|
const gov = requireGovernor(args.chainId, args.governor);
|
|
1724
2379
|
const proposalId = BigInt(String(args.proposalId).trim());
|
|
2380
|
+
if (args.weights.length < 3) {
|
|
2381
|
+
throw new Error("Delta vote must include one weight per option plus a NOTA slot.");
|
|
2382
|
+
}
|
|
2383
|
+
await requireVoteEligible(args);
|
|
1725
2384
|
const params = encodeDeltaVoteParams(args.weights);
|
|
1726
2385
|
const data = viem.encodeFunctionData({
|
|
1727
2386
|
abi: governorWriteAbi,
|
|
@@ -1774,7 +2433,7 @@ async function buildEvmMultisignBodyContinuumDaoCancel(args) {
|
|
|
1774
2433
|
"continuum-dao cancel"
|
|
1775
2434
|
);
|
|
1776
2435
|
}
|
|
1777
|
-
function
|
|
2436
|
+
function publicClient2(rpcUrl, chainId) {
|
|
1778
2437
|
return viem.createPublicClient({
|
|
1779
2438
|
chain: viem.defineChain({
|
|
1780
2439
|
id: chainId,
|
|
@@ -1788,7 +2447,7 @@ function publicClient(rpcUrl, chainId) {
|
|
|
1788
2447
|
async function continuumDaoHashProposal(args) {
|
|
1789
2448
|
const chainId = Number(args.chainId);
|
|
1790
2449
|
const gov = requireGovernor(chainId, args.governor);
|
|
1791
|
-
const client =
|
|
2450
|
+
const client = publicClient2(args.rpcUrl, chainId);
|
|
1792
2451
|
const id = await client.readContract({
|
|
1793
2452
|
address: gov,
|
|
1794
2453
|
abi: governorReadAbi,
|
|
@@ -1800,7 +2459,7 @@ async function continuumDaoHashProposal(args) {
|
|
|
1800
2459
|
async function continuumDaoFetchVotingPower(args) {
|
|
1801
2460
|
const chainId = Number(args.chainId);
|
|
1802
2461
|
const gov = requireGovernor(chainId, args.governor);
|
|
1803
|
-
const client =
|
|
2462
|
+
const client = publicClient2(args.rpcUrl, chainId);
|
|
1804
2463
|
const clock = await client.readContract({ address: gov, abi: governorReadAbi, functionName: "clock" });
|
|
1805
2464
|
const timepoint = clock > 0 ? clock - 1 : 0;
|
|
1806
2465
|
const [votes, threshold] = await Promise.all([
|
|
@@ -1817,22 +2476,74 @@ async function continuumDaoFetchVotingPower(args) {
|
|
|
1817
2476
|
async function continuumDaoFetchProposalState(args) {
|
|
1818
2477
|
const chainId = Number(args.chainId);
|
|
1819
2478
|
const gov = requireGovernor(chainId, args.governor);
|
|
1820
|
-
const client =
|
|
2479
|
+
const client = publicClient2(args.rpcUrl, chainId);
|
|
1821
2480
|
const proposalId = BigInt(String(args.proposalId).trim());
|
|
1822
|
-
const
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
2481
|
+
const state = await client.readContract({
|
|
2482
|
+
address: gov,
|
|
2483
|
+
abi: governorReadAbi,
|
|
2484
|
+
functionName: "state",
|
|
2485
|
+
args: [proposalId]
|
|
2486
|
+
});
|
|
2487
|
+
let againstVotes = "0";
|
|
2488
|
+
let forVotes = "0";
|
|
2489
|
+
let abstainVotes = "0";
|
|
2490
|
+
let votesPartial = false;
|
|
2491
|
+
try {
|
|
2492
|
+
const votes = await client.readContract({
|
|
2493
|
+
address: gov,
|
|
2494
|
+
abi: governorReadAbi,
|
|
2495
|
+
functionName: "proposalVotes",
|
|
2496
|
+
args: [proposalId]
|
|
2497
|
+
});
|
|
2498
|
+
againstVotes = votes[0].toString();
|
|
2499
|
+
forVotes = votes[1].toString();
|
|
2500
|
+
abstainVotes = votes[2].toString();
|
|
2501
|
+
} catch {
|
|
2502
|
+
votesPartial = true;
|
|
2503
|
+
}
|
|
1826
2504
|
return {
|
|
1827
2505
|
state: Number(state),
|
|
1828
|
-
againstVotes
|
|
1829
|
-
forVotes
|
|
1830
|
-
abstainVotes
|
|
2506
|
+
againstVotes,
|
|
2507
|
+
forVotes,
|
|
2508
|
+
abstainVotes,
|
|
2509
|
+
votesPartial
|
|
2510
|
+
};
|
|
2511
|
+
}
|
|
2512
|
+
async function continuumDaoFetchProposalVoteEligibility(args) {
|
|
2513
|
+
const chainId = Number(args.chainId);
|
|
2514
|
+
const gov = requireGovernor(chainId, args.governor);
|
|
2515
|
+
const client = publicClient2(args.rpcUrl, chainId);
|
|
2516
|
+
const proposalId = BigInt(String(args.proposalId).trim());
|
|
2517
|
+
const account = viem.getAddress(args.account);
|
|
2518
|
+
const [hasVoted, snapshotBlock] = await Promise.all([
|
|
2519
|
+
client.readContract({
|
|
2520
|
+
address: gov,
|
|
2521
|
+
abi: governorReadAbi,
|
|
2522
|
+
functionName: "hasVoted",
|
|
2523
|
+
args: [proposalId, account]
|
|
2524
|
+
}),
|
|
2525
|
+
client.readContract({
|
|
2526
|
+
address: gov,
|
|
2527
|
+
abi: governorReadAbi,
|
|
2528
|
+
functionName: "proposalSnapshot",
|
|
2529
|
+
args: [proposalId]
|
|
2530
|
+
})
|
|
2531
|
+
]);
|
|
2532
|
+
const snapshotVotes = await client.readContract({
|
|
2533
|
+
address: gov,
|
|
2534
|
+
abi: governorReadAbi,
|
|
2535
|
+
functionName: "getVotes",
|
|
2536
|
+
args: [account, snapshotBlock]
|
|
2537
|
+
});
|
|
2538
|
+
return {
|
|
2539
|
+
hasVoted,
|
|
2540
|
+
snapshotVotes: snapshotVotes.toString(),
|
|
2541
|
+
snapshotBlock: snapshotBlock.toString()
|
|
1831
2542
|
};
|
|
1832
2543
|
}
|
|
1833
2544
|
async function continuumDaoFetchProposalCount(args) {
|
|
1834
2545
|
const gov = requireGovernor(args.chainId, args.governor);
|
|
1835
|
-
const client =
|
|
2546
|
+
const client = publicClient2(args.rpcUrl, args.chainId);
|
|
1836
2547
|
const count = await client.readContract({ address: gov, abi: governorReadAbi, functionName: "proposalCount" });
|
|
1837
2548
|
return { count: count.toString() };
|
|
1838
2549
|
}
|
|
@@ -2167,7 +2878,7 @@ var continuumDaoProtocolModule = {
|
|
|
2167
2878
|
{ id: "continuum-dao.undelegate", protocolId: CONTINUUM_DAO_PROTOCOL_ID, chainCategory: "evm", description: "Return voting power to the KeyGen (delegate to self)", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
|
|
2168
2879
|
{ id: "continuum-dao.fetch-delegates", protocolId: CONTINUUM_DAO_PROTOCOL_ID, chainCategory: "evm", description: "Read VotingEscrow.delegates(account)", commonParams: [], params: { account: { type: "string", required: true, description: "KeyGen or wallet address" } } },
|
|
2169
2880
|
{ id: "continuum-dao.transfer", protocolId: CONTINUUM_DAO_PROTOCOL_ID, chainCategory: "evm", description: "Transfer a veCTM NFT", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: { tokenId: { type: "string", required: true, description: "veCTM token id" }, to: { type: "string", required: true, description: "Recipient" } } },
|
|
2170
|
-
{ id: "continuum-dao.attach", protocolId: CONTINUUM_DAO_PROTOCOL_ID, chainCategory: "evm", description: "Attach veCTM to the node (authority KeyGen)", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: { nodeKey: { type: "string", required: true, description: "Node key" }, tokenId: { type: "string", required: true, description: "veCTM token id" }, mpaWallet: { type: "string", required: true, description: "MultiSignAgentWallet address" } } },
|
|
2881
|
+
{ id: "continuum-dao.attach", protocolId: CONTINUUM_DAO_PROTOCOL_ID, chainCategory: "evm", description: "Attach veCTM to the node (authority KeyGen). groupId is implicit from that KeyGen and binds the fee waiver. A second group attaches after rotating authority.", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: { nodeKey: { type: "string", required: true, description: "Node key" }, tokenId: { type: "string", required: true, description: "veCTM token id" }, mpaWallet: { type: "string", required: true, description: "MultiSignAgentWallet address" } } },
|
|
2171
2882
|
{ id: "continuum-dao.request-detach", protocolId: CONTINUUM_DAO_PROTOCOL_ID, chainCategory: "evm", description: "Request governance detach", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: { tokenId: { type: "string", required: true, description: "Attached token id" }, nodeProperties: { type: "string", required: true, description: "NodeProperties address" } } },
|
|
2172
2883
|
{ id: "continuum-dao.propose-bravo", protocolId: CONTINUUM_DAO_PROTOCOL_ID, chainCategory: "evm", description: "Propose a Bravo (For/Against/Abstain) proposal", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: { title: { type: "string", required: true, description: "On-chain description (title)" }, forumKey: { type: "string", required: true, description: "Created forum thread URL from forum_create_topic" } } },
|
|
2173
2884
|
{ id: "continuum-dao.propose-delta", protocolId: CONTINUUM_DAO_PROTOCOL_ID, chainCategory: "evm", description: "Propose a Delta multi-option proposal", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: { title: { type: "string", required: true, description: "On-chain description (title)" }, nWinners: { type: "number", required: true, description: "Winning options to execute" }, forumKey: { type: "string", required: true, description: "Created forum thread URL from forum_create_topic" } } },
|
|
@@ -2217,6 +2928,7 @@ exports.CONTINUUM_DAO_SPLIT_FALLBACK = CONTINUUM_DAO_SPLIT_FALLBACK;
|
|
|
2217
2928
|
exports.CONTINUUM_DAO_TRANSFER_FALLBACK = CONTINUUM_DAO_TRANSFER_FALLBACK;
|
|
2218
2929
|
exports.CONTINUUM_DAO_VOTE_FALLBACK = CONTINUUM_DAO_VOTE_FALLBACK;
|
|
2219
2930
|
exports.CONTINUUM_DAO_WITHDRAW_FALLBACK = CONTINUUM_DAO_WITHDRAW_FALLBACK;
|
|
2931
|
+
exports.CTM_TOKEN_ADDRESS = CTM_TOKEN_ADDRESS;
|
|
2220
2932
|
exports.CTM_TOKEN_DECIMALS = CTM_TOKEN_DECIMALS;
|
|
2221
2933
|
exports.CTM_TOKEN_NAME = CTM_TOKEN_NAME;
|
|
2222
2934
|
exports.CTM_TOKEN_SYMBOL = CTM_TOKEN_SYMBOL;
|
|
@@ -2228,9 +2940,15 @@ exports.GOVERNOR_STATE_LABELS = GOVERNOR_STATE_LABELS;
|
|
|
2228
2940
|
exports.MAXTIME_SECONDS = MAXTIME_SECONDS;
|
|
2229
2941
|
exports.PROPOSAL_TYPE_LABELS = PROPOSAL_TYPE_LABELS;
|
|
2230
2942
|
exports.PROPOSAL_TYPE_TO_FORUM_SECTION = PROPOSAL_TYPE_TO_FORUM_SECTION;
|
|
2943
|
+
exports.VECTM_DEFAULT_MINIMUM_LOCK_WEI = VECTM_DEFAULT_MINIMUM_LOCK_WEI;
|
|
2944
|
+
exports.VECTM_LIQ_MIN_LOCKED_WEI = VECTM_LIQ_MIN_LOCKED_WEI;
|
|
2945
|
+
exports.VECTM_LIQ_PENALTY_DEN = VECTM_LIQ_PENALTY_DEN;
|
|
2946
|
+
exports.VECTM_LIQ_PENALTY_NUM = VECTM_LIQ_PENALTY_NUM;
|
|
2947
|
+
exports.VECTM_MAX_LOCK_WEEKS = VECTM_MAX_LOCK_WEEKS;
|
|
2231
2948
|
exports.VECTM_NODE_INFO_TUPLE = VECTM_NODE_INFO_TUPLE;
|
|
2232
2949
|
exports.VECTM_TOKEN_NAME = VECTM_TOKEN_NAME;
|
|
2233
2950
|
exports.VECTM_TOKEN_SYMBOL = VECTM_TOKEN_SYMBOL;
|
|
2951
|
+
exports.VOTING_ESCROW_LINEA_ADDRESS = VOTING_ESCROW_LINEA_ADDRESS;
|
|
2234
2952
|
exports.WEEK_SECONDS = WEEK_SECONDS;
|
|
2235
2953
|
exports.applyForumSectionCheck = applyForumSectionCheck;
|
|
2236
2954
|
exports.assertContinuumDaoForumDeleteInput = assertContinuumDaoForumDeleteInput;
|
|
@@ -2238,6 +2956,19 @@ exports.assertContinuumDaoForumMarkReadInput = assertContinuumDaoForumMarkReadIn
|
|
|
2238
2956
|
exports.assertContinuumDaoForumRecentInput = assertContinuumDaoForumRecentInput;
|
|
2239
2957
|
exports.assertContinuumDaoForumSearchInput = assertContinuumDaoForumSearchInput;
|
|
2240
2958
|
exports.assertContinuumDaoForumTopicKey = assertContinuumDaoForumTopicKey;
|
|
2959
|
+
exports.assertCreateLockAmount = assertCreateLockAmount;
|
|
2960
|
+
exports.assertCtmAmountAtLeastMinimum = assertCtmAmountAtLeastMinimum;
|
|
2961
|
+
exports.assertDelegatee = assertDelegatee;
|
|
2962
|
+
exports.assertExecutorOwnsLock = assertExecutorOwnsLock;
|
|
2963
|
+
exports.assertIncreaseAmount = assertIncreaseAmount;
|
|
2964
|
+
exports.assertIncreaseUnlockTime = assertIncreaseUnlockTime;
|
|
2965
|
+
exports.assertLiquidate = assertLiquidate;
|
|
2966
|
+
exports.assertLockDurationSeconds = assertLockDurationSeconds;
|
|
2967
|
+
exports.assertMerge = assertMerge;
|
|
2968
|
+
exports.assertSplitExtracted = assertSplitExtracted;
|
|
2969
|
+
exports.assertTransfer = assertTransfer;
|
|
2970
|
+
exports.assertUndelegateNotAlreadySelf = assertUndelegateNotAlreadySelf;
|
|
2971
|
+
exports.assertWithdraw = assertWithdraw;
|
|
2241
2972
|
exports.bucketGovernorState = bucketGovernorState;
|
|
2242
2973
|
exports.buildBravoProposalArgs = buildBravoProposalArgs;
|
|
2243
2974
|
exports.buildDeltaProposalArgs = buildDeltaProposalArgs;
|
|
@@ -2263,6 +2994,7 @@ exports.buildEvmMultisignBodyContinuumDaoSplit = buildEvmMultisignBodyContinuumD
|
|
|
2263
2994
|
exports.buildEvmMultisignBodyContinuumDaoTransfer = buildEvmMultisignBodyContinuumDaoTransfer;
|
|
2264
2995
|
exports.buildEvmMultisignBodyContinuumDaoUndelegate = buildEvmMultisignBodyContinuumDaoUndelegate;
|
|
2265
2996
|
exports.buildEvmMultisignBodyContinuumDaoWithdraw = buildEvmMultisignBodyContinuumDaoWithdraw;
|
|
2997
|
+
exports.computeLiquidationAmounts = computeLiquidationAmounts;
|
|
2266
2998
|
exports.continuumDaoDeployment = continuumDaoDeployment;
|
|
2267
2999
|
exports.continuumDaoExplainProposal = continuumDaoExplainProposal;
|
|
2268
3000
|
exports.continuumDaoFetchDelegates = continuumDaoFetchDelegates;
|
|
@@ -2270,6 +3002,7 @@ exports.continuumDaoFetchLiveProposals = continuumDaoFetchLiveProposals;
|
|
|
2270
3002
|
exports.continuumDaoFetchProposal = continuumDaoFetchProposal;
|
|
2271
3003
|
exports.continuumDaoFetchProposalCount = continuumDaoFetchProposalCount;
|
|
2272
3004
|
exports.continuumDaoFetchProposalState = continuumDaoFetchProposalState;
|
|
3005
|
+
exports.continuumDaoFetchProposalVoteEligibility = continuumDaoFetchProposalVoteEligibility;
|
|
2273
3006
|
exports.continuumDaoFetchProposals = continuumDaoFetchProposals;
|
|
2274
3007
|
exports.continuumDaoFetchVotingPower = continuumDaoFetchVotingPower;
|
|
2275
3008
|
exports.continuumDaoForumCreateIdea = continuumDaoForumCreateIdea;
|
|
@@ -2311,6 +3044,7 @@ exports.encodeGovActionCalldata = encodeGovActionCalldata;
|
|
|
2311
3044
|
exports.expectedForumSectionForProposalType = expectedForumSectionForProposalType;
|
|
2312
3045
|
exports.explainGovAction = explainGovAction;
|
|
2313
3046
|
exports.explainProposalRecord = explainProposalRecord;
|
|
3047
|
+
exports.floorUnlockTimeSeconds = floorUnlockTimeSeconds;
|
|
2314
3048
|
exports.governorAddressOnEvmChain = governorAddressOnEvmChain;
|
|
2315
3049
|
exports.isConfiguredAddress = isConfiguredAddress;
|
|
2316
3050
|
exports.isContinuumDaoCtmOnAssetsChain = isContinuumDaoCtmOnAssetsChain;
|
|
@@ -2322,7 +3056,24 @@ exports.isForumIdeaSection = isForumIdeaSection;
|
|
|
2322
3056
|
exports.isGovNoOpAction = isGovNoOpAction;
|
|
2323
3057
|
exports.isVotingEscrowContinuumName = isVotingEscrowContinuumName;
|
|
2324
3058
|
exports.listContinuumDaoDefaultAssets = listContinuumDaoDefaultAssets;
|
|
3059
|
+
exports.maxLockDurationSeconds = maxLockDurationSeconds;
|
|
3060
|
+
exports.preflightAttachVeCtm = preflightAttachVeCtm;
|
|
3061
|
+
exports.preflightCreateLock = preflightCreateLock;
|
|
3062
|
+
exports.preflightDelegate = preflightDelegate;
|
|
3063
|
+
exports.preflightIncreaseAmount = preflightIncreaseAmount;
|
|
3064
|
+
exports.preflightIncreaseUnlockTime = preflightIncreaseUnlockTime;
|
|
3065
|
+
exports.preflightLiquidate = preflightLiquidate;
|
|
3066
|
+
exports.preflightMerge = preflightMerge;
|
|
3067
|
+
exports.preflightRequestDetach = preflightRequestDetach;
|
|
3068
|
+
exports.preflightSplit = preflightSplit;
|
|
3069
|
+
exports.preflightTransfer = preflightTransfer;
|
|
3070
|
+
exports.preflightUndelegate = preflightUndelegate;
|
|
3071
|
+
exports.preflightWithdraw = preflightWithdraw;
|
|
2325
3072
|
exports.proposalDescriptionHash = proposalDescriptionHash;
|
|
3073
|
+
exports.readCtmBalanceWei = readCtmBalanceWei;
|
|
3074
|
+
exports.readMinimumLockWei = readMinimumLockWei;
|
|
3075
|
+
exports.readVeCtmLockState = readVeCtmLockState;
|
|
3076
|
+
exports.resolveAttachGroupId = resolveAttachGroupId;
|
|
2326
3077
|
exports.summarizeLiveProposals = summarizeLiveProposals;
|
|
2327
3078
|
exports.votingEscrowAddressOnEvmChain = votingEscrowAddressOnEvmChain;
|
|
2328
3079
|
//# sourceMappingURL=index.cjs.map
|