Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
d1735ff
chore(content): bump src/content — remove Red ATM from marketing
0xkkonrad Jun 16, 2026
db86328
fix(p2p): correct two request-pot display bugs (slider 49.98%, $1k+ p…
Hugo0 Jun 17, 2026
9a45cff
feat(card): "Split this bill" CTA on card-spend receipts (TASK-19739)
Hugo0 Jun 17, 2026
a3280d1
fix(split-bill): URL-encode merchant name in the split CTA query (Cod…
Hugo0 Jun 17, 2026
2a64883
Merge pull request #2235 from peanutprotocol/fix/p2p-display-amounts
Hugo0 Jun 17, 2026
82563a7
fix(pix): canonicalize +55 phone keys that already carry a + prefix
Hugo0 Jun 17, 2026
75f6aa4
Merge pull request #2240 from peanutprotocol/fix/pix-phone-canonicali…
Hugo0 Jun 17, 2026
c4b28fa
test(split-bill): extract + unit-test the "Split this bill" CTA URL b…
Hugo0 Jun 17, 2026
55010cc
content: advance src/content to latest main (358b6a6)
Hugo0 Jun 18, 2026
568f626
test(split-bill): URL-encode the amount param too (CodeRabbit)
Hugo0 Jun 18, 2026
4b50a10
Merge pull request #2241 from peanutprotocol/test/split-bill-cta-e2e
Hugo0 Jun 18, 2026
2ed85a9
content: drop avalanche deposit/withdraw to match content removal
Hugo0 Jun 18, 2026
9fc9cb3
refactor(seo): single source of truth for deposit rails
Hugo0 Jun 18, 2026
9cf06f8
docs(seo): correct fallback description in exchanges header comment
Hugo0 Jun 18, 2026
cdab7e5
Merge pull request #2232 from peanutprotocol/chore/content-remove-red…
Hugo0 Jun 18, 2026
032683b
feat(seo): register Faster Payments + SPEI as deposit rails
Hugo0 Jun 18, 2026
4705743
Merge remote-tracking branch 'origin/main' into chore/backmerge-main-dev
Hugo0 Jun 18, 2026
676a41d
content(llms): expand + correct llms.txt and llms-full.txt
Hugo0 Jun 18, 2026
e4e1b26
content(llms): fix stale card eligibility — denylist, not 29-country …
Hugo0 Jun 18, 2026
1a9ed38
Merge pull request #2244 from peanutprotocol/fix/deposit-rails-fp-spei
Hugo0 Jun 18, 2026
731d9c5
fix(deposit): stop offering Scroll deposits (silently lost) + drop st…
Hugo0 Jun 19, 2026
08ca06d
Merge pull request #2248 from peanutprotocol/fix/deposit-flow-scroll-…
Hugo0 Jun 19, 2026
7a57b70
fix(claim): restore dynamic social-preview metadata for claim links
Hugo0 Jun 19, 2026
2d700a7
fix(claim): address review — non-barrel import, clear ENS timeout, sp…
Hugo0 Jun 19, 2026
9ddd515
Merge pull request #2249 from peanutprotocol/fix/claim-og-metadata
Hugo0 Jun 19, 2026
08ec5af
refactor(og): single buildOgImageUrl() helper for /api/og links
Hugo0 Jun 19, 2026
4292749
Merge pull request #2251 from peanutprotocol/fix/og-url-builder
Hugo0 Jun 19, 2026
4abd233
content: bump src/content to latest peanut-content main (f066775)
Hugo0 Jun 19, 2026
6bac289
ci(content): base auto-bump on dev + content-only auto-merge
Hugo0 Jun 19, 2026
bd2f6c7
Merge pull request #2252 from peanutprotocol/chore/content-bump-autom…
Hugo0 Jun 19, 2026
def5c62
fix(home): show "You're unlocked" modal once, off a milestone
Hugo0 Jun 19, 2026
6842d34
fix(add-money): back button no longer dies on the amount screen
Hugo0 Jun 19, 2026
706232a
feat(kyc): skippable advisory pre-empt at add/withdraw for future-dat…
Hugo0 Jun 19, 2026
fb4a20e
Merge pull request #2254 from peanutprotocol/fix/addmoney-back-nuqs-r…
Hugo0 Jun 19, 2026
bb764f3
Merge pull request #2256 from peanutprotocol/main
Hugo0 Jun 19, 2026
59c7ee3
test(add-money): cover the reported Manteca back-button path in e2e
Hugo0 Jun 19, 2026
063ece7
fix(kyc): advisory pre-empt — dispatch via start-action, safe dismiss…
Hugo0 Jun 19, 2026
d9ca6dd
Merge remote-tracking branch 'origin/dev' into feat/bridge-advisory-p…
Hugo0 Jun 19, 2026
7acbaea
Merge pull request #2257 from peanutprotocol/test/addmoney-manteca-ba…
Hugo0 Jun 19, 2026
1569160
Merge pull request #2253 from peanutprotocol/fix/unlock-modal-milestone
Hugo0 Jun 19, 2026
28a211d
Merge remote-tracking branch 'origin/dev' into feat/bridge-advisory-p…
Hugo0 Jun 19, 2026
f85760d
fix(split-bill): hide "Split this bill" only on charges that didn't s…
Hugo0 Jun 19, 2026
21098a2
Merge pull request #2258 from peanutprotocol/fix/split-bill-settled-gate
Hugo0 Jun 19, 2026
938e717
feat(card): show registered cardholder name on reveal
abalinda Jun 19, 2026
23abae6
fix(kyc): correct DUPLICATE_EMAIL copy — sign in / contact support
jjramirezn Jun 19, 2026
784912b
fix(sentry): don't report qr-payment/init 422 as a client error
Hugo0 Jun 20, 2026
802d1b5
Merge pull request #2264 from peanutprotocol/fix/sentry-skip-qr-init-422
Hugo0 Jun 20, 2026
c19f628
fix(kyc): route advisory Complete now through self-heal relay
jjramirezn Jun 20, 2026
832ec52
fix(kyc): guard against double-submit in advisory completeNow (CodeRa…
jjramirezn Jun 20, 2026
7ea2b35
fix(request): show spendable balance incl. card collateral
abalinda Jun 21, 2026
b817da4
Merge pull request #2265 from peanutprotocol/fix/kyc-duplicate-email-…
jjramirezn Jun 22, 2026
2b014c1
Merge pull request #2255 from peanutprotocol/feat/bridge-advisory-pre…
jjramirezn Jun 22, 2026
66f5505
feat(bridge): pass claimer details for travel rule in guest claims
kushagrasarathe Jun 23, 2026
b25f3c8
fix(card): drop "Expiry"/"CVV" labels so PAN + name clear the artwork
abalinda Jun 23, 2026
53aeeb6
test(card): assert registered name stays inside ph-no-capture wrapper
abalinda Jun 23, 2026
d3eb9a3
Merge pull request #2260 from peanutprotocol/card-registered-name
jjramirezn Jun 23, 2026
a94ea7e
Merge remote-tracking branch 'origin/main' into chore/backmerge-main-…
Hugo0 Jun 23, 2026
d2cfdfe
fix(balance): gate money-flows on available-now spendable, not displa…
Hugo0 Jun 23, 2026
68c1412
Merge pull request #2273 from peanutprotocol/chore/backmerge-main-int…
Hugo0 Jun 23, 2026
5460596
fix(balance): address CodeRabbit review on the gate commit
Hugo0 Jun 23, 2026
8541340
refactor(balance): unify gate messaging (settling vs insufficient) + …
Hugo0 Jun 23, 2026
d466312
fix(balance): enforce send gate at submit + show $0 balance on manteca
Hugo0 Jun 24, 2026
bc3d2bb
fix(offramp): derive destination from account type, not country
Hugo0 Jun 2, 2026
7fdb792
fix(withdraw): stop false-rejecting IBANs whose country != the dropdown
Hugo0 Jun 20, 2026
116627a
fix(withdraw): source the Bridge countryCode from the IBAN, not the d…
Hugo0 Jun 20, 2026
c38e2b8
fix(offramp): preserve account type through bank details + normalize …
Hugo0 Jun 20, 2026
48e749d
fix(withdraw): derive offramp config from account + guard fresh account
Hugo0 Jun 23, 2026
ec95c9d
refactor(balance): fail-late on display gate + refetch on failure (dr…
Hugo0 Jun 24, 2026
9e6e63e
fix(balance): address /code-review findings (loading guards, refetch,…
Hugo0 Jun 24, 2026
10a7398
fix(balance): guard isDisplayBalanceSufficient against non-finite amo…
Hugo0 Jun 24, 2026
9a3f743
Merge pull request #2263 from peanutprotocol/hotfix/uk-gbp-withdraw-flow
kushagrasarathe Jun 24, 2026
71da9f5
fix(balance): adversarial-review fixes (orphan charges, button dead-e…
Hugo0 Jun 24, 2026
4661a2b
fix(balance): preserve submit-time errors + don't disable Continue du…
Hugo0 Jun 24, 2026
0901421
Merge pull request #2266 from peanutprotocol/fix/request-spendable-ba…
Hugo0 Jun 24, 2026
b1f9896
Merge pull request #2267 from peanutprotocol/feat/bridge-travel-rule
jjramirezn Jun 24, 2026
bac6b09
fix(add-money): skip the redundant second bank/method selection
jjramirezn Jun 24, 2026
f934eb4
test(add-money): country click goes straight to bank step
jjramirezn Jun 24, 2026
5f37002
Merge pull request #2276 from peanutprotocol/fix/add-money-double-ban…
jjramirezn Jun 24, 2026
ea33c3f
fix(amount-input): reliably autofocus the amount field on desktop
Hugo0 Jun 24, 2026
ee360db
Merge pull request #2277 from peanutprotocol/fix/amount-input-autofocus
Hugo0 Jun 24, 2026
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
32 changes: 27 additions & 5 deletions .github/workflows/update-content.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,14 @@ jobs:
update:
runs-on: ubuntu-latest
steps:
# Base the bump on `dev` (the PR target), NOT the repo default branch.
# Branching off a different branch than the base is what let unrelated
# code drift leak into the auto-PR (#2226) and made it conflict with dev
# once dev's content pointer moved (#2247). Off `dev`, the PR is
# content-only by construction and always cleanly mergeable.
- uses: actions/checkout@v4
with:
ref: dev

- name: Init and update submodule
env:
Expand All @@ -34,14 +41,19 @@ jobs:
echo "changed=true" >> "$GITHUB_OUTPUT"
fi

- name: Create PR
- name: Create PR + auto-merge (content-only)
if: steps.check.outputs.changed == 'true'
# Prefer a PAT (CONTENT_BOT_TOKEN) so the PR triggers CI and auto-merge
# can fire on green checks. Falls back to GITHUB_TOKEN — the PR still
# opens, but GITHUB_TOKEN-created PRs don't trigger CI, so auto-merge
# won't fire until the PAT is configured (no regression vs today).
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.CONTENT_BOT_TOKEN || secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
BRANCH="auto/update-content-$(date -u +%Y%m%d-%H%M%S)"
SUBMODULE_SHA=$(git -C src/content rev-parse HEAD)
PARENT=$(git rev-parse HEAD)
PARENT=$(git rev-parse HEAD) # dev tip — bump is content-only vs dev
BASE_TREE=$(gh api repos/${{ github.repository }}/git/commits/$PARENT --jq '.tree.sha')
# Create tree via API with updated submodule pointer
TREE=$(gh api repos/${{ github.repository }}/git/trees \
Expand All @@ -64,8 +76,18 @@ jobs:
--method POST \
-f "ref=refs/heads/$BRANCH" \
-f "sha=$COMMIT_SHA"
gh pr create \
PR_URL=$(gh pr create \
--head "$BRANCH" \
--base dev \
--title "Update content submodule" \
--body "Auto-generated: updates content submodule to latest peanut-content main."
--body "Auto-generated: bumps the content submodule to latest peanut-content main. Based on dev, so it's content-only and auto-merges once checks pass.")
# Guard: only auto-merge when the PR touches NOTHING but the submodule
# pointer. If anything else slipped in, leave it for a human.
FILES=$(gh pr diff "$PR_URL" --name-only)
if [ "$FILES" = "src/content" ]; then
gh pr merge "$PR_URL" --auto --squash \
|| echo "::warning::auto-merge not enabled/permitted — left for manual merge ($PR_URL)"
else
echo "::warning::PR touches more than src/content — left for manual review:"
echo "$FILES"
fi
2 changes: 1 addition & 1 deletion .verify-content-baseline
Original file line number Diff line number Diff line change
@@ -1 +1 @@
745
740
65 changes: 65 additions & 0 deletions e2e/flows/add-money.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,69 @@ test.describe('Add money flow', () => {
consoleLogs.flush(testInfo, 'add-money-us-bank')
await context.close()
})

// Regression: the NavHeader back button must LEAVE the amount screen on the first tap.
// Before fix/addmoney-back-nuqs-replace the flow used nuqs { history: 'push' }, so every
// amount keystroke stacked a same-screen history entry and useSafeBack's router.back()
// only stepped through stale amounts — the back button looked dead (MP/bank reports).
test('add-money/AR/bank — back button leaves the amount screen after typing (verified-ar)', async ({
browser,
}, testInfo) => {
const context = await browser.newContext({ ...devices['Pixel 7'] })
await usePersona(context, 'verified-ar')

const page = await context.newPage()
const consoleLogs = collectConsoleLogs(page)
await installApiMocks(page)

await page.goto('/add-money/AR/bank')

// amount step renders (verified persona skips the "country not found" gate)
const amountInput = page.locator('input[inputmode="decimal"]').first()
await amountInput.waitFor({ state: 'visible', timeout: 15000 })

// typing writes ?amount= — with the old { history: 'push' } this stacked back-stack
// entries; with the default 'replace' it does not.
await amountInput.fill('100')
await captureStep(page, testInfo, { name: '01-add-money-ar-bank-amount-typed' })

// one tap must exit to the country page, not linger on /bank with a stale amount
await page.locator('[data-testid="nav-back"]').first().click()
await expect(page).toHaveURL(/\/add-money\/AR(?:\?.*)?$/)
await captureStep(page, testInfo, { name: '02-add-money-ar-bank-back-left-screen' })

consoleLogs.flush(testInfo, 'add-money-ar-bank-back')
await context.close()
})

// Same regression, the originally-reported flow: Manteca (MP) AR deposit at
// /add-money/argentina/manteca. Both add-money amount screens shared the
// { history: 'push' } bug; this covers the reported variant directly.
test('add-money/argentina/manteca — back button leaves the amount screen after typing (verified-ar)', async ({
browser,
}, testInfo) => {
const context = await browser.newContext({ ...devices['Pixel 7'] })
await usePersona(context, 'verified-ar')

const page = await context.newPage()
const consoleLogs = collectConsoleLogs(page)
await installApiMocks(page)

await page.goto('/add-money/argentina/manteca')

// amount step renders (verified persona; currency rate is mocked)
const amountInput = page.locator('input[inputmode="decimal"]').first()
await amountInput.waitFor({ state: 'visible', timeout: 15000 })

await amountInput.fill('100')
await captureStep(page, testInfo, { name: '01-add-money-manteca-amount-typed' })

// one tap must exit to the country page, not linger on /manteca with a stale amount
await page.locator('[data-testid="nav-back"]').first().click()
await expect(page).toHaveURL(/\/add-money\/argentina(?:\?.*)?$/)
await captureStep(page, testInfo, { name: '02-add-money-manteca-back-left-screen' })

consoleLogs.flush(testInfo, 'add-money-manteca-back')
await context.close()
})
})
10 changes: 10 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,16 @@ module.exports = [
message:
"window.history.length is the pre-useSafeBack idiom (history.length > 1 ? back : push). It misfires on cold-load from external referrers — useSafeBack's pushState counter is more accurate. See PR #1965.",
},
{
// nuqs `history: 'push'` stacks a browser-history entry on every URL write.
// For per-keystroke params (e.g. `amount`) that poisons the back stack:
// useSafeBack → router.back() then steps through stale same-screen states
// and the back button looks dead (add-money MP/bank reports, June 2026).
selector:
"CallExpression[callee.name=/^useQueryStates?$/] Property[key.name='history'][value.value='push']",
message:
"Don't pass { history: 'push' } to nuqs useQueryState(s) — a history entry per URL write breaks the back button (useSafeBack steps through same-screen states instead of leaving). Use the default 'replace'; the URL stays shareable. If a flow genuinely needs push-per-step, add a scoped file exemption with a comment (see useNativePlugins).",
},
],
},
},
Expand Down
97 changes: 49 additions & 48 deletions public/llms-full.txt
Original file line number Diff line number Diff line change
@@ -1,77 +1,78 @@
# Peanut — Full Product Description

> Instant global peer-to-peer payments in digital dollars.
> Spend, send, and cash out digital dollars anywhere — pay local QR codes in Argentina and Brazil with just your passport, spend on a card, and move money across borders without a local bank account or local tax ID.

## Overview

Peanut is a peer-to-peer payments app that lets users send and receive money globally using digital dollars (USDC stablecoins). It provides a consumer-grade UX on top of blockchain infrastructure — users never need to understand crypto, manage wallets, or handle gas fees.
Peanut is a self-custody money app built on digital dollars (USDC). Users hold dollars in an account that only they control and spend them like a local — scanning the same QR codes locals use, paying with a card, sending a link, or cashing out to a bank. The experience is consumer-grade: users never manage wallets, seed phrases, or gas fees. Where identity verification is needed it takes a passport and under two minutes — no local ID, bank account, or residency required. Core crypto features require no verification at all.

## Key Features
## Headline differentiators

### Instant P2P Transfers
Send digital dollars to any Peanut user instantly. No waiting for bank processing, no wire fees.
### Pay PIX in Brazil without a CPF
PIX is Brazil's instant payment network — ~150 million people use it daily. Normally it requires a CPF (Brazilian tax ID) and a Brazilian bank account, which locks out tourists, nomads, and expats. Peanut lets anyone scan a merchant PIX QR and pay in BRL using a passport-verified account funded with digital dollars. The merchant receives BRL in seconds and sees an ordinary PIX payment. The conversion isn't subject to IOF (Brazil's financial-operations tax), saving up to ~3.5% versus cards and bank transfers. Free, 24/7/365, QR scan only.

### Payment Links
Generate a shareable link containing funds. The recipient clicks the link to claim the money — no account needed. Links work across messaging apps, email, and social media.
### Pay MercadoPago in Argentina without a DNI
MercadoPago QR is accepted at 1,000,000+ merchants in Argentina. Locals need a DNI to open an account; Peanut gives access to the payment network without one — pay in pesos with a passport-verified account. Conversion uses the cripto dólar rate (a direct dollar-to-peso market rate that beats the regulated MEP rate cards use), typically several percent to ~11% more pesos per dollar. Free, instant, rate locked at payment.

### Bank Cash-Out
Connect a local bank account and convert digital dollars to local currency. Supported rails:
- **Argentina**: Bank transfer, MercadoPago
- **Brazil**: PIX, bank transfer
- **Mexico**: SPEI, bank transfer
- **Colombia**: Bank transfer
- **Peru**: Bank transfer
- **Bolivia**: Bank transfer (via Meru)
### The Peanut Card
A virtual Visa card that spends the user's digital-dollar balance anywhere Visa is accepted. Free to issue and top up; the only cost is the exchange-rate spread on currency conversion. Available in most countries (the US, Europe, the UK, Latin America, Africa, and more) and requires identity verification. A short list of regions is excluded — the card issuer's restricted-issuance list (China, India, Russia, Turkey, Vietnam, Iran, Israel, and a handful of others).

### Crypto Deposit
Fund your account by depositing crypto from any exchange (Coinbase, Binance, Kraken, Bybit, OKX, etc.) or external wallet.
## Core features

### Card Payments
Physical and virtual debit cards for spending digital dollars at any merchant that accepts card payments.
### Peanut Links
Put money in a shareable link or QR; the recipient claims it with no account needed. Works across messengers, email, and social. Unclaimed links are reclaimable; claimed is final.

### QR Payments
Generate and scan QR codes for in-person payments.
### Peanut Requests
A collection link for splitting bills, tips, or donations. Multiple contributors, funds arrive instantly to the balance.

## Security Model
### Add money (deposit)
- Crypto: USDC or USDT (and ETH on major EVM networks, auto-converted) from any exchange or wallet on Solana, Arbitrum, Base, Tron, Polygon, or Ethereum. No verification. Gas covered.
- Bank: SEPA (EUR), ACH (USD), SPEI (MXN), Faster Payments (GBP), and incoming wires (USD/EUR).
- All deposits free.

- **Self-custodied smart accounts**: User funds sit in ERC-4337 smart accounts, not on Peanut servers
- **Biometric passkeys**: Account access is secured by the device's Secure Enclave (face/fingerprint). The private key never leaves the device
- **No server-side keys**: Peanut cannot access, freeze, or move user funds — even under regulatory pressure
- **Independent recovery**: If Peanut goes offline, users can recover access via any ERC-4337-compatible wallet
### Cash out (withdraw)
- Bank: SEPA, ACH, SPEI, Faster Payments — to your own or any third party.
- Crypto: to any wallet on any supported network; gas covered.
- Argentina: MercadoPago or a local account.
- All withdrawals free from Peanut.

## KYC / Compliance
### Direct bank transfers
Send from balance straight to any third-party bank account, and receive into the balance, via SEPA/ACH/SPEI/Faster Payments — no link required.

- Core features (send, receive, payment links) work without KYC
- Bank connections trigger a one-time identity check via Persona (SOC2 Type 2, GDPR, ISO 27001)
- Peanut only receives a pass/fail result — no documents stored on Peanut servers
## Security & custody

## Fee Structure
- Non-custodial smart accounts (ERC-4337) on Arbitrum. User funds never sit on Peanut servers.
- Biometric passkey auth: the private key is generated from device biometrics and sealed in the device Secure Enclave — never exported, never sent to Peanut.
- Peanut cannot freeze, seize, or move user funds. If Peanut went offline, users keep full control via any ERC-4337-compatible wallet.
- Every transaction requires an on-device biometric signature.

- Peer-to-peer transfers: minimal fees
- Bank cash-out: small conversion spread
- No monthly subscription or account fees
- Merchant payments planned with fees lower than Visa/Mastercard
## Verification & limits

## Target Markets
- Required only for bank deposits/withdrawals and local QR payments. Passport or national ID from any country (US driver's license accepted for US users). No local ID anywhere.
- Crypto deposits, crypto withdrawals, and browsing require no verification.
- Limits: Latin America ~$2,000/month combined (raisable with documents); US/Europe/Mexico/UK no hard limit (very large transactions reviewed); crypto unlimited.

Primary focus on Latin America:
- Argentina, Brazil, Mexico (largest markets)
- Colombia, Peru, Bolivia, Chile, Ecuador
## Fees

Use cases: remittances, freelancer payments, cross-border transfers, savings in stable currency, merchant payments.
- No per-transaction fee from Peanut. Same-currency moves (USD↔USDC) are free; cross-currency conversions carry a small spread embedded in the displayed, locked rate. Gas is always covered. No monthly or account fees.

## Technical Stack
## Where Peanut works

- Next.js web application (progressive web app)
- ERC-4337 smart accounts on Base (Ethereum L2)
- Biometric passkeys via WebAuthn / Secure Enclave
- Licensed banking partners for fiat on/off ramps
- Local QR spending live: Argentina (MercadoPago), Brazil (PIX).
- Bank rails live: 36 SEPA-zone countries (EUR), US (ACH/wire), Mexico (SPEI), UK (Faster Payments).
- Crypto deposit/withdraw: global, all non-restricted countries.
- Card: available in most countries; excludes a short restricted-issuance list (China, India, Russia, Turkey, Vietnam, and others).
- Roadmap (not live): local payment methods in many more countries (CoDi, Transfiya, Yape, Bizum, MB WAY, UPI, and others). Only Argentina and Brazil have live local spending today.

## Who it's for

Tourists, digital nomads, expats, remote workers, freelancers, and families moving money across borders — especially anyone wanting to spend or save in dollars in Latin America without a local ID or bank account.

## Company

- Founded by Konrad Kononenko and Hugo Montenegro
- Based in Europe, serving Latin America
- Website: https://peanut.me
- Twitter: https://twitter.com/PeanutProtocol
- Twitter/X: https://twitter.com/PeanutProtocol
- GitHub: https://github.com/peanutprotocol
- LinkedIn: https://www.linkedin.com/company/peanut-trade/
- Careers: https://peanut.me/careers
- Support: https://peanut.me/support
Loading
Loading