by unspentTx

The coin that buys itself back

A self‑reinforcing market where early members profit and a growing last‑buyer prize drives financial incentives on chain.

Built on Cardano eUTXONon‑custodialOpen‑source
Rules are enforced 100% on‑chain with open source code and without batchers, offchain data feeds, custodians, or admins.

How it works

1) Buy

Mint the next numbered NFT. Your buy routes ADA on‑chain and extends the timer.

2) Burn

When eligible, burn your NFT to withdraw a deterministic share from the treasury.

3) Win

If the timer hits zero while you are the latest buyer, you can withdraw the pot.

The Incentive Loop

Fixed entry

Join at face value, like everyone else.

Early exits

A fixed share of early members can cash out value by burning their NFT.

Pot and timer grow

Each entry increases the prize and extends the clock fixed amounts.

Trust builds

On when demand ceases will a winner be determined.

More buy‑insMore early cash‑outsBigger last‑buyer prizeMore incentive to buy in

Knots sell value on discount in competitions that harness humans acting in their own best interest

Trust-based Growth Model

Knots attempt to create wealth through collective trust, not speculation on others' mistakes, rather it aknowledges human greed to arbitrage value as a constant that be can be built ontop of.

Decentralized identity

Burn rewards go to the wallet who destroys the NFT, not the wallet who minted it. Therefore potential value is easily transferred to other wallets or through secondary markets.

Automated buyback

Every entry routes value on‑chain: growing the pot and funding early exits in transparent and predictable ways.

Dual incentives

Be early or be last, users buy because they want to take risk and make a profit. The carrot‑on‑a‑stick design ensures compounded trust and risk as the clock and pot grow.

0 admins0 custodians100% on‑chain buyback logic

Why KnotCash?

Open source code

Deterministic and auditable by anyone, read the docs.

Web3 only

Built on UTXO first principles, Knots are not conceivable in legacy finance.

Solo Dev

Built from curiosity and the love of programming, not money.

Freedom technology

No one can tell you what is valuable and what is Knot.

oracle.ak
// 🖲️ store and spend the state thread game logic
use cardano/transaction.{Input,
  Output, OutputReference, Transaction, find_input}
use cocktail.{inputs_at_with_policy, outputs_at_with_policy}
use utils/datum_oracle.{OracleDatum}
use utils/find_policy_id_of_first_token.{find_policy_id_of_first_token}
use utils/redeemer_oracle.{MintDsNFT, OracleRedeemer}
use utils/utils_oracle.{is_datum_updated, is_output_value_clean, is_value_paid}
 
pub fn oracle_spend(
  datum_opt: Option<OracleDatum>,
  redeemer: OracleRedeemer,
  input: OutputReference,
  tx: Transaction,
) {
  // find the input being spent
  expect Some(own_input) = find_input(tx.inputs, input)
  // find the NFT from its own input
  let oracle_nft_policy = find_policy_id_of_first_token(own_input)
  // find the address of the input being spent
  let own_address = own_input.output.address
  // destructure input datum
  expect Some(input_datum) = datum_opt
  when
    (
      redeemer,
      inputs_at_with_policy(tx.inputs, own_address, oracle_nft_policy),
      outputs_at_with_policy(tx.outputs, own_address, oracle_nft_policy),
    )
  is {
    (
      // when the redeemer includes a new_winner
      MintDsNFT { winner: new_winner },
      // when 1 input with oracle nft is present
      [_],
      // when 1 output with oracle nft is present
      [only_output],
    ) ->
      and {
        is_output_value_clean(only_output),
        is_datum_updated(input_datum, only_output, new_winner),
        is_value_paid(tx, input_datum),
      }
    _ -> False
  }
}
 
validator oracle {
  spend(
    datum_opt: Option<OracleDatum>,
    redeemer: OracleRedeemer,
    input: OutputReference,
    tx: Transaction,
  ) {
    oracle_spend(datum_opt, redeemer, input, tx)
  }
 
  else(_) {
    fail
  }
}
 
oracle_nft.ak
// 🖲️ one shot nft policy for state thread
use cardano/address.{Address}
use cardano/assets.{PolicyId}
use cardano/transaction.{OutputReference, Transaction}
use utils/utils_oracle_nft.{
  listing_is_sent, nft_names, one_time, oracle_is_sent, tokens_are_minted,
}
 
pub fn oracle_nft_mint(
  utxo_ref: OutputReference,
  oracle_address: Address,
  knot_address: Address,
  knot_fee: Int,
  policy_id: PolicyId,
  tx: Transaction,
) {
  // [utxo_ref.transaction_id, "Knot A Receipt"]
  expect [oracle_name, receipt_name] = nft_names(utxo_ref)
 
  and {
    // Makes sure utxo_ref is a part of the inputs
    one_time(tx.inputs, utxo_ref)?,
    // Checks if only two tokens are minted and their names are orcale_name and receipt_name
    tokens_are_minted(tx.mint, policy_id, oracle_name, receipt_name, 1)?,
    // Checks if oracle_nft is (name and policy) is sent to oracle_address
    oracle_is_sent(tx.outputs, policy_id, oracle_address, oracle_name)?,
    // Checks if correct fee is sent to knot_address. 
    listing_is_sent(tx.outputs, knot_address, knot_fee)?,
  }
}
 
