Skip to content

Commit

Permalink
add benfen&ton&sui&sol token transfer (#266)
Browse files Browse the repository at this point in the history
  • Loading branch information
xixixueling authored Dec 16, 2024
1 parent 8465574 commit 339d50e
Show file tree
Hide file tree
Showing 9 changed files with 488 additions and 21 deletions.
109 changes: 105 additions & 4 deletions packages/example/components/chains/benfen/example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import { WalletWithRequiredFeatures } from '@benfen/bfc.js/dist/cjs/wallet-stand
function Example() {
const client = useBenfenClient();
const { setProvider } = useWallet();
const [customToAddress, setCustomToAddress] = useState<string>('');

const currentAccount = useCurrentAccount();
const { isConnected } = useCurrentWallet();
Expand All @@ -64,10 +65,14 @@ function Example() {
return params.signTransaction(currentAccount?.address ?? '');
}, [currentAccount?.address]);

const signTokenTransactionParams = useMemo(() => {
return params.signTokenTransaction(currentAccount?.address ?? '');
}, [currentAccount?.address]);

return (
<>
<ApiGroup title="SignMessage">
<ApiPayload
{/* <ApiPayload
title="signMessage"
description="签名消息, signMessage 不安全已经弃用, 目前(OneKey、Suiet、Sui Wallet、Martian) signMessage 实际实现已经变成了 signPersonalMessage"
presupposeParams={params.signMessage}
Expand All @@ -94,11 +99,11 @@ function Example() {
bytesToHex(currentAccount.publicKey) === bytesToHex(publicKey.toRawBytes())
).toString();
}}
/>
/> */}

<ApiPayload
title="signPersonalMessage"
description="签名消息(SDK 验证依赖网络可能会失败,可以刷新网页重试 或 稍后重试,问题上下文 https://github.com/MystenLabs/sui/issues/17912#issuecomment-2166621747)"
description="签名消息(SDK 验证依赖网络可能失败,可以刷新网页重试 或 稍后重试,问题上下文 https://github.com/MystenLabs/sui/issues/17912#issuecomment-2166621747)"
presupposeParams={params.signPersonalMessage}
onExecute={async (request: string) => {
const res = await signPersonalMessage({
Expand Down Expand Up @@ -196,7 +201,7 @@ function Example() {
const transfer = new TransactionBlock();
transfer.setSender(from);
const [coin] = transfer.splitCoins(transfer.gas, [transfer.pure(amount)]);
transfer.transferObjects([coin], transfer.pure(to));
transfer.transferObjects([coin], transfer.pure(customToAddress || to));

const tx = await sponsorTransaction(
client,
Expand Down Expand Up @@ -276,6 +281,102 @@ function Example() {
).toString();
}}
/>

<ApiPayload
title="signTransactionBlock (BUSD)"
description="BUSD代币转账签名"
presupposeParams={signTokenTransactionParams}
onExecute={async (request: string) => {
const { from, to, amount ,token} = JSON.parse(request);

const transfer = new TransactionBlock();
transfer.setSender(from);

const { data: coins } = await client.getCoins({
owner: from,
coinType: token,
});

if (!coins.length) {
throw new Error('No BUSD coins found');
}

const [coin] = transfer.splitCoins(
transfer.object(coins[0].coinObjectId),
[transfer.pure(amount)]
);
transfer.transferObjects([coin], transfer.pure(to));

const tx = await sponsorTransaction(
client,
from,
await transfer.build({
client,
onlyTransactionKind: true,
}),
);

const res = await signTransactionBlock({
transactionBlock: tx,
account: currentAccount,
});
return JSON.stringify(res);
}}
onValidate={async (request: string, result: string) => {
const { transactionBlockBytes, signature } = JSON.parse(result);
const publicKey = await verifyTransactionBlock(
Buffer.from(transactionBlockBytes, 'base64'),
signature,
);

return (
bytesToHex(currentAccount.publicKey) === bytesToHex(publicKey.toRawBytes())
).toString();
}}
/>

<ApiPayload
title="signAndExecuteTransactionBlock (BUSD)"
description="BUSD代币转账签名并执行"
presupposeParams={signTokenTransactionParams}
onExecute={async (request: string) => {
const { from, to, amount, token } = JSON.parse(request);

const transfer = new TransactionBlock();
transfer.setSender(from);

const { data: coins } = await client.getCoins({
owner: from,
coinType: token,
});

if (!coins.length) {
throw new Error('No BUSD coins found');
}

const [coin] = transfer.splitCoins(
transfer.object(coins[0].coinObjectId),
[transfer.pure(BigInt(amount))]
);
transfer.transferObjects([coin], transfer.pure(to));

const tx = await sponsorTransaction(
client,
from,
await transfer.build({
client,
onlyTransactionKind: true,
}),
);

const res = await signAndExecuteTransactionBlock({
transactionBlock: tx,
account: currentAccount,
});

return JSON.stringify(res);
}}
/>
</ApiGroup>

<DappList dapps={dapps} />
Expand Down
12 changes: 12 additions & 0 deletions packages/example/components/chains/benfen/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,16 @@ export default {
}),
},
],
signTokenTransaction: (address: string) => [
{
id: 'signUSDTransaction',
name: 'BUSD_TYPE',
value: JSON.stringify({
from: address,
to: address,
amount: 1000, // 0.000001 USD
token: '0x00000000000000000000000000000000000000000000000000000000000000c8::busd::BUSD'
}),
},
],
};
39 changes: 39 additions & 0 deletions packages/example/components/chains/solana/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import {
TransactionMessage,
VersionedMessage,
VersionedTransaction,
Connection,
} from '@solana/web3.js';
import { TOKEN_PROGRAM_ID, createTransferInstruction, getAssociatedTokenAddress } from '@solana/spl-token';

export const createTransferTransaction = (
publicKey: PublicKey,
Expand Down Expand Up @@ -54,3 +56,40 @@ export const createVersionedTransaction = (
const transaction = new VersionedTransaction(messageV0);
return transaction;
};

// 将 async function 改为箭头函数形式的导出
export const createTokenTransferTransaction = async (
connection: Connection,
fromPubkey: PublicKey,
toPubkey: PublicKey,
tokenMint: PublicKey,
recentBlockhash: string,
amount: number,
decimals: number
): Promise<Transaction> => {
const transaction = new Transaction();

const fromTokenAccount = await getAssociatedTokenAddress(
tokenMint,
fromPubkey
);

const toTokenAccount = await getAssociatedTokenAddress(
tokenMint,
toPubkey
);

transaction.add(
createTransferInstruction(
fromTokenAccount,
toTokenAccount,
fromPubkey,
BigInt(amount * Math.pow(10, decimals)),
)
);

transaction.feePayer = fromPubkey;
transaction.recentBlockhash = recentBlockhash;

return transaction;
};
69 changes: 60 additions & 9 deletions packages/example/components/chains/solana/example.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-return */
import { dapps } from './dapps.config';
import ConnectButton from '../../../components/connect/ConnectButton';
import ConnectButton from '../../connect/ConnectButton';
import { useEffect, useMemo, useRef } from 'react';
import { get, set } from 'lodash-es';
import { IProviderApi, IProviderInfo } from './types';
import { ApiPayload, ApiGroup } from '../../ApiActuator';
import { useWallet } from '../../../components/connect/WalletContext';
import type { IKnownWallet } from '../../../components/connect/types';
import DappList from '../../../components/DAppList';
import { useWallet } from '../../connect/WalletContext';
import type { IKnownWallet } from '../../connect/types';
import DappList from '../../DAppList';
import { Connection, PublicKey, Transaction, VersionedTransaction, clusterApiUrl } from '@solana/web3.js';
import params from './params';
import { createTransferTransaction, createVersionedTransaction } from './builder';
import { createTransferTransaction, createVersionedTransaction, createTokenTransferTransaction } from './builder';
import nacl from 'tweetnacl';
import { toast } from '../../ui/use-toast';
// import { TOKEN_PROGRAM_ID } from '@solana/spl-token';

const NETWORK = clusterApiUrl('mainnet-beta');

Expand Down Expand Up @@ -103,6 +104,21 @@ export default function Example() {
};
}, [account, provider, setAccount]);

console.log('createTokenTransferTransaction exists:', typeof createTokenTransferTransaction);

const transactionStatus = {
status: 'pending',
message: `
交易尚未在本地确认
这是正常的,因为交易刚刚被广播到网络
交易需要等待网络确认,这个过程需要一些时间
请等待区块确认...
`
};

return (
<>
<ConnectButton<IProviderApi>
Expand Down Expand Up @@ -216,16 +232,19 @@ export default function Example() {
return Buffer.from(res.serialize()).toString('hex')
}}
onValidate={async (request: string, result: string) => {
const tx = Transaction.from(Buffer.from(result, 'hex'))
const verified = tx.verifySignatures()
const tx = Transaction.from(Buffer.from(result, 'hex'));
const verified = tx.verifySignatures();

const res = await connection.simulateTransaction(tx, {
sigVerify: false,
});

const res = await connection.simulateTransaction(tx)
return {
success: res.value.err === null,
verified,
tryRun: res,
tx
}
};
}}
/>
<ApiPayload
Expand Down Expand Up @@ -301,6 +320,38 @@ export default function Example() {
return verifiedResult
}}
/>
<ApiPayload
title="transferToken"
description="代币转账"
presupposeParams={params.signAndSendTokenTransaction(account?.publicKey)}
onExecute={async (request: string) => {
const {
tokenMint,
toPubkey,
amount,
decimals
}: {
tokenMint: string;
toPubkey: string;
amount: number;
decimals: number;
} = JSON.parse(request);

const recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
const transaction = await createTokenTransferTransaction(
connection,
new PublicKey(account?.publicKey),
new PublicKey(toPubkey),
new PublicKey(tokenMint),
recentBlockhash,
amount,
decimals
);

const res = await provider?.signAndSendTransaction(transaction);
return JSON.stringify(res);
}}
/>
</ApiGroup>

<DappList dapps={dapps} />
Expand Down
28 changes: 28 additions & 0 deletions packages/example/components/chains/solana/params.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
const TOKEN_LIST = [
{
symbol: 'USDT',
tokenMint: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
decimals: 6
},
{
symbol: 'USDC',
tokenMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
decimals: 6
},
// {
// symbol: 'RNDR',
// tokenMint: '7atgF8KQo4wJrD5ATGX7t1V2zVvykPJbFfNeVf1icFv1',
// decimals: 8
// },
];
export default {
signMessage: [
{
Expand All @@ -16,6 +33,17 @@ export default {
}),
},
],
signAndSendTokenTransaction: (publicKey: string) =>
TOKEN_LIST.map(token => ({
id: `signAndSendTokenTransaction_${token.symbol}`,
name: `Send ${token.symbol} Token`,
value: JSON.stringify({
tokenMint: token.tokenMint,
toPubkey: publicKey,
amount: 0.000001,
decimals: token.decimals
}),
})),
signMultipleTransaction: (publicKey: string) => [
{
id: 'signMultipleTransaction',
Expand Down
Loading

0 comments on commit 339d50e

Please sign in to comment.