How Canvaspad works
A Canvaspad round is a coin that does not exist yet. It has a name, a ticker, a 16-colour palette and a clock, and instead of a logo it has a blank 64 x 64 canvas that lives on chain. Committing SOL buys paint. When the clock ends, the canvas is frozen and the coin is created with the canvas as its picture, bought with the whole pool at one price.
Overview
- No coin, no contract address until the round ends. Nothing can be sniped because there is nothing to buy.
- SOL buys paint: every 0.002 SOL committed is one pixel of paint. Painting over someone else's pixel costs x2.
- The picture is the canvas. The coin is created once, with its final picture. There is no placeholder and no metadata rewrite later.
- One price. Every wallet receives tokens in proportion to the SOL it committed.
- Surviving pixels earn. The coin's creator income is shared by the painters whose pixels are in the final logo.
A round, step by step
| State | What it means | What can happen |
|---|---|---|
| Open | The clock is running. The canvas can change. | commit, paint; after the bell anyone calls freeze |
| Frozen | The bell rang with the pool at or above the minimum. The canvas is final and its hash is on chain. | the keeper creates the coin (launch); if it does not within the launch window, anyone calls void |
| Launched | The coin exists with the canvas as its picture. | claim_tokens, claim_fees |
| Failed | The bell rang below the minimum. | refund, in full |
| Void | Frozen but not created in time. | refund, in full |
- Open a round. The opener chooses the name, the ticker, the palette, the target, the clock and the minimum. Their wallet creates the blank canvas account in the same transaction and pays its rent; the account stays on chain as the logo's source.
- Commit. Anyone commits between the per-wallet minimum and maximum. The commit that crosses the target is cut to exactly the target; after that the pool is full, but painting continues until the bell.
- Paint. Painters spend their paint on pixels. Every stroke is a transaction and an event.
- The bell. At the end of the clock (plus overtime) the canvas is frozen and hashed, or the round fails if the pool is under the minimum.
- Birth. The coin is created with the canvas and bought with the pool in one transaction.
- Claims. Each wallet claims its tokens. Painters with surviving pixels claim their share of the income as it accrues.
Paint and its price
Paint is counted in pixels. You get floor(committed / pixel_price) pixels in total and spend them as you paint. The cost of one pixel is decided by who owns it now:
| The pixel is | Cost |
|---|---|
| blank | 1 |
| yours, another colour | 1 |
| yours, the same colour | 0 |
| someone else's | x2 |
A paint transaction is all-or-nothing: if you do not have the paint for the whole stroke, nothing changes. The site prices your draft with this same rule before you send it. Strokes are sent as two kinds of operations: Rect {x, y, w, h, color} fills a rectangle; Blit {x, y, w, h, data} copies w x h pixels, one 4-bit colour each, high nibble first.
Overtime
A canvas that ends at a known second gets repainted in that second. So any commit or paint in the last 2 minutes pushes the bell back to 2 minutes from that moment, up to 30 minutes past the original end (the hard end, set when the round opens). The last word always has time for an answer.
The freeze
freeze can be called by anyone after the bell. If the pool reached the minimum, the canvas can no longer change and the program writes
canvas_hash = sha256("canvas:v1" || palette[48] || colors[4096])
into the round. Blank pixels have colour 0, the first colour of the palette. Survivor counts are final at this moment: they decide the income split.
The birth transaction
The keeper renders the frozen canvas to a 1024 x 1024 PNG (each pixel a 16 x 16 square), uploads it with metadata that carries the same canvas_hash, and sends launch(uri). In one instruction the program:
- checks the round is Frozen and inside the launch window, and that the uri is an IPFS address;
- sends the platform fee (1% of the pool) to the treasury and keeps a small rent reserve for the new accounts;
- creates the coin on pump.fun with the round's name and ticker, the canvas picture, and the round's fee account as its creator;
- buys it with everything left in the pool, in the same instruction. Nobody can buy before the pool.
If the keeper does not do it within the launch window (2 hours), anyone can void the round and every commit is refunded. The keeper can also decline to create a coin whose canvas is illegal content; the round is then voided the same way.
Worked example
A round ends with 20 SOL from 48 wallets. Fee 1% = 0.2 SOL to the treasury, rent reserve 0.03 SOL, buy with 19.77 SOL. If that buys 540,000,000 tokens, a wallet that committed 0.5 SOL claims 540,000,000 x 0.5 / 20 = 13,500,000 tokens. Everyone paid the same price per SOL.
Claims and refunds
claim_tokens:tokens_bought x committed / total, once per wallet.refund: after Failed or Void, the full committed amount back to the wallet that committed it. Anyone can push a refund; the SOL only goes to its owner.- Paint is not refunded separately: in a failed round nothing was bought, so the whole commit comes back.
Income by surviving pixels
The coin's creator income flows to the round's fee account. sync_fees splits new income: 60% to painters, 25% to the opener, 15% to the treasury. The painters' part is shared by surviving pixels:
your share = survivors[you] x acc_fee_per_pixel / 10^12 - already_paid
Tokens follow SOL; income follows the picture. Painting early and being painted over keeps your tokens; holding your pixels to the bell adds income.
Parameters
Read live from the program's config. Every round copies these at opening; a later config change never touches an open round.
| Parameter | Value |
|---|---|
| Loading from chain | |
Program reference
Program --. Anchor 0.31, the full interface is the IDL.
| Account | Seeds | Holds |
|---|---|---|
| Config | ["config"] | admin, treasury, keeper, paused, params, next round id |
| Round | ["round", id u64 LE] | name, ticker, palette, copy of the params, clock, pool, state, canvas hash, mint, fee accounting |
| Canvas | a plain account owned by the program (14,332 bytes) | colors[4096], owners[4096], survivors[1001], painted |
| Painter | ["painter", round, wallet] | index on the canvas, committed, paint bought and spent, claims |
| Vault | ["vault", round] | the pool; after the birth it holds the bought tokens until claimed |
| Fees | ["fees", round] | the coin's creator on pump.fun; income waits here until claimed |
| Instruction | Who can call |
|---|---|
| open_round | anyone (becomes the opener) |
| commit, paint | anyone, while Open |
| freeze | anyone, after the bell |
| launch | the keeper, while Frozen and inside the window |
| void | anyone, Frozen and the window has passed |
| refund, claim_tokens, claim_fees | anyone; the SOL or tokens go only to the painter's wallet |
| collect_fees, unwrap_fees, sync_fees | anyone |
| claim_opener_fees, collect_treasury | anyone; paid only to the opener / treasury |
| init_config, update_config, set_* | the admin |
Errors
Every refusal has a name. The site shows the message; the code is what an explorer shows.
| Code | Name | Meaning |
|---|
Verify on chain
- The program. Open the program id in an explorer. Check the upgrade authority and that the IDL matches the one served here.
- The pool. The round's Vault holds exactly the pool (plus rent) while it is Open:
vault = total + rent. - The canvas. Read the Canvas account: 4,096 colour bytes at offset 40. Hash them with the palette as above and compare with
canvas_hashin the round. - The logo. Open the coin's metadata. Its picture, sampled at the centre of each 16 x 16 square, gives back the 4,096 colours. The Born list on the site does this comparison for every coin and shows the result.
- The birth. In the launch transaction you see the coin's creation and one buy by the round's vault, in the same instruction, and nothing else buying before it.
- One price. For any two claims, tokens divided by committed SOL is the same number.
What the admin can do
| Can | Cannot |
|---|---|
| pause new rounds | touch a pool, a vault, tokens or income |
| change the params for future rounds | change an open round's rules |
| change the treasury and the keeper | paint, change a frozen canvas or the picture of a coin |
| hand over the admin role | stop refunds or claims |
Risks
- The program is upgradeable (the upgrade authority is the project wallet) and has not been audited by a third party.
- The keeper renders and uploads the picture. The hash on chain lets anyone check it, but a keeper that stops working means the round is voided and refunded, not launched.
- pump.fun can reassign a coin's creator by hand; income would then stop reaching the fee account.
- A whale can repaint the whole canvas. That is the game, and it is visible to everyone while it happens.
- A coin is a market. Its price can go to zero.
FAQ
Can I take my SOL back before the bell?
No. A commit is paint you bought. Refunds exist only for a round that fails or is voided.
Why does the bell keep moving?
Someone painted in the last minutes. It moves at most 30 minutes past the planned end.
What if I paint and get painted over?
Your tokens do not change: they follow the SOL you committed. Only the income share follows surviving pixels.
Why is there no picture upload for the whole logo?
There is: the Stamp tool maps any picture to the round's palette and paints it as a draft. You still pay for every pixel, like everyone else.