|
| 1 | +# stackpay-contracts 🪨 |
| 2 | + |
| 3 | +> Soroban smart contracts that power **StackPay** — on-chain **payment requests**, escrowed settlement, and payment proofs on [Stellar](https://stellar.org). |
| 4 | +
|
| 5 | +[](https://github.com/Stack-Rocks/stackpay-contracts/actions) |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | + |
| 10 | +This is the **on-chain layer** of StackPay, written in **Rust** and compiled to WebAssembly for **Soroban**. |
| 11 | + |
| 12 | +--- |
| 13 | + |
| 14 | +## Table of contents |
| 15 | +- [Why StackPay (and why Stellar needs it)](#why-stackpay) |
| 16 | +- [Architecture](#architecture) |
| 17 | +- [Contract: PaymentRequest](#contract-paymentrequest) |
| 18 | +- [Core concepts](#core-concepts) |
| 19 | +- [Getting started](#getting-started) |
| 20 | +- [Building](#building) |
| 21 | +- [Testing](#testing) |
| 22 | +- [Local network](#local-network) |
| 23 | +- [Deployment](#deployment) |
| 24 | +- [Security](#security) |
| 25 | +- [Contributing](#contributing) |
| 26 | +- [License](#license) |
| 27 | + |
| 28 | +--- |
| 29 | + |
| 30 | +## Why StackPay |
| 31 | + |
| 32 | +Stellar is one of the best networks for moving money — but the ecosystem has no simple, standard way to **request** a payment and prove it settled. Sending is easy; *asking* someone to pay you (an invoice, a donation, a subscription, a split) still means copy-pasting addresses and hoping. |
| 33 | + |
| 34 | +StackPay adds that missing primitive: |
| 35 | +- A **payment request** is a tiny on-chain record: who's owed, what asset, how much, and a memo. |
| 36 | +- The payer pays; the contract settles and records a **payment proof**. |
| 37 | +- The requester shares one link; the payer pays from any Stellar wallet. |
| 38 | + |
| 39 | +Use cases: freelancer invoices, creator tips, DAO bounty payouts, event tickets, donation jars — all natively on Stellar. |
| 40 | + |
| 41 | +## Architecture |
| 42 | + |
| 43 | +``` |
| 44 | + requester ──create_request──▶ PaymentRequest (Soroban) |
| 45 | + │ emits RequestCreated |
| 46 | + ▼ |
| 47 | + payer ─────────pay──────────▶ contract pulls asset (token transfer) |
| 48 | + │ emits RequestPaid (payment proof) |
| 49 | + ▼ |
| 50 | + stackpay-backend (indexes events) |
| 51 | + │ |
| 52 | + ▼ |
| 53 | + stackpay-frontend (dApp: links, status) |
| 54 | +``` |
| 55 | + |
| 56 | +- **PaymentRequest** holds requests and performs the asset transfer via the Stellar Asset Contract (SAC) token client. |
| 57 | +- Events are indexed off-chain by [`stackpay-backend`](https://github.com/Stack-Rocks/stackpay-backend) and surfaced in the dApp. |
| 58 | + |
| 59 | +## Contract: PaymentRequest |
| 60 | + |
| 61 | +| Function | Description | |
| 62 | +| --- | --- | |
| 63 | +| `create_request(payee, asset, amount, memo, expires_in)` | Create a new request; returns `request_id`. | |
| 64 | +| `pay(request_id)` | Payer transfers `amount` of `asset` to `payee`; marks `Paid`, emits `RequestPaid`. | |
| 65 | +| `cancel(request_id)` | Requester cancels an unpaid, unexpired request. | |
| 66 | +| `get_request(request_id)` | View: full request state. | |
| 67 | +| `status(request_id)` | View: `Open` / `Paid` / `Cancelled` / `Expired`. | |
| 68 | + |
| 69 | +All amounts use Stroops (7 decimals) for XLM and the asset's own decimals. `asset` is the Stellar Asset Contract address for the asset being requested. |
| 70 | + |
| 71 | +## Core concepts |
| 72 | + |
| 73 | +- **Request** — `{ id, payee, asset, amount, memo, status, created_at, expires_at }`. |
| 74 | +- **Payment proof** — once `pay` succeeds, the `RequestPaid` event + on-chain `Paid` status is the immutable receipt. |
| 75 | +- **Expiry** — requests can auto-expire; only unpaid, unexpired requests are payable. |
| 76 | + |
| 77 | +## Getting started |
| 78 | + |
| 79 | +Prerequisites: |
| 80 | +- [Rust](https://rustup.rs/) with `wasm32-unknown-unknown`. |
| 81 | +- [Stellar CLI](https://developers.stellar.org/docs/build/guides/cli) (includes Soroban support): |
| 82 | + |
| 83 | +```bash |
| 84 | +rustup target add wasm32-unknown-unknown |
| 85 | +``` |
| 86 | + |
| 87 | +Clone & build: |
| 88 | +```bash |
| 89 | +git clone https://github.com/Stack-Rocks/stackpay-contracts.git |
| 90 | +cd stackpay-contracts |
| 91 | +make build |
| 92 | +``` |
| 93 | + |
| 94 | +## Building |
| 95 | +```bash |
| 96 | +make build # -> target/wasm32-unknown-unknown/release/stackpay_contracts.wasm |
| 97 | +make optimize # smaller wasm |
| 98 | +``` |
| 99 | + |
| 100 | +## Testing |
| 101 | +Unit tests use `soroban-sdk` testutils (in-memory ledger): |
| 102 | +```bash |
| 103 | +make test |
| 104 | +``` |
| 105 | +Example: |
| 106 | +```rust |
| 107 | +#[test] |
| 108 | +fn pay_marks_paid() { |
| 109 | + // create request, pay with token client, assert status == Paid |
| 110 | +} |
| 111 | +``` |
| 112 | + |
| 113 | +## Local network |
| 114 | +```bash |
| 115 | +stellar network container start # local sandbox |
| 116 | +stellar contract deploy --wasm target/.../stackpay_contracts.wasm --network local |
| 117 | +``` |
| 118 | + |
| 119 | +## Deployment |
| 120 | +1. Build + optimize wasm. |
| 121 | +2. Deploy to **Testnet** for staging, then **Mainnet**. |
| 122 | +3. Publish the contract id to `stackpay-backend` via its `.env`. |
| 123 | + |
| 124 | +## Security |
| 125 | +- Asset transfers use the official SAC token client (no custom token logic). |
| 126 | +- `require_auth` on every state-changing call. |
| 127 | +- Intended for audit before mainnet (see `docs/security.md`, WIP). |
| 128 | + |
| 129 | +## Contributing |
| 130 | +Part of the **Stellar Wave Program** on Drips. Look for `Stellar Wave` / `Good first issue` labels. Run `make test && make lint` before a PR. |
| 131 | + |
| 132 | +## License |
| 133 | +[MIT](./LICENSE). |
0 commit comments