web/src/types.ts61 lines · 2459 bytes
| 1 | // Demo implementations, rule ids and small number helpers shared by the whole app. |
| 2 | import { keccak256, stringToBytes, type Hex } from 'viem' |
| 3 | |
| 4 | /** Implementations deployed by script/DeployEth.s.sol that the page recognises by address */ |
| 5 | export type CardId = 'evilMint' | 'evilOwner' | 'evilFee' | 'evilBaseFee' | 'evilDrain' | 'v2' |
| 6 | export type ImplName = CardId | 'v1' | 'paused' |
| 7 | export const IMPL_KEYS: readonly ImplName[] = ['v1', 'v2', 'evilMint', 'evilOwner', 'evilFee', 'evilBaseFee', 'evilDrain', 'paused'] |
| 8 | |
| 9 | export interface CardInfo { |
| 10 | id: CardId |
| 11 | /** Contract name (a proper noun, never translated) */ |
| 12 | name: string |
| 13 | expect: 'veto' | 'pass' |
| 14 | expectRule: RuleId | null |
| 15 | } |
| 16 | |
| 17 | export const CARDS: CardInfo[] = [ |
| 18 | { id: 'evilMint', name: 'EvilMint', expect: 'veto', expectRule: 'R1_TOTAL_SUPPLY' }, |
| 19 | { id: 'evilOwner', name: 'EvilOwner', expect: 'veto', expectRule: 'R2_OWNER' }, |
| 20 | { id: 'evilFee', name: 'EvilFee', expect: 'veto', expectRule: 'R3_TRANSFER_CONSERVATION' }, |
| 21 | { id: 'evilBaseFee', name: 'EvilBaseFee', expect: 'veto', expectRule: 'R9_NEW_OPCODES' }, |
| 22 | { id: 'evilDrain', name: 'EvilDrain', expect: 'veto', expectRule: 'R3B_THIRD_PARTY_FUNDS' }, |
| 23 | { id: 'v2', name: 'DemoBTC v2', expect: 'pass', expectRule: null }, |
| 24 | ] |
| 25 | |
| 26 | /** Rule ids of the CRE workflow; ruleHash = keccak256(utf8("GUARD/<ID>")), the bytes32 carried by Vetoed */ |
| 27 | export const RULE_IDS = [ |
| 28 | 'R1_TOTAL_SUPPLY', |
| 29 | 'R2_OWNER', |
| 30 | 'R3_TRANSFER_CONSERVATION', |
| 31 | 'R3B_THIRD_PARTY_FUNDS', |
| 32 | 'R4_TRANSFER_LIVENESS', |
| 33 | 'R5_STRICT_CODEHASH', |
| 34 | 'R6_SIM_FAILURE', |
| 35 | 'R7_CONFIG_GUARD', |
| 36 | 'R8_INIT_DATA', |
| 37 | 'R9_NEW_OPCODES', |
| 38 | ] as const |
| 39 | export type RuleId = (typeof RULE_IDS)[number] |
| 40 | |
| 41 | export const ruleHashOf = (id: string): Hex => keccak256(stringToBytes(`GUARD/${id}`)) |
| 42 | /** ruleHash (lowercase) -> rule id */ |
| 43 | export const RULE_BY_HASH = new Map<string, RuleId>(RULE_IDS.map((r) => [ruleHashOf(r).toLowerCase(), r])) |
| 44 | |
| 45 | /** "R1_TOTAL_SUPPLY" -> "R1" */ |
| 46 | export const ruleShort = (rule: string): string => rule.split('_')[0] |
| 47 | |
| 48 | export function toBig(x: unknown): bigint | null { |
| 49 | try { |
| 50 | if (x === null || x === undefined || x === '') return null |
| 51 | if (typeof x === 'bigint') return x |
| 52 | if (typeof x === 'number') return BigInt(Math.round(x)) |
| 53 | if (typeof x === 'string') return BigInt(x) |
| 54 | } catch { |
| 55 | return null |
| 56 | } |
| 57 | return null |
| 58 | } |
| 59 | |
| 60 | export const ZERO32 = ('0x' + '00'.repeat(32)) as Hex |
| 61 | export const isZero32 = (h: string | null | undefined): boolean => !h || /^0x0*$/i.test(h) |