validator oracle_nft(
  utxo_ref: OutputReference,
  oracle_address: Address,
  knot_address: Address,
  knot_fee: Int,
) {
  mint(_redeemer: Data, policy_id: PolicyId, tx: Transaction) {
    oracle_nft_mint(
      utxo_ref,
      oracle_address,
      knot_address,
      knot_fee,
      policy_id,
      tx,
    )
  }
 
  else(_) {
    fail
  }
}
 
ds_nft.ak
// 🫀 mint and burn ds_nft (ds is a nod to the original contract I called Double Spent)
use aiken/primitive/bytearray.{from_string}
use cardano/assets.{PolicyId}
use cardano/transaction.{InlineDatum, Input, Transaction}
use cocktail.{
  check_policy_only_burn, convert_int_to_bytes, inputs_with, inputs_with_policy,
  only_minted_token,
}
use utils/datum_oracle.{OracleDatum}
use utils/utils_ds_nft.{MintPolarity, RBurn, RMint, check_game_mode}
use utils/config.{config_receipt_name_string}
 
pub fn ds_nft_mint(
  oracle_nft: PolicyId,
  redeemer: MintPolarity,
  policy_id: PolicyId,
  tx: Transaction,
) {
  when redeemer is {
    RMint ->
      when inputs_with_policy(tx.inputs, oracle_nft) is {
        // when 1 oracle input is present
        [oracle_input] ->
          // There are 2 nfts from this policy so we make sure the receipt is not present, and infer the real oracle nft is being spent
          when
            inputs_with(
              [oracle_input],
              oracle_nft,
              from_string(config_receipt_name_string),
            )
          is {
            [_] -> False
            _ -> {
              // Oracle NFT is being spent
              // with inline datum
              expect InlineDatum(input_datum) = oracle_input.output.datum
              expect OracleDatum { count, mode, slot_start, slot_increase, .. } =
                input_datum
              and {
                only_minted_token(
                  tx.mint,
                  policy_id,
                  convert_int_to_bytes(count),
                  1,
                ),
                check_game_mode(tx, slot_start, slot_increase, count, mode),
              }
            }
          }
        _ -> False
      }
    // all minting values are negative 
    RBurn -> check_policy_only_burn(tx.mint, policy_id)
  }
}
 
validator ds_nft(oracle_nft: PolicyId) {
  mint(redeemer: MintPolarity, policy_id: PolicyId, tx: Transaction) {
    ds_nft_mint(oracle_nft, redeemer, policy_id, tx)
  }
 
  else(_) {
    fail
  }
}
 
treasury.ak
// 💰 burn a ds_nft to unlock utxos length of divisor
use aiken/builtin.{divide_integer, less_than_integer}
use aiken/collection/list
use aiken/primitive/int.{from_utf8}
use cardano/assets.{PolicyId}
use cardano/transaction.{
  InlineDatum, Output, OutputReference, Transaction, find_input,
}
use cocktail.{inputs_at, inputs_with_policy, only_minted_token}
use utils/datum_oracle.{OracleDatum}
use utils/redeemer_treasury.{TreasuryRedeemer, Withdraw}
 
pub fn treasury_spend(
  oracle_nft: PolicyId,
  nft_policy: PolicyId,
  redeemer: TreasuryRedeemer,
  input: OutputReference,
  tx: Transaction,
) {
  when
    (
      redeemer,
      inputs_with_policy(tx.reference_inputs, oracle_nft),
      find_input(tx.inputs, input),
    )
  is {
    (
      // when redeemer has asset name
      Withdraw { asset_name },
      // when 1 input reference with oracle nft is present
      [oracle_input_ref],
      // when we are spending our own input
      Some(own_input),
    ) ->
      when (oracle_input_ref.output.datum, from_utf8(asset_name)) is {
        (
          // when oracle utxo has some inline datum
          InlineDatum(oracle_datum),
          // when the redeemer's asset name converts to an integer from utf8
          Some(asset_name_int),
        ) -> {
          // oracle datum is valid
          expect OracleDatum { count, divisor, .. } = oracle_datum
          // use asset_name to check for burn
          let is_burned = only_minted_token(tx.mint, nft_policy, asset_name, -1)
          // use asset_name_int to check if less than count divided by divisor
          let under_threshold =
            less_than_integer(asset_name_int, divide_integer(count, divisor))
          // use divisor to check amount of inputs being spent
          let is_correct_input_count =
            list.length(inputs_at(tx.inputs, own_input.output.address)) == divisor
          is_burned? && under_threshold? && is_correct_input_count?
        }
        _ -> {
          trace @"Invalid oracle datum or nft name integer"
          False
        }
      }
    _ -> {
      trace @"Invalid redeemer, oracle input reference, or own input"
      False
    }
  }
}
 
