dilatant

:: The sample

Handling it

The sample is a rendering. It reports nothing, it reads nothing from the chain, and no number shown beside it describes the state of the supply. What it responds to is the visitor, and only the visitor.

Push it gently and it flows. The mass gives, the lobes stretch, and it follows the pointer wherever it is taken. Push it hard and it will not go. The surface tightens, the give disappears, and the same gesture that moved it easily a moment ago moves it barely at all. Release it and it softens on its own over a couple of seconds, without being asked and without anything being reset.

The curve governing that resistance is the curve on the sheet, with the same floor, the same ceiling, and the same exponent. Only the input differs. Here the force applied is a hand on a screen. There it is the volume moved through the program inside the trailing window. The response is identical in both cases because it is the same function, and it is the closest thing to the material anyone can handle directly.


:: Source

Native. No framework. No interface definition file. Upgrade authority burned.


1// dilatant
2// a shear thickening supply
3// no framework, no idl, no admin, no upgrade path
4
5#![deny(unsafe_code)]
6
7use solana_program::{
8 account_info::{next_account_info, AccountInfo},
9 clock::Clock,
10 entrypoint,
11 entrypoint::ProgramResult,
12 program::invoke_signed,
13 program_error::ProgramError,
14 pubkey::Pubkey,
15 sysvar::Sysvar,
16};
17
18// ---------------------------------------------------------------
19// constants. compiled in. no instruction reaches these.
20// ---------------------------------------------------------------
21
22/// trailing window, in slots. roughly twelve minutes.
23pub const WINDOW_SLOTS: u64 = 1_800;
24
25/// the window is a ring of buckets rather than a list of transfers,
26/// so the record is bounded and the read cost is constant.
27pub const BUCKETS: usize = 60;
28pub const BUCKET_SLOTS: u64 = WINDOW_SLOTS / BUCKETS as u64; // 30
29
30/// resistance floor and ceiling, in basis points.
31pub const BASE_BPS: u64 = 30;
32pub const CEILING_BPS: u64 = 900;
33
34/// the reference cannot be zero or the curve is undefined before
35/// the first transfer.
36pub const REFERENCE_FLOOR_BPS: u64 = 25;
37
38pub const BPS: u128 = 10_000;
39
40// ---------------------------------------------------------------
41// state. one account. written by the hook, read by anyone.
42// ---------------------------------------------------------------
43
44#[repr(C)]
45#[derive(Clone, Copy)]
46pub struct Material {
47 /// pda bump for the delegate authority
48 pub bump: u8,
49 pub _pad: [u8; 7],
50 /// slot of the most recent observation
51 pub last_slot: u64,
52 /// index of the bucket that last_slot falls in
53 pub cursor: u64,
54 /// highest shear ever recorded, in bps of supply. never falls.
55 pub set_bps: u64,
56 /// total burned by resistance, in base units. never falls.
57 pub taken: u64,
58 /// transfers observed. never falls.
59 pub strikes: u64,
60 /// the ring
61 pub buckets: [u64; BUCKETS],
62}
63
64impl Material {
65 pub const LEN: usize = 8 + 8 + 8 + 8 + 8 + 8 + (8 * BUCKETS);
66
67 /// advance the cursor and zero everything it passes.
68 /// this is the whole of relaxation. nothing is scheduled and
69 /// nothing has to be called for it to happen.
70 fn age(&mut self, slot: u64) {
71 let elapsed = slot.saturating_sub(self.last_slot);
72 let steps = (elapsed / BUCKET_SLOTS).min(BUCKETS as u64);
73
74 let mut i = 1;
75 while i <= steps {
76 let idx = ((self.cursor + i) % BUCKETS as u64) as usize;
77 self.buckets[idx] = 0;
78 i += 1;
79 }
80
81 if steps > 0 {
82 self.cursor = (self.cursor + steps) % BUCKETS as u64;
83 }
84 self.last_slot = slot;
85 }
86
87 /// sum of the ring as a fraction of supply, in bps.
88 /// measured against supply because supply falls permanently.
89 fn shear_bps(&self, supply: u64) -> u64 {
90 if supply == 0 {
91 return 0;
92 }
93 let mut sum: u128 = 0;
94 let mut i = 0;
95 while i < BUCKETS {
96 sum = sum.saturating_add(self.buckets[i] as u128);
97 i += 1;
98 }
99 ((sum * BPS) / supply as u128).min(BPS) as u64
100 }
101
102 fn observe(&mut self, amount: u64) {
103 let idx = (self.cursor % BUCKETS as u64) as usize;
104 self.buckets[idx] = self.buckets[idx].saturating_add(amount);
105 self.strikes = self.strikes.saturating_add(1);
106 }
107}
108
109// ---------------------------------------------------------------
110// the curve. integer only. no floating point anywhere.
111// ---------------------------------------------------------------
112
113/// yield = base + (ceiling - base) * min(1, shear/reference)^2
114///
115/// the ratio is squared rather than the amount, so nothing
116/// overflows at any supply this material can reach. rounding is
117/// toward zero at every step, so the resistance charged is never
118/// more than the resistance computed.
119pub fn yield_bps(shear_bps: u64, set_bps: u64) -> u64 {
120 let reference = core::cmp::max(set_bps, REFERENCE_FLOOR_BPS) as u128;
121 let ratio = ((shear_bps as u128 * BPS) / reference).min(BPS);
122 let squared = (ratio * ratio) / BPS;
123 let span = (CEILING_BPS - BASE_BPS) as u128;
124 BASE_BPS + ((span * squared) / BPS) as u64
125}
126
127pub fn resistance(amount: u64, yield_bps: u64) -> u64 {
128 ((amount as u128 * yield_bps as u128) / BPS) as u64
129}
130
131// ---------------------------------------------------------------
132// entrypoint
133// ---------------------------------------------------------------
134
135entrypoint!(process);
136
137/// discriminator for the transfer hook interface execute
138/// instruction. taken from the interface definition, not typed
139/// from memory. verify against the published constant before
140/// deploying.
141const EXECUTE: [u8; 8] = spl_transfer_hook_interface::instruction::ExecuteInstruction::SPL_DISCRIMINATOR
142 .into_bytes();
143
144pub fn process(
145 program_id: &Pubkey,
146 accounts: &[AccountInfo],
147 data: &[u8],
148) -> ProgramResult {
149 if data.len() < 8 {
150 return Err(ProgramError::InvalidInstructionData);
151 }
152 match data[0..8] {
153 d if d == EXECUTE => execute(program_id, accounts, &data[8..]),
154 _ => Err(ProgramError::InvalidInstructionData),
155 }
156}
157
158// ---------------------------------------------------------------
159// the hook. invoked by the balance program on every transfer.
160// there is no path around this call. it is enforced by the
161// program that holds the balances.
162// ---------------------------------------------------------------
163
164fn execute(
165 program_id: &Pubkey,
166 accounts: &[AccountInfo],
167 data: &[u8],
168) -> ProgramResult {
169 let amount = u64::from_le_bytes(
170 data.get(0..8)
171 .ok_or(ProgramError::InvalidInstructionData)?
172 .try_into()
173 .unwrap(),
174 );
175
176 let iter = &mut accounts.iter();
177 let source = next_account_info(iter)?;
178 let mint = next_account_info(iter)?;
179 let _destination = next_account_info(iter)?;
180 let _owner = next_account_info(iter)?;
181 let _extra_metas = next_account_info(iter)?;
182 let state = next_account_info(iter)?;
183 let delegate = next_account_info(iter)?;
184 let balance_program = next_account_info(iter)?;
185
186 if state.owner != program_id {
187 return Err(ProgramError::IllegalOwner);
188 }
189
190 let slot = Clock::get()?.slot;
191 let supply = read_supply(mint)?;
192
193 let mut m = load(state)?;
194
195 // 1. age the record. everything outside the window is gone.
196 m.age(slot);
197
198 // 2. measure the force applied before this transfer.
199 let shear = m.shear_bps(supply);
200
201 // 3. price this transfer against the state that existed
202 // before it. nothing prices itself.
203 let y = yield_bps(shear, m.set_bps);
204 let take = resistance(amount, y);
205
206 // 4. destroy it. there is no pool. nothing accumulates
207 // anywhere and there is nothing to claim.
208 if take > 0 {
209 burn(
210 balance_program,
211 source,
212 mint,
213 delegate,
214 take,
215 m.bump,
216 program_id,
217 )?;
218 m.taken = m.taken.saturating_add(take);
219 }
220
221 // 5. record it, and mark the set if this is the hardest
222 // this material has ever been pushed. the mark is
223 // permanent and moves in one direction only.
224 m.observe(amount);
225 let after = m.shear_bps(supply);
226 if after > m.set_bps {
227 m.set_bps = after;
228 }
229
230 store(state, &m)
231}
232
233// ---------------------------------------------------------------
234// burn, via the permanent delegate. the delegate is a pda with
235// no private key. no person can sign for it. this is the only
236// place in the program it is used, and it can only burn.
237// ---------------------------------------------------------------
238
239fn burn(
240 balance_program: &AccountInfo,
241 source: &AccountInfo,
242 mint: &AccountInfo,
243 delegate: &AccountInfo,
244 amount: u64,
245 bump: u8,
246 program_id: &Pubkey,
247) -> ProgramResult {
248 let ix = spl_token_2022::instruction::burn(
249 balance_program.key,
250 source.key,
251 mint.key,
252 delegate.key,
253 &[],
254 amount,
255 )?;
256
257 let seeds: &[&[u8]] = &[b"delegate", &[bump]];
258 let _ = program_id;
259
260 invoke_signed(
261 &ix,
262 &[source.clone(), mint.clone(), delegate.clone()],
263 &[seeds],
264 )
265}

The listing above is the source that was deployed. The build is reproducible and its hash can be compared against the program account. Nothing on this page is generated for display, including the part of it that moves.