ForgeVault
ForgeVault locks and vests tokens on Kaspa L1. You choose the token, the amount, the wallet that receives it and the dates; your wallet signs; a contract on the chain holds the tokens and releases them on schedule. ForgeVault never holds your keys or your tokens.
GET /api/v1/locked: every open lock, with its contract script.
At a glance
| Item | Value |
|---|---|
| Network | Kaspa mainnet |
| Tokens | Any KCC-20 token (KasForge, KasSeal, KaspaRocket, standard KRON tokens) and KRON's own format |
| Kinds | Time lock (one date), cliff vesting (up to three dates), linear vesting. Payment streams: coming soon |
| Who can collect | Only the receiving wallet, once a date has passed |
| Changes | None: a lock cannot be cancelled, shortened or redirected, not even by PumpForge |
| Custody | None: every transaction is signed in your own wallet |
| Audit | Tested, not independently audited (see Risks) |
Locks and vesting
Three kinds of lock, all enforced by a contract on the chain.
| Kind | How it releases | Contract |
|---|---|---|
| Time lock | Everything at one date | ForgeLock |
| Cliff vesting | Up to three dates, each releasing its own share | one ForgeLock per date |
| Linear vesting | Nothing before the cliff, then a straight line from the start to the end date | ForgeVest |
How far ahead
- Time locks and cliff dates: each date up to 10 years away (a site rule; the time-lock contract itself has no maximum date).
- Linear vesting: the site lets it end up to about 2000 days (about 5.5 years) from now. The contract itself allows at most 2000 days from the start to the end (it keeps the vesting arithmetic inside the numbers a Kaspa script can use); the site's rule is a little stricter and simpler. For longer schedules, use cliff dates.
Making a lock
- Connect your wallet and pick the token. ForgeVault lists the tokens your wallet holds.
- Enter the amount, the receiving wallet (yours by default) and the date or dates.
- Check the summary: the fee, the deposits and the network fee, and what your wallet will pay in total.
- Sign in your wallet. The lock gets its own public page as soon as the network accepts it.
Collecting
- Only the receiving wallet can collect, from the lock's page, once a date has passed (linear vesting: whatever has vested so far, at any time).
- Unlocked tokens wait in the contract until they are collected. Nothing expires.
- One Collect takes every unlocked date of a lock at once (KRON's own format: one date at a time).
Dates and times
Kaspa contracts count time in DAA score, which rises about ten times a second. ForgeVault turns your dates into DAA scores, so a lock can open a little earlier or later than the clock time shown, more so for dates far away. The DAA score is the rule.
Nothing can be changed
A lock cannot be cancelled, shortened, extended or redirected once it is on the chain. Check the receiving wallet and the dates before you sign.
Payment streams
A stream pays a receiver second by second between two dates, in KAS or in a token. A cancellable stream can be stopped by the payer: the receiver keeps what has unlocked and the rest returns to the payer.
Supported tokens
| Format | Who uses it | Available |
|---|---|---|
| KCC-20 reference format | KasForge, KasSeal, KaspaRocket and standard KRON tokens | Time lock, cliff vesting, linear vesting |
| KRON's own format | Custom KRON tokens | Time lock and cliff vesting (up to three dates) |
The badge next to a token says which launchpad's programs it matches. It is not a review of the token: names, tickers and logos are set by the token's creator and can imitate other projects. Always check the token id.
What you sign
ForgeVault prepares each transaction; your wallet shows it and signs it. Nothing moves until you approve.
The check before your wallet opens
Before your wallet is asked to sign, the page checks the transaction ForgeVault prepared. It stops, and nothing is signed, unless all of this holds:
- only your own coins and the token pieces you chose are signed, with the standard signature type (SIGHASH_ALL);
- KAS goes only back to you, into the lock, and to the ForgeVault fee wallet, which receives exactly the fee shown;
- in total, no more leaves your wallet than the fee, the deposits and the network fee shown.
The contracts themselves also accept only that signature type, so a collect signature always covers the whole transaction and can never be reused for one that sends the tokens somewhere else.
The check runs in your browser and guards against a fault or tampering on our side. It does not protect you from a fake site or a compromised device: use only vault.pumpforge.tech, and read what your wallet shows.
Prepared transactions
A prepared transaction is valid for 5 minutes and can be sent once. After that, start again.
Accepting the terms
The first time a wallet uses ForgeVault, it signs its acceptance of the Terms, Privacy Policy and Risk Disclosure: a message, or with wallets that cannot sign messages, a transaction that is never sent. No KAS moves. It is asked again only when the terms change.
Wallets and phones
| Where | How to connect |
|---|---|
| Computer | The Kasware, Kastle or Kaspire browser extension, or the Kaspire app on your phone by scanning a QR code (WalletConnect) |
| Phone, Chrome or Safari | Pick Kaspire: the Kaspire app (Android) connects with WalletConnect. Your phone switches to Kaspire to approve, then back. |
| Phone, Kastle or Kasware app | Open vault.pumpforge.tech inside the app's own browser and connect there. ForgeVault shows the steps and copies the link for you. |
Wallet names
Where a wallet has a .kaspa or .kas name, ForgeVault shows the name in place of the address. Names come from public name services and are for display only; the summary before you sign always shows the address itself.
Fees and deposits
| Item | Amount |
|---|---|
| Lock or vesting | About $10, paid in KAS at the last hour's average KAS price (shown before you sign) |
| Collecting, merging pieces | No ForgeVault fee |
| Network fee | Every transaction, usually a small fraction of a KAS |
| Deposits | A small amount of KAS that each lock piece and lock coin needs to exist on the chain (about 1.2 KAS per date, up to 3 KAS). Not a fee: it comes back when the lock is collected. |
The live amounts are on the Fees page.
Verify a lock
You don't have to trust this site: a lock is a contract on the chain, and anyone can check it.
How a lock holds tokens
A locked token piece is owned by a script, not a wallet: its owner is the hash of the lock contract (KCC-20 owner scheme 3, pay-to-script-hash; KRON: a script owner). The token then moves only together with a KAS coin locked to the same script, and that coin opens only by the contract's rules: the receiving wallet's signature, after the date.
Check it
- Open the lock's page and copy the token id; or find the lock in the locked tokens feed.
- In the feed,
contract.redeemScriptis the lock's contract. Its BLAKE2b-256 hash must equalholder.hash, and that must be the owner of the token piece on chain (open the token on Kascov and find the holderholder.address). On your own node, the piece attokensOutpointshould show owner scheme 3 with that hash, and borrowing disabled (borrow scheme 0). - Read the script: for a time lock it names the receiving wallet's key and the unlock DAA score (layout in Contracts).
- Or let a tool do steps 2 and 3 for every lock: the public repository has a Rust checker that rebuilds each lock's script from the published source with its arguments, and checks the feed's dates, wallets and token against it, and a quick JavaScript check for time locks. Values a script does not contain (a time lock's token and amount, a vesting's current balance) are shown as "feed only": confirm those on the chain.
If the hash matches, the script is the rule the chain enforces: no one, including PumpForge, can move the tokens any other way.
Risks
- Not audited. The contracts are tested against Kaspa's own transaction rules and the live token programs they hold, but have not been independently audited. Only lock what you can afford to lose.
- Final. A wrong amount, date or receiving wallet cannot be fixed.
- Dates are estimates. The DAA score is the rule; clock times shown are estimates.
- Tokens. A lock only proves tokens are held until a date; it says nothing about a token's value or team.
- Keys. If the receiving wallet's key is lost, nobody can collect, including PumpForge.
- Lock addresses. Never send tokens or KAS to a lock's address by hand: only locks made through ForgeVault are tracked, and KAS sent to a vesting's address after it is fully collected stays there.
- Your device. Sign only on vault.pumpforge.tech and read what your wallet shows. A fake site or a compromised device can ask you to sign something else; no contract can protect against that.
- Service. If ForgeVault is offline the contracts keep working and the tokens stay locked for the receiving wallet; collecting through the site waits until it is back.
The full text: Risk Disclosure.
For explorers and indexers
When tokens are locked, the token's holder list shows the lock contract as a holder: a script address (kaspa:p…). ForgeVault publishes which of those holders are locks, so an explorer can show them as locked instead of as a wallet.
Marking locked holders
- Fetch
GET /api/v1/locked(all open locks) or?token=<token id>for one token, every few minutes. - For each lock,
holder.hashis the owner of a token piece (KCC-20: owner scheme3with that owner; KRON: script owner type1).holder.addressis the same as akaspa:p…address. - Check it: BLAKE2b-256 of
contract.redeemScriptmust equalholder.hash(see the snippet). Never mark a holder from the feed alone. - Show it, for example: Locked · unlocks 12 Mar 2027 · ForgeVault, linking to
page. For linear vesting uselinear.endAtand say "vesting".
What the feed covers
- Open locks made through ForgeVault: time locks, cliff vesting dates and linear vestings.
- A lock leaves the feed once its tokens are collected (they leave the script).
- Unlocked but not yet collected tokens stay in the feed with
status: "unlocked": they still sit in the contract. - Linear vestings made before 26 October 2026 used an older contract and are not listed.
The lock's KAS coin
Each lock also holds a small KAS coin (the deposit) at the same script address (lockCoinOutpoint). It is part of the lock, not anyone's balance.
Locked tokens feed
Every open ForgeVault lock, with the holder it appears as and its contract script. Public, no key, readable from any origin (CORS *).
Query parameters
| Parameter | Meaning |
|---|---|
token | Only this token (64-hex token id) |
holder | Only this holder: a kaspa:p… address or the 64-hex hash |
beneficiary | Only locks that release to this wallet address |
Response
{
"ok": true, "version": 1, "network": "mainnet",
"daa": 412345678, "now": 1793049024, "count": 1,
"locks": [{
"id": "34f2…2752:0", // the lock piece (stable id)
"lock": "34f2…2752", // the lock (one page; a cliff vesting has one piece per date)
"page": "https://vault.pumpforge.tech/lock/34f2…2752",
"token": "abab…abab", "format": "kcc20", "kind": "time-lock",
"holder": {
"address": "kaspa:pphwmvrd…zppa",
"hash": "6eedb06d…cebbf",
"owner": { "ownerScheme": 3, "owner": "6eedb06d…cebbf" }
},
"amount": "300000", "claimable": "0", "status": "locked",
"beneficiary": "kaspa:qpx5…pmd", "creator": "kaspa:qqdc…q3",
"unlockDaa": 418000000, "unlockAt": 1800000000, "linear": null,
"tokensOutpoint": "34f2…2752:0", "lockCoinOutpoint": "34f2…2752:2",
"createdTxid": "34f2…2752", "createdAt": 1793000000,
"contract": { "name": "ForgeLock v4", "redeemScript": "76043f64…6a68",
"args": [ { "name": "beneficiary", "type": "pubkey", "value": "4d4b…0766" }, { "name": "unlockDaa", "type": "int", "value": 418000000 } ] }
}]
}
Fields
| Field | Meaning |
|---|---|
holder.hash, holder.address | The token piece's owner: the lock script's hash, and the same as a script address |
holder.owner | How the token's state names it: KCC-20 {ownerScheme: 3, owner}; KRON {kronOwnerType: 1, owner} |
amount | Tokens in the piece now, in base units, as a string (amounts can exceed 253) |
claimable | Of those, how many the receiver could collect now (null if the chain could not be read) |
status | locked, unlocking (linear vesting under way), unlocked (all collectable, not yet collected), unknown |
kind | time-lock (also each date of a cliff vesting) or linear-vesting |
unlockDaa, unlockAt | Unlock DAA score (the rule) and its estimated unix time. Linear vesting: the end. |
linear | For linear vesting: total, startDaa/cliffDaa/endDaa and the estimated startAt/cliffAt/endAt |
contract.redeemScript | The lock contract (hex). BLAKE2b-256 of it is holder.hash. |
contract.args | The arguments the script was compiled from (name, type, value, in the contract's order). Compiling the published source with them gives redeemScript byte for byte. |
Stability and limits
/api/v1/…is versioned: fields are not removed or renamed in v1; new fields may be added.- Up to 600 requests a minute per address. One full fetch every few minutes is plenty.
- Questions or a higher limit: contact@pumpforge.tech.
Contracts
Locks use plain pay-to-script-hash contracts written in SilverScript. Their sources are public.
| Contract | Used for | Arguments |
|---|---|---|
ForgeLock v4 | Time locks and each date of a cliff vesting | beneficiary (32-byte x-only key), unlockDaa |
ForgeVest v6 | Linear vesting | beneficiary, total, start/cliff/end DAA, the token's template, the token id and a salt |
Compiler: SilverScript 1.0.0 (kaspanet/silverscript, commit 3ed97333). Compiling a source with a lock's arguments (contract.args) gives its redeemScript byte for byte.
ForgeLock layout
A ForgeLock script is fixed bytes around its two arguments:
76043f64dcc7876375768201419d75 // fixed
<unlockDaa> // the unlock DAA score as a minimal script-number push
7600050088526a74a569b07676827c75519601419c6976014001417f010187697820
// fixed (checks the SIGHASH_ALL byte; ends with a 32-byte push)
<beneficiary> // 32-byte x-only public key of the receiving wallet
ac69757551676a68 // fixed
So the receiving wallet and the unlock score can be read straight from the script, and a script with other fixed bytes is not a ForgeLock.
Check a lock (JavaScript)
import { blake2b } from '@noble/hashes/blake2b';
const r = await fetch('https://vault.pumpforge.tech/api/v1/locked?token=' + TOKEN_ID);
const { locks } = await r.json();
for (const l of locks) {
const h = Buffer.from(blake2b(Buffer.from(l.contract.redeemScript, 'hex'), { dkLen: 32 })).toString('hex');
if (h !== l.holder.hash) continue; // not proven: do not mark
markLocked(l.holder.address, l); // e.g. "Locked until …, ForgeVault"
}
Kaspa's pay-to-script-hash uses the same hash: the output script is OP_BLAKE2B OP_DATA_32 <hash> OP_EQUAL.
Other endpoints
The site's own endpoints. They are public but shaped for ForgeVault's pages and may change; for integrations use /api/v1.
Network, node, fees and counts.
Locks grouped as the pages show them. ?token=, ?address=.
One lock with its dates and collects.
Support and legal
- Email: contact@pumpforge.tech
- Discord: PumpForge
- Terms of Use · Privacy Policy · Risk Disclosure · Fees
Nothing in these docs is financial advice.