Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .env.deploy.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ FEE_ACCOUNT=
# Contract caps at 1000 (10%) per audit L4 (2026-06 Stellar-skill audit).
FEE_BPS=250

# Initial credit balance for newly-bootstrapped profiles (u32).
# Per boundless-credits-reputation-prd.md the default is 10.
BOOTSTRAP_CREDITS=10
# Contract 1.0.0 also required BOOTSTRAP_CREDITS here. The 1.1.0
# credit-removal upgrade (2026-06) moved credits to an off-chain ledger in
# boundless-nestjs; the profile constructor now takes only --admin.
135 changes: 0 additions & 135 deletions .github/workflows/contract-deploy.yml

This file was deleted.

20 changes: 1 addition & 19 deletions .github/workflows/rustfmt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,12 @@ on:
branches:
- main
- develop
- testnet
pull_request:
branches:
- main
- develop
- testnet
workflow_call:
secrets:
STELLAR_SECRET_KEY:
required: true
SOROBAN_SECRET_KEY:
required: true
CONTRACT_ID:
required: false

permissions:
contents: read
Expand All @@ -41,14 +34,3 @@ jobs:

- name: Run rustfmt
run: cargo fmt -- --check

deploy:
needs: rustfmt
# Never deploy from a PR run. Deploy only on direct pushes (the workflow
# is chained here for the push-to-branch CD path, not for PR checks).
if: github.event_name == 'push'
uses: ./.github/workflows/contract-deploy.yml
secrets:
STELLAR_SECRET_KEY: ${{ secrets.STELLAR_SECRET_KEY }}
SOROBAN_SECRET_KEY: ${{ secrets.SOROBAN_SECRET_KEY }}
CONTRACT_ID: ${{ secrets.CONTRACT_ID }}
12 changes: 1 addition & 11 deletions .github/workflows/verify-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
branches:
- main
- develop
- testnet
paths:
- 'contracts/**'
- '.github/workflows/verify-build.yml'
Expand Down Expand Up @@ -57,14 +58,3 @@ jobs:

- name: Run tests
run: cargo test --release

rustfmt:
needs: build
# On PRs the standalone rustfmt workflow posts the `rustfmt` check; this
# chained call (which fans out to deploy) runs only on push, never on a PR.
if: success() && github.event_name == 'push'
uses: ./.github/workflows/rustfmt.yml
secrets:
STELLAR_SECRET_KEY: ${{ secrets.STELLAR_SECRET_KEY }}
SOROBAN_SECRET_KEY: ${{ secrets.SOROBAN_SECRET_KEY }}
CONTRACT_ID: ${{ secrets.CONTRACT_ID }}
62 changes: 34 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,28 @@ Two contracts in one workspace.

| Contract | Path | Purpose |
|----------|------|---------|
| `boundless-events` | `contracts/events` | Event records (hackathon, bounty, grant) and inlined escrow. Multi-token whitelist. Idempotency. Per-pillar dispatch on a single canonical `create_event`. |
| `boundless-profile` | `contracts/profile` | Per-user credits and reputation. Lazy bootstrap. Per-token earnings tracking. Mutated almost exclusively by the events contract. |
| `boundless-events` | `contracts/events` | Event records for the four pillars (hackathon, bounty, grant, crowdfunding) with inlined escrow. Multi-token whitelist. Idempotent operations. Per-pillar dispatch on a single canonical `create_event`. Paged cancellation and timelocked upgrades. |
| `boundless-profile` | `contracts/profile` | Per-user reputation and per-token earnings. Lazy profile bootstrap. Mutated almost exclusively by the events contract. |

Specs live in the platform PRD set under the parent `boundless-repos/` directory:
## Deployments

