@walletconnect/staking-cli 0.1.0
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/cli.js +586 -0
- package/dist/index.cjs +22 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +68 -0
- package/dist/index.d.ts +68 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/package.json +52 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,586 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import { WalletConnectCLI, resolveProjectId } from "@walletconnect/cli-sdk";
|
|
5
|
+
|
|
6
|
+
// src/constants.ts
|
|
7
|
+
var CAIP2_CHAIN_ID = "eip155:10";
|
|
8
|
+
var L2_WCT_ADDRESS = "0xeF4461891DfB3AC8572cCf7C794664A8DD927945";
|
|
9
|
+
var STAKE_WEIGHT_ADDRESS = "0x521B4C065Bbdbe3E20B3727340730936912DfA46";
|
|
10
|
+
var STAKING_REWARD_DISTRIBUTOR_ADDRESS = "0xF368F535e329c6d08DFf0d4b2dA961C4e7F3fCAF";
|
|
11
|
+
var OPTIMISM_RPC_URL = "https://mainnet.optimism.io";
|
|
12
|
+
var FOUNDATION_API_URL = "https://api.walletconnect.network";
|
|
13
|
+
var ONE_WEEK_IN_SECONDS = 604800;
|
|
14
|
+
var WCT_DECIMALS = 18;
|
|
15
|
+
var APY_SLOPE = -0.06464;
|
|
16
|
+
var APY_INTERCEPT = 12.0808;
|
|
17
|
+
var APY_STAKE_WEIGHT_DIVISOR = 1e6;
|
|
18
|
+
var MAX_LOCK_WEEKS = 104;
|
|
19
|
+
var CLI_METADATA = {
|
|
20
|
+
name: "walletconnect-staking",
|
|
21
|
+
description: "WalletConnect WCT Staking CLI",
|
|
22
|
+
url: "https://walletconnect.com",
|
|
23
|
+
icons: []
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// src/commands.ts
|
|
27
|
+
import { parseUnits } from "viem";
|
|
28
|
+
|
|
29
|
+
// src/contracts.ts
|
|
30
|
+
import { encodeFunctionData, parseAbi } from "viem";
|
|
31
|
+
var erc20Abi = parseAbi([
|
|
32
|
+
"function approve(address spender, uint256 value) returns (bool)",
|
|
33
|
+
"function balanceOf(address account) view returns (uint256)",
|
|
34
|
+
"function allowance(address owner, address spender) view returns (uint256)"
|
|
35
|
+
]);
|
|
36
|
+
var stakeWeightAbi = parseAbi([
|
|
37
|
+
"function createLock(uint256 amount, uint256 unlockTime)",
|
|
38
|
+
"function updateLock(uint256 amount, uint256 unlockTime)",
|
|
39
|
+
"function increaseLockAmount(uint256 amount)",
|
|
40
|
+
"function increaseUnlockTime(uint256 newUnlockTime)",
|
|
41
|
+
"function withdrawAll()",
|
|
42
|
+
"function locks(address) view returns (int128 amount, uint256 end, uint256 transferredAmount)"
|
|
43
|
+
]);
|
|
44
|
+
var stakingRewardDistributorAbi = parseAbi([
|
|
45
|
+
"function claim(address user) returns (uint256)"
|
|
46
|
+
]);
|
|
47
|
+
function buildApprove(spender, amount) {
|
|
48
|
+
return {
|
|
49
|
+
to: L2_WCT_ADDRESS,
|
|
50
|
+
data: encodeFunctionData({
|
|
51
|
+
abi: erc20Abi,
|
|
52
|
+
functionName: "approve",
|
|
53
|
+
args: [spender, amount]
|
|
54
|
+
})
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function buildCreateLock(amount, unlockTime) {
|
|
58
|
+
return {
|
|
59
|
+
to: STAKE_WEIGHT_ADDRESS,
|
|
60
|
+
data: encodeFunctionData({
|
|
61
|
+
abi: stakeWeightAbi,
|
|
62
|
+
functionName: "createLock",
|
|
63
|
+
args: [amount, unlockTime]
|
|
64
|
+
})
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function buildUpdateLock(amount, unlockTime) {
|
|
68
|
+
return {
|
|
69
|
+
to: STAKE_WEIGHT_ADDRESS,
|
|
70
|
+
data: encodeFunctionData({
|
|
71
|
+
abi: stakeWeightAbi,
|
|
72
|
+
functionName: "updateLock",
|
|
73
|
+
args: [amount, unlockTime]
|
|
74
|
+
})
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function buildIncreaseLockAmount(amount) {
|
|
78
|
+
return {
|
|
79
|
+
to: STAKE_WEIGHT_ADDRESS,
|
|
80
|
+
data: encodeFunctionData({
|
|
81
|
+
abi: stakeWeightAbi,
|
|
82
|
+
functionName: "increaseLockAmount",
|
|
83
|
+
args: [amount]
|
|
84
|
+
})
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function buildWithdrawAll() {
|
|
88
|
+
return {
|
|
89
|
+
to: STAKE_WEIGHT_ADDRESS,
|
|
90
|
+
data: encodeFunctionData({
|
|
91
|
+
abi: stakeWeightAbi,
|
|
92
|
+
functionName: "withdrawAll"
|
|
93
|
+
})
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function buildClaim(user) {
|
|
97
|
+
return {
|
|
98
|
+
to: STAKING_REWARD_DISTRIBUTOR_ADDRESS,
|
|
99
|
+
data: encodeFunctionData({
|
|
100
|
+
abi: stakingRewardDistributorAbi,
|
|
101
|
+
functionName: "claim",
|
|
102
|
+
args: [user]
|
|
103
|
+
})
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function buildBalanceOfCallData(account) {
|
|
107
|
+
return {
|
|
108
|
+
to: L2_WCT_ADDRESS,
|
|
109
|
+
data: encodeFunctionData({
|
|
110
|
+
abi: erc20Abi,
|
|
111
|
+
functionName: "balanceOf",
|
|
112
|
+
args: [account]
|
|
113
|
+
})
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function buildAllowanceCallData(owner, spender) {
|
|
117
|
+
return {
|
|
118
|
+
to: L2_WCT_ADDRESS,
|
|
119
|
+
data: encodeFunctionData({
|
|
120
|
+
abi: erc20Abi,
|
|
121
|
+
functionName: "allowance",
|
|
122
|
+
args: [owner, spender]
|
|
123
|
+
})
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function buildLocksCallData(account) {
|
|
127
|
+
return {
|
|
128
|
+
to: STAKE_WEIGHT_ADDRESS,
|
|
129
|
+
data: encodeFunctionData({
|
|
130
|
+
abi: stakeWeightAbi,
|
|
131
|
+
functionName: "locks",
|
|
132
|
+
args: [account]
|
|
133
|
+
})
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/rpc.ts
|
|
138
|
+
import { decodeAbiParameters } from "viem";
|
|
139
|
+
var requestId = 1;
|
|
140
|
+
async function rpcRequest(method, params, rpcUrl) {
|
|
141
|
+
const res = await fetch(rpcUrl, {
|
|
142
|
+
method: "POST",
|
|
143
|
+
headers: { "Content-Type": "application/json" },
|
|
144
|
+
body: JSON.stringify({
|
|
145
|
+
jsonrpc: "2.0",
|
|
146
|
+
id: requestId++,
|
|
147
|
+
method,
|
|
148
|
+
params
|
|
149
|
+
})
|
|
150
|
+
});
|
|
151
|
+
if (!res.ok) {
|
|
152
|
+
throw new Error(`RPC request failed: ${res.status} ${res.statusText}`);
|
|
153
|
+
}
|
|
154
|
+
const json = await res.json();
|
|
155
|
+
if (json.error) {
|
|
156
|
+
throw new Error(`RPC error: ${json.error.message}`);
|
|
157
|
+
}
|
|
158
|
+
return json.result;
|
|
159
|
+
}
|
|
160
|
+
async function ethCall(tx, rpcUrl) {
|
|
161
|
+
return rpcRequest("eth_call", [{ to: tx.to, data: tx.data }, "latest"], rpcUrl);
|
|
162
|
+
}
|
|
163
|
+
async function readUint256(tx, rpcUrl = OPTIMISM_RPC_URL) {
|
|
164
|
+
const result = await ethCall(tx, rpcUrl);
|
|
165
|
+
const [value] = decodeAbiParameters([{ type: "uint256" }], result);
|
|
166
|
+
return value;
|
|
167
|
+
}
|
|
168
|
+
async function estimateGas(from, tx, rpcUrl = OPTIMISM_RPC_URL) {
|
|
169
|
+
const result = await rpcRequest(
|
|
170
|
+
"eth_estimateGas",
|
|
171
|
+
[{ from, to: tx.to, data: tx.data, value: "0x0" }, "latest"],
|
|
172
|
+
rpcUrl
|
|
173
|
+
);
|
|
174
|
+
const estimate = BigInt(result);
|
|
175
|
+
const buffered = estimate + estimate / 5n;
|
|
176
|
+
return `0x${buffered.toString(16)}`;
|
|
177
|
+
}
|
|
178
|
+
async function waitForTx(txHash, rpcUrl = OPTIMISM_RPC_URL, { intervalMs = 2e3, timeoutMs = 6e4 } = {}) {
|
|
179
|
+
const start = Date.now();
|
|
180
|
+
while (Date.now() - start < timeoutMs) {
|
|
181
|
+
try {
|
|
182
|
+
const receipt = await rpcRequest(
|
|
183
|
+
"eth_getTransactionReceipt",
|
|
184
|
+
[txHash],
|
|
185
|
+
rpcUrl
|
|
186
|
+
);
|
|
187
|
+
if (receipt) {
|
|
188
|
+
if (receipt.status === "0x0") {
|
|
189
|
+
throw new Error(`Transaction ${txHash} reverted`);
|
|
190
|
+
}
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
} catch (err) {
|
|
194
|
+
if (err instanceof Error && err.message.includes("reverted")) throw err;
|
|
195
|
+
}
|
|
196
|
+
await new Promise((r) => setTimeout(r, intervalMs));
|
|
197
|
+
}
|
|
198
|
+
throw new Error(`Transaction ${txHash} not confirmed within ${timeoutMs / 1e3}s`);
|
|
199
|
+
}
|
|
200
|
+
async function readLocks(tx, rpcUrl = OPTIMISM_RPC_URL) {
|
|
201
|
+
const result = await ethCall(tx, rpcUrl);
|
|
202
|
+
const [amount, end, transferredAmount] = decodeAbiParameters(
|
|
203
|
+
[{ type: "int128" }, { type: "uint256" }, { type: "uint256" }],
|
|
204
|
+
result
|
|
205
|
+
);
|
|
206
|
+
return { amount: BigInt(amount), end, transferredAmount };
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// src/api.ts
|
|
210
|
+
function getBaseUrl() {
|
|
211
|
+
return process.env.FOUNDATION_API_URL || FOUNDATION_API_URL;
|
|
212
|
+
}
|
|
213
|
+
async function fetchStaking(address) {
|
|
214
|
+
const url = `${getBaseUrl()}/staking?address=${address}`;
|
|
215
|
+
const res = await fetch(url);
|
|
216
|
+
if (!res.ok) {
|
|
217
|
+
throw new Error(`Foundation API error: ${res.status} ${res.statusText}`);
|
|
218
|
+
}
|
|
219
|
+
return await res.json();
|
|
220
|
+
}
|
|
221
|
+
async function fetchStakeWeight() {
|
|
222
|
+
const url = `${getBaseUrl()}/stake-weight`;
|
|
223
|
+
const res = await fetch(url);
|
|
224
|
+
if (!res.ok) {
|
|
225
|
+
throw new Error(`Foundation API error: ${res.status} ${res.statusText}`);
|
|
226
|
+
}
|
|
227
|
+
return await res.json();
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// src/format.ts
|
|
231
|
+
import { formatUnits } from "viem";
|
|
232
|
+
function formatWCT(amount) {
|
|
233
|
+
const raw = formatUnits(amount, WCT_DECIMALS);
|
|
234
|
+
const num = parseFloat(raw);
|
|
235
|
+
return num.toLocaleString("en-US", {
|
|
236
|
+
minimumFractionDigits: 2,
|
|
237
|
+
maximumFractionDigits: 2
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
function formatDate(timestamp) {
|
|
241
|
+
return new Date(timestamp * 1e3).toLocaleDateString("en-US", {
|
|
242
|
+
year: "numeric",
|
|
243
|
+
month: "short",
|
|
244
|
+
day: "numeric"
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
function calculateAPY(stakeWeight) {
|
|
248
|
+
return Math.max(
|
|
249
|
+
stakeWeight / APY_STAKE_WEIGHT_DIVISOR * APY_SLOPE + APY_INTERCEPT,
|
|
250
|
+
0
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
function calculateWeeklyAPY(baseAPY, weeks) {
|
|
254
|
+
return baseAPY * (Math.min(weeks, MAX_LOCK_WEEKS) / 52);
|
|
255
|
+
}
|
|
256
|
+
function label(key, value) {
|
|
257
|
+
return ` ${key.padEnd(12)} ${value}`;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// src/commands.ts
|
|
261
|
+
function computeUnlockTime(weeks) {
|
|
262
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
263
|
+
return BigInt(Math.floor((now + weeks * ONE_WEEK_IN_SECONDS) / ONE_WEEK_IN_SECONDS)) * BigInt(ONE_WEEK_IN_SECONDS);
|
|
264
|
+
}
|
|
265
|
+
async function sendTx(wallet, from, tx) {
|
|
266
|
+
const gas = await estimateGas(from, tx);
|
|
267
|
+
return wallet.request({
|
|
268
|
+
chainId: CAIP2_CHAIN_ID,
|
|
269
|
+
request: {
|
|
270
|
+
method: "eth_sendTransaction",
|
|
271
|
+
params: [{ from, to: tx.to, data: tx.data, value: "0x0", gas }]
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
async function stake(wallet, address, amount, weeks) {
|
|
276
|
+
const amountWei = parseUnits(amount, WCT_DECIMALS);
|
|
277
|
+
const requestedUnlockTime = computeUnlockTime(weeks);
|
|
278
|
+
const lock = await readLocks(buildLocksCallData(address));
|
|
279
|
+
const hasPosition = lock.amount > 0n;
|
|
280
|
+
if (hasPosition) {
|
|
281
|
+
console.log("\nExisting staking position:");
|
|
282
|
+
console.log(label("Staked", `${formatWCT(BigInt(lock.amount))} WCT`));
|
|
283
|
+
console.log(label("Unlocks", formatDate(Number(lock.end))));
|
|
284
|
+
}
|
|
285
|
+
let effectiveUnlockTime = requestedUnlockTime;
|
|
286
|
+
const extendingTime = !hasPosition || requestedUnlockTime > lock.end;
|
|
287
|
+
if (hasPosition && requestedUnlockTime <= lock.end) {
|
|
288
|
+
effectiveUnlockTime = lock.end;
|
|
289
|
+
console.log(`
|
|
290
|
+
Requested unlock (${formatDate(Number(requestedUnlockTime))}) is before existing lock end.`);
|
|
291
|
+
console.log(`Keeping current unlock date: ${formatDate(Number(lock.end))}`);
|
|
292
|
+
}
|
|
293
|
+
console.log(`
|
|
294
|
+
Adding ${amount} WCT${extendingTime ? `, extending lock to ${formatDate(Number(effectiveUnlockTime))}` : ""}...`);
|
|
295
|
+
const allowance = await readUint256(buildAllowanceCallData(address, STAKE_WEIGHT_ADDRESS));
|
|
296
|
+
if (allowance < amountWei) {
|
|
297
|
+
console.log("\nApproving WCT spend...");
|
|
298
|
+
const approveTxHash = await sendTx(wallet, address, buildApprove(STAKE_WEIGHT_ADDRESS, amountWei));
|
|
299
|
+
console.log(label("Approve tx", approveTxHash));
|
|
300
|
+
console.log("Waiting for confirmation...");
|
|
301
|
+
await waitForTx(approveTxHash);
|
|
302
|
+
}
|
|
303
|
+
let txHash;
|
|
304
|
+
if (!hasPosition) {
|
|
305
|
+
console.log("\nCreating new lock...");
|
|
306
|
+
txHash = await sendTx(wallet, address, buildCreateLock(amountWei, effectiveUnlockTime));
|
|
307
|
+
} else if (extendingTime) {
|
|
308
|
+
console.log("\nUpdating lock (amount + time)...");
|
|
309
|
+
txHash = await sendTx(wallet, address, buildUpdateLock(amountWei, effectiveUnlockTime));
|
|
310
|
+
} else {
|
|
311
|
+
console.log("\nIncreasing lock amount...");
|
|
312
|
+
txHash = await sendTx(wallet, address, buildIncreaseLockAmount(amountWei));
|
|
313
|
+
}
|
|
314
|
+
console.log(label("Tx hash", txHash));
|
|
315
|
+
console.log("\nStake submitted successfully.");
|
|
316
|
+
}
|
|
317
|
+
async function unstake(wallet, address) {
|
|
318
|
+
const staking = await fetchStaking(address);
|
|
319
|
+
if (!staking.position) {
|
|
320
|
+
console.log("\nNo staking position found.");
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
if (staking.position.unlocksAt) {
|
|
324
|
+
const unlocksAt = new Date(staking.position.unlocksAt).getTime() / 1e3;
|
|
325
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
326
|
+
if (unlocksAt > now) {
|
|
327
|
+
console.log(`
|
|
328
|
+
Lock has not expired yet. Unlocks ${formatDate(unlocksAt)}.`);
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
console.log("\nWithdrawing all staked WCT...");
|
|
333
|
+
const txHash = await sendTx(wallet, address, buildWithdrawAll());
|
|
334
|
+
console.log(label("Tx hash", txHash));
|
|
335
|
+
console.log("\nUnstake submitted successfully.");
|
|
336
|
+
}
|
|
337
|
+
async function claim(wallet, address) {
|
|
338
|
+
const staking = await fetchStaking(address);
|
|
339
|
+
if (!staking.rewards || staking.rewards.amount === "0") {
|
|
340
|
+
console.log("\nNo rewards to claim.");
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
console.log(`
|
|
344
|
+
Claiming ${staking.rewards.amount} WCT in rewards...`);
|
|
345
|
+
const txHash = await sendTx(wallet, address, buildClaim(address));
|
|
346
|
+
console.log(label("Tx hash", txHash));
|
|
347
|
+
console.log("\nClaim submitted successfully.");
|
|
348
|
+
}
|
|
349
|
+
async function status(address) {
|
|
350
|
+
const [staking, stakeWeightRes] = await Promise.all([
|
|
351
|
+
fetchStaking(address),
|
|
352
|
+
fetchStakeWeight()
|
|
353
|
+
]);
|
|
354
|
+
console.log(`
|
|
355
|
+
Staking status for ${address}
|
|
356
|
+
`);
|
|
357
|
+
if (!staking.position) {
|
|
358
|
+
console.log(" No staking position found.\n");
|
|
359
|
+
} else {
|
|
360
|
+
const pos = staking.position;
|
|
361
|
+
console.log(label("Amount", `${pos.amount} WCT`));
|
|
362
|
+
console.log(label("Permanent", pos.isPermanent ? "Yes" : "No"));
|
|
363
|
+
console.log(label("Created", new Date(pos.createdAt).toLocaleDateString("en-US")));
|
|
364
|
+
if (pos.unlocksAt) {
|
|
365
|
+
console.log(label("Unlocks", new Date(pos.unlocksAt).toLocaleDateString("en-US")));
|
|
366
|
+
}
|
|
367
|
+
if (pos.duration) {
|
|
368
|
+
const durationWeeks = Math.round(parseInt(pos.duration, 10) / ONE_WEEK_IN_SECONDS);
|
|
369
|
+
console.log(label("Duration", `${durationWeeks} week(s)`));
|
|
370
|
+
}
|
|
371
|
+
console.log();
|
|
372
|
+
}
|
|
373
|
+
if (staking.rewards) {
|
|
374
|
+
console.log(label("Rewards", `${staking.rewards.amount} WCT`));
|
|
375
|
+
}
|
|
376
|
+
const stakeWeight = parseFloat(stakeWeightRes.stakeWeight);
|
|
377
|
+
const baseAPY = calculateAPY(stakeWeight);
|
|
378
|
+
console.log(label("Base APY", `${baseAPY.toFixed(2)}%`));
|
|
379
|
+
if (staking.position?.duration) {
|
|
380
|
+
const weeks = Math.round(parseInt(staking.position.duration, 10) / ONE_WEEK_IN_SECONDS);
|
|
381
|
+
const weeklyAPY = calculateWeeklyAPY(baseAPY, weeks);
|
|
382
|
+
console.log(label("Your APY", `${weeklyAPY.toFixed(2)}%`));
|
|
383
|
+
}
|
|
384
|
+
console.log();
|
|
385
|
+
}
|
|
386
|
+
async function balance(address) {
|
|
387
|
+
const bal = await readUint256(buildBalanceOfCallData(address));
|
|
388
|
+
console.log(`
|
|
389
|
+
${label("WCT balance", `${formatWCT(bal)} WCT`)}
|
|
390
|
+
`);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// src/cli.ts
|
|
394
|
+
function usage() {
|
|
395
|
+
console.log(`Usage: walletconnect-staking <command> [options]
|
|
396
|
+
|
|
397
|
+
Commands:
|
|
398
|
+
stake <amount> <weeks> Stake WCT (approve + createLock/updateLock)
|
|
399
|
+
unstake Withdraw all staked WCT (after lock expires)
|
|
400
|
+
claim Claim staking rewards
|
|
401
|
+
status Show staking position, rewards, and APY
|
|
402
|
+
balance Show WCT token balance
|
|
403
|
+
|
|
404
|
+
Options:
|
|
405
|
+
--address=0x... Use address directly (for read-only commands)
|
|
406
|
+
--browser Use browser UI for wallet connection
|
|
407
|
+
--help Show this help message
|
|
408
|
+
|
|
409
|
+
Environment:
|
|
410
|
+
WALLETCONNECT_PROJECT_ID Overrides config project-id when set
|
|
411
|
+
|
|
412
|
+
Configure project ID globally with: walletconnect config set project-id <id>`);
|
|
413
|
+
}
|
|
414
|
+
function getProjectId() {
|
|
415
|
+
const id = resolveProjectId();
|
|
416
|
+
if (!id) {
|
|
417
|
+
console.error("Error: No project ID found. Set via: walletconnect config set project-id <id>");
|
|
418
|
+
process.exit(1);
|
|
419
|
+
}
|
|
420
|
+
return id;
|
|
421
|
+
}
|
|
422
|
+
function parseArgs(argv) {
|
|
423
|
+
let address;
|
|
424
|
+
let browser = false;
|
|
425
|
+
const positional = [];
|
|
426
|
+
for (const arg of argv) {
|
|
427
|
+
if (arg.startsWith("--address=")) {
|
|
428
|
+
address = arg.slice("--address=".length);
|
|
429
|
+
} else if (arg === "--browser") {
|
|
430
|
+
browser = true;
|
|
431
|
+
} else if (arg === "--help" || arg === "-h") {
|
|
432
|
+
positional.unshift("--help");
|
|
433
|
+
} else if (!arg.startsWith("-")) {
|
|
434
|
+
positional.push(arg);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
return {
|
|
438
|
+
command: positional[0],
|
|
439
|
+
positional: positional.slice(1),
|
|
440
|
+
address,
|
|
441
|
+
browser
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
function parseAccount(caip10) {
|
|
445
|
+
const lastColon = caip10.lastIndexOf(":");
|
|
446
|
+
return caip10.slice(lastColon + 1);
|
|
447
|
+
}
|
|
448
|
+
function findOptimismAccount(accounts) {
|
|
449
|
+
const match = accounts.find((a) => a.startsWith("eip155:10:"));
|
|
450
|
+
return match ? parseAccount(match) : null;
|
|
451
|
+
}
|
|
452
|
+
async function resolveAddress(opts) {
|
|
453
|
+
if (opts.address) {
|
|
454
|
+
return { address: opts.address, wallet: null };
|
|
455
|
+
}
|
|
456
|
+
const projectId = opts.requireWallet ? getProjectId() : process.env.WALLETCONNECT_PROJECT_ID || "";
|
|
457
|
+
const wallet = new WalletConnectCLI({
|
|
458
|
+
projectId,
|
|
459
|
+
metadata: CLI_METADATA,
|
|
460
|
+
chains: [CAIP2_CHAIN_ID],
|
|
461
|
+
ui: opts.browser ? "browser" : "terminal"
|
|
462
|
+
});
|
|
463
|
+
const existing = await wallet.tryRestore();
|
|
464
|
+
if (existing) {
|
|
465
|
+
const addr2 = findOptimismAccount(existing.accounts);
|
|
466
|
+
if (addr2) {
|
|
467
|
+
return { address: addr2, wallet };
|
|
468
|
+
}
|
|
469
|
+
console.log("Existing session does not include Optimism. Requesting new connection...\n");
|
|
470
|
+
await wallet.disconnect();
|
|
471
|
+
}
|
|
472
|
+
if (!opts.requireWallet) {
|
|
473
|
+
await wallet.destroy();
|
|
474
|
+
console.error("Error: No session with Optimism support found. Use --address=0x... or connect a wallet first.");
|
|
475
|
+
process.exit(1);
|
|
476
|
+
}
|
|
477
|
+
console.log("Scan this QR code with your wallet app:\n");
|
|
478
|
+
const result = await wallet.connect();
|
|
479
|
+
console.log(`
|
|
480
|
+
Connected to ${result.session.peer.metadata.name}
|
|
481
|
+
`);
|
|
482
|
+
const addr = findOptimismAccount(result.accounts);
|
|
483
|
+
if (!addr) {
|
|
484
|
+
await wallet.destroy();
|
|
485
|
+
console.error("Error: Wallet did not approve Optimism (eip155:10). Please try again and approve the Optimism chain.");
|
|
486
|
+
process.exit(1);
|
|
487
|
+
}
|
|
488
|
+
return { address: addr, wallet };
|
|
489
|
+
}
|
|
490
|
+
async function main() {
|
|
491
|
+
const { command, positional, address, browser } = parseArgs(process.argv.slice(2));
|
|
492
|
+
switch (command) {
|
|
493
|
+
case "stake": {
|
|
494
|
+
const amount = positional[0];
|
|
495
|
+
const weeks = positional[1];
|
|
496
|
+
if (!amount || !weeks) {
|
|
497
|
+
console.error("Usage: walletconnect-staking stake <amount> <weeks>");
|
|
498
|
+
process.exit(1);
|
|
499
|
+
}
|
|
500
|
+
const weeksNum = parseInt(weeks, 10);
|
|
501
|
+
if (isNaN(weeksNum) || weeksNum <= 0) {
|
|
502
|
+
console.error("Error: <weeks> must be a positive integer.");
|
|
503
|
+
process.exit(1);
|
|
504
|
+
}
|
|
505
|
+
const { address: addr, wallet } = await resolveAddress({
|
|
506
|
+
address,
|
|
507
|
+
requireWallet: true,
|
|
508
|
+
browser
|
|
509
|
+
});
|
|
510
|
+
try {
|
|
511
|
+
await stake(wallet, addr, amount, weeksNum);
|
|
512
|
+
} finally {
|
|
513
|
+
await wallet.destroy();
|
|
514
|
+
}
|
|
515
|
+
break;
|
|
516
|
+
}
|
|
517
|
+
case "unstake": {
|
|
518
|
+
const { address: addr, wallet } = await resolveAddress({
|
|
519
|
+
address,
|
|
520
|
+
requireWallet: true,
|
|
521
|
+
browser
|
|
522
|
+
});
|
|
523
|
+
try {
|
|
524
|
+
await unstake(wallet, addr);
|
|
525
|
+
} finally {
|
|
526
|
+
await wallet.destroy();
|
|
527
|
+
}
|
|
528
|
+
break;
|
|
529
|
+
}
|
|
530
|
+
case "claim": {
|
|
531
|
+
const { address: addr, wallet } = await resolveAddress({
|
|
532
|
+
address,
|
|
533
|
+
requireWallet: true,
|
|
534
|
+
browser
|
|
535
|
+
});
|
|
536
|
+
try {
|
|
537
|
+
await claim(wallet, addr);
|
|
538
|
+
} finally {
|
|
539
|
+
await wallet.destroy();
|
|
540
|
+
}
|
|
541
|
+
break;
|
|
542
|
+
}
|
|
543
|
+
case "status": {
|
|
544
|
+
const { address: addr, wallet } = await resolveAddress({
|
|
545
|
+
address,
|
|
546
|
+
requireWallet: false,
|
|
547
|
+
browser
|
|
548
|
+
});
|
|
549
|
+
try {
|
|
550
|
+
await status(addr);
|
|
551
|
+
} finally {
|
|
552
|
+
if (wallet) await wallet.destroy();
|
|
553
|
+
}
|
|
554
|
+
break;
|
|
555
|
+
}
|
|
556
|
+
case "balance": {
|
|
557
|
+
const { address: addr, wallet } = await resolveAddress({
|
|
558
|
+
address,
|
|
559
|
+
requireWallet: false,
|
|
560
|
+
browser
|
|
561
|
+
});
|
|
562
|
+
try {
|
|
563
|
+
await balance(addr);
|
|
564
|
+
} finally {
|
|
565
|
+
if (wallet) await wallet.destroy();
|
|
566
|
+
}
|
|
567
|
+
break;
|
|
568
|
+
}
|
|
569
|
+
case "--help":
|
|
570
|
+
case "-h":
|
|
571
|
+
case void 0:
|
|
572
|
+
usage();
|
|
573
|
+
break;
|
|
574
|
+
default:
|
|
575
|
+
console.error(`Unknown command: ${command}`);
|
|
576
|
+
usage();
|
|
577
|
+
process.exit(1);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
main().then(
|
|
581
|
+
() => process.exit(0),
|
|
582
|
+
(err) => {
|
|
583
|
+
console.error(err instanceof Error ? err.message : err);
|
|
584
|
+
process.exit(1);
|
|
585
|
+
}
|
|
586
|
+
);
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";var y=Object.defineProperty;var it=Object.getOwnPropertyDescriptor;var rt=Object.getOwnPropertyNames;var st=Object.prototype.hasOwnProperty;var ct=(t,n)=>{for(var o in n)y(t,o,{get:n[o],enumerable:!0})},lt=(t,n,o,i)=>{if(n&&typeof n=="object"||typeof n=="function")for(let e of rt(n))!st.call(t,e)&&e!==o&&y(t,e,{get:()=>n[e],enumerable:!(i=it(n,e))||i.enumerable});return t};var ut=t=>lt(y({},"__esModule",{value:!0}),t);var ft={};ct(ft,{CAIP2_CHAIN_ID:()=>D,CHAIN_ID:()=>M,CLI_METADATA:()=>H,L2_WCT_ADDRESS:()=>g,STAKE_WEIGHT_ADDRESS:()=>c,STAKING_REWARD_DISTRIBUTOR_ADDRESS:()=>b,balance:()=>at,buildAllowanceCallData:()=>E,buildApprove:()=>S,buildBalanceOfCallData:()=>P,buildClaim:()=>W,buildCreateLock:()=>C,buildIncreaseLockAmount:()=>_,buildIncreaseUnlockTime:()=>G,buildLocksCallData:()=>R,buildUpdateLock:()=>I,buildWithdrawAll:()=>h,calculateAPY:()=>N,calculateWeeklyAPY:()=>$,claim:()=>ot,fetchStakeWeight:()=>L,fetchStaking:()=>d,formatDate:()=>u,formatWCT:()=>k,stake:()=>tt,status:()=>et,unstake:()=>nt});module.exports=ut(ft);var Z=require("viem");var M=10,D="eip155:10",g="0xeF4461891DfB3AC8572cCf7C794664A8DD927945",c="0x521B4C065Bbdbe3E20B3727340730936912DfA46",b="0xF368F535e329c6d08DFf0d4b2dA961C4e7F3fCAF",p="https://mainnet.optimism.io",K="https://api.walletconnect.network";var H={name:"walletconnect-staking",description:"WalletConnect WCT Staking CLI",url:"https://walletconnect.com",icons:[]};var s=require("viem");var U=(0,s.parseAbi)(["function approve(address spender, uint256 value) returns (bool)","function balanceOf(address account) view returns (uint256)","function allowance(address owner, address spender) view returns (uint256)"]),m=(0,s.parseAbi)(["function createLock(uint256 amount, uint256 unlockTime)","function updateLock(uint256 amount, uint256 unlockTime)","function increaseLockAmount(uint256 amount)","function increaseUnlockTime(uint256 newUnlockTime)","function withdrawAll()","function locks(address) view returns (int128 amount, uint256 end, uint256 transferredAmount)"]),gt=(0,s.parseAbi)(["function claim(address user) returns (uint256)"]);function S(t,n){return{to:g,data:(0,s.encodeFunctionData)({abi:U,functionName:"approve",args:[t,n]})}}function C(t,n){return{to:c,data:(0,s.encodeFunctionData)({abi:m,functionName:"createLock",args:[t,n]})}}function I(t,n){return{to:c,data:(0,s.encodeFunctionData)({abi:m,functionName:"updateLock",args:[t,n]})}}function _(t){return{to:c,data:(0,s.encodeFunctionData)({abi:m,functionName:"increaseLockAmount",args:[t]})}}function G(t){return{to:c,data:(0,s.encodeFunctionData)({abi:m,functionName:"increaseUnlockTime",args:[t]})}}function h(){return{to:c,data:(0,s.encodeFunctionData)({abi:m,functionName:"withdrawAll"})}}function W(t){return{to:b,data:(0,s.encodeFunctionData)({abi:gt,functionName:"claim",args:[t]})}}function P(t){return{to:g,data:(0,s.encodeFunctionData)({abi:U,functionName:"balanceOf",args:[t]})}}function E(t,n){return{to:g,data:(0,s.encodeFunctionData)({abi:U,functionName:"allowance",args:[t,n]})}}function R(t){return{to:c,data:(0,s.encodeFunctionData)({abi:m,functionName:"locks",args:[t]})}}var O=require("viem");var mt=1;async function v(t,n,o){let i=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:mt++,method:t,params:n})});if(!i.ok)throw new Error(`RPC request failed: ${i.status} ${i.statusText}`);let e=await i.json();if(e.error)throw new Error(`RPC error: ${e.error.message}`);return e.result}async function j(t,n){return v("eth_call",[{to:t.to,data:t.data},"latest"],n)}async function F(t,n=p){let o=await j(t,n),[i]=(0,O.decodeAbiParameters)([{type:"uint256"}],o);return i}async function q(t,n,o=p){let i=await v("eth_estimateGas",[{from:t,to:n.to,data:n.data,value:"0x0"},"latest"],o),e=BigInt(i);return`0x${(e+e/5n).toString(16)}`}async function V(t,n=p,{intervalMs:o=2e3,timeoutMs:i=6e4}={}){let e=Date.now();for(;Date.now()-e<i;){try{let a=await v("eth_getTransactionReceipt",[t],n);if(a){if(a.status==="0x0")throw new Error(`Transaction ${t} reverted`);return}}catch(a){if(a instanceof Error&&a.message.includes("reverted"))throw a}await new Promise(a=>setTimeout(a,o))}throw new Error(`Transaction ${t} not confirmed within ${i/1e3}s`)}async function X(t,n=p){let o=await j(t,n),[i,e,a]=(0,O.decodeAbiParameters)([{type:"int128"},{type:"uint256"},{type:"uint256"}],o);return{amount:BigInt(i),end:e,transferredAmount:a}}function J(){return process.env.FOUNDATION_API_URL||K}async function d(t){let n=`${J()}/staking?address=${t}`,o=await fetch(n);if(!o.ok)throw new Error(`Foundation API error: ${o.status} ${o.statusText}`);return await o.json()}async function L(){let t=`${J()}/stake-weight`,n=await fetch(t);if(!n.ok)throw new Error(`Foundation API error: ${n.status} ${n.statusText}`);return await n.json()}var Q=require("viem");function k(t){let n=(0,Q.formatUnits)(t,18);return parseFloat(n).toLocaleString("en-US",{minimumFractionDigits:2,maximumFractionDigits:2})}function u(t){return new Date(t*1e3).toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"})}function N(t){return Math.max(t/1e6*-.06464+12.0808,0)}function $(t,n){return t*(Math.min(n,104)/52)}function r(t,n){return` ${t.padEnd(12)} ${n}`}function dt(t){let n=Math.floor(Date.now()/1e3);return BigInt(Math.floor((n+t*604800)/604800))*BigInt(604800)}async function f(t,n,o){let i=await q(n,o);return t.request({chainId:D,request:{method:"eth_sendTransaction",params:[{from:n,to:o.to,data:o.data,value:"0x0",gas:i}]}})}async function tt(t,n,o,i){let e=(0,Z.parseUnits)(o,18),a=dt(i),l=await X(R(n)),T=l.amount>0n;T&&(console.log(`
|
|
2
|
+
Existing staking position:`),console.log(r("Staked",`${k(BigInt(l.amount))} WCT`)),console.log(r("Unlocks",u(Number(l.end)))));let x=a,Y=!T||a>l.end;if(T&&a<=l.end&&(x=l.end,console.log(`
|
|
3
|
+
Requested unlock (${u(Number(a))}) is before existing lock end.`),console.log(`Keeping current unlock date: ${u(Number(l.end))}`)),console.log(`
|
|
4
|
+
Adding ${o} WCT${Y?`, extending lock to ${u(Number(x))}`:""}...`),await F(E(n,c))<e){console.log(`
|
|
5
|
+
Approving WCT spend...`);let B=await f(t,n,S(c,e));console.log(r("Approve tx",B)),console.log("Waiting for confirmation..."),await V(B)}let w;T?Y?(console.log(`
|
|
6
|
+
Updating lock (amount + time)...`),w=await f(t,n,I(e,x))):(console.log(`
|
|
7
|
+
Increasing lock amount...`),w=await f(t,n,_(e))):(console.log(`
|
|
8
|
+
Creating new lock...`),w=await f(t,n,C(e,x))),console.log(r("Tx hash",w)),console.log(`
|
|
9
|
+
Stake submitted successfully.`)}async function nt(t,n){let o=await d(n);if(!o.position){console.log(`
|
|
10
|
+
No staking position found.`);return}if(o.position.unlocksAt){let e=new Date(o.position.unlocksAt).getTime()/1e3,a=Math.floor(Date.now()/1e3);if(e>a){console.log(`
|
|
11
|
+
Lock has not expired yet. Unlocks ${u(e)}.`);return}}console.log(`
|
|
12
|
+
Withdrawing all staked WCT...`);let i=await f(t,n,h());console.log(r("Tx hash",i)),console.log(`
|
|
13
|
+
Unstake submitted successfully.`)}async function ot(t,n){let o=await d(n);if(!o.rewards||o.rewards.amount==="0"){console.log(`
|
|
14
|
+
No rewards to claim.`);return}console.log(`
|
|
15
|
+
Claiming ${o.rewards.amount} WCT in rewards...`);let i=await f(t,n,W(n));console.log(r("Tx hash",i)),console.log(`
|
|
16
|
+
Claim submitted successfully.`)}async function et(t){let[n,o]=await Promise.all([d(t),L()]);if(console.log(`
|
|
17
|
+
Staking status for ${t}
|
|
18
|
+
`),!n.position)console.log(` No staking position found.
|
|
19
|
+
`);else{let a=n.position;if(console.log(r("Amount",`${a.amount} WCT`)),console.log(r("Permanent",a.isPermanent?"Yes":"No")),console.log(r("Created",new Date(a.createdAt).toLocaleDateString("en-US"))),a.unlocksAt&&console.log(r("Unlocks",new Date(a.unlocksAt).toLocaleDateString("en-US"))),a.duration){let l=Math.round(parseInt(a.duration,10)/604800);console.log(r("Duration",`${l} week(s)`))}console.log()}n.rewards&&console.log(r("Rewards",`${n.rewards.amount} WCT`));let i=parseFloat(o.stakeWeight),e=N(i);if(console.log(r("Base APY",`${e.toFixed(2)}%`)),n.position?.duration){let a=Math.round(parseInt(n.position.duration,10)/604800),l=$(e,a);console.log(r("Your APY",`${l.toFixed(2)}%`))}console.log()}async function at(t){let n=await F(P(t));console.log(`
|
|
20
|
+
${r("WCT balance",`${k(n)} WCT`)}
|
|
21
|
+
`)}0&&(module.exports={CAIP2_CHAIN_ID,CHAIN_ID,CLI_METADATA,L2_WCT_ADDRESS,STAKE_WEIGHT_ADDRESS,STAKING_REWARD_DISTRIBUTOR_ADDRESS,balance,buildAllowanceCallData,buildApprove,buildBalanceOfCallData,buildClaim,buildCreateLock,buildIncreaseLockAmount,buildIncreaseUnlockTime,buildLocksCallData,buildUpdateLock,buildWithdrawAll,calculateAPY,calculateWeeklyAPY,claim,fetchStakeWeight,fetchStaking,formatDate,formatWCT,stake,status,unstake});
|
|
22
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands.ts","../src/constants.ts","../src/contracts.ts","../src/rpc.ts","../src/api.ts","../src/format.ts"],"sourcesContent":["export { stake, unstake, claim, status, balance } from \"./commands.js\";\nexport { formatWCT, formatDate, calculateAPY, calculateWeeklyAPY } from \"./format.js\";\nexport { fetchStaking, fetchStakeWeight } from \"./api.js\";\nexport type { StakingPosition, StakingRewards, StakingResponse, StakeWeightResponse } from \"./api.js\";\nexport {\n buildApprove,\n buildCreateLock,\n buildUpdateLock,\n buildIncreaseLockAmount,\n buildIncreaseUnlockTime,\n buildWithdrawAll,\n buildClaim,\n buildBalanceOfCallData,\n buildAllowanceCallData,\n buildLocksCallData,\n} from \"./contracts.js\";\nexport type { TxData } from \"./contracts.js\";\nexport {\n CHAIN_ID,\n CAIP2_CHAIN_ID,\n L2_WCT_ADDRESS,\n STAKE_WEIGHT_ADDRESS,\n STAKING_REWARD_DISTRIBUTOR_ADDRESS,\n CLI_METADATA,\n} from \"./constants.js\";\n","import { parseUnits } from \"viem\";\nimport type { WalletConnectCLI } from \"@walletconnect/cli-sdk\";\nimport {\n CAIP2_CHAIN_ID,\n STAKE_WEIGHT_ADDRESS,\n ONE_WEEK_IN_SECONDS,\n WCT_DECIMALS,\n} from \"./constants.js\";\nimport {\n buildApprove,\n buildCreateLock,\n buildUpdateLock,\n buildIncreaseLockAmount,\n buildWithdrawAll,\n buildClaim,\n buildBalanceOfCallData,\n buildAllowanceCallData,\n buildLocksCallData,\n type TxData,\n} from \"./contracts.js\";\nimport { readUint256, readLocks, estimateGas, waitForTx } from \"./rpc.js\";\nimport { fetchStaking, fetchStakeWeight } from \"./api.js\";\nimport { formatWCT, formatDate, calculateAPY, calculateWeeklyAPY, label } from \"./format.js\";\n\n// ---- Helpers ---------------------------------------------------------- //\n\nfunction computeUnlockTime(weeks: number): bigint {\n const now = Math.floor(Date.now() / 1000);\n return (BigInt(Math.floor((now + weeks * ONE_WEEK_IN_SECONDS) / ONE_WEEK_IN_SECONDS)) *\n BigInt(ONE_WEEK_IN_SECONDS));\n}\n\nasync function sendTx(\n wallet: WalletConnectCLI,\n from: string,\n tx: TxData,\n): Promise<string> {\n const gas = await estimateGas(from, tx);\n return wallet.request<string>({\n chainId: CAIP2_CHAIN_ID,\n request: {\n method: \"eth_sendTransaction\",\n params: [{ from, to: tx.to, data: tx.data, value: \"0x0\", gas }],\n },\n });\n}\n\n// ---- Commands --------------------------------------------------------- //\n\nexport async function stake(\n wallet: WalletConnectCLI,\n address: string,\n amount: string,\n weeks: number,\n): Promise<void> {\n const amountWei = parseUnits(amount, WCT_DECIMALS);\n const requestedUnlockTime = computeUnlockTime(weeks);\n\n // Read on-chain position to determine the right action\n const lock = await readLocks(buildLocksCallData(address));\n const hasPosition = lock.amount > 0n;\n\n if (hasPosition) {\n console.log(\"\\nExisting staking position:\");\n console.log(label(\"Staked\", `${formatWCT(BigInt(lock.amount))} WCT`));\n console.log(label(\"Unlocks\", formatDate(Number(lock.end))));\n }\n\n // Determine effective unlock time — never shorten an existing lock\n let effectiveUnlockTime = requestedUnlockTime;\n const extendingTime = !hasPosition || requestedUnlockTime > lock.end;\n\n if (hasPosition && requestedUnlockTime <= lock.end) {\n effectiveUnlockTime = lock.end;\n console.log(`\\nRequested unlock (${formatDate(Number(requestedUnlockTime))}) is before existing lock end.`);\n console.log(`Keeping current unlock date: ${formatDate(Number(lock.end))}`);\n }\n\n console.log(`\\nAdding ${amount} WCT${extendingTime ? `, extending lock to ${formatDate(Number(effectiveUnlockTime))}` : \"\"}...`);\n\n // Check allowance and approve if needed\n const allowance = await readUint256(buildAllowanceCallData(address, STAKE_WEIGHT_ADDRESS));\n if (allowance < amountWei) {\n console.log(\"\\nApproving WCT spend...\");\n const approveTxHash = await sendTx(wallet, address, buildApprove(STAKE_WEIGHT_ADDRESS, amountWei));\n console.log(label(\"Approve tx\", approveTxHash));\n console.log(\"Waiting for confirmation...\");\n await waitForTx(approveTxHash);\n }\n\n let txHash: string;\n\n if (!hasPosition) {\n console.log(\"\\nCreating new lock...\");\n txHash = await sendTx(wallet, address, buildCreateLock(amountWei, effectiveUnlockTime));\n } else if (extendingTime) {\n console.log(\"\\nUpdating lock (amount + time)...\");\n txHash = await sendTx(wallet, address, buildUpdateLock(amountWei, effectiveUnlockTime));\n } else {\n console.log(\"\\nIncreasing lock amount...\");\n txHash = await sendTx(wallet, address, buildIncreaseLockAmount(amountWei));\n }\n\n console.log(label(\"Tx hash\", txHash));\n console.log(\"\\nStake submitted successfully.\");\n}\n\nexport async function unstake(\n wallet: WalletConnectCLI,\n address: string,\n): Promise<void> {\n const staking = await fetchStaking(address);\n\n if (!staking.position) {\n console.log(\"\\nNo staking position found.\");\n return;\n }\n\n if (staking.position.unlocksAt) {\n const unlocksAt = new Date(staking.position.unlocksAt).getTime() / 1000;\n const now = Math.floor(Date.now() / 1000);\n if (unlocksAt > now) {\n console.log(`\\nLock has not expired yet. Unlocks ${formatDate(unlocksAt)}.`);\n return;\n }\n }\n\n console.log(\"\\nWithdrawing all staked WCT...\");\n const txHash = await sendTx(wallet, address, buildWithdrawAll());\n console.log(label(\"Tx hash\", txHash));\n console.log(\"\\nUnstake submitted successfully.\");\n}\n\nexport async function claim(\n wallet: WalletConnectCLI,\n address: string,\n): Promise<void> {\n const staking = await fetchStaking(address);\n\n if (!staking.rewards || staking.rewards.amount === \"0\") {\n console.log(\"\\nNo rewards to claim.\");\n return;\n }\n\n console.log(`\\nClaiming ${staking.rewards.amount} WCT in rewards...`);\n const txHash = await sendTx(wallet, address, buildClaim(address));\n console.log(label(\"Tx hash\", txHash));\n console.log(\"\\nClaim submitted successfully.\");\n}\n\nexport async function status(address: string): Promise<void> {\n const [staking, stakeWeightRes] = await Promise.all([\n fetchStaking(address),\n fetchStakeWeight(),\n ]);\n\n console.log(`\\nStaking status for ${address}\\n`);\n\n if (!staking.position) {\n console.log(\" No staking position found.\\n\");\n } else {\n const pos = staking.position;\n console.log(label(\"Amount\", `${pos.amount} WCT`));\n console.log(label(\"Permanent\", pos.isPermanent ? \"Yes\" : \"No\"));\n console.log(label(\"Created\", new Date(pos.createdAt).toLocaleDateString(\"en-US\")));\n if (pos.unlocksAt) {\n console.log(label(\"Unlocks\", new Date(pos.unlocksAt).toLocaleDateString(\"en-US\")));\n }\n if (pos.duration) {\n const durationWeeks = Math.round(parseInt(pos.duration, 10) / ONE_WEEK_IN_SECONDS);\n console.log(label(\"Duration\", `${durationWeeks} week(s)`));\n }\n console.log();\n }\n\n if (staking.rewards) {\n console.log(label(\"Rewards\", `${staking.rewards.amount} WCT`));\n }\n\n const stakeWeight = parseFloat(stakeWeightRes.stakeWeight);\n const baseAPY = calculateAPY(stakeWeight);\n console.log(label(\"Base APY\", `${baseAPY.toFixed(2)}%`));\n\n if (staking.position?.duration) {\n const weeks = Math.round(parseInt(staking.position.duration, 10) / ONE_WEEK_IN_SECONDS);\n const weeklyAPY = calculateWeeklyAPY(baseAPY, weeks);\n console.log(label(\"Your APY\", `${weeklyAPY.toFixed(2)}%`));\n }\n\n console.log();\n}\n\nexport async function balance(address: string): Promise<void> {\n const bal = await readUint256(buildBalanceOfCallData(address));\n console.log(`\\n${label(\"WCT balance\", `${formatWCT(bal)} WCT`)}\\n`);\n}\n","/** Optimism chain ID */\nexport const CHAIN_ID = 10;\nexport const CAIP2_CHAIN_ID = \"eip155:10\";\n\n/** Contract addresses on Optimism */\nexport const L2_WCT_ADDRESS = \"0xeF4461891DfB3AC8572cCf7C794664A8DD927945\";\nexport const STAKE_WEIGHT_ADDRESS = \"0x521B4C065Bbdbe3E20B3727340730936912DfA46\";\nexport const STAKING_REWARD_DISTRIBUTOR_ADDRESS = \"0xF368F535e329c6d08DFf0d4b2dA961C4e7F3fCAF\";\n\n/** Public Optimism RPC endpoint */\nexport const OPTIMISM_RPC_URL = \"https://mainnet.optimism.io\";\n\n/** Foundation API */\nexport const FOUNDATION_API_URL = \"https://api.walletconnect.network\";\n\n/** Time constants */\nexport const ONE_WEEK_IN_SECONDS = 604800;\n\n/** WCT token decimals */\nexport const WCT_DECIMALS = 18;\n\n/** APY formula constants (from math.ts) */\nexport const APY_SLOPE = -0.06464;\nexport const APY_INTERCEPT = 12.0808;\nexport const APY_STAKE_WEIGHT_DIVISOR = 1_000_000;\nexport const MAX_LOCK_WEEKS = 104;\n\n/** CLI metadata for WalletConnect pairing */\nexport const CLI_METADATA = {\n name: \"walletconnect-staking\",\n description: \"WalletConnect WCT Staking CLI\",\n url: \"https://walletconnect.com\",\n icons: [],\n};\n","import { encodeFunctionData, parseAbi } from \"viem\";\nimport {\n L2_WCT_ADDRESS,\n STAKE_WEIGHT_ADDRESS,\n STAKING_REWARD_DISTRIBUTOR_ADDRESS,\n} from \"./constants.js\";\n\n// ---- ABI fragments ---------------------------------------------------- //\n\nconst erc20Abi = parseAbi([\n \"function approve(address spender, uint256 value) returns (bool)\",\n \"function balanceOf(address account) view returns (uint256)\",\n \"function allowance(address owner, address spender) view returns (uint256)\",\n]);\n\nconst stakeWeightAbi = parseAbi([\n \"function createLock(uint256 amount, uint256 unlockTime)\",\n \"function updateLock(uint256 amount, uint256 unlockTime)\",\n \"function increaseLockAmount(uint256 amount)\",\n \"function increaseUnlockTime(uint256 newUnlockTime)\",\n \"function withdrawAll()\",\n \"function locks(address) view returns (int128 amount, uint256 end, uint256 transferredAmount)\",\n]);\n\nconst stakingRewardDistributorAbi = parseAbi([\n \"function claim(address user) returns (uint256)\",\n]);\n\n// ---- Transaction builders --------------------------------------------- //\n\nexport interface TxData {\n to: string;\n data: string;\n}\n\nexport function buildApprove(spender: string, amount: bigint): TxData {\n return {\n to: L2_WCT_ADDRESS,\n data: encodeFunctionData({\n abi: erc20Abi,\n functionName: \"approve\",\n args: [spender as `0x${string}`, amount],\n }),\n };\n}\n\nexport function buildCreateLock(amount: bigint, unlockTime: bigint): TxData {\n return {\n to: STAKE_WEIGHT_ADDRESS,\n data: encodeFunctionData({\n abi: stakeWeightAbi,\n functionName: \"createLock\",\n args: [amount, unlockTime],\n }),\n };\n}\n\nexport function buildUpdateLock(amount: bigint, unlockTime: bigint): TxData {\n return {\n to: STAKE_WEIGHT_ADDRESS,\n data: encodeFunctionData({\n abi: stakeWeightAbi,\n functionName: \"updateLock\",\n args: [amount, unlockTime],\n }),\n };\n}\n\nexport function buildIncreaseLockAmount(amount: bigint): TxData {\n return {\n to: STAKE_WEIGHT_ADDRESS,\n data: encodeFunctionData({\n abi: stakeWeightAbi,\n functionName: \"increaseLockAmount\",\n args: [amount],\n }),\n };\n}\n\nexport function buildIncreaseUnlockTime(newUnlockTime: bigint): TxData {\n return {\n to: STAKE_WEIGHT_ADDRESS,\n data: encodeFunctionData({\n abi: stakeWeightAbi,\n functionName: \"increaseUnlockTime\",\n args: [newUnlockTime],\n }),\n };\n}\n\nexport function buildWithdrawAll(): TxData {\n return {\n to: STAKE_WEIGHT_ADDRESS,\n data: encodeFunctionData({\n abi: stakeWeightAbi,\n functionName: \"withdrawAll\",\n }),\n };\n}\n\nexport function buildClaim(user: string): TxData {\n return {\n to: STAKING_REWARD_DISTRIBUTOR_ADDRESS,\n data: encodeFunctionData({\n abi: stakingRewardDistributorAbi,\n functionName: \"claim\",\n args: [user as `0x${string}`],\n }),\n };\n}\n\n// ---- Call data builders (for eth_call) -------------------------------- //\n\nexport function buildBalanceOfCallData(account: string): TxData {\n return {\n to: L2_WCT_ADDRESS,\n data: encodeFunctionData({\n abi: erc20Abi,\n functionName: \"balanceOf\",\n args: [account as `0x${string}`],\n }),\n };\n}\n\nexport function buildAllowanceCallData(owner: string, spender: string): TxData {\n return {\n to: L2_WCT_ADDRESS,\n data: encodeFunctionData({\n abi: erc20Abi,\n functionName: \"allowance\",\n args: [owner as `0x${string}`, spender as `0x${string}`],\n }),\n };\n}\n\nexport function buildLocksCallData(account: string): TxData {\n return {\n to: STAKE_WEIGHT_ADDRESS,\n data: encodeFunctionData({\n abi: stakeWeightAbi,\n functionName: \"locks\",\n args: [account as `0x${string}`],\n }),\n };\n}\n","import { decodeAbiParameters } from \"viem\";\nimport { OPTIMISM_RPC_URL } from \"./constants.js\";\nimport type { TxData } from \"./contracts.js\";\n\nlet requestId = 1;\n\nasync function rpcRequest<T = string>(\n method: string,\n params: unknown[],\n rpcUrl: string,\n): Promise<T> {\n const res = await fetch(rpcUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: requestId++,\n method,\n params,\n }),\n });\n\n if (!res.ok) {\n throw new Error(`RPC request failed: ${res.status} ${res.statusText}`);\n }\n\n const json = (await res.json()) as { result?: T; error?: { message: string } };\n\n if (json.error) {\n throw new Error(`RPC error: ${json.error.message}`);\n }\n\n return json.result!;\n}\n\nasync function ethCall(tx: TxData, rpcUrl: string): Promise<string> {\n return rpcRequest(\"eth_call\", [{ to: tx.to, data: tx.data }, \"latest\"], rpcUrl);\n}\n\n/** Read a uint256 from an eth_call result */\nexport async function readUint256(\n tx: TxData,\n rpcUrl: string = OPTIMISM_RPC_URL,\n): Promise<bigint> {\n const result = await ethCall(tx, rpcUrl);\n const [value] = decodeAbiParameters([{ type: \"uint256\" }], result as `0x${string}`);\n return value;\n}\n\n/** Estimate gas for a transaction, with a 20% buffer */\nexport async function estimateGas(\n from: string,\n tx: TxData,\n rpcUrl: string = OPTIMISM_RPC_URL,\n): Promise<string> {\n const result = await rpcRequest(\n \"eth_estimateGas\",\n [{ from, to: tx.to, data: tx.data, value: \"0x0\" }, \"latest\"],\n rpcUrl,\n );\n // Add 20% buffer to the estimate\n const estimate = BigInt(result);\n const buffered = estimate + estimate / 5n;\n return `0x${buffered.toString(16)}`;\n}\n\ninterface TxReceipt {\n status: string;\n blockNumber: string;\n transactionHash: string;\n}\n\n/** Wait for a transaction to be confirmed (polls eth_getTransactionReceipt) */\nexport async function waitForTx(\n txHash: string,\n rpcUrl: string = OPTIMISM_RPC_URL,\n { intervalMs = 2000, timeoutMs = 60000 } = {},\n): Promise<void> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n try {\n const receipt = await rpcRequest<TxReceipt | null>(\n \"eth_getTransactionReceipt\",\n [txHash],\n rpcUrl,\n );\n if (receipt) {\n if (receipt.status === \"0x0\") {\n throw new Error(`Transaction ${txHash} reverted`);\n }\n return;\n }\n } catch (err) {\n // Re-throw revert errors, swallow \"receipt not available yet\"\n if (err instanceof Error && err.message.includes(\"reverted\")) throw err;\n }\n await new Promise((r) => setTimeout(r, intervalMs));\n }\n throw new Error(`Transaction ${txHash} not confirmed within ${timeoutMs / 1000}s`);\n}\n\n/** Read the locks() return: (int128 amount, uint256 end, uint256 transferredAmount) */\nexport async function readLocks(\n tx: TxData,\n rpcUrl: string = OPTIMISM_RPC_URL,\n): Promise<{ amount: bigint; end: bigint; transferredAmount: bigint }> {\n const result = await ethCall(tx, rpcUrl);\n const [amount, end, transferredAmount] = decodeAbiParameters(\n [{ type: \"int128\" }, { type: \"uint256\" }, { type: \"uint256\" }],\n result as `0x${string}`,\n );\n return { amount: BigInt(amount), end, transferredAmount };\n}\n","import { FOUNDATION_API_URL } from \"./constants.js\";\n\nexport interface StakingPosition {\n isPermanent: boolean;\n amount: string;\n createdAt: string;\n unlocksAt?: string;\n duration?: string;\n}\n\nexport interface StakingRewards {\n amount: string;\n}\n\nexport interface StakingResponse {\n position: StakingPosition | null;\n rewards: StakingRewards | null;\n}\n\nexport interface StakeWeightResponse {\n stakeWeight: string;\n}\n\nfunction getBaseUrl(): string {\n return process.env.FOUNDATION_API_URL || FOUNDATION_API_URL;\n}\n\nexport async function fetchStaking(address: string): Promise<StakingResponse> {\n const url = `${getBaseUrl()}/staking?address=${address}`;\n const res = await fetch(url);\n if (!res.ok) {\n throw new Error(`Foundation API error: ${res.status} ${res.statusText}`);\n }\n return (await res.json()) as StakingResponse;\n}\n\nexport async function fetchStakeWeight(): Promise<StakeWeightResponse> {\n const url = `${getBaseUrl()}/stake-weight`;\n const res = await fetch(url);\n if (!res.ok) {\n throw new Error(`Foundation API error: ${res.status} ${res.statusText}`);\n }\n return (await res.json()) as StakeWeightResponse;\n}\n","import { formatUnits } from \"viem\";\nimport {\n WCT_DECIMALS,\n APY_SLOPE,\n APY_INTERCEPT,\n APY_STAKE_WEIGHT_DIVISOR,\n MAX_LOCK_WEEKS,\n} from \"./constants.js\";\n\n/** Format a bigint WCT amount as a human-readable string with 2 decimals */\nexport function formatWCT(amount: bigint): string {\n const raw = formatUnits(amount, WCT_DECIMALS);\n const num = parseFloat(raw);\n return num.toLocaleString(\"en-US\", {\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n });\n}\n\n/** Format a unix timestamp as a locale date string */\nexport function formatDate(timestamp: number): string {\n return new Date(timestamp * 1000).toLocaleDateString(\"en-US\", {\n year: \"numeric\",\n month: \"short\",\n day: \"numeric\",\n });\n}\n\n/** Calculate base APY from total stake weight (from math.ts) */\nexport function calculateAPY(stakeWeight: number): number {\n return Math.max(\n (stakeWeight / APY_STAKE_WEIGHT_DIVISOR) * APY_SLOPE + APY_INTERCEPT,\n 0,\n );\n}\n\n/** Calculate weekly APY adjusted for lock duration */\nexport function calculateWeeklyAPY(baseAPY: number, weeks: number): number {\n return baseAPY * (Math.min(weeks, MAX_LOCK_WEEKS) / 52);\n}\n\n/** Print a labeled key-value pair */\nexport function label(key: string, value: string): string {\n return ` ${key.padEnd(12)} ${value}`;\n}\n"],"mappings":"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","names":["index_exports","__export","CAIP2_CHAIN_ID","CHAIN_ID","CLI_METADATA","L2_WCT_ADDRESS","STAKE_WEIGHT_ADDRESS","STAKING_REWARD_DISTRIBUTOR_ADDRESS","balance","buildAllowanceCallData","buildApprove","buildBalanceOfCallData","buildClaim","buildCreateLock","buildIncreaseLockAmount","buildIncreaseUnlockTime","buildLocksCallData","buildUpdateLock","buildWithdrawAll","calculateAPY","calculateWeeklyAPY","claim","fetchStakeWeight","fetchStaking","formatDate","formatWCT","stake","status","unstake","__toCommonJS","import_viem","CHAIN_ID","CAIP2_CHAIN_ID","L2_WCT_ADDRESS","STAKE_WEIGHT_ADDRESS","STAKING_REWARD_DISTRIBUTOR_ADDRESS","OPTIMISM_RPC_URL","FOUNDATION_API_URL","CLI_METADATA","import_viem","erc20Abi","stakeWeightAbi","stakingRewardDistributorAbi","buildApprove","spender","amount","L2_WCT_ADDRESS","buildCreateLock","unlockTime","STAKE_WEIGHT_ADDRESS","buildUpdateLock","buildIncreaseLockAmount","buildIncreaseUnlockTime","newUnlockTime","buildWithdrawAll","buildClaim","user","STAKING_REWARD_DISTRIBUTOR_ADDRESS","buildBalanceOfCallData","account","buildAllowanceCallData","owner","buildLocksCallData","import_viem","requestId","rpcRequest","method","params","rpcUrl","res","json","ethCall","tx","readUint256","OPTIMISM_RPC_URL","result","value","estimateGas","from","estimate","waitForTx","txHash","intervalMs","timeoutMs","start","receipt","err","r","readLocks","amount","end","transferredAmount","getBaseUrl","FOUNDATION_API_URL","fetchStaking","address","url","res","fetchStakeWeight","import_viem","formatWCT","amount","raw","formatDate","timestamp","calculateAPY","stakeWeight","calculateWeeklyAPY","baseAPY","weeks","label","key","value","computeUnlockTime","weeks","now","sendTx","wallet","from","tx","gas","estimateGas","CAIP2_CHAIN_ID","stake","address","amount","amountWei","requestedUnlockTime","lock","readLocks","buildLocksCallData","hasPosition","label","formatWCT","formatDate","effectiveUnlockTime","extendingTime","readUint256","buildAllowanceCallData","STAKE_WEIGHT_ADDRESS","approveTxHash","buildApprove","waitForTx","txHash","buildUpdateLock","buildIncreaseLockAmount","buildCreateLock","unstake","staking","fetchStaking","unlocksAt","buildWithdrawAll","claim","buildClaim","status","stakeWeightRes","fetchStakeWeight","pos","durationWeeks","stakeWeight","baseAPY","calculateAPY","weeklyAPY","calculateWeeklyAPY","balance","bal","buildBalanceOfCallData"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { WalletConnectCLI } from '@walletconnect/cli-sdk';
|
|
2
|
+
|
|
3
|
+
declare function stake(wallet: WalletConnectCLI, address: string, amount: string, weeks: number): Promise<void>;
|
|
4
|
+
declare function unstake(wallet: WalletConnectCLI, address: string): Promise<void>;
|
|
5
|
+
declare function claim(wallet: WalletConnectCLI, address: string): Promise<void>;
|
|
6
|
+
declare function status(address: string): Promise<void>;
|
|
7
|
+
declare function balance(address: string): Promise<void>;
|
|
8
|
+
|
|
9
|
+
/** Format a bigint WCT amount as a human-readable string with 2 decimals */
|
|
10
|
+
declare function formatWCT(amount: bigint): string;
|
|
11
|
+
/** Format a unix timestamp as a locale date string */
|
|
12
|
+
declare function formatDate(timestamp: number): string;
|
|
13
|
+
/** Calculate base APY from total stake weight (from math.ts) */
|
|
14
|
+
declare function calculateAPY(stakeWeight: number): number;
|
|
15
|
+
/** Calculate weekly APY adjusted for lock duration */
|
|
16
|
+
declare function calculateWeeklyAPY(baseAPY: number, weeks: number): number;
|
|
17
|
+
|
|
18
|
+
interface StakingPosition {
|
|
19
|
+
isPermanent: boolean;
|
|
20
|
+
amount: string;
|
|
21
|
+
createdAt: string;
|
|
22
|
+
unlocksAt?: string;
|
|
23
|
+
duration?: string;
|
|
24
|
+
}
|
|
25
|
+
interface StakingRewards {
|
|
26
|
+
amount: string;
|
|
27
|
+
}
|
|
28
|
+
interface StakingResponse {
|
|
29
|
+
position: StakingPosition | null;
|
|
30
|
+
rewards: StakingRewards | null;
|
|
31
|
+
}
|
|
32
|
+
interface StakeWeightResponse {
|
|
33
|
+
stakeWeight: string;
|
|
34
|
+
}
|
|
35
|
+
declare function fetchStaking(address: string): Promise<StakingResponse>;
|
|
36
|
+
declare function fetchStakeWeight(): Promise<StakeWeightResponse>;
|
|
37
|
+
|
|
38
|
+
interface TxData {
|
|
39
|
+
to: string;
|
|
40
|
+
data: string;
|
|
41
|
+
}
|
|
42
|
+
declare function buildApprove(spender: string, amount: bigint): TxData;
|
|
43
|
+
declare function buildCreateLock(amount: bigint, unlockTime: bigint): TxData;
|
|
44
|
+
declare function buildUpdateLock(amount: bigint, unlockTime: bigint): TxData;
|
|
45
|
+
declare function buildIncreaseLockAmount(amount: bigint): TxData;
|
|
46
|
+
declare function buildIncreaseUnlockTime(newUnlockTime: bigint): TxData;
|
|
47
|
+
declare function buildWithdrawAll(): TxData;
|
|
48
|
+
declare function buildClaim(user: string): TxData;
|
|
49
|
+
declare function buildBalanceOfCallData(account: string): TxData;
|
|
50
|
+
declare function buildAllowanceCallData(owner: string, spender: string): TxData;
|
|
51
|
+
declare function buildLocksCallData(account: string): TxData;
|
|
52
|
+
|
|
53
|
+
/** Optimism chain ID */
|
|
54
|
+
declare const CHAIN_ID = 10;
|
|
55
|
+
declare const CAIP2_CHAIN_ID = "eip155:10";
|
|
56
|
+
/** Contract addresses on Optimism */
|
|
57
|
+
declare const L2_WCT_ADDRESS = "0xeF4461891DfB3AC8572cCf7C794664A8DD927945";
|
|
58
|
+
declare const STAKE_WEIGHT_ADDRESS = "0x521B4C065Bbdbe3E20B3727340730936912DfA46";
|
|
59
|
+
declare const STAKING_REWARD_DISTRIBUTOR_ADDRESS = "0xF368F535e329c6d08DFf0d4b2dA961C4e7F3fCAF";
|
|
60
|
+
/** CLI metadata for WalletConnect pairing */
|
|
61
|
+
declare const CLI_METADATA: {
|
|
62
|
+
name: string;
|
|
63
|
+
description: string;
|
|
64
|
+
url: string;
|
|
65
|
+
icons: never[];
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export { CAIP2_CHAIN_ID, CHAIN_ID, CLI_METADATA, L2_WCT_ADDRESS, STAKE_WEIGHT_ADDRESS, STAKING_REWARD_DISTRIBUTOR_ADDRESS, type StakeWeightResponse, type StakingPosition, type StakingResponse, type StakingRewards, type TxData, balance, buildAllowanceCallData, buildApprove, buildBalanceOfCallData, buildClaim, buildCreateLock, buildIncreaseLockAmount, buildIncreaseUnlockTime, buildLocksCallData, buildUpdateLock, buildWithdrawAll, calculateAPY, calculateWeeklyAPY, claim, fetchStakeWeight, fetchStaking, formatDate, formatWCT, stake, status, unstake };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { WalletConnectCLI } from '@walletconnect/cli-sdk';
|
|
2
|
+
|
|
3
|
+
declare function stake(wallet: WalletConnectCLI, address: string, amount: string, weeks: number): Promise<void>;
|
|
4
|
+
declare function unstake(wallet: WalletConnectCLI, address: string): Promise<void>;
|
|
5
|
+
declare function claim(wallet: WalletConnectCLI, address: string): Promise<void>;
|
|
6
|
+
declare function status(address: string): Promise<void>;
|
|
7
|
+
declare function balance(address: string): Promise<void>;
|
|
8
|
+
|
|
9
|
+
/** Format a bigint WCT amount as a human-readable string with 2 decimals */
|
|
10
|
+
declare function formatWCT(amount: bigint): string;
|
|
11
|
+
/** Format a unix timestamp as a locale date string */
|
|
12
|
+
declare function formatDate(timestamp: number): string;
|
|
13
|
+
/** Calculate base APY from total stake weight (from math.ts) */
|
|
14
|
+
declare function calculateAPY(stakeWeight: number): number;
|
|
15
|
+
/** Calculate weekly APY adjusted for lock duration */
|
|
16
|
+
declare function calculateWeeklyAPY(baseAPY: number, weeks: number): number;
|
|
17
|
+
|
|
18
|
+
interface StakingPosition {
|
|
19
|
+
isPermanent: boolean;
|
|
20
|
+
amount: string;
|
|
21
|
+
createdAt: string;
|
|
22
|
+
unlocksAt?: string;
|
|
23
|
+
duration?: string;
|
|
24
|
+
}
|
|
25
|
+
interface StakingRewards {
|
|
26
|
+
amount: string;
|
|
27
|
+
}
|
|
28
|
+
interface StakingResponse {
|
|
29
|
+
position: StakingPosition | null;
|
|
30
|
+
rewards: StakingRewards | null;
|
|
31
|
+
}
|
|
32
|
+
interface StakeWeightResponse {
|
|
33
|
+
stakeWeight: string;
|
|
34
|
+
}
|
|
35
|
+
declare function fetchStaking(address: string): Promise<StakingResponse>;
|
|
36
|
+
declare function fetchStakeWeight(): Promise<StakeWeightResponse>;
|
|
37
|
+
|
|
38
|
+
interface TxData {
|
|
39
|
+
to: string;
|
|
40
|
+
data: string;
|
|
41
|
+
}
|
|
42
|
+
declare function buildApprove(spender: string, amount: bigint): TxData;
|
|
43
|
+
declare function buildCreateLock(amount: bigint, unlockTime: bigint): TxData;
|
|
44
|
+
declare function buildUpdateLock(amount: bigint, unlockTime: bigint): TxData;
|
|
45
|
+
declare function buildIncreaseLockAmount(amount: bigint): TxData;
|
|
46
|
+
declare function buildIncreaseUnlockTime(newUnlockTime: bigint): TxData;
|
|
47
|
+
declare function buildWithdrawAll(): TxData;
|
|
48
|
+
declare function buildClaim(user: string): TxData;
|
|
49
|
+
declare function buildBalanceOfCallData(account: string): TxData;
|
|
50
|
+
declare function buildAllowanceCallData(owner: string, spender: string): TxData;
|
|
51
|
+
declare function buildLocksCallData(account: string): TxData;
|
|
52
|
+
|
|
53
|
+
/** Optimism chain ID */
|
|
54
|
+
declare const CHAIN_ID = 10;
|
|
55
|
+
declare const CAIP2_CHAIN_ID = "eip155:10";
|
|
56
|
+
/** Contract addresses on Optimism */
|
|
57
|
+
declare const L2_WCT_ADDRESS = "0xeF4461891DfB3AC8572cCf7C794664A8DD927945";
|
|
58
|
+
declare const STAKE_WEIGHT_ADDRESS = "0x521B4C065Bbdbe3E20B3727340730936912DfA46";
|
|
59
|
+
declare const STAKING_REWARD_DISTRIBUTOR_ADDRESS = "0xF368F535e329c6d08DFf0d4b2dA961C4e7F3fCAF";
|
|
60
|
+
/** CLI metadata for WalletConnect pairing */
|
|
61
|
+
declare const CLI_METADATA: {
|
|
62
|
+
name: string;
|
|
63
|
+
description: string;
|
|
64
|
+
url: string;
|
|
65
|
+
icons: never[];
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export { CAIP2_CHAIN_ID, CHAIN_ID, CLI_METADATA, L2_WCT_ADDRESS, STAKE_WEIGHT_ADDRESS, STAKING_REWARD_DISTRIBUTOR_ADDRESS, type StakeWeightResponse, type StakingPosition, type StakingResponse, type StakingRewards, type TxData, balance, buildAllowanceCallData, buildApprove, buildBalanceOfCallData, buildClaim, buildCreateLock, buildIncreaseLockAmount, buildIncreaseUnlockTime, buildLocksCallData, buildUpdateLock, buildWithdrawAll, calculateAPY, calculateWeeklyAPY, claim, fetchStakeWeight, fetchStaking, formatDate, formatWCT, stake, status, unstake };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import{parseUnits as nt}from"viem";var X=10,D="eip155:10",d="0xeF4461891DfB3AC8572cCf7C794664A8DD927945",c="0x521B4C065Bbdbe3E20B3727340730936912DfA46",b="0xF368F535e329c6d08DFf0d4b2dA961C4e7F3fCAF",f="https://mainnet.optimism.io",B="https://api.walletconnect.network";var J={name:"walletconnect-staking",description:"WalletConnect WCT Staking CLI",url:"https://walletconnect.com",icons:[]};import{encodeFunctionData as l,parseAbi as S}from"viem";var C=S(["function approve(address spender, uint256 value) returns (bool)","function balanceOf(address account) view returns (uint256)","function allowance(address owner, address spender) view returns (uint256)"]),g=S(["function createLock(uint256 amount, uint256 unlockTime)","function updateLock(uint256 amount, uint256 unlockTime)","function increaseLockAmount(uint256 amount)","function increaseUnlockTime(uint256 newUnlockTime)","function withdrawAll()","function locks(address) view returns (int128 amount, uint256 end, uint256 transferredAmount)"]),z=S(["function claim(address user) returns (uint256)"]);function I(t,n){return{to:d,data:l({abi:C,functionName:"approve",args:[t,n]})}}function _(t,n){return{to:c,data:l({abi:g,functionName:"createLock",args:[t,n]})}}function h(t,n){return{to:c,data:l({abi:g,functionName:"updateLock",args:[t,n]})}}function W(t){return{to:c,data:l({abi:g,functionName:"increaseLockAmount",args:[t]})}}function Q(t){return{to:c,data:l({abi:g,functionName:"increaseUnlockTime",args:[t]})}}function P(){return{to:c,data:l({abi:g,functionName:"withdrawAll"})}}function E(t){return{to:b,data:l({abi:z,functionName:"claim",args:[t]})}}function R(t){return{to:d,data:l({abi:C,functionName:"balanceOf",args:[t]})}}function L(t,n){return{to:d,data:l({abi:C,functionName:"allowance",args:[t,n]})}}function N(t){return{to:c,data:l({abi:g,functionName:"locks",args:[t]})}}import{decodeAbiParameters as M}from"viem";var Z=1;async function $(t,n,o){let a=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:Z++,method:t,params:n})});if(!a.ok)throw new Error(`RPC request failed: ${a.status} ${a.statusText}`);let i=await a.json();if(i.error)throw new Error(`RPC error: ${i.error.message}`);return i.result}async function K(t,n){return $("eth_call",[{to:t.to,data:t.data},"latest"],n)}async function y(t,n=f){let o=await K(t,n),[a]=M([{type:"uint256"}],o);return a}async function H(t,n,o=f){let a=await $("eth_estimateGas",[{from:t,to:n.to,data:n.data,value:"0x0"},"latest"],o),i=BigInt(a);return`0x${(i+i/5n).toString(16)}`}async function G(t,n=f,{intervalMs:o=2e3,timeoutMs:a=6e4}={}){let i=Date.now();for(;Date.now()-i<a;){try{let e=await $("eth_getTransactionReceipt",[t],n);if(e){if(e.status==="0x0")throw new Error(`Transaction ${t} reverted`);return}}catch(e){if(e instanceof Error&&e.message.includes("reverted"))throw e}await new Promise(e=>setTimeout(e,o))}throw new Error(`Transaction ${t} not confirmed within ${a/1e3}s`)}async function j(t,n=f){let o=await K(t,n),[a,i,e]=M([{type:"int128"},{type:"uint256"},{type:"uint256"}],o);return{amount:BigInt(a),end:i,transferredAmount:e}}function q(){return process.env.FOUNDATION_API_URL||B}async function p(t){let n=`${q()}/staking?address=${t}`,o=await fetch(n);if(!o.ok)throw new Error(`Foundation API error: ${o.status} ${o.statusText}`);return await o.json()}async function U(){let t=`${q()}/stake-weight`,n=await fetch(t);if(!n.ok)throw new Error(`Foundation API error: ${n.status} ${n.statusText}`);return await n.json()}import{formatUnits as tt}from"viem";function w(t){let n=tt(t,18);return parseFloat(n).toLocaleString("en-US",{minimumFractionDigits:2,maximumFractionDigits:2})}function u(t){return new Date(t*1e3).toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"})}function O(t){return Math.max(t/1e6*-.06464+12.0808,0)}function v(t,n){return t*(Math.min(n,104)/52)}function r(t,n){return` ${t.padEnd(12)} ${n}`}function ot(t){let n=Math.floor(Date.now()/1e3);return BigInt(Math.floor((n+t*604800)/604800))*BigInt(604800)}async function m(t,n,o){let a=await H(n,o);return t.request({chainId:D,request:{method:"eth_sendTransaction",params:[{from:n,to:o.to,data:o.data,value:"0x0",gas:a}]}})}async function et(t,n,o,a){let i=nt(o,18),e=ot(a),s=await j(N(n)),A=s.amount>0n;A&&(console.log(`
|
|
2
|
+
Existing staking position:`),console.log(r("Staked",`${w(BigInt(s.amount))} WCT`)),console.log(r("Unlocks",u(Number(s.end)))));let T=e,F=!A||e>s.end;if(A&&e<=s.end&&(T=s.end,console.log(`
|
|
3
|
+
Requested unlock (${u(Number(e))}) is before existing lock end.`),console.log(`Keeping current unlock date: ${u(Number(s.end))}`)),console.log(`
|
|
4
|
+
Adding ${o} WCT${F?`, extending lock to ${u(Number(T))}`:""}...`),await y(L(n,c))<i){console.log(`
|
|
5
|
+
Approving WCT spend...`);let Y=await m(t,n,I(c,i));console.log(r("Approve tx",Y)),console.log("Waiting for confirmation..."),await G(Y)}let x;A?F?(console.log(`
|
|
6
|
+
Updating lock (amount + time)...`),x=await m(t,n,h(i,T))):(console.log(`
|
|
7
|
+
Increasing lock amount...`),x=await m(t,n,W(i))):(console.log(`
|
|
8
|
+
Creating new lock...`),x=await m(t,n,_(i,T))),console.log(r("Tx hash",x)),console.log(`
|
|
9
|
+
Stake submitted successfully.`)}async function at(t,n){let o=await p(n);if(!o.position){console.log(`
|
|
10
|
+
No staking position found.`);return}if(o.position.unlocksAt){let i=new Date(o.position.unlocksAt).getTime()/1e3,e=Math.floor(Date.now()/1e3);if(i>e){console.log(`
|
|
11
|
+
Lock has not expired yet. Unlocks ${u(i)}.`);return}}console.log(`
|
|
12
|
+
Withdrawing all staked WCT...`);let a=await m(t,n,P());console.log(r("Tx hash",a)),console.log(`
|
|
13
|
+
Unstake submitted successfully.`)}async function it(t,n){let o=await p(n);if(!o.rewards||o.rewards.amount==="0"){console.log(`
|
|
14
|
+
No rewards to claim.`);return}console.log(`
|
|
15
|
+
Claiming ${o.rewards.amount} WCT in rewards...`);let a=await m(t,n,E(n));console.log(r("Tx hash",a)),console.log(`
|
|
16
|
+
Claim submitted successfully.`)}async function rt(t){let[n,o]=await Promise.all([p(t),U()]);if(console.log(`
|
|
17
|
+
Staking status for ${t}
|
|
18
|
+
`),!n.position)console.log(` No staking position found.
|
|
19
|
+
`);else{let e=n.position;if(console.log(r("Amount",`${e.amount} WCT`)),console.log(r("Permanent",e.isPermanent?"Yes":"No")),console.log(r("Created",new Date(e.createdAt).toLocaleDateString("en-US"))),e.unlocksAt&&console.log(r("Unlocks",new Date(e.unlocksAt).toLocaleDateString("en-US"))),e.duration){let s=Math.round(parseInt(e.duration,10)/604800);console.log(r("Duration",`${s} week(s)`))}console.log()}n.rewards&&console.log(r("Rewards",`${n.rewards.amount} WCT`));let a=parseFloat(o.stakeWeight),i=O(a);if(console.log(r("Base APY",`${i.toFixed(2)}%`)),n.position?.duration){let e=Math.round(parseInt(n.position.duration,10)/604800),s=v(i,e);console.log(r("Your APY",`${s.toFixed(2)}%`))}console.log()}async function st(t){let n=await y(R(t));console.log(`
|
|
20
|
+
${r("WCT balance",`${w(n)} WCT`)}
|
|
21
|
+
`)}export{D as CAIP2_CHAIN_ID,X as CHAIN_ID,J as CLI_METADATA,d as L2_WCT_ADDRESS,c as STAKE_WEIGHT_ADDRESS,b as STAKING_REWARD_DISTRIBUTOR_ADDRESS,st as balance,L as buildAllowanceCallData,I as buildApprove,R as buildBalanceOfCallData,E as buildClaim,_ as buildCreateLock,W as buildIncreaseLockAmount,Q as buildIncreaseUnlockTime,N as buildLocksCallData,h as buildUpdateLock,P as buildWithdrawAll,O as calculateAPY,v as calculateWeeklyAPY,it as claim,U as fetchStakeWeight,p as fetchStaking,u as formatDate,w as formatWCT,et as stake,rt as status,at as unstake};
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands.ts","../src/constants.ts","../src/contracts.ts","../src/rpc.ts","../src/api.ts","../src/format.ts"],"sourcesContent":["import { parseUnits } from \"viem\";\nimport type { WalletConnectCLI } from \"@walletconnect/cli-sdk\";\nimport {\n CAIP2_CHAIN_ID,\n STAKE_WEIGHT_ADDRESS,\n ONE_WEEK_IN_SECONDS,\n WCT_DECIMALS,\n} from \"./constants.js\";\nimport {\n buildApprove,\n buildCreateLock,\n buildUpdateLock,\n buildIncreaseLockAmount,\n buildWithdrawAll,\n buildClaim,\n buildBalanceOfCallData,\n buildAllowanceCallData,\n buildLocksCallData,\n type TxData,\n} from \"./contracts.js\";\nimport { readUint256, readLocks, estimateGas, waitForTx } from \"./rpc.js\";\nimport { fetchStaking, fetchStakeWeight } from \"./api.js\";\nimport { formatWCT, formatDate, calculateAPY, calculateWeeklyAPY, label } from \"./format.js\";\n\n// ---- Helpers ---------------------------------------------------------- //\n\nfunction computeUnlockTime(weeks: number): bigint {\n const now = Math.floor(Date.now() / 1000);\n return (BigInt(Math.floor((now + weeks * ONE_WEEK_IN_SECONDS) / ONE_WEEK_IN_SECONDS)) *\n BigInt(ONE_WEEK_IN_SECONDS));\n}\n\nasync function sendTx(\n wallet: WalletConnectCLI,\n from: string,\n tx: TxData,\n): Promise<string> {\n const gas = await estimateGas(from, tx);\n return wallet.request<string>({\n chainId: CAIP2_CHAIN_ID,\n request: {\n method: \"eth_sendTransaction\",\n params: [{ from, to: tx.to, data: tx.data, value: \"0x0\", gas }],\n },\n });\n}\n\n// ---- Commands --------------------------------------------------------- //\n\nexport async function stake(\n wallet: WalletConnectCLI,\n address: string,\n amount: string,\n weeks: number,\n): Promise<void> {\n const amountWei = parseUnits(amount, WCT_DECIMALS);\n const requestedUnlockTime = computeUnlockTime(weeks);\n\n // Read on-chain position to determine the right action\n const lock = await readLocks(buildLocksCallData(address));\n const hasPosition = lock.amount > 0n;\n\n if (hasPosition) {\n console.log(\"\\nExisting staking position:\");\n console.log(label(\"Staked\", `${formatWCT(BigInt(lock.amount))} WCT`));\n console.log(label(\"Unlocks\", formatDate(Number(lock.end))));\n }\n\n // Determine effective unlock time — never shorten an existing lock\n let effectiveUnlockTime = requestedUnlockTime;\n const extendingTime = !hasPosition || requestedUnlockTime > lock.end;\n\n if (hasPosition && requestedUnlockTime <= lock.end) {\n effectiveUnlockTime = lock.end;\n console.log(`\\nRequested unlock (${formatDate(Number(requestedUnlockTime))}) is before existing lock end.`);\n console.log(`Keeping current unlock date: ${formatDate(Number(lock.end))}`);\n }\n\n console.log(`\\nAdding ${amount} WCT${extendingTime ? `, extending lock to ${formatDate(Number(effectiveUnlockTime))}` : \"\"}...`);\n\n // Check allowance and approve if needed\n const allowance = await readUint256(buildAllowanceCallData(address, STAKE_WEIGHT_ADDRESS));\n if (allowance < amountWei) {\n console.log(\"\\nApproving WCT spend...\");\n const approveTxHash = await sendTx(wallet, address, buildApprove(STAKE_WEIGHT_ADDRESS, amountWei));\n console.log(label(\"Approve tx\", approveTxHash));\n console.log(\"Waiting for confirmation...\");\n await waitForTx(approveTxHash);\n }\n\n let txHash: string;\n\n if (!hasPosition) {\n console.log(\"\\nCreating new lock...\");\n txHash = await sendTx(wallet, address, buildCreateLock(amountWei, effectiveUnlockTime));\n } else if (extendingTime) {\n console.log(\"\\nUpdating lock (amount + time)...\");\n txHash = await sendTx(wallet, address, buildUpdateLock(amountWei, effectiveUnlockTime));\n } else {\n console.log(\"\\nIncreasing lock amount...\");\n txHash = await sendTx(wallet, address, buildIncreaseLockAmount(amountWei));\n }\n\n console.log(label(\"Tx hash\", txHash));\n console.log(\"\\nStake submitted successfully.\");\n}\n\nexport async function unstake(\n wallet: WalletConnectCLI,\n address: string,\n): Promise<void> {\n const staking = await fetchStaking(address);\n\n if (!staking.position) {\n console.log(\"\\nNo staking position found.\");\n return;\n }\n\n if (staking.position.unlocksAt) {\n const unlocksAt = new Date(staking.position.unlocksAt).getTime() / 1000;\n const now = Math.floor(Date.now() / 1000);\n if (unlocksAt > now) {\n console.log(`\\nLock has not expired yet. Unlocks ${formatDate(unlocksAt)}.`);\n return;\n }\n }\n\n console.log(\"\\nWithdrawing all staked WCT...\");\n const txHash = await sendTx(wallet, address, buildWithdrawAll());\n console.log(label(\"Tx hash\", txHash));\n console.log(\"\\nUnstake submitted successfully.\");\n}\n\nexport async function claim(\n wallet: WalletConnectCLI,\n address: string,\n): Promise<void> {\n const staking = await fetchStaking(address);\n\n if (!staking.rewards || staking.rewards.amount === \"0\") {\n console.log(\"\\nNo rewards to claim.\");\n return;\n }\n\n console.log(`\\nClaiming ${staking.rewards.amount} WCT in rewards...`);\n const txHash = await sendTx(wallet, address, buildClaim(address));\n console.log(label(\"Tx hash\", txHash));\n console.log(\"\\nClaim submitted successfully.\");\n}\n\nexport async function status(address: string): Promise<void> {\n const [staking, stakeWeightRes] = await Promise.all([\n fetchStaking(address),\n fetchStakeWeight(),\n ]);\n\n console.log(`\\nStaking status for ${address}\\n`);\n\n if (!staking.position) {\n console.log(\" No staking position found.\\n\");\n } else {\n const pos = staking.position;\n console.log(label(\"Amount\", `${pos.amount} WCT`));\n console.log(label(\"Permanent\", pos.isPermanent ? \"Yes\" : \"No\"));\n console.log(label(\"Created\", new Date(pos.createdAt).toLocaleDateString(\"en-US\")));\n if (pos.unlocksAt) {\n console.log(label(\"Unlocks\", new Date(pos.unlocksAt).toLocaleDateString(\"en-US\")));\n }\n if (pos.duration) {\n const durationWeeks = Math.round(parseInt(pos.duration, 10) / ONE_WEEK_IN_SECONDS);\n console.log(label(\"Duration\", `${durationWeeks} week(s)`));\n }\n console.log();\n }\n\n if (staking.rewards) {\n console.log(label(\"Rewards\", `${staking.rewards.amount} WCT`));\n }\n\n const stakeWeight = parseFloat(stakeWeightRes.stakeWeight);\n const baseAPY = calculateAPY(stakeWeight);\n console.log(label(\"Base APY\", `${baseAPY.toFixed(2)}%`));\n\n if (staking.position?.duration) {\n const weeks = Math.round(parseInt(staking.position.duration, 10) / ONE_WEEK_IN_SECONDS);\n const weeklyAPY = calculateWeeklyAPY(baseAPY, weeks);\n console.log(label(\"Your APY\", `${weeklyAPY.toFixed(2)}%`));\n }\n\n console.log();\n}\n\nexport async function balance(address: string): Promise<void> {\n const bal = await readUint256(buildBalanceOfCallData(address));\n console.log(`\\n${label(\"WCT balance\", `${formatWCT(bal)} WCT`)}\\n`);\n}\n","/** Optimism chain ID */\nexport const CHAIN_ID = 10;\nexport const CAIP2_CHAIN_ID = \"eip155:10\";\n\n/** Contract addresses on Optimism */\nexport const L2_WCT_ADDRESS = \"0xeF4461891DfB3AC8572cCf7C794664A8DD927945\";\nexport const STAKE_WEIGHT_ADDRESS = \"0x521B4C065Bbdbe3E20B3727340730936912DfA46\";\nexport const STAKING_REWARD_DISTRIBUTOR_ADDRESS = \"0xF368F535e329c6d08DFf0d4b2dA961C4e7F3fCAF\";\n\n/** Public Optimism RPC endpoint */\nexport const OPTIMISM_RPC_URL = \"https://mainnet.optimism.io\";\n\n/** Foundation API */\nexport const FOUNDATION_API_URL = \"https://api.walletconnect.network\";\n\n/** Time constants */\nexport const ONE_WEEK_IN_SECONDS = 604800;\n\n/** WCT token decimals */\nexport const WCT_DECIMALS = 18;\n\n/** APY formula constants (from math.ts) */\nexport const APY_SLOPE = -0.06464;\nexport const APY_INTERCEPT = 12.0808;\nexport const APY_STAKE_WEIGHT_DIVISOR = 1_000_000;\nexport const MAX_LOCK_WEEKS = 104;\n\n/** CLI metadata for WalletConnect pairing */\nexport const CLI_METADATA = {\n name: \"walletconnect-staking\",\n description: \"WalletConnect WCT Staking CLI\",\n url: \"https://walletconnect.com\",\n icons: [],\n};\n","import { encodeFunctionData, parseAbi } from \"viem\";\nimport {\n L2_WCT_ADDRESS,\n STAKE_WEIGHT_ADDRESS,\n STAKING_REWARD_DISTRIBUTOR_ADDRESS,\n} from \"./constants.js\";\n\n// ---- ABI fragments ---------------------------------------------------- //\n\nconst erc20Abi = parseAbi([\n \"function approve(address spender, uint256 value) returns (bool)\",\n \"function balanceOf(address account) view returns (uint256)\",\n \"function allowance(address owner, address spender) view returns (uint256)\",\n]);\n\nconst stakeWeightAbi = parseAbi([\n \"function createLock(uint256 amount, uint256 unlockTime)\",\n \"function updateLock(uint256 amount, uint256 unlockTime)\",\n \"function increaseLockAmount(uint256 amount)\",\n \"function increaseUnlockTime(uint256 newUnlockTime)\",\n \"function withdrawAll()\",\n \"function locks(address) view returns (int128 amount, uint256 end, uint256 transferredAmount)\",\n]);\n\nconst stakingRewardDistributorAbi = parseAbi([\n \"function claim(address user) returns (uint256)\",\n]);\n\n// ---- Transaction builders --------------------------------------------- //\n\nexport interface TxData {\n to: string;\n data: string;\n}\n\nexport function buildApprove(spender: string, amount: bigint): TxData {\n return {\n to: L2_WCT_ADDRESS,\n data: encodeFunctionData({\n abi: erc20Abi,\n functionName: \"approve\",\n args: [spender as `0x${string}`, amount],\n }),\n };\n}\n\nexport function buildCreateLock(amount: bigint, unlockTime: bigint): TxData {\n return {\n to: STAKE_WEIGHT_ADDRESS,\n data: encodeFunctionData({\n abi: stakeWeightAbi,\n functionName: \"createLock\",\n args: [amount, unlockTime],\n }),\n };\n}\n\nexport function buildUpdateLock(amount: bigint, unlockTime: bigint): TxData {\n return {\n to: STAKE_WEIGHT_ADDRESS,\n data: encodeFunctionData({\n abi: stakeWeightAbi,\n functionName: \"updateLock\",\n args: [amount, unlockTime],\n }),\n };\n}\n\nexport function buildIncreaseLockAmount(amount: bigint): TxData {\n return {\n to: STAKE_WEIGHT_ADDRESS,\n data: encodeFunctionData({\n abi: stakeWeightAbi,\n functionName: \"increaseLockAmount\",\n args: [amount],\n }),\n };\n}\n\nexport function buildIncreaseUnlockTime(newUnlockTime: bigint): TxData {\n return {\n to: STAKE_WEIGHT_ADDRESS,\n data: encodeFunctionData({\n abi: stakeWeightAbi,\n functionName: \"increaseUnlockTime\",\n args: [newUnlockTime],\n }),\n };\n}\n\nexport function buildWithdrawAll(): TxData {\n return {\n to: STAKE_WEIGHT_ADDRESS,\n data: encodeFunctionData({\n abi: stakeWeightAbi,\n functionName: \"withdrawAll\",\n }),\n };\n}\n\nexport function buildClaim(user: string): TxData {\n return {\n to: STAKING_REWARD_DISTRIBUTOR_ADDRESS,\n data: encodeFunctionData({\n abi: stakingRewardDistributorAbi,\n functionName: \"claim\",\n args: [user as `0x${string}`],\n }),\n };\n}\n\n// ---- Call data builders (for eth_call) -------------------------------- //\n\nexport function buildBalanceOfCallData(account: string): TxData {\n return {\n to: L2_WCT_ADDRESS,\n data: encodeFunctionData({\n abi: erc20Abi,\n functionName: \"balanceOf\",\n args: [account as `0x${string}`],\n }),\n };\n}\n\nexport function buildAllowanceCallData(owner: string, spender: string): TxData {\n return {\n to: L2_WCT_ADDRESS,\n data: encodeFunctionData({\n abi: erc20Abi,\n functionName: \"allowance\",\n args: [owner as `0x${string}`, spender as `0x${string}`],\n }),\n };\n}\n\nexport function buildLocksCallData(account: string): TxData {\n return {\n to: STAKE_WEIGHT_ADDRESS,\n data: encodeFunctionData({\n abi: stakeWeightAbi,\n functionName: \"locks\",\n args: [account as `0x${string}`],\n }),\n };\n}\n","import { decodeAbiParameters } from \"viem\";\nimport { OPTIMISM_RPC_URL } from \"./constants.js\";\nimport type { TxData } from \"./contracts.js\";\n\nlet requestId = 1;\n\nasync function rpcRequest<T = string>(\n method: string,\n params: unknown[],\n rpcUrl: string,\n): Promise<T> {\n const res = await fetch(rpcUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: requestId++,\n method,\n params,\n }),\n });\n\n if (!res.ok) {\n throw new Error(`RPC request failed: ${res.status} ${res.statusText}`);\n }\n\n const json = (await res.json()) as { result?: T; error?: { message: string } };\n\n if (json.error) {\n throw new Error(`RPC error: ${json.error.message}`);\n }\n\n return json.result!;\n}\n\nasync function ethCall(tx: TxData, rpcUrl: string): Promise<string> {\n return rpcRequest(\"eth_call\", [{ to: tx.to, data: tx.data }, \"latest\"], rpcUrl);\n}\n\n/** Read a uint256 from an eth_call result */\nexport async function readUint256(\n tx: TxData,\n rpcUrl: string = OPTIMISM_RPC_URL,\n): Promise<bigint> {\n const result = await ethCall(tx, rpcUrl);\n const [value] = decodeAbiParameters([{ type: \"uint256\" }], result as `0x${string}`);\n return value;\n}\n\n/** Estimate gas for a transaction, with a 20% buffer */\nexport async function estimateGas(\n from: string,\n tx: TxData,\n rpcUrl: string = OPTIMISM_RPC_URL,\n): Promise<string> {\n const result = await rpcRequest(\n \"eth_estimateGas\",\n [{ from, to: tx.to, data: tx.data, value: \"0x0\" }, \"latest\"],\n rpcUrl,\n );\n // Add 20% buffer to the estimate\n const estimate = BigInt(result);\n const buffered = estimate + estimate / 5n;\n return `0x${buffered.toString(16)}`;\n}\n\ninterface TxReceipt {\n status: string;\n blockNumber: string;\n transactionHash: string;\n}\n\n/** Wait for a transaction to be confirmed (polls eth_getTransactionReceipt) */\nexport async function waitForTx(\n txHash: string,\n rpcUrl: string = OPTIMISM_RPC_URL,\n { intervalMs = 2000, timeoutMs = 60000 } = {},\n): Promise<void> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n try {\n const receipt = await rpcRequest<TxReceipt | null>(\n \"eth_getTransactionReceipt\",\n [txHash],\n rpcUrl,\n );\n if (receipt) {\n if (receipt.status === \"0x0\") {\n throw new Error(`Transaction ${txHash} reverted`);\n }\n return;\n }\n } catch (err) {\n // Re-throw revert errors, swallow \"receipt not available yet\"\n if (err instanceof Error && err.message.includes(\"reverted\")) throw err;\n }\n await new Promise((r) => setTimeout(r, intervalMs));\n }\n throw new Error(`Transaction ${txHash} not confirmed within ${timeoutMs / 1000}s`);\n}\n\n/** Read the locks() return: (int128 amount, uint256 end, uint256 transferredAmount) */\nexport async function readLocks(\n tx: TxData,\n rpcUrl: string = OPTIMISM_RPC_URL,\n): Promise<{ amount: bigint; end: bigint; transferredAmount: bigint }> {\n const result = await ethCall(tx, rpcUrl);\n const [amount, end, transferredAmount] = decodeAbiParameters(\n [{ type: \"int128\" }, { type: \"uint256\" }, { type: \"uint256\" }],\n result as `0x${string}`,\n );\n return { amount: BigInt(amount), end, transferredAmount };\n}\n","import { FOUNDATION_API_URL } from \"./constants.js\";\n\nexport interface StakingPosition {\n isPermanent: boolean;\n amount: string;\n createdAt: string;\n unlocksAt?: string;\n duration?: string;\n}\n\nexport interface StakingRewards {\n amount: string;\n}\n\nexport interface StakingResponse {\n position: StakingPosition | null;\n rewards: StakingRewards | null;\n}\n\nexport interface StakeWeightResponse {\n stakeWeight: string;\n}\n\nfunction getBaseUrl(): string {\n return process.env.FOUNDATION_API_URL || FOUNDATION_API_URL;\n}\n\nexport async function fetchStaking(address: string): Promise<StakingResponse> {\n const url = `${getBaseUrl()}/staking?address=${address}`;\n const res = await fetch(url);\n if (!res.ok) {\n throw new Error(`Foundation API error: ${res.status} ${res.statusText}`);\n }\n return (await res.json()) as StakingResponse;\n}\n\nexport async function fetchStakeWeight(): Promise<StakeWeightResponse> {\n const url = `${getBaseUrl()}/stake-weight`;\n const res = await fetch(url);\n if (!res.ok) {\n throw new Error(`Foundation API error: ${res.status} ${res.statusText}`);\n }\n return (await res.json()) as StakeWeightResponse;\n}\n","import { formatUnits } from \"viem\";\nimport {\n WCT_DECIMALS,\n APY_SLOPE,\n APY_INTERCEPT,\n APY_STAKE_WEIGHT_DIVISOR,\n MAX_LOCK_WEEKS,\n} from \"./constants.js\";\n\n/** Format a bigint WCT amount as a human-readable string with 2 decimals */\nexport function formatWCT(amount: bigint): string {\n const raw = formatUnits(amount, WCT_DECIMALS);\n const num = parseFloat(raw);\n return num.toLocaleString(\"en-US\", {\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n });\n}\n\n/** Format a unix timestamp as a locale date string */\nexport function formatDate(timestamp: number): string {\n return new Date(timestamp * 1000).toLocaleDateString(\"en-US\", {\n year: \"numeric\",\n month: \"short\",\n day: \"numeric\",\n });\n}\n\n/** Calculate base APY from total stake weight (from math.ts) */\nexport function calculateAPY(stakeWeight: number): number {\n return Math.max(\n (stakeWeight / APY_STAKE_WEIGHT_DIVISOR) * APY_SLOPE + APY_INTERCEPT,\n 0,\n );\n}\n\n/** Calculate weekly APY adjusted for lock duration */\nexport function calculateWeeklyAPY(baseAPY: number, weeks: number): number {\n return baseAPY * (Math.min(weeks, MAX_LOCK_WEEKS) / 52);\n}\n\n/** Print a labeled key-value pair */\nexport function label(key: string, value: string): string {\n return ` ${key.padEnd(12)} ${value}`;\n}\n"],"mappings":"AAAA,OAAS,cAAAA,OAAkB,OCCpB,IAAMC,EAAW,GACXC,EAAiB,YAGjBC,EAAiB,6CACjBC,EAAuB,6CACvBC,EAAqC,6CAGrCC,EAAmB,8BAGnBC,EAAqB,oCAe3B,IAAMC,EAAe,CAC1B,KAAM,wBACN,YAAa,gCACb,IAAK,4BACL,MAAO,CAAC,CACV,ECjCA,OAAS,sBAAAC,EAAoB,YAAAC,MAAgB,OAS7C,IAAMC,EAAWC,EAAS,CACxB,kEACA,6DACA,2EACF,CAAC,EAEKC,EAAiBD,EAAS,CAC9B,0DACA,0DACA,8CACA,qDACA,yBACA,8FACF,CAAC,EAEKE,EAA8BF,EAAS,CAC3C,gDACF,CAAC,EASM,SAASG,EAAaC,EAAiBC,EAAwB,CACpE,MAAO,CACL,GAAIC,EACJ,KAAMC,EAAmB,CACvB,IAAKR,EACL,aAAc,UACd,KAAM,CAACK,EAA0BC,CAAM,CACzC,CAAC,CACH,CACF,CAEO,SAASG,EAAgBH,EAAgBI,EAA4B,CAC1E,MAAO,CACL,GAAIC,EACJ,KAAMH,EAAmB,CACvB,IAAKN,EACL,aAAc,aACd,KAAM,CAACI,EAAQI,CAAU,CAC3B,CAAC,CACH,CACF,CAEO,SAASE,EAAgBN,EAAgBI,EAA4B,CAC1E,MAAO,CACL,GAAIC,EACJ,KAAMH,EAAmB,CACvB,IAAKN,EACL,aAAc,aACd,KAAM,CAACI,EAAQI,CAAU,CAC3B,CAAC,CACH,CACF,CAEO,SAASG,EAAwBP,EAAwB,CAC9D,MAAO,CACL,GAAIK,EACJ,KAAMH,EAAmB,CACvB,IAAKN,EACL,aAAc,qBACd,KAAM,CAACI,CAAM,CACf,CAAC,CACH,CACF,CAEO,SAASQ,EAAwBC,EAA+B,CACrE,MAAO,CACL,GAAIJ,EACJ,KAAMH,EAAmB,CACvB,IAAKN,EACL,aAAc,qBACd,KAAM,CAACa,CAAa,CACtB,CAAC,CACH,CACF,CAEO,SAASC,GAA2B,CACzC,MAAO,CACL,GAAIL,EACJ,KAAMH,EAAmB,CACvB,IAAKN,EACL,aAAc,aAChB,CAAC,CACH,CACF,CAEO,SAASe,EAAWC,EAAsB,CAC/C,MAAO,CACL,GAAIC,EACJ,KAAMX,EAAmB,CACvB,IAAKL,EACL,aAAc,QACd,KAAM,CAACe,CAAqB,CAC9B,CAAC,CACH,CACF,CAIO,SAASE,EAAuBC,EAAyB,CAC9D,MAAO,CACL,GAAId,EACJ,KAAMC,EAAmB,CACvB,IAAKR,EACL,aAAc,YACd,KAAM,CAACqB,CAAwB,CACjC,CAAC,CACH,CACF,CAEO,SAASC,EAAuBC,EAAelB,EAAyB,CAC7E,MAAO,CACL,GAAIE,EACJ,KAAMC,EAAmB,CACvB,IAAKR,EACL,aAAc,YACd,KAAM,CAACuB,EAAwBlB,CAAwB,CACzD,CAAC,CACH,CACF,CAEO,SAASmB,EAAmBH,EAAyB,CAC1D,MAAO,CACL,GAAIV,EACJ,KAAMH,EAAmB,CACvB,IAAKN,EACL,aAAc,QACd,KAAM,CAACmB,CAAwB,CACjC,CAAC,CACH,CACF,CChJA,OAAS,uBAAAI,MAA2B,OAIpC,IAAIC,EAAY,EAEhB,eAAeC,EACbC,EACAC,EACAC,EACY,CACZ,IAAMC,EAAM,MAAM,MAAMD,EAAQ,CAC9B,OAAQ,OACR,QAAS,CAAE,eAAgB,kBAAmB,EAC9C,KAAM,KAAK,UAAU,CACnB,QAAS,MACT,GAAIJ,IACJ,OAAAE,EACA,OAAAC,CACF,CAAC,CACH,CAAC,EAED,GAAI,CAACE,EAAI,GACP,MAAM,IAAI,MAAM,uBAAuBA,EAAI,MAAM,IAAIA,EAAI,UAAU,EAAE,EAGvE,IAAMC,EAAQ,MAAMD,EAAI,KAAK,EAE7B,GAAIC,EAAK,MACP,MAAM,IAAI,MAAM,cAAcA,EAAK,MAAM,OAAO,EAAE,EAGpD,OAAOA,EAAK,MACd,CAEA,eAAeC,EAAQC,EAAYJ,EAAiC,CAClE,OAAOH,EAAW,WAAY,CAAC,CAAE,GAAIO,EAAG,GAAI,KAAMA,EAAG,IAAK,EAAG,QAAQ,EAAGJ,CAAM,CAChF,CAGA,eAAsBK,EACpBD,EACAJ,EAAiBM,EACA,CACjB,IAAMC,EAAS,MAAMJ,EAAQC,EAAIJ,CAAM,EACjC,CAACQ,CAAK,EAAIC,EAAoB,CAAC,CAAE,KAAM,SAAU,CAAC,EAAGF,CAAuB,EAClF,OAAOC,CACT,CAGA,eAAsBE,EACpBC,EACAP,EACAJ,EAAiBM,EACA,CACjB,IAAMC,EAAS,MAAMV,EACnB,kBACA,CAAC,CAAE,KAAAc,EAAM,GAAIP,EAAG,GAAI,KAAMA,EAAG,KAAM,MAAO,KAAM,EAAG,QAAQ,EAC3DJ,CACF,EAEMY,EAAW,OAAOL,CAAM,EAE9B,MAAO,MADUK,EAAWA,EAAW,IAClB,SAAS,EAAE,CAAC,EACnC,CASA,eAAsBC,EACpBC,EACAd,EAAiBM,EACjB,CAAE,WAAAS,EAAa,IAAM,UAAAC,EAAY,GAAM,EAAI,CAAC,EAC7B,CACf,IAAMC,EAAQ,KAAK,IAAI,EACvB,KAAO,KAAK,IAAI,EAAIA,EAAQD,GAAW,CACrC,GAAI,CACF,IAAME,EAAU,MAAMrB,EACpB,4BACA,CAACiB,CAAM,EACPd,CACF,EACA,GAAIkB,EAAS,CACX,GAAIA,EAAQ,SAAW,MACrB,MAAM,IAAI,MAAM,eAAeJ,CAAM,WAAW,EAElD,MACF,CACF,OAASK,EAAK,CAEZ,GAAIA,aAAe,OAASA,EAAI,QAAQ,SAAS,UAAU,EAAG,MAAMA,CACtE,CACA,MAAM,IAAI,QAASC,GAAM,WAAWA,EAAGL,CAAU,CAAC,CACpD,CACA,MAAM,IAAI,MAAM,eAAeD,CAAM,yBAAyBE,EAAY,GAAI,GAAG,CACnF,CAGA,eAAsBK,EACpBjB,EACAJ,EAAiBM,EACoD,CACrE,IAAMC,EAAS,MAAMJ,EAAQC,EAAIJ,CAAM,EACjC,CAACsB,EAAQC,EAAKC,CAAiB,EAAIf,EACvC,CAAC,CAAE,KAAM,QAAS,EAAG,CAAE,KAAM,SAAU,EAAG,CAAE,KAAM,SAAU,CAAC,EAC7DF,CACF,EACA,MAAO,CAAE,OAAQ,OAAOe,CAAM,EAAG,IAAAC,EAAK,kBAAAC,CAAkB,CAC1D,CCzFA,SAASC,GAAqB,CAC5B,OAAO,QAAQ,IAAI,oBAAsBC,CAC3C,CAEA,eAAsBC,EAAaC,EAA2C,CAC5E,IAAMC,EAAM,GAAGJ,EAAW,CAAC,oBAAoBG,CAAO,GAChDE,EAAM,MAAM,MAAMD,CAAG,EAC3B,GAAI,CAACC,EAAI,GACP,MAAM,IAAI,MAAM,yBAAyBA,EAAI,MAAM,IAAIA,EAAI,UAAU,EAAE,EAEzE,OAAQ,MAAMA,EAAI,KAAK,CACzB,CAEA,eAAsBC,GAAiD,CACrE,IAAMF,EAAM,GAAGJ,EAAW,CAAC,gBACrBK,EAAM,MAAM,MAAMD,CAAG,EAC3B,GAAI,CAACC,EAAI,GACP,MAAM,IAAI,MAAM,yBAAyBA,EAAI,MAAM,IAAIA,EAAI,UAAU,EAAE,EAEzE,OAAQ,MAAMA,EAAI,KAAK,CACzB,CC3CA,OAAS,eAAAE,OAAmB,OAUrB,SAASC,EAAUC,EAAwB,CAChD,IAAMC,EAAMC,GAAYF,EAAQ,EAAY,EAE5C,OADY,WAAWC,CAAG,EACf,eAAe,QAAS,CACjC,sBAAuB,EACvB,sBAAuB,CACzB,CAAC,CACH,CAGO,SAASE,EAAWC,EAA2B,CACpD,OAAO,IAAI,KAAKA,EAAY,GAAI,EAAE,mBAAmB,QAAS,CAC5D,KAAM,UACN,MAAO,QACP,IAAK,SACP,CAAC,CACH,CAGO,SAASC,EAAaC,EAA6B,CACxD,OAAO,KAAK,IACTA,EAAc,IAA4B,QAAY,QACvD,CACF,CACF,CAGO,SAASC,EAAmBC,EAAiBC,EAAuB,CACzE,OAAOD,GAAW,KAAK,IAAIC,EAAO,GAAc,EAAI,GACtD,CAGO,SAASC,EAAMC,EAAaC,EAAuB,CACxD,MAAO,KAAKD,EAAI,OAAO,EAAE,CAAC,IAAIC,CAAK,EACrC,CLlBA,SAASC,GAAkBC,EAAuB,CAChD,IAAMC,EAAM,KAAK,MAAM,KAAK,IAAI,EAAI,GAAI,EACxC,OAAQ,OAAO,KAAK,OAAOA,EAAMD,EAAQ,QAAuB,MAAmB,CAAC,EAClF,OAAO,MAAmB,CAC9B,CAEA,eAAeE,EACbC,EACAC,EACAC,EACiB,CACjB,IAAMC,EAAM,MAAMC,EAAYH,EAAMC,CAAE,EACtC,OAAOF,EAAO,QAAgB,CAC5B,QAASK,EACT,QAAS,CACP,OAAQ,sBACR,OAAQ,CAAC,CAAE,KAAAJ,EAAM,GAAIC,EAAG,GAAI,KAAMA,EAAG,KAAM,MAAO,MAAO,IAAAC,CAAI,CAAC,CAChE,CACF,CAAC,CACH,CAIA,eAAsBG,GACpBN,EACAO,EACAC,EACAX,EACe,CACf,IAAMY,EAAYC,GAAWF,EAAQ,EAAY,EAC3CG,EAAsBf,GAAkBC,CAAK,EAG7Ce,EAAO,MAAMC,EAAUC,EAAmBP,CAAO,CAAC,EAClDQ,EAAcH,EAAK,OAAS,GAE9BG,IACF,QAAQ,IAAI;AAAA,2BAA8B,EAC1C,QAAQ,IAAIC,EAAM,SAAU,GAAGC,EAAU,OAAOL,EAAK,MAAM,CAAC,CAAC,MAAM,CAAC,EACpE,QAAQ,IAAII,EAAM,UAAWE,EAAW,OAAON,EAAK,GAAG,CAAC,CAAC,CAAC,GAI5D,IAAIO,EAAsBR,EACpBS,EAAgB,CAACL,GAAeJ,EAAsBC,EAAK,IAYjE,GAVIG,GAAeJ,GAAuBC,EAAK,MAC7CO,EAAsBP,EAAK,IAC3B,QAAQ,IAAI;AAAA,oBAAuBM,EAAW,OAAOP,CAAmB,CAAC,CAAC,gCAAgC,EAC1G,QAAQ,IAAI,gCAAgCO,EAAW,OAAON,EAAK,GAAG,CAAC,CAAC,EAAE,GAG5E,QAAQ,IAAI;AAAA,SAAYJ,CAAM,OAAOY,EAAgB,uBAAuBF,EAAW,OAAOC,CAAmB,CAAC,CAAC,GAAK,EAAE,KAAK,EAG7G,MAAME,EAAYC,EAAuBf,EAASgB,CAAoB,CAAC,EACzEd,EAAW,CACzB,QAAQ,IAAI;AAAA,uBAA0B,EACtC,IAAMe,EAAgB,MAAMzB,EAAOC,EAAQO,EAASkB,EAAaF,EAAsBd,CAAS,CAAC,EACjG,QAAQ,IAAIO,EAAM,aAAcQ,CAAa,CAAC,EAC9C,QAAQ,IAAI,6BAA6B,EACzC,MAAME,EAAUF,CAAa,CAC/B,CAEA,IAAIG,EAECZ,EAGMK,GACT,QAAQ,IAAI;AAAA,iCAAoC,EAChDO,EAAS,MAAM5B,EAAOC,EAAQO,EAASqB,EAAgBnB,EAAWU,CAAmB,CAAC,IAEtF,QAAQ,IAAI;AAAA,0BAA6B,EACzCQ,EAAS,MAAM5B,EAAOC,EAAQO,EAASsB,EAAwBpB,CAAS,CAAC,IAPzE,QAAQ,IAAI;AAAA,qBAAwB,EACpCkB,EAAS,MAAM5B,EAAOC,EAAQO,EAASuB,EAAgBrB,EAAWU,CAAmB,CAAC,GASxF,QAAQ,IAAIH,EAAM,UAAWW,CAAM,CAAC,EACpC,QAAQ,IAAI;AAAA,8BAAiC,CAC/C,CAEA,eAAsBI,GACpB/B,EACAO,EACe,CACf,IAAMyB,EAAU,MAAMC,EAAa1B,CAAO,EAE1C,GAAI,CAACyB,EAAQ,SAAU,CACrB,QAAQ,IAAI;AAAA,2BAA8B,EAC1C,MACF,CAEA,GAAIA,EAAQ,SAAS,UAAW,CAC9B,IAAME,EAAY,IAAI,KAAKF,EAAQ,SAAS,SAAS,EAAE,QAAQ,EAAI,IAC7DlC,EAAM,KAAK,MAAM,KAAK,IAAI,EAAI,GAAI,EACxC,GAAIoC,EAAYpC,EAAK,CACnB,QAAQ,IAAI;AAAA,oCAAuCoB,EAAWgB,CAAS,CAAC,GAAG,EAC3E,MACF,CACF,CAEA,QAAQ,IAAI;AAAA,8BAAiC,EAC7C,IAAMP,EAAS,MAAM5B,EAAOC,EAAQO,EAAS4B,EAAiB,CAAC,EAC/D,QAAQ,IAAInB,EAAM,UAAWW,CAAM,CAAC,EACpC,QAAQ,IAAI;AAAA,gCAAmC,CACjD,CAEA,eAAsBS,GACpBpC,EACAO,EACe,CACf,IAAMyB,EAAU,MAAMC,EAAa1B,CAAO,EAE1C,GAAI,CAACyB,EAAQ,SAAWA,EAAQ,QAAQ,SAAW,IAAK,CACtD,QAAQ,IAAI;AAAA,qBAAwB,EACpC,MACF,CAEA,QAAQ,IAAI;AAAA,WAAcA,EAAQ,QAAQ,MAAM,oBAAoB,EACpE,IAAML,EAAS,MAAM5B,EAAOC,EAAQO,EAAS8B,EAAW9B,CAAO,CAAC,EAChE,QAAQ,IAAIS,EAAM,UAAWW,CAAM,CAAC,EACpC,QAAQ,IAAI;AAAA,8BAAiC,CAC/C,CAEA,eAAsBW,GAAO/B,EAAgC,CAC3D,GAAM,CAACyB,EAASO,CAAc,EAAI,MAAM,QAAQ,IAAI,CAClDN,EAAa1B,CAAO,EACpBiC,EAAiB,CACnB,CAAC,EAID,GAFA,QAAQ,IAAI;AAAA,qBAAwBjC,CAAO;AAAA,CAAI,EAE3C,CAACyB,EAAQ,SACX,QAAQ,IAAI;AAAA,CAAgC,MACvC,CACL,IAAMS,EAAMT,EAAQ,SAOpB,GANA,QAAQ,IAAIhB,EAAM,SAAU,GAAGyB,EAAI,MAAM,MAAM,CAAC,EAChD,QAAQ,IAAIzB,EAAM,YAAayB,EAAI,YAAc,MAAQ,IAAI,CAAC,EAC9D,QAAQ,IAAIzB,EAAM,UAAW,IAAI,KAAKyB,EAAI,SAAS,EAAE,mBAAmB,OAAO,CAAC,CAAC,EAC7EA,EAAI,WACN,QAAQ,IAAIzB,EAAM,UAAW,IAAI,KAAKyB,EAAI,SAAS,EAAE,mBAAmB,OAAO,CAAC,CAAC,EAE/EA,EAAI,SAAU,CAChB,IAAMC,EAAgB,KAAK,MAAM,SAASD,EAAI,SAAU,EAAE,EAAI,MAAmB,EACjF,QAAQ,IAAIzB,EAAM,WAAY,GAAG0B,CAAa,UAAU,CAAC,CAC3D,CACA,QAAQ,IAAI,CACd,CAEIV,EAAQ,SACV,QAAQ,IAAIhB,EAAM,UAAW,GAAGgB,EAAQ,QAAQ,MAAM,MAAM,CAAC,EAG/D,IAAMW,EAAc,WAAWJ,EAAe,WAAW,EACnDK,EAAUC,EAAaF,CAAW,EAGxC,GAFA,QAAQ,IAAI3B,EAAM,WAAY,GAAG4B,EAAQ,QAAQ,CAAC,CAAC,GAAG,CAAC,EAEnDZ,EAAQ,UAAU,SAAU,CAC9B,IAAMnC,EAAQ,KAAK,MAAM,SAASmC,EAAQ,SAAS,SAAU,EAAE,EAAI,MAAmB,EAChFc,EAAYC,EAAmBH,EAAS/C,CAAK,EACnD,QAAQ,IAAImB,EAAM,WAAY,GAAG8B,EAAU,QAAQ,CAAC,CAAC,GAAG,CAAC,CAC3D,CAEA,QAAQ,IAAI,CACd,CAEA,eAAsBE,GAAQzC,EAAgC,CAC5D,IAAM0C,EAAM,MAAM5B,EAAY6B,EAAuB3C,CAAO,CAAC,EAC7D,QAAQ,IAAI;AAAA,EAAKS,EAAM,cAAe,GAAGC,EAAUgC,CAAG,CAAC,MAAM,CAAC;AAAA,CAAI,CACpE","names":["parseUnits","CHAIN_ID","CAIP2_CHAIN_ID","L2_WCT_ADDRESS","STAKE_WEIGHT_ADDRESS","STAKING_REWARD_DISTRIBUTOR_ADDRESS","OPTIMISM_RPC_URL","FOUNDATION_API_URL","CLI_METADATA","encodeFunctionData","parseAbi","erc20Abi","parseAbi","stakeWeightAbi","stakingRewardDistributorAbi","buildApprove","spender","amount","L2_WCT_ADDRESS","encodeFunctionData","buildCreateLock","unlockTime","STAKE_WEIGHT_ADDRESS","buildUpdateLock","buildIncreaseLockAmount","buildIncreaseUnlockTime","newUnlockTime","buildWithdrawAll","buildClaim","user","STAKING_REWARD_DISTRIBUTOR_ADDRESS","buildBalanceOfCallData","account","buildAllowanceCallData","owner","buildLocksCallData","decodeAbiParameters","requestId","rpcRequest","method","params","rpcUrl","res","json","ethCall","tx","readUint256","OPTIMISM_RPC_URL","result","value","decodeAbiParameters","estimateGas","from","estimate","waitForTx","txHash","intervalMs","timeoutMs","start","receipt","err","r","readLocks","amount","end","transferredAmount","getBaseUrl","FOUNDATION_API_URL","fetchStaking","address","url","res","fetchStakeWeight","formatUnits","formatWCT","amount","raw","formatUnits","formatDate","timestamp","calculateAPY","stakeWeight","calculateWeeklyAPY","baseAPY","weeks","label","key","value","computeUnlockTime","weeks","now","sendTx","wallet","from","tx","gas","estimateGas","CAIP2_CHAIN_ID","stake","address","amount","amountWei","parseUnits","requestedUnlockTime","lock","readLocks","buildLocksCallData","hasPosition","label","formatWCT","formatDate","effectiveUnlockTime","extendingTime","readUint256","buildAllowanceCallData","STAKE_WEIGHT_ADDRESS","approveTxHash","buildApprove","waitForTx","txHash","buildUpdateLock","buildIncreaseLockAmount","buildCreateLock","unstake","staking","fetchStaking","unlocksAt","buildWithdrawAll","claim","buildClaim","status","stakeWeightRes","fetchStakeWeight","pos","durationWeeks","stakeWeight","baseAPY","calculateAPY","weeklyAPY","calculateWeeklyAPY","balance","bal","buildBalanceOfCallData"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@walletconnect/staking-cli",
|
|
3
|
+
"description": "WalletConnect WCT staking CLI — stake, unstake, claim rewards from the terminal",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"private": false,
|
|
6
|
+
"author": "WalletConnect, Inc. <walletconnect.com>",
|
|
7
|
+
"license": "SEE LICENSE IN LICENSE.md",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "dist/index.cjs",
|
|
10
|
+
"module": "dist/index.js",
|
|
11
|
+
"types": "dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"require": "./dist/index.cjs"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": ["dist"],
|
|
20
|
+
"keywords": [
|
|
21
|
+
"walletconnect",
|
|
22
|
+
"wct",
|
|
23
|
+
"staking",
|
|
24
|
+
"cli",
|
|
25
|
+
"terminal",
|
|
26
|
+
"optimism",
|
|
27
|
+
"web3"
|
|
28
|
+
],
|
|
29
|
+
"bin": {
|
|
30
|
+
"walletconnect-staking": "dist/cli.js"
|
|
31
|
+
},
|
|
32
|
+
"sideEffects": false,
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsup",
|
|
35
|
+
"test": "vitest run --dir test --reporter=verbose",
|
|
36
|
+
"lint": "eslint --fix 'src/**/*.ts'",
|
|
37
|
+
"prettier": "prettier --check '{src,test}/**/*.{js,ts,jsx,tsx}'"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@walletconnect/cli-sdk": "*",
|
|
41
|
+
"viem": "^2.30.0"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^25.2.3",
|
|
45
|
+
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
46
|
+
"@typescript-eslint/parser": "^8.0.0",
|
|
47
|
+
"eslint": "^9.0.0",
|
|
48
|
+
"tsup": "^8.0.0",
|
|
49
|
+
"typescript": "^5.5.0",
|
|
50
|
+
"vitest": "^3.2.0"
|
|
51
|
+
}
|
|
52
|
+
}
|