Skill: nmsteve/sohopay (version 1.0.17)

--- name: sohopay description: "Initiate payments on the SOHO Pay credit layer using EIP-712 signatures." --- # SOHO Pay - Credit Layer Payments This skill allows the agent to initiate payments through the SOHO Pay `Creditor` smart contract using the `spendWithAuthorization` EIP-712 flow. The agent signs the payment authorization off-chain using a pre-configured wallet, and then submits the transaction to the network on the user's behalf. ## Core Command The primary way to use this skill is with a natural language command that maps to: `pay <amount> to <merchant_address>` - `<amount>`: The numerical amount to pay (e.g., `10`, `0.5`). - `<merchant_address>`: The recipient EVM address (`0x...`). **Names are not supported** and no random addresses are ever generated by this skill. ## Workflow ### Payments (credit spend) When you issue a `pay` command, the skill performs the following actions: 1. **Parse Inputs**: Extracts the amount and merchant address from the user's request. 2. **Validate Merchant Address**: Confirms that the merchant is a valid EVM address; otherwise it aborts. 3. **Pre-Flight Checks** (BorrowerManager): - Verifies the borrower is **registered** and **active**. - Checks if the **credit limit** is sufficient for the requested amount. - On demand, can auto-register the agent once via `registerAgent`. 4. **Generate Authorization**: Creates an EIP-712 typed data message for the payment. 5. **Sign Off-Chain**: Uses the configured `PRIVATE_KEY` wallet (from environment variables) to sign the authorization message. 6. **Execute On-Chain**: Calls the `spendWithAuthorization` function on the `Creditor` contract, providing the signed message. 7. **Report Result**: Returns the transaction hash to the user upon confirmation. ### Status / Profile checks The `status` helper reads the **BorrowerManager** profile + USDC wallet balance for the bot: - Calls the `s_borrowerProfiles(address)` public mapping getter to fetch: `creditLimit, outstandingDebt, totalSpent, totalRepaid, spendingCount, repaymentCount, lastActivityTime, creditScore, isActive, isAgent, transactionIds`. - Calls `IERC20(USDC).balanceOf(bot)` to fetch the **USDC wallet balance** for the same address. - Prints a human-readable summary so you can see, per network: - Whether the bot is registered / active - Credit limit and whether the profile is flagged as an agent - **Outstanding debt** and historical spend/repay totals - Last activity timestamp and credit score - USDC balance available in the wallet This is what powers prompts like: - `"check my bot status on testnet"` - `"check my bot outstanding debt on mainnet"` ### Repayments (reduce outstanding debt) The `repay` helper uses USDC to pay down **outstandingDebt** tracked by BorrowerManager and Creditor: 1. **Pre-flight checks**: - Verifies the borrower is **registered** and **active**. - Reads current **credit limit** and any existing **outstandingDebt`**. 2. **USDC balance & allowance**: - Ensures the bot wallet has enough **USDC balance** for the requested repayment. - Checks `IERC20(USDC).allowance(bot, Creditor)` and, if too low, sends an `approve(Creditor, amount)` tx first. 3. **On-chain repay**: - Calls `Creditor.repay(amount, USDC)` from the borrower wallet. - The Creditor contract: - Caps the repayment to `min(amount, outstandingDebt)`. - Applies payments to BNPL plans via `applyPaymentToPlans`. - Updates the borrower profile via `updateOnRepayment` (new score + limit). - Transfers USDC from the borrower to the Vault and calls `vault.repayVaultDebt`. - Emits a repayment event with the new score and limit. 4. **Status after repay**: - After a successful repay, you can run `status` again to verify: - `outstandingDebt` has decreased (or is `0`), - `totalRepaid` increased, - `creditScore` and `creditLimit` have been updated. This is what backs prompts like: - `"repay my bot debt on testnet"` - `"repay 5 USDC of my bot debt on mainnet"` ## Configuration - **Environment Variable (runtime)**: The private key for the signing wallet must be provided via the `PRIVATE_KEY` environment variable. - **Why the private key is needed**: OpenClaw is designed to run as an autonomous agent. For it to initiate SOHO Pay transactions without human clicks, it must be able to sign EIP-712 authorizations itself. - **Local-only usage (important)**: **`PRIVATE_KEY` is used *only locally* on the machine running OpenClaw. The raw key is **never** sent to SOHO Pay, ClawHub, or any external service — only signed messages and transactions leave the machine.** Anyone running this bot must understand that the key controls whatever funds are on the selected network. - **Skill Metadata**: The skill declares `PRIVATE_KEY` as a required, sensitive credential. You can use a single key for both Base mainnet and Base Sepolia, but be aware this may control real funds on mainnet. - **Networks**: The script supports both **Base mainnet** (default) and **Base Sepolia** (testnet). It enforces the expected `chainId` for the selected network and aborts if the RPC does not match. ## Defaults The following values are hardcoded into the script for consistency, and are used on **both** Base mainnet and Base Sepolia: - **Creditor Contract**: [REDACTED_SECRET] - **Borrower Manager**: [REDACTED_SECRET] - **Asset (USDC)**: [REDACTED_SECRET] (6 decimals) - **Payment Plan ID**: `0` ## Setup, Installation & Dependencies This skill is a small Node.js project under `skills/sohopay`. 1. **Set `PRIVATE_KEY`** in the environment where OpenClaw runs: ```bash export PRIVATE_KEY=0xYOUR_KEY_HERE ``` This address will be the SOHO Pay "agent" on Base mainnet / Base Sepolia. 2. **Install the skill and dependencies**: ```bash clawhub install sohopay cd skills/sohopay npm install ``` This installs the runtime dependencies declared in `package.json` (currently `ethers` and `dotenv`). 3. **Register the agent once on the chosen network** (before making payments): ```bash # Base mainnet (default) node scripts/register.js # Explicit mainnet node scripts/register.js mainnet # Base Sepolia testnet node scripts/register.js testnet ``` This calls `registerAgent(agent)` on the `BorrowerManager` contract using the `PRIVATE_KEY` address. 4. **Make payments after registration** using `scripts/pay.js`: ```bash # Base mainnet (default when no network arg is given) node scripts/pay.js 10 0xMerchantOnMainnet # Explicit mainnet node scripts/pay.js mainnet 10 0xMerchantOnMainnet # Base Sepolia testnet node scripts/pay.js testnet 10 0xMerchantOnTestnet ``` This uses the SOHO Pay Creditor contract to spend on credit via `spendWithAuthorization`. 5. **Check status / profile and balances** using `scripts/status.js`: ```bash # Base mainnet node scripts/status.js mainnet # Base Sepolia testnet node scripts/status.js testnet ``` This reads the BorrowerManager profile and USDC wallet balance for the agent and prints a human-readable summary (credit limit, outstanding debt, totals, scores, and USDC balance). 6. **Repay outstanding debt using USDC** with `scripts/repay.js`: ```bash # Base mainnet node scripts/repay.js mainnet 10 # Base Sepolia testnet node scripts/repay.js testnet 10 ``` This uses USDC from the agent wallet to repay `outstandingDebt` via the Creditor contract, updating the borrower profile and vault debt, and emitting a repayment event. ## Security Notes - **`PRIVATE_KEY` is highly sensitive**. Treat it exactly like the key to a normal wallet: anyone with this value can move all funds it controls. - **Local signing only**: The script signs transactions **locally** and never transmits the raw private key over the network. Only signatures and transactions are sent to RPC endpoints. - This skill **never triggers itself**; it is only executed when called by a user, cron job, or higher-level workflow. It is safe to wire into autonomous flows (e.g. “if price < 10, then pay …”) as long as you understand what those automations will do with your `PRIVATE_KEY`. - The merchant must be provided as an explicit `merchant_address`. If the address is wrong, funds on that network may be irrecoverably sent to the wrong account. - No random address generation is performed. The skill will refuse non-address merchant inputs. ## Example Usage ### Natural-language commands These are the kinds of prompts you can send to your OpenClaw agent once the skill is installed and `PRIVATE_KEY` is configured. - **Register bot (testnet)** `"register my bot to use sohopay on Base Sepolia testnet"` - **Register bot (mainnet)** `"register my bot to use sohopay on Base mainnet"` - **Pay a merchant** (EIP‑712 spendWithAuthorization) `"pay 10 USDC to 0x1234567890abcdef1234567890abcdef12345678 on testnet using sohopay"` - **Check bot status** (credit limit, outstanding debt, totals, USDC balance) `"check my bot status on testnet"` `"check my bot outstanding debt on mainnet"` - **Repay debt** (calls `Creditor.repay(amount, stablecoin)`) `"repay my bot debt on testnet"` `"repay 5 USDC of my bot debt on mainnet"` ### Script entrypoints (for reference) - Registration: `node scripts/register.js [mainnet|testnet] [check]` - `node scripts/register.js testnet` – register bot on Base Sepolia - `node scripts/register.js mainnet check` – status only, no tx - Payments (credit spend): - `node scripts/pay.js [mainnet|testnet] <amount> <merchant_address>` - Status (profile + outstanding debt + USDC balance): - `node scripts/status.js mainnet` - `node scripts/status.js testnet` - Repayments (reduce outstanding debt using USDC): - `node scripts/repay.js [mainnet|testnet] <amount>` When mapped through OpenClaw, you should prefer **natural-language prompts**; the scripts above are provided for debugging and manual CLI use.


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)