
Company News
Jerod Santo Joins Socket as Head of Media
Allow myself to introduce... myself.
@zktx.io/ptb-builder
Advanced tools
PTB Builder is a graphical toolkit for building, simulating, and executing Programmable Transaction Blocks (PTBs) on the Sui blockchain. It provides an intuitive drag‑and‑drop interface, automatic code generation, and on‑chain execution support — bridging the gap between developers and non‑developers.

TransferObjects, MergeCoins, MoveCall.dark, light, cobalt2, tokyo-night, cream, mint-breeze.The following PTB commands are currently supported:
(Additional commands can be added via registry extensions.)
Inputs follow tx.option conventions from the Sui TS SDK:
Coin<T>)
Below snippets mirror a typical setup using @mysten/dapp‑kit with PTB Builder.
App.tsximport { PTBBuilder, Chain, ToastVariant } from '@zktx.io/ptb-builder';
import { Transaction } from '@mysten/sui/transactions';
import {
useCurrentAccount,
useSignAndExecuteTransaction,
} from '@mysten/dapp-kit';
import { enqueueSnackbar } from 'notistack';
import '@mysten/dapp-kit/dist/index.css';
import '@zktx.io/ptb-builder/index.css';
function App() {
const account = useCurrentAccount();
const { mutate: signAndExecuteTransaction } = useSignAndExecuteTransaction();
// Toast adapter
const handleToast = ({
message,
variant,
}: {
message: string;
variant?: ToastVariant;
}) => {
enqueueSnackbar(message, { variant });
};
// Execute adapter
const executeTx = async (
chain: Chain,
transaction: Transaction | undefined,
): Promise<{ digest?: string; error?: string }> => {
if (!account || !transaction) return { error: 'No account or transaction' };
try {
const jsonTx = await transaction.toJSON();
return new Promise((resolve) => {
signAndExecuteTransaction(
{ transaction: jsonTx, chain },
{
onSuccess: (result) => resolve({ digest: result.digest }),
onError: (error) => resolve({ error: error.message }),
},
);
});
} catch (e: any) {
return { error: e.message || 'Serialization failed' };
}
};
return (
<PTBBuilder
toast={handleToast}
executeTx={executeTx}
address={account?.address}
showExportButton
/>
);
}
export default App;
pages/editor.tsximport { useCurrentAccount, useSuiClientContext } from '@mysten/dapp-kit';
import { PTB_VERSION, PTBDoc, usePTB } from '@zktx.io/ptb-builder';
import { DragAndDrop } from '../components/DragAndDrop';
type SuiNetwork = 'mainnet' | 'testnet' | 'devnet';
type SuiChain = `sui:${SuiNetwork}`;
export const Editor = () => {
const { network, selectNetwork } = useSuiClientContext();
const account = useCurrentAccount();
const { loadFromDoc } = usePTB();
// Safe parser for "sui:<network>"
const parseNetwork = (chain?: string): SuiNetwork | undefined => {
const m = chain?.match(/^sui:(mainnet|testnet|devnet)$/);
return m?.[1] as SuiNetwork | undefined;
};
const handleDrop = (file: PTBDoc) => {
// Align dapp-kit network only if valid and different
const target = parseNetwork(file.chain);
if (target && target !== network) selectNetwork(target);
loadFromDoc(file);
};
const handleChancel = () => {
// Reset with a current network
loadFromDoc(`sui:${network}` as SuiChain);
};
return (
<div style={{ width: '100vw', height: '100vh' }}>
{account && <DragAndDrop onDrop={handleDrop} onChancel={handleChancel} />}
</div>
);
};
pages/viewer.tsximport { useEffect, useRef, useState } from 'react';
import { usePTB } from '@zktx.io/ptb-builder';
import queryString from 'query-string';
import { useLocation } from 'react-router-dom';
export const Viewer = () => {
const initialized = useRef<boolean>(false);
const { loadFromOnChainTx } = usePTB();
const location = useLocation();
const [txHash, setTxHash] = useState<string | undefined>(undefined);
useEffect(() => {
const parsed = queryString.parse(location.search);
if (parsed.tx && !initialized.current) {
loadFromOnChainTx('sui:testnet', parsed.tx as string);
initialized.current = true;
} else {
setTxHash('');
}
}, [loadFromOnChainTx, location.search, txHash]);
return null;
};
import '@zktx.io/ptb-builder/index.css';
import '@zktx.io/ptb-builder/styles/themes-all.css';
// Or import a specific theme only: import '@zktx.io/ptb-builder/styles/theme-light.css';
import { PTBBuilder } from '@zktx.io/ptb-builder';
<PTBBuilder
theme="dark" // initial theme (dark | light | cobalt2 | tokyo-night | cream | mint-breeze); defaults to "dark"
address={myAddress} // sender address
gasBudget={500_000_000} // optional gas budget
executeTx={execAdapter} // adapter to execute transactions
onDocChange={saveDoc} // PTBDoc autosave callback (debounced)
showExportButton // optional: show Export .ptb button (default: hidden)
>
{/* your app here */}
</PTBBuilder>;
import { usePTB } from '@zktx.io/ptb-builder';
const { exportDoc, loadFromDoc, loadFromOnChainTx, setTheme } = usePTB();
// Export current PTB document
const doc = exportDoc({ sender: myAddress });
// Load document from memory or disk
loadFromDoc(doc);
// Load graph from on-chain transaction digest
await loadFromOnChainTx('sui:testnet', '0x1234…');
// Switch theme at runtime
setTheme('tokyo-night');
@zktx.io/ptb-builder/index.css contains the structural styles for nodes, edges, and the builder chrome. It should be imported exactly once in your host app (or exposed by your bundler) regardless of the theme you choose.@zktx.io/ptb-builder/styles/themes-all.css bundles every theme token file so you can switch themes at runtime with setTheme. Pulling in the whole pack adds roughly ~18 kB pre-gzip.import '@zktx.io/ptb-builder/styles/theme-dark.css';. Each theme file is ~3 kB pre-gzip, so picking a single one keeps the bundle lean while still allowing dynamic switching between the themes you explicitly include.theme value (e.g., theme="light") and set showThemeSelector={false} so the UI doesn’t expose choices that aren’t bundled.onDocChangeonDocChange immediately when the underlying PTB graph, modules, objects, or active chain changes. Viewport changes (pan/zoom) are debounced by 250 ms so autosave targets are not overwhelmed while the user drags the canvas.loadFromDoc/loadFromOnChainTx resets the internal history cache, replays the snapshot once, and suppresses duplicate events until the user edits again.usePtbUndo hook keeps a stable signature per PTBDoc, so undo/redo operations call loadFromDoc without collapsing the redo stack. A single flag (suppressNext) prevents the ensuing onDocChange from being treated as a fresh edit.onDocChange to fire often during graph edits but only after the debounce window for viewport-only motions.<PTBBuilder />)| Prop | Type | Default | Description |
|---|---|---|---|
theme | Theme (dark | light | cobalt2 | tokyo-night | cream | mint-breeze) | "dark" | Initial UI theme. |
showThemeSelector | boolean | true | Renders the theme dropdown in the CodePip panel. |
address | string | – | Sender address for generated transactions. |
gasBudget | number | – | Optional gas budget used for tx build/exec. |
executeTx | (chain: Chain, tx?: Transaction) => Promise<{ digest?: string; error?: string }> | – | Adapter to execute transactions. |
toast | ToastAdapter | console | Custom toast adapter used by the provider. |
onDocChange | (doc: PTBDoc) => void | – | Autosave callback (debounced). |
showExportButton | boolean | false | If true, shows Export .ptb button in the CodePip panel. |
children | React.ReactNode | – | Children rendered inside the Provider. |
PTB Builder persists graphs as PTBDoc objects containing:
sui:testnet)This enables saving, sharing, and reloading graphs consistently across environments.
useSuiClientContext() from @mysten/dapp‑kit to read/change the active Sui network.doc.chain in the form sui:<network>, e.g., sui:testnet./^sui:(mainnet|testnet|devnet)$/ before switching the network.FAQs
Sui programmable transaction blocks builder
The npm package @zktx.io/ptb-builder receives a total of 8 weekly downloads. As such, @zktx.io/ptb-builder popularity was classified as not popular.
We found that @zktx.io/ptb-builder demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Company News
Allow myself to introduce... myself.

Research
/Security News
A Twitch browser extension on Chrome and Firefox forwards users’ live OAuth session tokens through proxies controlled by a Russian bot service.

Security News
Anthropic found biased reasoning and recklessness drove Claude Mythos 5 to publish malware on PyPI and compromise a security vendor.