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

A round, step by step

StateWhat it meansWhat can happen
OpenThe clock is running. The canvas can change.commit, paint; after the bell anyone calls freeze
FrozenThe 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
LaunchedThe coin exists with the canvas as its picture.claim_tokens, claim_fees
FailedThe bell rang below the minimum.refund, in full
VoidFrozen but not created in time.refund, in full
  1. 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.
  2. 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.
  3. Paint. Painters spend their paint on pixels. Every stroke is a transaction and an event.
  4. 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.
  5. Birth. The coin is created with the canvas and bought with the pool in one transaction.
  6. 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 isCost
blank1
yours, another colour1
yours, the same colour0
someone else'sx2

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:

  1. checks the round is Frozen and inside the launch window, and that the uri is an IPFS address;
  2. sends the platform fee (1% of the pool) to the treasury and keeps a small rent reserve for the new accounts;
  3. 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;
  4. 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

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.

ParameterValue
Loading from chain

Program reference

Program --. Anchor 0.31, the full interface is the IDL.

AccountSeedsHolds
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
Canvasa 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
InstructionWho can call
open_roundanyone (becomes the opener)
commit, paintanyone, while Open
freezeanyone, after the bell
launchthe keeper, while Frozen and inside the window
voidanyone, Frozen and the window has passed
refund, claim_tokens, claim_feesanyone; the SOL or tokens go only to the painter's wallet
collect_fees, unwrap_fees, sync_feesanyone
claim_opener_fees, collect_treasuryanyone; 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.

CodeNameMeaning

Verify on chain

  1. The program. Open the program id in an explorer. Check the upgrade authority and that the IDL matches the one served here.
  2. The pool. The round's Vault holds exactly the pool (plus rent) while it is Open: vault = total + rent.
  3. The canvas. Read the Canvas account: 4,096 colour bytes at offset 40. Hash them with the palette as above and compare with canvas_hash in the round.
  4. 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.
  5. 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.
  6. One price. For any two claims, tokens divided by committed SOL is the same number.

What the admin can do

CanCannot
pause new roundstouch a pool, a vault, tokens or income
change the params for future roundschange an open round's rules
change the treasury and the keeperpaint, change a frozen canvas or the picture of a coin
hand over the admin rolestop refunds or claims

Risks

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.