Skip to content

ODbeke/Splipha

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

33 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Pharos Payment Splitter Skill

A clean, production-grade API Skill for the Pharos AI Agent Carnival hackathon. It exposes a single deployable HTTP endpoint that sequentially splits USDC or native PROS payments from a funding wallet to multiple recipients on Pharos Mainnet without taking custody of any funds.

Live Demo

This Skill is deployed and running on Railway: https://splipha-production.up.railway.app/

Warning

The deployed instance uses a Skill Wallet funded with a small amount of PROS/USDC for demonstration purposes only. Please test using very small sandbox amounts (e.g. 0.01 PROS / 0.01 USDC) to verify execution and avoid draining the sandbox. For production use or to test with larger sums, clone this repo and run it with your own SKILL_PRIVATE_KEY in environment variables.

Standardized Skill Specification

This module complies with the Pharos Standardized Skill Specification and includes a machine-readable OpenAPI 3.0 descriptor:

  • OpenAPI Schema File: openapi.json

This schema allows frameworks, testing tools, and future Phase 2 AI Agents to automatically discover, validate, and orchestrate calls to this skill's endpoints.

Architecture & Data Flow

graph TD
    A[Caller Request] --> B[Pre-flight Validation validate.ts]
    B -->|Check 1-6: Formats & Bounds| C{Passed?}
    C -->|No| D[Return 400 Bad Request]
    C -->|Yes| E[Check 7-8: Onchain Balances & Allowance]
    E -->|Failed| D
    E -->|Passed| F[Execution Engine splitter.ts]
    F -->|Sequential Tx 1| G[Pharos Mainnet]
    G -->|Receipt Success| H[Sequential Tx 2]
    H -->|Receipt Success| I[Return 200 OK + explorerUrls]
    F -->|Any Tx Reverts| J[Halt Immediately + Return partial success & failedAt details]
Loading

Pre-flight Validation Checklist

All validations run in src/validate.ts before any transaction is submitted onchain to protect callers from wasting gas fees:

  • Local Input Validations (Checks 1-6): In-memory checks completed instantly without network calls.
    1. Token: Must be exactly "PROS" or "USDC".
    2. Caller Address: Must be a valid EVM address format (/^0x[a-fA-F0-9]{40}$/).
    3. Recipient Addresses: All recipient addresses must be valid EVM format.
    4. Duplicates: No duplicate recipient addresses allowed.
    5. Amounts: All amounts must be positive, non-zero integer strings.
    6. Recipient Count: Must have between 2 and 20 recipients.
  • Onchain Network Validations (Checks 7-8): Queries live blockchain state via Pharos RPC. 7. Balance: Verifies the caller has enough tokens (including gas reserves for PROS splits). 8. Allowance: Verifies the caller has approved the Skill Wallet (USDC only).

Security & Safety Design

Splipha is engineered following strict security principles for financial skill modules:

  • Zero-Custody Architecture: The API is completely stateless and does not store private keys, session data, or tokens. It acts strictly as an execution router.
  • Onchain Checksum Protection: All inputs undergo lowercase normalization to prevent transaction failures caused by invalid EIP-55 checksum formats.
  • Sequential Atomic-Halting: Transactions are executed one-by-one. If a transaction fails mid-execution, the loop terminates immediately, returning the exact transaction index that failed and listing all successful transfers to avoid silent partial executions.

Network Details

  • Network Name: Pharos Mainnet
  • Chain ID: 1672
  • RPC URL: https://rpc.pharos.xyz
  • Block Explorer: https://pharosscan.xyz

Supported Tokens

Token Decimals Contract Address
PROS 18 Native Token
USDC 6 0xc879c018db60520f4355c26ed1a6d572cdac1815 (ERC-20, verified on PharosScan)

Precision & Decimals

To prevent floating-point rounding errors in JavaScript, all arithmetic is executed using native BigInt operations. Amounts in API requests must be passed in the token's smallest atomic unit:

  • USDC (6 Decimals):
    • Formula: $\text{Units} = \text{Amount} \times 10^6$
    • Example: To send 1.5 USDC, write "1500000"
  • PROS (18 Decimals):
    • Formula: $\text{Units} = \text{Amount} \times 10^{18}$
    • Example: To send 0.01 PROS, write "10000000000000000"

