Documentation
What the protocol does, what it will not do, what it costs, and what is still untrue. Every number here is read out of the contracts rather than repeated from memory.
Two crypto projects agree to work together. Instead of announcing it, each one buys some of the other's token on the open market and locks it here for a term they agree between themselves. Neither can take it out early without paying for it.
That is the whole mechanism. There is no clever part, no swap, no yield on what is locked, and nothing that needs a price feed to work.
What it changes is exposure. Once you are holding their token, a partner who goes quiet, rugs or simply fails costs you money rather than credibility. Anyone can check that you were holding, from when, for how long, and how it ended.
Each one of these agreements is called a Veil.
Every project has a partners page. None of them cost anything to make, which is exactly why nobody believes them, and three months later nobody remembers who actually did the work.
The usual answers to that are worse. An escrow needs someone to decide whether the work was done, and that person becomes a judge with an opinion. A milestone contract needs an oracle for facts that are not on any chain. Both put a referee in the middle of a relationship that was supposed to be between two parties.
A Veil settles a different question. It never asks whether the work was good. It only records who committed capital, for how long, and whether they saw the term out. That is a fact, and facts are the only thing a contract can settle honestly.
The limit of this, stated up front
A Veil is a costly signal, not collateral. At small sizes walking away is cheap. It filters out theatre. It does not make betrayal impossible, and it should never be sold as if it does.
You already know who you want. You name them, buy their token, and lock it. They mirror it on the terms you published, and the term starts the moment their transaction confirms. If they never answer, the offer expires and your deposit comes home in full.
You do not know who yet. You publish what you are looking for and deposit nothing, because until somebody answers there is no counterparty token to buy. Anyone may answer, and answering means they buy your token and lock it before you have chosen anybody.
You say how many partners you want, from one to fifty. Each one you accept becomes its own separate agreement, funded and bonded on its own, with its own term running from the moment you accepted it. One call does not mean one clock.
The call keeps taking answers until every place is filled or you close it. Accepting somebody is never a rejection of the rest: every other application stays pending and can be withdrawn in full, at any moment, whatever you do or fail to do.
The rule that does not change between them
Whoever wants the partnership pays before the other side has agreed to anything. On a direct Veil that is the proposer. On an open call it is the applicant. Which is why a call with ten answers is ten projects who each put money down.
One side has funded and locked. The other has not answered yet. The deposit can be reclaimed once the deadline passes.
Both sides funded. Nothing can be withdrawn, for any reason, by anyone, until the term ends.
Past the term and releasing linearly across the release window. Neither side can speed it up.
Fully released, expired, or ended early. The record stays either way.
| Setting | What it does | Range |
|---|---|---|
| Term | How long neither side can withdraw anything | 7 to 730 days |
| Release window | How long the linear unlock takes afterwards | 1 to 180 days |
| Acceptance window | How long a direct proposal waits for an answer | up to 30 days |
| Call window | How long an open call keeps taking answers | up to 90 days |
| Partners | How many places an open call has | 1 to 50 |
When the term ends, nothing unlocks at once. Both positions release evenly across the release window, so a Veil ending cannot dump two charts in a single block. This is not configurable, because the version of this product with a cliff would be actively harmful to the projects using it.
The text of the agreement lives off-chain. Only its keccak256 hash is
stored on-chain, which means the words can be proven later but never quietly
rewritten. Either side may flag it delivered. That flag moves no money and it never
has to.
Nothing traps anyone. Either side may end an active Veil at any moment before the term is up. The consequence is written into the instrument rather than argued about afterwards.
brokenBy is written into the Veil and never cleared.The split is fixed when the Veil is made and no later change to the protocol can reach it. On an open call it is fixed when the application is made, which is the earliest moment anybody committed anything.
Why there is no penalty beyond the bond
A larger penalty would need someone to decide whether leaving was justified, and that is the referee this whole design exists without. The bond is what somebody agreed to lose in advance, and the record of having lost it is the rest.
Each of these is enforced by code rather than promised by anyone, and each has a test that proves it.
Most of the design is refusal. These are not missing features.
A flat fee per side, payable in the chain's native currency or in VEIL at a discount. Flat rather than a percentage, because a percentage of locked value needs a price and the contract deliberately has no way to learn one.
On an open call the fee is charged once, to the maker, at posting, however many partners the call ends up taking. Applicants pay no protocol fee to answer: they are already committing capital, and taxing the answers would thin the very pool an open call exists to reach.
| Where | What for | Share |
|---|---|---|
| Buyback, burned | Buys VEIL on the open market and burns it | 40% |
| Marketing | ETH, straight to the marketing wallet | 40% |
| Buyback, to holders | Buys VEIL on the open market and shares it out to holders | 20% |
Nothing here is a privileged action. Anyone may call distribute() on the
splitter, and buyback() on either buyback contract. Each buyback runs at most
once a day, spends at most a fifth of what it holds, and never moves the price more than
1%, so it cannot be timed or traded around. Neither buyback has an owner.
The split can be fixed for good with lockSplit(). Until then the owner can
change it, which is stated here rather than discovered later.
$VEIL has two jobs inside the protocol, and both fall out of the mechanism rather than being bolted on: it pays the fee at a discount, and it is the bond you lose if you walk. Around those sits a small tax on trades.
The fee is payable in VEIL at a discount. Nobody is forced to touch the token; the product works entirely without it.
Both sides post one. End a Veil early and you forfeit it, half to the side you left and half burned. This needs no arbiter, because whether you ended it before the agreed date is a fact rather than a judgement.
2% on every buy and every sell against the pool, taken in VEIL and split in the same transaction:
| Where | How | Of the tax |
|---|---|---|
| Burned | Destroyed on the spot, so the supply falls as volume grows | 40% |
| Holders | Paid in VEIL to every holder, pro rata | 20% |
| Marketing | Sold for ETH in small pieces, sent to the marketing wallet | 40% |
The ceiling is 3%, and it is a constant the owner cannot raise, which is the usual way a tax token turns out to be a trap. The tax can be locked for good; after that the rate, the split and every exemption are fixed. One thing stays possible after the lock: a new pool holding VEIL can be marked as a market, so nobody can dodge the tax by trading in a second pool. An ordinary wallet can never be marked.
Moving tokens between your own wallets is not taxed. Neither is the protocol: taxing a bond going in and coming back would mean honouring an agreement costs money while walking away costs nothing, so the vault, the splitter and both buybacks never pay it.
It collects in the token and is sold during sells, never during buys: a pool is locked for the whole of its own swap, so selling into it inside a buy is impossible. Each sale is at most 0.3% of the pool, one per block, and the ETH goes straight to the marketing wallet. A sale that fails is skipped and tried again later; it can never make somebody else's trade fail. Because a sell can carry one small sale in front of it, set 3 to 4% slippage when trading.
Every wallet holding VEIL earns its share of the holder part of the tax, and of the
protocol's buyback for holders. Rewards land in the wallet with its next transfer, or
can be claimed at any time with claimRewards(). Nobody earns from their own
trade.
Some addresses never earn: the pool, because a pool whose balance grows by itself can be drained by anyone; the protocol's contracts, because they hold other people's money; and the treasury, because it starts with the whole supply and would otherwise collect most of it. Rewards are only shared once at least 1,000,000 VEIL is held by earning wallets in total. Below that they wait and are paid out with the next distribution, which keeps the arithmetic safe whatever anyone holds.
A fixed supply of one billion, minted once at deployment. There is no mint function, so supply can only ever go down: through the burn on every trade, the daily buyback, and forfeited bonds. The allocation is published with its wallet addresses before launch.
On timing, plainly
The token is worth nothing without Veils flowing through the protocol. The buyback is a credibility mechanism long before it is ever a price mechanism, and anybody who tells you otherwise is selling you something.
The bond can only be switched on once VEIL is actually tradeable. Before that, a non-zero bond would make the protocol unusable, since it pulls a token nobody can buy. It starts at zero and is turned on later, in public, with one transaction.
A project can publish a name, a ticker, a logo and links by signing a message with the address it operates under. That is the only thing the signature proves.
What "signed" means, and what it does not
It means that wallet produced a signature proving it controls that address. It is not a statement that the project is real, solvent or honest, and the API returns that caveat inside the payload so no interface can quietly upgrade it into a trust badge.
Nothing verifies that a token belongs to the project offering it either. A call can name any ERC-20 as "your token". Nobody can be robbed that way, because an applicant may always withdraw and an accepted Veil returns each side's own deposit, but a call can misrepresent what it is offering. Read the token address, not the name beside it.
The contracts are not audited by a third party. Do not commit capital you cannot afford to lose until they are.
In review we found that bonds were refunded using a mutable setting rather than the value recorded on the Veil itself. Pointing that setting at another token mid-term would have made a claim revert, which would have locked a user's holdings for good, and pointing it at nothing would have stranded the bond silently.
That broke the protocol's own second guarantee, so it was fixed before anything was published: the bond token and break split are now written into each Veil when it is made and never read from configuration again. Three tests attempt exactly that attack and fail to land it.
lockTax() and lockSplit() fix them for good, and neither can reach fees already paid or any locked position.The contracts are public and so is everything around them. The chain is the only thing that settles anything; the indexer and the API exist so a browser does not have to scan logs.
| Call | What it does |
|---|---|
proposePact | Name a counterparty and fund your side |
acceptPact | Mirror it and start the term |
cancelExpiredProposal | Reclaim a deposit nobody answered |
postOffer | Publish an open call with a number of places |
applyToOffer | Answer one by funding first |
withdrawApplication | Take a pending answer back, always available |
acceptApplication | Fill one place and start that term |
closeOffer | Stop taking answers early |
claim | Take whatever has vested; can never be paused |
breakPact | End early and forfeit the bond |
flagCompleted | Record that you consider it delivered; moves no money |
GET /api/pacts?status=active
GET /api/pacts/:id
GET /api/offers?status=open
GET /api/offers/:id
GET /api/parties/:address/pacts
GET /api/stats
Every Veil and every call renders its own image, engraved from its own number with the same arithmetic the board uses, so a posted link shows the instrument itself.
/v/:id a Veil, with preview tags
/c/:id a call, with preview tags
/cards/veil/:id.png
/cards/call/:id.png
npm install
npm test # 76 contract tests
npm run smoke # 51 backend checks
npm start # API and the board on :8787
Where this actually is
Not audited. Do not put money through these contracts that you cannot afford to lose. Nothing here is investment advice and none of it is a promise of return.
The protocol is built and tested. What happens next, in order: contracts deployed and verified, the first Veils made by hand with people we know, a real audit, and only then anything about a token.
Progress is posted weekly, including the weeks where nothing worked. When a Veil is ended early and somebody forfeits their bond, that gets posted the same way the successes do.
| Word | Meaning |
|---|---|
| Veil | One agreement. Two parties, two locked positions, one term. |
| Open call | A published request for partners that anybody may answer. |
| Application | An answer to a call, funded by the applicant before any choice is made. |
| Place | One partner slot on a call. A call has between one and fifty. |
| Term | The stretch during which nothing can be withdrawn. |
| Release window | How long the linear unlock takes once the term is over. |
| Bond | What each side stands to forfeit by ending a Veil early. |
| Scope | What two parties agreed. Kept off-chain, hashed on-chain. |
| Brief | What a call is asking for. Same arrangement as a scope. |
| Seal | The engraving belonging to one instrument, cut from its own number. |
If something here disagrees with the contracts, the contracts are right and this page is a bug. Every figure on it was read out of the code rather than remembered.