dilatant

:: Program

What is fixed and what is not

This page exists so that everything claimed elsewhere on the site can be checked instead of trusted. All of it is verifiable against the chain by anyone, without permission and without asking.

:: What is fixed


The window, the base, the ceiling, and the exponent are compiled into the program as constants. There is no instruction that modifies any of them. This is not an access control placed on those values. There is no code path that reaches them, and adding one would require replacing the program, which cannot be done.

The upgrade authority is burned. Once burned the program cannot be replaced, patched, or amended by anyone, including the person who deployed it. The transaction that burned it is on chain and dated and can be read directly.

There is no admin key, no multisig, no pause, no emergency stop, and no privileged caller. There is no instruction that moves the supply on anyone's behalf. There is no instruction that claims what the resistance destroys, because what the resistance destroys is burned at the moment it is taken and there is nothing left anywhere for anyone to claim.

The mint authority is revoked. The supply cannot increase. It only falls.

The permanent delegate is a program derived address with no private key. It appears in exactly one place in the source, in the burn performed inside the hook, and it is used for nothing else. It cannot transfer, only burn, and it burns only the computed fraction of an amount already in motion.

:: What is not fixed


This site is a website. It is hosted, it can go down, and it can be changed. Nothing described on this page depends on it. If it disappears entirely the program continues and the state remains readable by anyone with a connection to the chain.

The figures are drawn by this site from values it reads. The values are on the chain. The drawing is not.

Market state and price are not part of this system and are not claimed anywhere on this site. The program has no knowledge of price. It measures movement and nothing else.

:: Verification


The source below is the source that was deployed. The build is reproducible and the resulting hash can be compared against the program account.

The extensions attached to the mint are readable directly from the mint account, so the claim that every transfer is intercepted does not depend on anything written on this page. Anyone can confirm it against the mint itself in one read.

Anyone who wants to confirm that a specific transfer paid the resistance stated here can read that transaction, read the state account as it was, and recompute the figure from the function above. That is the intended use of this page.

:: Source


Native, no framework, no interface definition file. Constants first, then state, then arithmetic, then the hook.

// dilatant
// a shear thickening supply
// no framework, no idl, no admin, no upgrade path

#![deny(unsafe_code)]

use solana_program::{
    account_info::{next_account_info, AccountInfo},
    clock::Clock,
    entrypoint,
    entrypoint::ProgramResult,
    program::invoke_signed,
    program_error::ProgramError,
    pubkey::Pubkey,
    sysvar::Sysvar,
};

// ---------------------------------------------------------------
// constants. compiled in. no instruction reaches these.
// ---------------------------------------------------------------

/// trailing window, in slots. roughly twelve minutes.
pub const WINDOW_SLOTS: u64 = 1_800;

/// the window is a ring of buckets rather than a list of transfers,
/// so the record is bounded and the read cost is constant.
pub const BUCKETS: usize = 60;
pub const BUCKET_SLOTS: u64 = WINDOW_SLOTS / BUCKETS as u64; // 30

/// resistance floor and ceiling, in basis points.
pub const BASE_BPS: u64 = 30;
pub const CEILING_BPS: u64 = 900;

/// the reference cannot be zero or the curve is undefined before
/// the first transfer.
pub const REFERENCE_FLOOR_BPS: u64 = 25;

pub const BPS: u128 = 10_000;

// ---------------------------------------------------------------
// state. one account. written by the hook, read by anyone.
// ---------------------------------------------------------------

#[repr(C)]
#[derive(Clone, Copy)]
pub struct Material {
    /// pda bump for the delegate authority
    pub bump: u8,
    pub _pad: [u8; 7],
    /// slot of the most recent observation
    pub last_slot: u64,
    /// index of the bucket that last_slot falls in
    pub cursor: u64,
    /// highest shear ever recorded, in bps of supply. never falls.
    pub set_bps: u64,
    /// total burned by resistance, in base units. never falls.
    pub taken: u64,
    /// transfers observed. never falls.
    pub strikes: u64,
    /// the ring
    pub buckets: [u64; BUCKETS],
}

impl Material {
    pub const LEN: usize = 8 + 8 + 8 + 8 + 8 + 8 + (8 * BUCKETS);

    /// advance the cursor and zero everything it passes.
    /// this is the whole of relaxation. nothing is scheduled and
    /// nothing has to be called for it to happen.
    fn age(&mut self, slot: u64) {
        let elapsed = slot.saturating_sub(self.last_slot);
        let steps = (elapsed / BUCKET_SLOTS).min(BUCKETS as u64);

        let mut i = 1;
        while i <= steps {
            let idx = ((self.cursor + i) % BUCKETS as u64) as usize;
            self.buckets[idx] = 0;
            i += 1;
        }

        if steps > 0 {
            self.cursor = (self.cursor + steps) % BUCKETS as u64;
        }
        self.last_slot = slot;
    }

    /// sum of the ring as a fraction of supply, in bps.
    /// measured against supply because supply falls permanently.
    fn shear_bps(&self, supply: u64) -> u64 {
        if supply == 0 {
            return 0;
        }
        let mut sum: u128 = 0;
        let mut i = 0;
        while i < BUCKETS {
            sum = sum.saturating_add(self.buckets[i] as u128);
            i += 1;
        }
        ((sum * BPS) / supply as u128).min(BPS) as u64
    }