- `boundless-platform-contract-prd.md` (events contract)
- `boundless-credits-reputation-prd.md` (profile contract)
- `boundless-chain-abstraction-adr.md` (off-chain readiness for a future second chain)
- `boundless-organizer-end-to-end-prd.md` (umbrella; everything organizer-side)
| Network | Contract | Address | Version |
|---------|----------|---------|---------|
| Mainnet | `boundless-events` | `CCFVEGOQJEM47LRAJU2LHEK4KTL5VYN7AOGZ2HH2GNHAMXTILNMMJGQZ` | `1.1.0` |
| Mainnet | `boundless-profile` | `CD3KH4OE7HDHHHUYFX3U4L7NLIILMXAY6HM5FEH2UH6UBOKX4HDNE3PC` | `1.1.0` |
| Testnet | `boundless-events` | `CBEODVJGUYCIYTVXD7KI5UG3BJ2UE4T7AGI2TGY3T4Q5GQRFGTRYVTZP` | `1.0.0` |
| Testnet | `boundless-profile` | `CCA3OAIBOZBUPHPRI5GI6N5PDTE7RTNLKAEID4JTC2YZIHIZNDX5Q6T3` | `1.0.0` |

Both contracts expose an on-chain `version()` view; the versions above are live reads.

## Architecture in one paragraph

The events contract is the on-chain anchor of event existence, key terms, escrow custody, submission anchors, and winner records. The profile contract is the on-chain anchor of credit balances and reputation scores. The events contract calls into the profile contract for credit charging on apply, credit earning on accept, and reputation bumping on win. The off-chain orchestrator (`boundless-nestjs`) handles everything else: drafts, rich content via `content_uri`, KYC, role policies, AI features, moderation. The contracts hold the things the platform cannot afford to be trusted on; nestjs holds the things that benefit from iteration speed.
The events contract is the on-chain anchor of event existence, key terms, escrow custody, submission anchors, and winner records. Funds enter escrow at creation (or through top-ups), fees are taken at deposit, and payouts release through `select_winners` or per-milestone claims. The profile contract is the on-chain anchor of reputation scores and per-token earnings. The events contract calls into the profile contract to bootstrap profiles on first touch, bump reputation on wins and milestones, and register earnings on payout. Every state-mutating operation carries an idempotency key, admin surfaces are pausable, and upgrades are timelocked.

## Prerequisites

- Rust 1.90.0 (`rust-toolchain.toml` pins this).
- Soroban SDK 23.5.2.
- Soroban SDK 23.5.x (workspace-pinned in `Cargo.toml`).
- `stellar` CLI for building WASM (`brew install stellar/tap/stellar-cli`).
- `wasm32v1-none` target: `rustup target add wasm32v1-none`.

