@0xwork/cli 1.0.0 → 1.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/package.json +1 -1
- package/src/commands/post.js +31 -0
package/package.json
CHANGED
package/src/commands/post.js
CHANGED
|
@@ -8,6 +8,14 @@ const { fmtBounty, fmtDeadline, fmtAxobotl } = require('../format');
|
|
|
8
8
|
|
|
9
9
|
const VALID_CATEGORIES = ['Writing', 'Research', 'Code', 'Creative', 'Data', 'Social'];
|
|
10
10
|
|
|
11
|
+
// ─── Spending Guardrails ────────────────────────────────────────────
|
|
12
|
+
// Two layers of protection for agents interacting with unaudited escrow:
|
|
13
|
+
// 1. Percentage cap: never lock more than MAX_BOUNTY_PERCENT of USDC balance (default 20%)
|
|
14
|
+
// 2. Absolute cap: never post more than MAX_BOUNTY_USDC in a single task (default $50)
|
|
15
|
+
// Both can be overridden via env vars or --force flag for experienced users.
|
|
16
|
+
const DEFAULT_MAX_BOUNTY_PERCENT = parseFloat(process.env.MAX_BOUNTY_PERCENT || '20');
|
|
17
|
+
const DEFAULT_MAX_BOUNTY_USDC = parseFloat(process.env.MAX_BOUNTY_USDC || '50');
|
|
18
|
+
|
|
11
19
|
function register(program) {
|
|
12
20
|
program
|
|
13
21
|
.command('post')
|
|
@@ -16,6 +24,7 @@ function register(program) {
|
|
|
16
24
|
.requiredOption('--bounty <amount>', 'Bounty in USDC (e.g. 10)')
|
|
17
25
|
.option('--category <cat>', 'Category: Writing, Research, Code, Creative, Data, Social', 'Code')
|
|
18
26
|
.option('--deadline <dur>', 'Deadline: 7d, 24h, 30m (default: 7d)', '7d')
|
|
27
|
+
.option('--force', 'Bypass spending guardrails (percentage + absolute cap)')
|
|
19
28
|
.action(async (opts) => {
|
|
20
29
|
try {
|
|
21
30
|
await run(opts);
|
|
@@ -90,6 +99,28 @@ async function run(opts) {
|
|
|
90
99
|
fail(`Need ${fmtBounty(bountyNum)} USDC`, { suggestion: `Have: ${fmtBounty(ethers.formatUnits(usdcBalance, 6))}. Send USDC on Base to ${address}` });
|
|
91
100
|
}
|
|
92
101
|
|
|
102
|
+
// ── Spending guardrails ──
|
|
103
|
+
if (!opts.force) {
|
|
104
|
+
const balanceNum = parseFloat(ethers.formatUnits(usdcBalance, 6));
|
|
105
|
+
|
|
106
|
+
// 1. Absolute cap
|
|
107
|
+
if (bountyNum > DEFAULT_MAX_BOUNTY_USDC) {
|
|
108
|
+
s1.fail('Bounty exceeds safety cap');
|
|
109
|
+
fail(`Bounty $${bountyNum} exceeds max $${DEFAULT_MAX_BOUNTY_USDC} per task`, {
|
|
110
|
+
suggestion: `Set MAX_BOUNTY_USDC in .env to raise the limit, or use --force to bypass.`,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 2. Percentage cap
|
|
115
|
+
const pctUsed = (bountyNum / balanceNum) * 100;
|
|
116
|
+
if (pctUsed > DEFAULT_MAX_BOUNTY_PERCENT) {
|
|
117
|
+
s1.fail('Bounty exceeds balance percentage cap');
|
|
118
|
+
fail(`Bounty $${bountyNum} is ${pctUsed.toFixed(1)}% of your $${balanceNum.toFixed(2)} balance (max ${DEFAULT_MAX_BOUNTY_PERCENT}%)`, {
|
|
119
|
+
suggestion: `Set MAX_BOUNTY_PERCENT in .env to raise the limit, or use --force to bypass.`,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
93
124
|
const posterStake = await sdk.taskPool.calculatePosterStake(bountyAmount);
|
|
94
125
|
if (posterStake > 0n) {
|
|
95
126
|
const axobotlBalance = await sdk.axobotl.balanceOf(address);
|