    fn observe(&mut self, amount: u64) {
        let idx = (self.cursor % BUCKETS as u64) as usize;
        self.buckets[idx] = self.buckets[idx].saturating_add(amount);
        self.strikes = self.strikes.saturating_add(1);
    }
}

// ---------------------------------------------------------------
// the curve. integer only. no floating point anywhere.
// ---------------------------------------------------------------

/// yield = base + (ceiling - base) * min(1, shear/reference)^2
///
/// the ratio is squared rather than the amount, so nothing
/// overflows at any supply this material can reach. rounding is
/// toward zero at every step, so the resistance charged is never
/// more than the resistance computed.
pub fn yield_bps(shear_bps: u64, set_bps: u64) -> u64 {
    let reference = core::cmp::max(set_bps, REFERENCE_FLOOR_BPS) as u128;
    let ratio = ((shear_bps as u128 * BPS) / reference).min(BPS);
    let squared = (ratio * ratio) / BPS;
    let span = (CEILING_BPS - BASE_BPS) as u128;
    BASE_BPS + ((span * squared) / BPS) as u64
}

pub fn resistance(amount: u64, yield_bps: u64) -> u64 {
    ((amount as u128 * yield_bps as u128) / BPS) as u64
}

// ---------------------------------------------------------------
// entrypoint
// ---------------------------------------------------------------

entrypoint!(process);

/// discriminator for the transfer hook interface execute
/// instruction. taken from the interface definition, not typed
/// from memory. verify against the published constant before
/// deploying.
const EXECUTE: [u8; 8] = spl_transfer_hook_interface::instruction::ExecuteInstruction::SPL_DISCRIMINATOR
    .into_bytes();

pub fn process(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    data: &[u8],
) -> ProgramResult {
    if data.len() < 8 {
        return Err(ProgramError::InvalidInstructionData);
    }
    match data[0..8] {
        d if d == EXECUTE => execute(program_id, accounts, &data[8..]),
        _ => Err(ProgramError::InvalidInstructionData),
    }
}

// ---------------------------------------------------------------
// the hook. invoked by the balance program on every transfer.
// there is no path around this call. it is enforced by the
// program that holds the balances.
// ---------------------------------------------------------------

fn execute(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    data: &[u8],
) -> ProgramResult {
    let amount = u64::from_le_bytes(
        data.get(0..8)
            .ok_or(ProgramError::InvalidInstructionData)?
            .try_into()
            .unwrap(),
    );

    let iter = &mut accounts.iter();
    let source = next_account_info(iter)?;
    let mint = next_account_info(iter)?;
    let _destination = next_account_info(iter)?;
    let _owner = next_account_info(iter)?;
    let _extra_metas = next_account_info(iter)?;
    let state = next_account_info(iter)?;
    let delegate = next_account_info(iter)?;
    let balance_program = next_account_info(iter)?;

    if state.owner != program_id {
        return Err(ProgramError::IllegalOwner);
    }

    let slot = Clock::get()?.slot;
    let supply = read_supply(mint)?;

    let mut m = load(state)?;

    // 1. age the record. everything outside the window is gone.
    m.age(slot);

    // 2. measure the force applied before this transfer.
    let shear = m.shear_bps(supply);

    // 3. price this transfer against the state that existed
    //    before it. nothing prices itself.
    let y = yield_bps(shear, m.set_bps);
    let take = resistance(amount, y);

    // 4. destroy it. there is no pool. nothing accumulates
    //    anywhere and there is nothing to claim.
    if take > 0 {
        burn(
            balance_program,
            source,
            mint,
            delegate,
            take,
            m.bump,
            program_id,
        )?;
        m.taken = m.taken.saturating_add(take);
    }

    // 5. record it, and mark the set if this is the hardest
    //    this material has ever been pushed. the mark is
    //    permanent and moves in one direction only.
    m.observe(amount);
    let after = m.shear_bps(supply);
    if after > m.set_bps {
        m.set_bps = after;
    }

    store(state, &m)
}

// ---------------------------------------------------------------
// burn, via the permanent delegate. the delegate is a pda with
// no private key. no person can sign for it. this is the only
// place in the program it is used, and it can only burn.
// ---------------------------------------------------------------

fn burn(
    balance_program: &AccountInfo,
    source: &AccountInfo,
    mint: &AccountInfo,
    delegate: &AccountInfo,
    amount: u64,
    bump: u8,
    program_id: &Pubkey,
) -> ProgramResult {
    let ix = spl_token_2022::instruction::burn(
        balance_program.key,
        source.key,
        mint.key,
        delegate.key,
        &[],
        amount,
    )?;

    let seeds: &[&[u8]] = &[b"delegate", &[bump]];
    let _ = program_id;

    invoke_signed(
        &ix,
        &[source.clone(), mint.clone(), delegate.clone()],
        &[seeds],
    )
}

Nothing on this page is a projection. If a value is not currently readable it is a single em dash.