Expand All @@ -44,14 +48,17 @@ cd contracts/events && make size && cd ../..
cd contracts/profile && make size && cd ../..
```

Test snapshots under `contracts/*/test_snapshots/` are the audit trail. When fixtures change shape, regenerate snapshots intentionally and commit them in the same PR.

## Repo layout

```
boundless-contract/
├── Cargo.toml # workspace
├── rust-toolchain.toml
├── .cargo/
├── .github/workflows/ # verify, deploy, rustfmt
├── deploy_and_upgrade.sh # testnet deploy / upgrade helper
├── deploy_mainnet.sh # mainnet cold deploy
├── .github/workflows/ # verify-build, rustfmt, deploy
├── contracts/
│ ├── events/
│ │ ├── Cargo.toml
Expand All @@ -62,48 +69,47 @@ boundless-contract/
│ │ ├── errors.rs # error code enum
│ │ ├── events.rs # contract event emissions
│ │ ├── storage.rs # persistent / temporary key helpers
│ │ ├── admin.rs # init, rotation, pause, upgrade
│ │ ├── admin.rs # init, rotation, pause, timelocked upgrade
│ │ ├── token_whitelist.rs # admin-managed supported-tokens set
│ │ ├── escrow.rs # fee math, token transfer helpers
│ │ ├── event_ops.rs # canonical create / submit / select_winners
│ │ ├── hackathon.rs # pillar-specific validation
│ │ ├── bounty.rs # pillar-specific validation + apply / withdraw
│ │ ├── grant.rs # pillar-specific validation + claim_milestone
│ │ ├── crowdfunding.rs # pillar-specific validation
│ │ ├── profile_client.rs # cross-contract interface to boundless-profile
│ │ ├── idempotency.rs # OpSeen helpers + deployment-epoch ID base
│ │ └── tests/ # per-area integration tests
│ └── profile/
│ ├── Cargo.toml
│ ├── Makefile
│ └── src/
│ ├── lib.rs # contract entry, public surface
│ ├── types.rs # Profile, PendingAdmin
│ ├── types.rs # Profile, PendingAdmin, PendingUpgrade
│ ├── errors.rs
│ ├── events.rs
│ ├── storage.rs
│ ├── admin.rs # init, two-step rotations, pause, upgrade
│ ├── credits.rs # bootstrap, spend, earn, refund, admin_grant
│ ├── admin.rs # init, two-step rotations, pause, timelocked upgrade
│ ├── bootstrap.rs # lazy profile creation (bootstrap / bootstrap_self)
│ ├── reputation.rs # bump, slash, admin_slash
│ ├── earnings.rs # per-token earnings registration
│ ├── idempotency.rs # OpSeen helpers
│ └── tests/
└── docs/
└── ARCHITECTURE.md # the why
└── scripts/
├── admin/ # verify-multisig.sh
└── deploy/ # deploy.sh, register_token.sh
```

## Deployment

Two-step sequence (see `boundless-credits-reputation-prd.md` Section 13.1):

1. Deploy `boundless-profile` with `default_bootstrap_credits = 10`.
2. Deploy `boundless-events` with the profile contract's address + admin + fee_account + fee_bps.
3. Call `profile.set_events_contract(events_addr)`, then `accept_events_contract` as the events contract address.
4. Register supported tokens on `boundless-events` (USDC at launch).
## Deployment and upgrades

Deployment scripts live in `scripts/`. Mainnet deploys are multisig-gated and only after external audit clears.
Fresh deploy sequence for a new network:

## Audit
1. Deploy `boundless-profile` with the admin address.
2. Deploy `boundless-events` with the profile contract's address, admin, fee account, and fee bps.
3. Call `profile.set_events_contract(events_addr)` (first-set-only; later rotation is a timelocked two-step).
4. Register supported tokens on `boundless-events`.

External audit is the hard gate before mainnet. Audit checklist is in the platform contract PRD Section 15.3.
Upgrades are timelocked three-step operations: `propose_upgrade(wasm_hash, version)`, wait the timelock (~1 day on mainnet), `apply_upgrade()`, then `migrate()` to stamp the migration marker. A pending proposal can be inspected with `get_pending_upgrade()` and withdrawn with `cancel_pending_upgrade()`.

## Contributing

Expand Down
2 changes: 1 addition & 1 deletion deploy_and_upgrade.sh
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ deploy_contract() {
echo -e "${YELLOW}NOTE: This script does NOT pass constructor args.${NC}"
echo "After the deploy succeeds, invoke the constructor manually per the runbook:"
echo " docs/mainnet-deploy-runbook.md (events: admin, fee_account, fee_bps, profile_contract)"
echo " docs/mainnet-deploy-runbook.md (profile: admin, default_bootstrap_credits)"
echo " docs/mainnet-deploy-runbook.md (profile: admin)"
echo ""

CONTRACT_ID=$(stellar contract deploy \
Expand Down
4 changes: 1 addition & 3 deletions deploy_mainnet.sh
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ cmd_build_release() {

cmd_deploy_profile() {
require_env INITIAL_ADMIN_KEY
require_env BOOTSTRAP_PROFILE_CREDITS
require_cli
confirm_mainnet
ensure_deployments_dir
Expand All @@ -136,8 +135,7 @@ cmd_deploy_profile() {
--source "$INITIAL_ADMIN_KEY" \
--wasm "$wasm" \
-- \
--admin "$(stellar keys address "$INITIAL_ADMIN_KEY")" \
--default_bootstrap_credits "$BOOTSTRAP_PROFILE_CREDITS")
--admin "$(stellar keys address "$INITIAL_ADMIN_KEY")")

ok "profile_contract=$profile_id"
deployment_set profile_contract "$profile_id"
Expand Down
Loading
Loading