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:
- Parse Inputs: Extracts the amount and merchant address from the user's request.
- Validate Merchant Address: Confirms that the merchant is a valid EVM address; otherwise it aborts.
- Pre-Flight Checks (BorrowerManager):
- Verifies the borrower is registered and active.
- Checks if the credit limit (agent spend limit) is sufficient for the requested amount.
- On demand, can auto-register the agent once via
registerAgent.
- Generate Authorization: Creates an EIP-712 typed data message for the payment.
- Sign Off-Chain: Uses the configured
PRIVATE_KEY wallet (from environment variables) to sign the authorization message.
- Execute On-Chain: Calls the
spendWithAuthorization function on the Creditor contract, providing the signed message.
- 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, agentSpendLimit.
- 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 agent spend limit
- 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:
- Pre-flight checks:
- Verifies the borrower is registered and active.
- Reads current credit limit and any existing outstandingDebt`.
- 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.
- 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.
- 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:
0xa7cf4D816183F5fC48e46Ccdaeea77311c69B568
- Borrower Manager:
0xa891C7F98e3Eb42cB61213F28f3B8Aa13a8Be435
- Asset (USDC):
0xB8c7a6A36978a7f9dc2C80e44533e7f17e271864 (6 decimals)
- Payment Plan ID:
0
Setup, Installation & Dependencies
This skill is a small Node.js project under skills/sohopay.
Set PRIVATE_KEY in the environment where OpenClaw runs:
export PRIVATE_KEY=0xYOUR_KEY_HERE
This address will be the SOHO Pay "agent" on Base mainnet / Base Sepolia.
Install the skill and dependencies:
clawhub install sohopay
cd skills/sohopay
npm install
This installs the runtime dependencies declared in package.json (currently ethers and dotenv).
Register the agent once on the chosen network (before making payments):
# 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.
Make payments after registration using scripts/pay.js:
# 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.
Check status / profile and balances using scripts/status.js:
# 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).
Repay outstanding debt using USDC with scripts/repay.js:
# 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.
1---2name: sohopay3description: Initiate payments on the SOHO Pay credit layer using EIP-712 signatures.4---5
6# SOHO Pay - Credit Layer Payments
7
8This skill allows the agent to initiate payments through the SOHO Pay `Creditor` smart contract using the `spendWithAuthorization` EIP-712 flow.
9
10The 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.
11
12## Core Command
13
14The primary way to use this skill is with a natural language command that maps to:
15
16`pay <amount> to <merchant_address>`
17
18- `<amount>`: The numerical amount to pay (e.g., `10`, `0.5`).
19- `<merchant_address>`: The recipient EVM address (`0x...`). **Names are not supported** and no random addresses are ever generated by this skill.
20
21## Workflow
22
23### Payments (credit spend)
24
25When you issue a `pay` command, the skill performs the following actions:
26
271. **Parse Inputs**: Extracts the amount and merchant address from the user's request.
282. **Validate Merchant Address**: Confirms that the merchant is a valid EVM address; otherwise it aborts.
293. **Pre-Flight Checks** (BorrowerManager):
30 - Verifies the borrower is **registered** and **active**.
31 - Checks if the **credit limit** (agent spend limit) is sufficient for the requested amount.
32 - On demand, can auto-register the agent once via `registerAgent`.
334. **Generate Authorization**: Creates an EIP-712 typed data message for the payment.
345. **Sign Off-Chain**: Uses the configured `PRIVATE_KEY` wallet (from environment variables) to sign the authorization message.
356. **Execute On-Chain**: Calls the `spendWithAuthorization` function on the `Creditor` contract, providing the signed message.
367. **Report Result**: Returns the transaction hash to the user upon confirmation.
37
38### Status / Profile checks
39
40The `status` helper reads the **BorrowerManager** profile + USDC wallet balance for the bot:
41
42- Calls the `s_borrowerProfiles(address)` public mapping getter to fetch:
43 `creditLimit, outstandingDebt, totalSpent, totalRepaid, spendingCount, repaymentCount, lastActivityTime, creditScore, isActive, agentSpendLimit`.
44- Calls `IERC20(USDC).balanceOf(bot)` to fetch the **USDC wallet balance** for the same address.
45- Prints a human-readable summary so you can see, per network:
46 - Whether the bot is registered / active
47 - Credit limit and **agent spend limit**
48 - **Outstanding debt** and historical spend/repay totals
49 - Last activity timestamp and credit score
50 - USDC balance available in the wallet
51
52This is what powers prompts like:
53
54- `"check my bot status on testnet"`
55- `"check my bot outstanding debt on mainnet"`
56
57### Repayments (reduce outstanding debt)
58
59The `repay` helper uses USDC to pay down **outstandingDebt** tracked by BorrowerManager and Creditor:
60
611. **Pre-flight checks**:
62 - Verifies the borrower is **registered** and **active**.
63 - Reads current **credit limit** and any existing **outstandingDebt`**.
642. **USDC balance & allowance**:
65 - Ensures the bot wallet has enough **USDC balance** for the requested repayment.
66 - Checks `IERC20(USDC).allowance(bot, Creditor)` and, if too low, sends an `approve(Creditor, amount)` tx first.
673. **On-chain repay**:
68 - Calls `Creditor.repay(amount, USDC)` from the borrower wallet.
69 - The Creditor contract:
70 - Caps the repayment to `min(amount, outstandingDebt)`.
71 - Applies payments to BNPL plans via `applyPaymentToPlans`.
72 - Updates the borrower profile via `updateOnRepayment` (new score + limit).
73 - Transfers USDC from the borrower to the Vault and calls `vault.repayVaultDebt`.
74 - Emits a repayment event with the new score and limit.
754. **Status after repay**:
76 - After a successful repay, you can run `status` again to verify:
77 - `outstandingDebt` has decreased (or is `0`),
78 - `totalRepaid` increased,
79 - `creditScore` and `creditLimit` have been updated.
80
81This is what backs prompts like:
82
83- `"repay my bot debt on testnet"`
84- `"repay 5 USDC of my bot debt on mainnet"`
85
86## Configuration
87
88- **Environment Variable (runtime)**: The private key for the signing wallet must be provided via the `PRIVATE_KEY` environment variable.
89- **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.
90- **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.
91- **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.
92- **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.
93
94## Defaults
95
96The following values are hardcoded into the script for consistency, and are used on **both** Base mainnet and Base Sepolia:
97
98- **Creditor Contract**: `0xa7cf4D816183F5fC48e46Ccdaeea77311c69B568`
99- **Borrower Manager**: `0xa891C7F98e3Eb42cB61213F28f3B8Aa13a8Be435`
100- **Asset (USDC)**: `0xB8c7a6A36978a7f9dc2C80e44533e7f17e271864` (6 decimals)
101- **Payment Plan ID**: `0`
102
103## Setup, Installation & Dependencies
104
105This skill is a small Node.js project under `skills/sohopay`.
106
1071. **Set `PRIVATE_KEY`** in the environment where OpenClaw runs:
108 ```bash
109 export PRIVATE_KEY=0xYOUR_KEY_HERE
110 ```
111 This address will be the SOHO Pay "agent" on Base mainnet / Base Sepolia.
112
1132. **Install the skill and dependencies**:
114 ```bash
115 clawhub install sohopay
116 cd skills/sohopay
117 npm install
118 ```
119 This installs the runtime dependencies declared in `package.json` (currently `ethers` and `dotenv`).
120
1213. **Register the agent once on the chosen network** (before making payments):
122 ```bash
123 # Base mainnet (default)
124 node scripts/register.js
125
126 # Explicit mainnet
127 node scripts/register.js mainnet
128
129 # Base Sepolia testnet
130 node scripts/register.js testnet
131 ```
132 This calls `registerAgent(agent)` on the `BorrowerManager` contract using the `PRIVATE_KEY` address.
133
1344. **Make payments after registration** using `scripts/pay.js`:
135 ```bash
136 # Base mainnet (default when no network arg is given)
137 node scripts/pay.js 10 0xMerchantOnMainnet
138
139 # Explicit mainnet
140 node scripts/pay.js mainnet 10 0xMerchantOnMainnet
141
142 # Base Sepolia testnet
143 node scripts/pay.js testnet 10 0xMerchantOnTestnet
144 ```
145 This uses the SOHO Pay Creditor contract to spend on credit via `spendWithAuthorization`.
146
1475. **Check status / profile and balances** using `scripts/status.js`:
148 ```bash
149 # Base mainnet
150 node scripts/status.js mainnet
151
152 # Base Sepolia testnet
153 node scripts/status.js testnet
154 ```
155 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).
156
1576. **Repay outstanding debt using USDC** with `scripts/repay.js`:
158 ```bash
159 # Base mainnet
160 node scripts/repay.js mainnet 10
161
162 # Base Sepolia testnet
163 node scripts/repay.js testnet 10
164 ```
165 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.
166
167## Security Notes
168
169- **`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.
170- **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.
171- 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`.
172- 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.
173- No random address generation is performed. The skill will refuse non-address merchant inputs.
174
175## Example Usage
176
177### Natural-language commands
178
179These are the kinds of prompts you can send to your OpenClaw agent once the skill is installed and `PRIVATE_KEY` is configured.
180
181- **Register bot (testnet)**
182 `"register my bot to use sohopay on Base Sepolia testnet"`
183
184- **Register bot (mainnet)**
185 `"register my bot to use sohopay on Base mainnet"`
186
187- **Pay a merchant** (EIP‑712 spendWithAuthorization)
188 `"pay 10 USDC to 0x1234567890abcdef1234567890abcdef12345678 on testnet using sohopay"`
189
190- **Check bot status** (credit limit, outstanding debt, totals, USDC balance)
191 `"check my bot status on testnet"`
192 `"check my bot outstanding debt on mainnet"`
193
194- **Repay debt** (calls `Creditor.repay(amount, stablecoin)`)
195 `"repay my bot debt on testnet"`
196 `"repay 5 USDC of my bot debt on mainnet"`
197
198### Script entrypoints (for reference)
199
200- Registration: `node scripts/register.js [mainnet|testnet] [check]`
201 - `node scripts/register.js testnet` – register bot on Base Sepolia
202 - `node scripts/register.js mainnet check` – status only, no tx
203
204- Payments (credit spend):
205 - `node scripts/pay.js [mainnet|testnet] <amount> <merchant_address>`
206
207- Status (profile + outstanding debt + USDC balance):
208 - `node scripts/status.js mainnet`
209 - `node scripts/status.js testnet`
210
211- Repayments (reduce outstanding debt using USDC):
212 - `node scripts/repay.js [mainnet|testnet] <amount>`
213
214When mapped through OpenClaw, you should prefer **natural-language prompts**; the scripts above are provided for debugging and manual CLI use.