validator treasury(oracle_nft: PolicyId, nft_policy: PolicyId) {
  spend(
    _datum_opt: Option<Data>,
    redeemer: TreasuryRedeemer,
    input: OutputReference,
    tx: Transaction,
  ) {
    treasury_spend(oracle_nft, nft_policy, redeemer, input, tx)
  }
 
  else(_) {
    fail
  }
}
 
pot_spend.ak
// 🪺 store utxos for winner - spend logic offloaded to pot_withdraw validator
use aiken/crypto.{ScriptHash}
use aiken_design_patterns/stake_validator
use cardano/transaction.{OutputReference, Transaction}
 
pub fn pot_spend_spend(withdraw_script_hash: ScriptHash, tx: Transaction) {
  stake_validator.spend_minimal(
    withdraw_script_hash: withdraw_script_hash,
    tx: tx,
  )
}
 
validator pot_spend(withdraw_script_hash: ScriptHash) {
  spend(
    _datum_opt: Option<Data>,
    _redeemer: Void,
    _input: OutputReference,
    tx: Transaction,
  ) {
    pot_spend_spend(withdraw_script_hash, tx)
  }
 
  else(_) {
    fail
  }
}
 
pot_withdraw.ak
// 🪺 be the winner and wait for timer to expire to withdraw the pot utxos
use aiken_design_patterns/stake_validator
use cardano/address.{Credential}
use cardano/assets.{PolicyId}
use cardano/transaction.{InlineDatum, Transaction}
use cocktail.{inputs_with_policy, key_signed, valid_after}
use utils/datum_oracle.{OracleDatum}
 
pub fn pot_withdraw_withdraw(
  oracle_nft: PolicyId,
  own_credential: Credential,
  tx: Transaction,
) {
  stake_validator.withdraw(
    // This logic runs once per transaction rather than once per utxo
    withdrawal_logic: fn(_own_validator, tx) {
      when inputs_with_policy(tx.reference_inputs, oracle_nft) is {
        [oracle_input_ref] ->
          when oracle_input_ref.output.datum is {
            // some datum is present
            InlineDatum(oracle_datum) -> {
              // oracle datum is valid
              expect OracleDatum {
                count,
                slot_start,
                slot_increase,
                winner,
                ..
              } = oracle_datum
              and {
                // is_winner?,
                key_signed(tx.extra_signatories, winner),
                // is_timer_expired?,
                valid_after(
                  tx.validity_range,
                  slot_start + count * slot_increase,
                ),
              }
            }
            _ -> {
              trace @"Invalid oracle datum"
              False
            }
          }
        _ -> {
          trace @"Invalid redeemer or oracle reference"
          False
        }
      }
    },
    stake_cred: own_credential,
    tx: tx,
  )
}
 
validator pot_withdraw(oracle_nft: PolicyId) {
  withdraw(_redeemer: Void, own_credential: Credential, tx: Transaction) {
    pot_withdraw_withdraw(oracle_nft, own_credential, tx)
  }
 
  else(_) {
    fail
  }
}
 
marketplace.ak
// 🔀 Trade NFTs peer to peer
use cardano/address.{Address}
use cardano/assets.{from_lovelace, lovelace_of}
use cardano/transaction.{Input, OutputReference, Transaction, find_input}
use cocktail.{
  address_pub_key, get_all_value_to, inputs_at, key_signed, value_geq,
}
use utils/datum_marketplace.{MarketplaceDatum}
use utils/redeemer_marketplace.{Buy, Close, MarketplaceRedeemer}
 
pub fn marketplace_spend(
  owner: Address,
  fee_percentage_basis_point: Int,
  datum_opt: Option<MarketplaceDatum>,
  redeemer: MarketplaceRedeemer,
  input: OutputReference,
  tx: Transaction,
) {
  expect Some(datum) = datum_opt
  when redeemer is {
    Buy -> {
      expect Some(own_input) = find_input(tx.inputs, input)
      let own_address = own_input.output.address
      let is_only_one_input_from_own_address =
        when inputs_at(tx.inputs, own_address) is {
          [_] -> True
          _ -> False
        }
      let is_proceed_paid =
        get_all_value_to(tx.outputs, datum.seller)
          |> value_geq(
              from_lovelace(datum.price + lovelace_of(own_input.output.value)),
            )
      let is_fee_paid =
        get_all_value_to(tx.outputs, owner)
          |> value_geq(
              from_lovelace(datum.price * fee_percentage_basis_point / 10000),
            )
      is_only_one_input_from_own_address && is_fee_paid && is_proceed_paid
    }
    Close -> {
      expect Some(pub_key) = address_pub_key(datum.seller)
      key_signed(tx.extra_signatories, pub_key)
    }
  }
}
 
validator marketplace(owner: Address, fee_percentage_basis_point: Int) {
  spend(
    datum_opt: Option<MarketplaceDatum>,
    redeemer: MarketplaceRedeemer,
    input: OutputReference,
    tx: Transaction,
  ) {
    marketplace_spend(
      owner,
      fee_percentage_basis_point,
      datum_opt,
      redeemer,
      input,
      tx,
    )
  }
 
  else(_) {
    fail
  }
}