Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions app/demos/b20/B20Demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { AnnouncementModule, SampleAnnouncementViewer } from './components/Annou
import { DeployModule } from './components/DeployModule';
import { MemoModule } from './components/MemoModule';
import { PolicyModule } from './components/PolicyModule';
import { client, CHAIN_ID, MODULES, SAMPLE_TOKEN } from './lib/constants';
import { client, CHAIN_ID, MODULES } from './lib/constants';
import {
b20Abi,
b20Variant,
Expand All @@ -40,6 +40,7 @@ import {
shortAddress,
} from './lib/protocol';
import { readRecent, readRecentPolicies, writeRecent, writeRecentPolicy } from './lib/recent';
import { sampleTokenForAddress } from './lib/samples';
import type {
ActivityItem,
CreatedToken,
Expand Down Expand Up @@ -102,7 +103,7 @@ export function B20Demo() {
useEffect(() => {
let cancelled = false;
setIsOperator(false);
if (!activeTokenAddress || !wallet || activeTokenAddress.toLowerCase() === SAMPLE_TOKEN.toLowerCase()) return;
if (!activeTokenAddress || !wallet || sampleTokenForAddress(activeTokenAddress)) return;
client
.readContract({
address: activeTokenAddress,
Expand All @@ -128,7 +129,7 @@ export function B20Demo() {
setTokenAdminCheckedFor(null);
if (!activeTokenAddress || !wallet) return;
const checkKey = `${activeTokenAddress.toLowerCase()}:${wallet.toLowerCase()}`;
if (activeTokenAddress.toLowerCase() === SAMPLE_TOKEN.toLowerCase()) {
if (sampleTokenForAddress(activeTokenAddress)) {
setTokenAdminCheckedFor(checkKey);
return;
}
Expand Down Expand Up @@ -206,6 +207,14 @@ export function B20Demo() {

const inspect = useCallback(
async (candidate = tokenAddress) => {
const sampleToken = sampleTokenForAddress(candidate);
if (sampleToken) {
setInspectError('');
setChecks(null);
setToken(sampleToken);
setTokenAddress(sampleToken.address);
return;
}
if (!isAddress(candidate)) {
setInspectError('Paste a valid token address, then try again.');
return;
Expand Down Expand Up @@ -235,13 +244,12 @@ export function B20Demo() {
if (!isB20 || !initialized) throw new Error('This address is not a ready-to-use B20 token.');
const variant = b20Variant(address);
if (!variant) throw new Error('We could not identify this B20 token type.');
const [name, symbol, decimals, supply, cap, contractURI, policyRows] = await Promise.all([
const [name, symbol, decimals, supply, cap, policyRows] = await Promise.all([
client.readContract({ address, abi: b20Abi, functionName: 'name' }),
client.readContract({ address, abi: b20Abi, functionName: 'symbol' }),
client.readContract({ address, abi: b20Abi, functionName: 'decimals' }),
client.readContract({ address, abi: b20Abi, functionName: 'totalSupply' }),
client.readContract({ address, abi: b20Abi, functionName: 'supplyCap' }),
client.readContract({ address, abi: b20Abi, functionName: 'contractURI' }),
Promise.all(
POLICY_SCOPES.map(async ([scope, label]) => {
const id = await client.readContract({
Expand All @@ -268,7 +276,7 @@ export function B20Demo() {
}),
),
]);
setToken({ address, name, symbol, decimals, variant, supply, cap, contractURI, policies: policyRows });
setToken({ address, name, symbol, decimals, variant, supply, cap, policies: policyRows });
setTokenAddress(address);
} catch (error) {
setToken(null);
Expand Down Expand Up @@ -367,7 +375,7 @@ export function B20Demo() {
trackB20ModuleSelect(next);
};
const tokenAccess: TokenAccess =
token?.address.toLowerCase() === SAMPLE_TOKEN.toLowerCase()
sampleTokenForAddress(token?.address)
? 'sample'
: isOperator
? 'operator'
Expand Down
80 changes: 0 additions & 80 deletions app/demos/b20/components/AnnouncementModule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -210,86 +210,6 @@ export function AnnouncementModule({
setError(walletErrorMessage(error));
}
};
if (token && tokenAccess === 'sample')
return (
<div className="flex flex-col gap-5">
<ModuleHeading
icon="◌"
title="Announcements"
description="Read announcements that explain an upcoming asset split before it takes effect."
action={<CopyPromptButton prompt={READ_ANNOUNCEMENT_PROMPT} module="announcements" />}
/>
<div className="grid gap-4">
<Card className="bg-background p-5 dark:bg-white/5">
<div className="flex flex-wrap items-start justify-between gap-3">
<div>
<span className="rounded-full bg-bds-orange-0 px-2 py-1 text-[11px] text-bds-orange-70">
Scheduled update · Mock data
</span>
<Text className="mt-3" variant="headline">
2027-Q1 forward split
</Text>
<Text variant="footnote" tone="muted">
This notice explains a two-for-one split and when wallets will show the new balance.
</Text>
</div>
<span className="font-mono text-[11px] text-bds-gray-50">2027-Q1-split</span>
</div>
<dl className="mt-5 grid gap-3 rounded-xl border border-bds-gray-10 p-4 text-[13px] sm:grid-cols-3 dark:border-white/10">
<div>
<dt className="text-[11px] text-bds-gray-50">Token change</dt>
<dd className="mt-1">Displayed balances double</dd>
</div>
<div>
<dt className="text-[11px] text-bds-gray-50">Effective</dt>
<dd className="mt-1">15 Jan 2027, 09:00 UTC</dd>
</div>
<div>
<dt className="text-[11px] text-bds-gray-50">Recorded together</dt>
<dd className="mt-1">Notice and token change</dd>
</div>
</dl>
</Card>
<Card className="bg-background p-5 dark:bg-white/5">
<div className="flex flex-wrap items-start justify-between gap-3">
<div>
<span className="rounded-full bg-bds-gray-5 px-2 py-1 text-[11px] text-bds-gray-60 dark:bg-white/10">
Information only · Mock data
</span>
<Text className="mt-3" variant="headline">
Quarterly reserve attestation
</Text>
<Text variant="footnote" tone="muted">
This notice shares information without changing the token.
</Text>
</div>
<span className="font-mono text-[11px] text-bds-gray-50">2026-Q4-reserves</span>
</div>
<dl className="mt-5 grid gap-3 rounded-xl border border-bds-gray-10 p-4 text-[13px] sm:grid-cols-2 dark:border-white/10">
<div>
<dt className="text-[11px] text-bds-gray-50">Token changes</dt>
<dd className="mt-1">None</dd>
</div>
<div>
<dt className="text-[11px] text-bds-gray-50">Supporting link</dt>
<dd className="mt-1 text-base-blue">https://example.com/disclosures/reserves</dd>
</div>
</dl>
</Card>
</div>
<Card className="flex flex-wrap items-center justify-between gap-3 bg-bds-blue-0 p-4">
<div>
<Text variant="label">Ready to publish an announcement?</Text>
<Text variant="footnote" tone="muted">
Create an Asset token to write and publish your own announcements.
</Text>
</div>
<Button size="sm" onClick={onDeploy}>
Create your own token
</Button>
</Card>
</div>
);
return (
<div className="flex flex-col gap-5">
<ModuleHeading
Expand Down
73 changes: 41 additions & 32 deletions app/demos/b20/components/MemoModule.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
'use client';

import Link from 'next/link';
import { useState } from 'react';
import { encodeFunctionData, isAddress, type Address, type Hex } from 'viem';

import { Button } from '../../../components/ui/Button';
import { Card } from '../../../components/ui/Card';
import { Text } from '../../../components/ui/Text';
import { VIBENET_EXPLORER_PATH } from '../../../vibenet/library/config';
import { walletErrorMessage } from '../../../vibenet/library/wallet';
import { SAMPLE_MEMO_TX } from '../lib/constants';
import { B20_HELP } from '../lib/glossary';
import { amount, b20Abi, memoToBytes32 } from '../lib/protocol';
import { amount, b20Abi, formatAmount, memoToBytes32, shortAddress } from '../lib/protocol';
import { READ_MEMO_PROMPT } from '../lib/prompts';
import { SAMPLE_MEMOS } from '../lib/samples';
import type { TokenAccess, TokenInfo } from '../lib/types';
import { CopyPromptButton } from './CopyPromptButton';
import { MemoHistory } from './MemoHistory';
Expand Down Expand Up @@ -63,48 +61,59 @@ export function MemoModule({
<div className="flex flex-wrap items-start justify-between gap-3">
<div>
<span className="rounded-full bg-bds-blue-0 px-2 py-1 text-[11px] text-base-blue">
Sample transaction
Sample data · Read only
</span>
<Text className="mt-3" variant="headline">
Transfer with memo
Memo history
</Text>
<Text variant="footnote" tone="muted">
A token transfer with a memo attached to help identify the transaction’s purpose.
Example token activity with short references attached to it. These records are local mock data.
</Text>
</div>
<Link
href={`${VIBENET_EXPLORER_PATH}/tx/${SAMPLE_MEMO_TX}`}
className="text-[12px] text-base-blue hover:underline"
>
View transaction ↗
</Link>
<span className="text-[12px] text-bds-gray-50">
{SAMPLE_MEMOS.length} memo{SAMPLE_MEMOS.length === 1 ? '' : 's'}
</span>
</div>
<div className="mt-5 divide-y divide-bds-gray-10 border-y border-bds-gray-10 dark:divide-white/10 dark:border-white/10">
{SAMPLE_MEMOS.map((row) => (
<article key={row.id} className="py-4">
<div className="flex flex-wrap items-start justify-between gap-3">
<div>
<p className="text-[11px] text-bds-gray-50">Memo</p>
<p className="mt-1 text-[16px] font-medium">{row.memo}</p>
</div>
<span className="rounded-full bg-bds-gray-5 px-2 py-1 text-[11px] capitalize text-bds-gray-60 dark:bg-white/10">
{row.operation} with memo
</span>
</div>
<dl className="mt-4 grid gap-3 text-[12px] sm:grid-cols-2 lg:grid-cols-4">
<div>
<dt className="text-bds-gray-50">Memo caller</dt>
<dd className="mt-0.5 font-mono">{shortAddress(row.caller)}</dd>
</div>
<div>
<dt className="text-bds-gray-50">From</dt>
<dd className="mt-0.5 font-mono">{shortAddress(row.from)}</dd>
</div>
<div>
<dt className="text-bds-gray-50">To</dt>
<dd className="mt-0.5 font-mono">{shortAddress(row.to)}</dd>
</div>
<div>
<dt className="text-bds-gray-50">Amount</dt>
<dd className="mt-0.5">{formatAmount(row.value, token.decimals)} {token.symbol}</dd>
</div>
</dl>
</article>
))}
</div>
<dl className="mt-5 grid gap-3 rounded-xl border border-bds-gray-10 p-4 text-[13px] sm:grid-cols-2 dark:border-white/10">
<div>
<dt className="text-[11px] text-bds-gray-50">Operation</dt>
<dd className="mt-1">Transfer with a note</dd>
</div>
<div>
<dt className="text-[11px] text-bds-gray-50">Amount</dt>
<dd className="mt-1">0.001 {token.symbol}</dd>
</div>
<div>
<dt className="text-[11px] text-bds-gray-50">Memo</dt>
<dd className="mt-1 font-medium">sending test</dd>
</div>
<div>
<dt className="text-[11px] text-bds-gray-50">Encoding</dt>
<dd className="mt-1 font-mono text-[11px]">bytes32</dd>
</div>
</dl>
<div className="mt-5 flex flex-wrap items-center justify-between gap-3 border-t border-bds-gray-10 pt-4 dark:border-white/10">
<p className="text-[12px] text-bds-gray-50">Create a token to add memos to your own transactions.</p>
<Button size="sm" onClick={onDeploy}>
Create your own token
</Button>
</div>
</Card>
<MemoHistory address={token.address} decimals={token.decimals} symbol={token.symbol} />
</div>
);
return (
Expand Down
Loading
Loading