Transfer
지갑을 연결한 후, to 주소로 SUI를 전송하는 PTB를 구성하고 useSignAndExecuteTransaction으로 실행합니다。
이 예제는
devnet을 사용합니다。
라이브 에디터
function Transfer() { const account = useCurrentAccount(); const { mutate: signAndExecuteTransaction, isPending } = useSignAndExecuteTransaction(); const { data: balance } = useSuiClientQuery('getBalance', { owner: account?.address ?? '' }, { enabled: !!account }); const [to, setTo] = useState(''); const [mist, setMist] = useState('1000000'); const [digest, setDigest] = useState(''); const [error, setError] = useState(''); if (!account) { return ( <div className="alert alert--info"> 먼저 지갑을 연결하세요 (우측 상단 지갑 아이콘). </div> ); } const hasValidTo = /^0x[0-9a-fA-F]+$/.test(to) && to.length >= 4; const hasValidAmount = /^[0-9]+$/.test(mist) && mist !== '0'; const canSubmit = hasValidTo && hasValidAmount && !isPending; return ( <div style={{ maxWidth: 980 }}> <div style={{ marginBottom: 10, fontSize: 12, fontWeight: 700, color: 'var(--ifm-color-emphasis-700)' }}> 일반 </div> <div style={{ border: '1px solid var(--ifm-color-emphasis-300)', borderRadius: 12, padding: 16, background: 'var(--ifm-background-surface-color)', }} > <div className="row" style={{ rowGap: 12 }}> <div className="col col--3"> <div className="text--muted" style={{ fontSize: 12 }}> 네트워크 </div> <div style={{ fontWeight: 700 }}> <code>sui:devnet</code> </div> </div> <div className="col col--3"> <div className="text--muted" style={{ fontSize: 12 }}> 잔액 </div> <div style={{ fontWeight: 700 }}> {balance ? ( <> <code>{balance.totalBalance}</code> <span className="text--muted">mist</span> </> ) : ( <span className="text--muted">불러오는 중…</span> )} </div> </div> <div className="col col--6"> <div className="text--muted" style={{ fontSize: 12 }}> 보내는 주소 </div> <div style={{ wordBreak: 'break-all' }}> <code>{account.address}</code> </div> </div> </div> </div> <div className="margin-top--lg" style={{ marginBottom: 10, fontSize: 12, fontWeight: 700, color: 'var(--ifm-color-emphasis-700)' }}> 트랜잭션 입력 </div> <div style={{ border: '1px solid var(--ifm-color-emphasis-300)', borderRadius: 12, padding: 16, background: 'var(--ifm-background-surface-color)', }} > <div className="row" style={{ rowGap: 16 }}> <div className="col col--8"> <label className="form-label" style={{ display: 'block' }}> <b>받는 주소</b> </label> <input className="input input--lg" value={to} onChange={(e) => setTo(e.target.value.trim())} placeholder="0x..." /> {!to ? null : hasValidTo ? null : ( <div className="margin-top--xs text--danger" style={{ fontSize: 13 }}> 유효한 0x 주소를 입력하세요. </div> )} </div> <div className="col col--4"> <label className="form-label" style={{ display: 'block' }}> <b>금액 (mist)</b> </label> <div style={{ display: 'flex', gap: 10, alignItems: 'center' }}> <input className="input input--lg" value={mist} onChange={(e) => setMist(e.target.value.trim())} inputMode="numeric" /> <button type="button" className="button button--secondary button--sm" onClick={() => { if (!balance) return; setMist(String(balance.totalBalance)); }} disabled={!balance} > 최대 </button> </div> {!mist ? null : hasValidAmount ? null : ( <div className="margin-top--xs text--danger" style={{ fontSize: 13 }}> 금액은 양의 정수여야 합니다. </div> )} </div> </div> <div className="margin-top--lg" style={{ display: 'flex', gap: 12, alignItems: 'center', flexWrap: 'wrap' }}> <button className="button button--warning button--lg" disabled={!canSubmit} onClick={() => { setError(''); setDigest(''); if (!hasValidTo) return; if (!hasValidAmount) return; const tx = new Transaction(); const [coin] = tx.splitCoins(tx.gas, [mist]); tx.transferObjects([coin], to); signAndExecuteTransaction( { transaction: tx, chain: 'sui:devnet' }, { onSuccess: (result) => setDigest(result.digest), onError: (e) => { const message = e?.message ?? String(e); if (message.includes('No valid gas coins found')) { setError( '이 주소의 Devnet에서 가스 코인을 찾을 수 없습니다. 지갑 네트워크를 Devnet으로 전환한 후 faucet에서 SUI를 받고 다시 시도하세요.', ); return; } setError(message); }, }, ); }} > {isPending ? '실행 중…' : '실행'} </button> <div style={{ flex: 1, minWidth: 260 }}> <div className="text--muted" style={{ fontSize: 12 }}> 결과 </div> {digest ? ( <div style={{ marginTop: 4, display: 'flex', gap: 10, alignItems: 'center', justifyContent: 'space-between', flexWrap: 'wrap' }}> <code style={{ wordBreak: 'break-all' }}>{digest}</code> <a href={`https://suiexplorer.com/txblock/${digest}?network=devnet`} target="_blank" rel="noreferrer" style={{ fontWeight: 600, whiteSpace: 'nowrap' }} > 열기 </a> </div> ) : ( <div className="text--muted" style={{ fontSize: 13, marginTop: 4 }}> 실행 후 결과가 여기에 표시됩니다. </div> )} </div> </div> </div> {error ? <div className="alert alert--danger margin-top--md">{error}</div> : null} </div> ); } render(<Transfer />);
결과
Loading...