尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗Tax-free refunds that land in the traveller's own currency the moment customs clears them, on Stellar.
Carimbo is Portuguese for stamp. In Carimbo, the customs stamp is the payment.
Visitors who live outside a country can reclaim the VAT on what they buy there and take home. In practice they lose a large part of it, or wait for it:
| Where | Who refunds | What the traveller loses |
|---|---|---|
| EU, Switzerland, Norway, Singapore, Korea | Private refund operators (Global Blue, Planet…) | Around a quarter of the reclaimable VAT in fees. Portugal: 23% VAT is 18.7% of the price, but travellers net about 14–16%. |
| United Arab Emirates | One licensed operator | Only 85% of the VAT, minus a fixed fee per receipt |
| Australia | The state, no fee | Nothing, but cards and bank accounts are credited within 60 days |
| Japan | Switching to a refund model on 1 November 2026 | Methods not standardised; the government is studying stablecoin refunds |
The market is large: Global Blue alone processed €28 bn of tax-free sales and earned €422 m in a year, across 53 countries.
The root cause is the same everywhere. Validating the export is already electronic: Portugal's e-Tax Free kiosks, for example. Paying a foreigner, in their own currency, at the moment they leave, is what is expensive. That gap is what intermediaries charge for, and it is exactly the job Stellar was built for.
The traveller gets 99.5% of the VAT instead of about 75%, in seconds, in dollars, yen, pounds or reais.
Carimbo is built on Stellar's native primitives. There is no backend server: the browser talks to Stellar Testnet, and the ledger is the shared state between devices.
sequenceDiagram
participant Shop
participant Ledger as Stellar Testnet
participant Phone as Traveller's phone
participant Customs
Shop->>Ledger: create_claimable_balance (VAT in cEUR)<br/>claimants: customs before deadline, shop after deadline
Shop-->>Phone: QR code (claim + balance id)
Phone->>Ledger: check the balance exists and matches
Phone->>Ledger: manage_data "carimbo:<balance>" = attached<br/>manage_data "carimbo:currency" = USD
Customs->>Ledger: reads the traveller's data entries (sync)
Customs->>Ledger: ONE atomic transaction:<br/>claim_claimable_balance ×n<br/>payment 0.5% fee → platform<br/>path_payment_strict_send cEUR → cUSD → traveller
Phone->>Ledger: sees the balance gone + the payment (sync)
| Need | Stellar feature | Where in the code |
|---|---|---|
| Lock the VAT until export, with a legal deadline | Claimable balances with time predicates: customs may claim before the deadline, the shop only after it | chainOpen in web/src/lib/stellar.ts |
| Return the VAT if the traveller never leaves | Shop's claimant predicate not(before_absolute_time(deadline)) | chainReclaim |
| Pay in the traveller's currency | Built-in DEX and path payments (path_payment_strict_send, path found with Horizon strict-send-paths) | chainRelease |
| All-or-nothing refund | Several operations in one atomic transaction: claim, fee, conversion, payout | chainRelease |
| Stablecoins per currency | Issued assets with trustlines: cEUR, cUSD, cGBP, cJPY, cBRL, cCNY, cCHF, cSGD, cKRW | web/src/views/Setup.tsx |
| Liquidity between currencies | Market-maker offers on the DEX, two-sided around a reference rate | Setup.tsx |
| Shared state across devices, no server | Traveller data entries (manage_data) and Horizon reads, polled every 4 s | web/src/lib/sync.ts |
| Deadline enforced by the network | A late customs stamp fails on-chain with op_cannot_claim; the shop's reclaim succeeds. Shown live with the 2-minute demo window | chainRelease, chainReclaim |
| Survive a busy public Testnet | Lookup by transaction hash and safe resubmission after a 504 | submitClassicTx |
At the till, the shop can choose Trustless Work escrow instead of the native claimable balance (web/src/lib/trustless.ts). The app calls Trustless Work's REST API, which returns unsigned transactions; each actor signs its own in the browser:
| Step | Trustless Work call | Signed by |
|---|---|---|
| Lock the VAT | deployer/single-release, then fund-escrow | the shop |
| Customs stamp | change-milestone-status → approve-milestone → release-funds | customs (service provider, approver, release signer) |
| Refusal | dispute-escrow → resolve-dispute back to the shop | customs (dispute resolver) |
| Conversion | Stellar DEX path payment, USDC → the traveller's currency | the traveller |
On-chain evidence, one refund through Trustless Work (Casa Verde, €37.40 of VAT escrowed as 43.38 USDC):
081e4980…2ba93edbc41b…dc1cTheir Testnet API holds Circle's USDC, so on this path the VAT is escrowed in USDC at the reference rate. Carimbo's 0.5% goes to the platform role; Trustless Work takes its own protocol fee. The phone follows the escrow through Trustless Work's indexer (get-escrow-by-contract-ids).
All accounts are created and funded by /#/setup, and the result is committed as web/public/chain.json. The demo shops are fictional (five in Lisbon, two per country elsewhere, 47 in all). The five Lisbon shops each have their own Testnet account, and the shops of other countries sign with those same accounts; shops added later are activated by Activate the shops on the same page.
| Role | Account |
|---|---|
| Stablecoin issuer | GAES72GC…QKMD |
| Customs signer | GBHEL52N…VRXS |
| Shop: Loja Azul | GAERIXHJ…LJWZ |
| Shop: Casa Verde | GAYSK5GX…7ZWK |
| Shop: Fio de Alfama | GDBE3247…K3LG |
| Shop: Ourivesaria Lume | GCTOUT37…L4QO |
| Shop: Sapataria Gaivota | GDUTP6VO…RKI4 |
| Traveller (demo) | GDOYUFNJ…D3OO |
| Platform (fees) | GACTLR4R…L5QH |
| DEX market maker |
On-chain evidence, one refund across two devices:
10a9fd5d…7b3ffc78d9db…bbb10719182a…d261On-chain evidence, the deadline enforced by the protocol (2-minute demo window, Ourivesaria Lume):
op_cannot_claim: b0568a1e…c5fd0fb87eaf…93bbAbout the keys in
chain.json: they are Testnet-only demo accounts holding worthless test assets. They are public on purpose, so judges can replay the whole flow without installing a wallet. A production version gives each actor their own wallet (see roadmap).
contracts/escrow is the same escrow written as a Soroban smart contract: open, attach, release (customs-only, batch), reject and reclaim (after the deadline), with a fee capped at 5%. It is covered by 8 unit tests.
It is not deployed. On 25 October 2026, Testnet runs protocol 29, and simulating the upload of this 9 KB Wasm returned a minimum resource fee of about 3,730 XLM, above the per-transaction fee cap (uint32 stroops). We therefore run the live flow on classic primitives, which give the same guarantees for this use case, and we keep the contract for a later deployment.
cargo test # 8 tests
stellar contract build # needs stellar-cli ≥ 25.2
cd web
npm install
npm run dev # http://localhost:5173
web/public/chain.json. Without it, the app runs in demo mode with simulated transactions and the same rules./#/setup and press Deploy to Testnet. It funds 7 accounts with Friendbot, issues the 9 stablecoins and places 16 DEX offers, then shows the new chain.json.One screen, about 20 s: open the live app and press Play the refund. Two shops lock VAT, the traveller adds both receipts, customs stamps once, and the refund arrives in dollars. Every line under On-chain activity links to Stellar Expert.
Two devices, the real flow:
The deadline, enforced by Stellar (about 3 minutes):
op_cannot_claim, and the refused transaction is linked.Also try: the shop switcher (several shops, one trip), several items per receipt, the country menu (VAT rates, minimums and export windows of 15 countries), and an unknown code at the customs desk.
web/src/lib/taxFreeRules.ts is the only place with legal figures: VAT rates, minimum (VAT included or excluded, and how receipts add up), export window, who is eligible (residence zone, minimum age, maximum stay), refund model, national validation system, exclusions and sources. Countries whose figures come from a single secondary source carry verified: false, and the interface shows Rules to be confirmed.web/src/lib/eligibility.ts is a pure engine: checkEligibility(rules, traveller, purchases, today) returns { eligible, reasons, deadline, warnings, fixes }. It checks residence outside the zone (EU = the 27 member states), age, length of stay, the minimum with each aggregation (per receipt, same shop same day, up to N receipts, same business within N days), the departure against the export deadline, scheme: "none" (United Kingdom) and excluded categories.npm test), including: Portugal €55 VAT included refused and €62 accepted (the minimum is €50 VAT excluded), a French resident in France refused, Japan with a departure 95 days after purchase refused, and a 15-year-old in Singapore refused.Before the traveller's account signs anything, the phone asks for Face ID, Touch ID, Windows Hello or a fingerprint through WebAuthn (web/src/lib/passkey.ts). The first scan creates a passkey on the device (ES256, the P-256 curve); the next ones must confirm it. On a device without a platform authenticator, the flow continues without it.
In this demo, the passkey gates the traveller's Testnet key held by the app. In production the same P-256 passkey becomes the signer of a Stellar smart account, verified on-chain, so the traveller has no secret key at all (see roadmap).
web/ React + TypeScript + Vite, deployed on Vercel
src/lib/stellar.ts every Stellar call: claimable balances, DEX paths, atomic release, reads
src/lib/ledger.ts app state and actions; live on Testnet or simulated with the same rules
src/lib/sync.ts multi-device sync from the ledger (attachments, currency, refunds)
src/lib/passkey.ts WebAuthn check before the traveller signs
src/lib/countries.ts tax-free rules: VAT rates, minimums, currencies, export windows
src/views/ Demo, Shop, Traveller, Customs, Setup
contracts/escrow/ Soroban version of the escrow + tests
MIT © 2026 Ferdinand Robichon, Nicolas Felemez
GDK5HA6P…A4LU