API Endpoints

1. Health Check

  • Endpoint: GET /health
  • Response:
{
  "status": "ok",
  "network": "Pharos Mainnet",
  "chainId": 1672,
  "supportedTokens": ["PROS", "USDC"]
}
  • cURL Command:
curl http://localhost:3000/health

2. Check Wallet Balance

  • Endpoint: GET /balance/:address
  • Response:
{
  "address": "0x1234567890123456789012345678901234567890",
  "PROS": "2300000000000000000",
  "USDC": "450000000"
}
  • cURL Command:
curl http://localhost:3000/balance/0x1234567890123456789012345678901234567890

3. Split Payments

  • Endpoint: POST /split
  • Request Format:
    • Minimum 2 recipients, maximum 20 recipients.
    • All amounts must be strings representing integers in the token's smallest unit (6 decimals for USDC, 18 decimals for PROS).
    • For USDC: callerAddress must have previously approved the Skill Wallet as a spender.
    • For PROS: callerAddress must match the Skill Wallet address since native transfers are executed directly from the transaction signer.

USDC Split Example Request (Verified Live on Pharos Mainnet)

curl -X 'POST' \
  'http://localhost:3000/split' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "token": "USDC",
  "callerAddress": "0xf9D38027Ace9abe0072d231F17d73850A96c3bBf",
  "recipients": [
    {
      "address": "0xBE3BC24E08e7f1335f06C36C0D7aE52a374Adb3b",
      "amount": "100000"
    },
    {
      "address": "0x2BFD1D773DB1b5e9A72ad918b4ECAF58f6D91760",
      "amount": "100000"
    },
    {
      "address": "0x325d336F21abB3011ea65Ea67C34E02083c73Bad",
      "amount": "100000"
    },
    {
      "address": "0xa991beDe7A2995B76C6C97fcC226dFbac358EE5B",
      "amount": "100000"
    }
  ]
}'

Success Response (200 OK)

{
  "success": true,
  "token": "USDC",
  "totalDistributed": "400000",
  "transfers": [
    {
      "to": "0xBE3BC24E08e7f1335f06C36C0D7aE52a374Adb3b",
      "amount": "100000",
      "txHash": "0x0a7108d5a7556922f20be902cd4e04e45497b1ae90794e19d37d5cc699162065",
      "explorerUrl": "https://pharosscan.xyz/tx/0x0a7108d5a7556922f20be902cd4e04e45497b1ae90794e19d37d5cc699162065"
    },
    {
      "to": "0x2BFD1D773DB1b5e9A72ad918b4ECAF58f6D91760",
      "amount": "100000",
      "txHash": "0xa48369bef81f08b29bbd680f5c234da73e4b23d67f0efed2307910242749c330",
      "explorerUrl": "https://pharosscan.xyz/tx/0xa48369bef81f08b29bbd680f5c234da73e4b23d67f0efed2307910242749c330"
    },
    {
      "to": "0x325d336F21abB3011ea65Ea67C34E02083c73Bad",
      "amount": "100000",
      "txHash": "0xe407a71823ff6a4a87029053283a2540a6f6546b0438a4105659727f19531ec4",
      "explorerUrl": "https://pharosscan.xyz/tx/0xe407a71823ff6a4a87029053283a2540a6f6546b0438a4105659727f19531ec4"
    },
    {
      "to": "0xa991beDe7A2995B76C6C97fcC226dFbac358EE5B",
      "amount": "100000",
      "txHash": "0x6c0433be5b45be97a456781c1e9ed54040a4121f10cd44ed747600f480ba8fd4",
      "explorerUrl": "https://pharosscan.xyz/tx/0x6c0433be5b45be97a456781c1e9ed54040a4121f10cd44ed747600f480ba8fd4"
    }
  ]
}

PROS Split Example Request (Verified Live on Pharos Mainnet)

