How Pact works on-chain
Every Pact lives twice: once as a web page, and once as a pair of NFTs permanently stored on the Base Sepolia testnet. Here’s exactly what gets stored, when, and why.
The basics
When you create or join a pact, Pact silently provisions a Coinbase Developer Platform (CDP) embedded wallet for you using your email address. You never see a seed phrase or sign a transaction — the wallet is managed server-side on your behalf.
Once both of you have checked in at least once, a nightly job mints a pair of NFTs — one to each participant’s wallet — called digital twins. Both tokens contain the same check-in record. The pact belongs to both of you equally.
What gets stored on-chain
Each NFT has nine on-chain parameters:
- goal — the goal text you typed (up to 60 characters)
- participantAName — the creator’s display name
- participantBName — the invitee’s display name
- record — the full check-in history, bit-packed (2 bits per day)
- status — Active, Complete, or Abandoned
- participantACheckins — running check-in count for the creator
- participantBCheckins — running check-in count for the invitee
- cadence — check-ins per week (3, 4, 5, or 7)
- duration — pact length in days (14, 28, or 56)
The record field encodes each day as 2 bits: 00 = neither checked in, 01 = A only, 10 = B only, 11 = both. A 56-day pact fits in 14 bytes — comfortably under the 32-byte param limit.
The contract: ABX SeriesCode
The NFTs live in an Art Blocks Experiment (ABX) SeriesCode contract deployed on Base Sepolia (chain ID 84532). ABX SeriesCode is a generative NFT standard that stores arbitrary typed parameters on-chain alongside the token, making them readable by any on-chain renderer or off-chain indexer.
Params are split into two storage paths in the ABX protocol:
- Data path (
configureTokenParamData) — for String, Bytes, and Select params. Stores the actual bytes on-chain; the contract records their keccak256 hash in the param slot so renderers can verify integrity. - Scalar path (
configureTokenParam) — for Uint256 and Range params. Writes a raw 32-byte value directly.
A common ABX integration mistake is using the scalar path for string params. That silently stores a raw bytes32 instead of the content hash — the contract doesn’t revert, but any renderer reading the data back gets garbage. Pact always uses the data path for goal, participantAName, participantBName, record, and status.
When minting happens
Minting is not retroactive. Only pacts created after Pact’s chain feature was activated are eligible. This prevents silently back-filling records for pacts that were created before the on-chain system existed.
Eligibility requires:
- Both participants have joined (pact status is active or completed).
- At least one check-in has been recorded by either participant.
- The pact was created on or after the chain launch date.
Once eligible, the nightly cron job mints both tokens and sends each participant an email with a link to their token on the Base Sepolia block explorer. After that, the same job updates the on-chain record nightly as new check-ins come in.
Nightly batch writes
The nightly job uses the ABX SDK’s batchOps() to collapse all param writes for both tokens into a single multicall transaction — one signature for many on-chain writes. Mints themselves cannot be batched (each one issues the next sequential token ID, so A must complete before B starts), but all nine param writes for both tokens are collapsed into one tx.
A single deployer key (ABX_DEPLOYER_PK) signs all transactions. The SDK’s makeHotSender pins the nonce at startup and increments it locally for each subsequent transaction, avoiding read-after-write lag on the RPC node.
Your names are permanent
Once minted, your display name and check-in history are part of an immutable blockchain record. Account deletion on Pact removes your email and off-chain data, but it cannot remove on-chain data. If you check in at least once, your name becomes permanent. We surface this prominently on the create and join forms so you can decide before you type anything.
Privacy
The record field encodes check-in dates as bit patterns — it does not identify which participant is A or B to any observer who only has the on-chain data. The goal text and display names are plain text and are publicly readable by anyone with the contract address and token ID.
The tokens are on Base Sepolia testnet, not mainnet. Testnet state can be reset by the network operators. We’ll document the path to mainnet when it’s ready.
View your token
When your token mints, you’ll receive an email with a direct link to it on Basescan (the Base Sepolia block explorer). You can also find it in your CDP wallet.