curl -X 'POST' \
  'http://localhost:3000/split' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "token": "PROS",
  "callerAddress": "0xf9D38027Ace9abe0072d231F17d73850A96c3bBf",
  "recipients": [
    {
      "address": "0xBE3BC24E08e7f1335f06C36C0D7aE52a374Adb3b",
      "amount": "10000000000000000"
    },
    {
      "address": "0x2BFD1D773DB1b5e9A72ad918b4ECAF58f6D91760",
      "amount": "10000000000000000"
    },
    {
      "address": "0x325d336F21abB3011ea65Ea67C34E02083c73Bad",
      "amount": "10000000000000000"
    },
    {
      "address": "0xa991beDe7A2995B76C6C97fcC226dFbac358EE5B",
      "amount": "10000000000000000"
    }
  ]
}'

PROS Split Success Response (200 OK)

{
  "success": true,
  "token": "PROS",
  "totalDistributed": "40000000000000000",
  "transfers": [
    {
      "to": "0xBE3BC24E08e7f1335f06C36C0D7aE52a374Adb3b",
      "amount": "10000000000000000",
      "txHash": "0xd33be01a4d36255da5e079468dbea038192e36e71bbc71806e54e8faede90f8d",
      "explorerUrl": "https://pharosscan.xyz/tx/0xd33be01a4d36255da5e079468dbea038192e36e71bbc71806e54e8faede90f8d"
    },
    {
      "to": "0x2BFD1D773DB1b5e9A72ad918b4ECAF58f6D91760",
      "amount": "10000000000000000",
      "txHash": "0x3f0d34bde7fbe0bae0c5786544484ab2928350f628165abe89f8e49f5c8e91b9",
      "explorerUrl": "https://pharosscan.xyz/tx/0x3f0d34bde7fbe0bae0c5786544484ab2928350f628165abe89f8e49f5c8e91b9"
    },
    {
      "to": "0x325d336F21abB3011ea65Ea67C34E02083c73Bad",
      "amount": "10000000000000000",
      "txHash": "0xd55415c4c4e406983690a0d6512b57dc23a2fb85b051d6c536038a448e7d8cda",
      "explorerUrl": "https://pharosscan.xyz/tx/0xd55415c4c4e406983690a0d6512b57dc23a2fb85b051d6c536038a448e7d8cda"
    },
    {
      "to": "0xa991beDe7A2995B76C6C97fcC226dFbac358EE5B",
      "amount": "10000000000000000",
      "txHash": "0x6610f7269f0493011f572f1d69a932f3fed0e54d1c3b55935d9af002a5e538a2",
      "explorerUrl": "https://pharosscan.xyz/tx/0x6610f7269f0493011f572f1d69a932f3fed0e54d1c3b55935d9af002a5e538a2"
    }
  ]
}

How to Approve USDC Spending (Prerequisite for USDC Splits)

Before executing a USDC split, the USDC owner wallet (callerAddress) must grant a spending allowance to the Skill Wallet address (your deployed server address, e.g. 0xf9D38027Ace9abe0072d231F17d73850A96c3bBf on the live sandbox demo).

You can easily execute this approval on the block explorer:

  1. Go to the USDC Contract on PharosScan: USDC Contract Write Tab.
  2. Click "Connect to Web3" and connect your wallet containing the USDC.
  3. Locate the approve function and fill in:
    • spender: The public address of your Skill Wallet (the address executing transactions).
    • value: The total amount of USDC you want to authorize in atomic units (6 decimals. E.g. 1000000 for 1.0 USDC, or 10000 for 0.01 USDC).
  4. Click "Write" and confirm the transaction in your wallet.

Once that transaction is confirmed, you are fully authorized to call /split for USDC!


Local Setup & Development

  1. Clone the workspace / folder:

    cd payment-splitter-skill
  2. Install dependencies:

    npm install
  3. Configure Environment Variables: Create a .env file based on .env.example:

    cp .env.example .env

    Open .env and set your SKILL_PRIVATE_KEY.

  4. Start the API server:

    npm start
  5. Build the production bundle:

    npm run build

About

A standardized, non-custodial TypeScript API Skill for splitting native PROS or ERC-20 USDC payments directly to multiple recipients on Pharos Mainnet. Features Swagger UI & OpenAPI 3.0. Built for the Pharos AI Agent Carnival.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors