Skip to content

Commit

Permalink
chore: sign tx example (#232)
Browse files Browse the repository at this point in the history
* feat: perfect sign tx check

* chore: ton scam dapp connect

* chore: alephium group account
  • Loading branch information
ByteZhang1024 authored Sep 9, 2024
1 parent 44a6d42 commit dda482c
Show file tree
Hide file tree
Showing 21 changed files with 676 additions and 76 deletions.
18 changes: 16 additions & 2 deletions packages/example/components/ApiActuator/useApiExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { stringifyWithSpecialType } from '../../lib/jsonUtils';

export type IApiExecutor = {
onExecute: (request: string) => Promise<any>;
onValidate?: (request: string, response: string) => Promise<string>;
onValidate?: (request: string, response: string) => Promise<any>;
};

export function useApiExecutor({ onExecute, onValidate }: IApiExecutor): {
Expand Down Expand Up @@ -51,8 +51,22 @@ export function useApiExecutor({ onExecute, onValidate }: IApiExecutor): {
const validate = useCallback(
async (request: string, result: string) => {
try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const validation = await onValidate(request, result);
return { validation, error: undefined };

let validationString: string;
// normal types
if (
typeof validation === 'number' ||
typeof validation === 'boolean' ||
typeof validation === 'string'
) {
validationString = validation.toString();
} else {
validationString = stringifyWithSpecialType(validation);
}

return { validation: validationString ?? 'null', error: undefined };
} catch (error) {
console.log('validate error', error);
return { validation: undefined, error: get(error, 'message', 'Validation error') };
Expand Down
52 changes: 51 additions & 1 deletion packages/example/components/chains/alephium/example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,21 @@ import {
} from '@alephium/web3-react';
import { verifySignedMessage } from '@alephium/web3';

import { NodeProvider, TransactionBuilder, buildScriptByteCode, buildContractByteCode, ONE_ALPH, DUST_AMOUNT } from "@alephium/web3"
import * as fetchRetry from 'fetch-retry'
import { useState } from 'react';
import { RadioGroup, RadioGroupItem } from '../../ui/radio-group';
import { Label } from '../../ui/label';

// 防止限频
const retryFetch = fetchRetry.default(fetch, {
retries: 10,
retryDelay: 1000
})

const nodeUrl = "https://node.testnet.alephium.org"
const nodeProvider = new NodeProvider(nodeUrl, undefined, retryFetch)

export function Example() {
const wallet = useWallet();
const balance = useBalance();
Expand Down Expand Up @@ -86,6 +101,14 @@ export function Example() {
onExecute={async (request: string) => {
return wallet.signer.signUnsignedTx(JSON.parse(request));
}}
onValidate={async (request: string, response: string) => {
const { unsignedTx, signature } = JSON.parse(response);
const txId = await nodeProvider.transactions.postTransactionsSubmit({
unsignedTx,
signature,
});
return txId.txId;
}}
/>
<ApiPayload
title="signMessage"
Expand Down Expand Up @@ -115,9 +138,36 @@ export function Example() {
);
}

const groupOptions = [
{ label: '不指定', value: -1 },
{ label: 'Group 0', value: 0 },
{ label: 'Group 1', value: 1 },
{ label: 'Group 2', value: 2 },
{ label: 'Group 3', value: 3 },
];

export default function App() {
const [group, setGroup] = useState(0);

return (
<AlephiumWalletProvider network="mainnet" theme="retro">
<AlephiumWalletProvider network="mainnet" theme="retro" addressGroup={group === -1 ? undefined : group}>
<InfoLayout title="连接指定 Group 账户">
<RadioGroup className='flex flex-row space-x-4' aria-labelledby="Select one item" defaultValue={"0"} name="form" onValueChange={(value) => {
const valueInt = parseInt(value);
if (valueInt === -1) {
setGroup(-1);
} else {
setGroup(valueInt);
}
}}>
{groupOptions.map((option) => (
<div className="items-center space-x-2">
<RadioGroupItem value={option.value.toString()} id={option.value.toString()} />
<Label htmlFor={option.value.toString()}>{option.label}</Label>
</div>
))}
</RadioGroup>
</InfoLayout>
<Example />
</AlephiumWalletProvider>
);
Expand Down
19 changes: 18 additions & 1 deletion packages/example/components/chains/aptos/example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { dapps } from './dapps.config';
import ConnectButton from '../../../components/connect/ConnectButton';
import { useEffect, useRef } from 'react';
import { get } from 'lodash';
import axios from 'axios';
import { bytesToHex, hexToBytes } from '@noble/hashes/utils';
import { IProviderApi, IProviderInfo, SignMessageResponse } from './types';
import { ApiPayload, ApiGroup } from '../../ApiActuator';
Expand Down Expand Up @@ -188,7 +189,23 @@ export default function Example() {
onExecute={async (request: string) => {
const obj = JSON.parse(request);
const res = await provider?.signTransaction(obj);
return JSON.stringify(res);
return res;
}}
onValidate={async (request: string, result: string) => {
const jsonObject = JSON.parse(result);
const buffer = new Uint8Array(jsonObject);

const options = {
method: 'POST',
url: 'https://api.mainnet.aptoslabs.com/v1/transactions',
headers: {'Content-Type': 'application/x.aptos.signed_transaction+bcs'},
data: buffer
};

const res = await axios.request(options);

console.log(res.data);
return Promise.resolve(JSON.stringify(res.data));
}}
/>
<ApiPayload
Expand Down
16 changes: 11 additions & 5 deletions packages/example/components/chains/aptosMartian/example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,10 @@ export default function Example() {
onExecute={async (request: string) => {
const obj = JSON.parse(request);
const tx = await provider?.generateTransaction(account?.address, obj);
const res = await provider?.signTransaction(tx);
return JSON.stringify(res);
return await provider?.signTransaction(tx);
}}
onValidate={async (request: string, result: string) => {
return await provider?.submitTransaction(new Uint8Array(result.split(",").map((item) => parseInt(item, 10))));
}}
/>
<ApiPayload
Expand All @@ -232,8 +234,7 @@ export default function Example() {
presupposeParams={params.signTransaction(account?.address ?? '')}
onExecute={async (request: string) => {
const obj = JSON.parse(request);
const res = await provider?.generateSignAndSubmitTransaction(account?.address, obj);
return JSON.stringify(res);
return await provider?.generateSignAndSubmitTransaction(account?.address, obj);
}}
/>
<ApiPayload
Expand All @@ -243,12 +244,17 @@ export default function Example() {
onExecute={async (request: string) => {
const obj = JSON.parse(request);
const res = await provider?.generateTransaction(account?.address, obj);
return res;
}}
onValidate={async (request: string, result: string) => {
const signedRawTx = await provider?.signTransaction(result);
const res = await provider?.submitTransaction(signedRawTx);
return JSON.stringify(res);
}}
/>
<ApiPayload
title="signGenericTransaction"
description="signGenericTransaction"
description="signGenericTransaction 会广播上链"
presupposeParams={params.signGenericTransaction(account?.address ?? '')}
onExecute={async (request: string) => {
const obj = JSON.parse(request);
Expand Down
11 changes: 10 additions & 1 deletion packages/example/components/chains/btc/example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ export default function BTCExample() {
title="requestAccounts"
description="请求连接 Wallet 获取账户"
disableRequestContent
allowCallWithoutProvider={true}
onExecute={async (request: string) => {
const res = await provider?.requestAccounts();
return JSON.stringify(res);
Expand Down Expand Up @@ -274,10 +275,14 @@ export default function BTCExample() {

return Promise.resolve(psbt);
}}
onValidate={async (request: string, response: string) => {
const res = await provider?.pushPsbt(response);
return JSON.stringify(res);
}}
/>
<ApiPayload
title="signPsbts"
description="signPsbts"
description="signPsbts、验证流程尝试广播第一个交易"
presupposeParams={params.signPsbts}
onExecute={async (request: string) => {
const { psbtHexs, options } = JSON.parse(request) as {
Expand Down Expand Up @@ -338,6 +343,10 @@ export default function BTCExample() {
}),
);
}}
onValidate={async (request: string, response: string) => {
const [psbtHexs] = JSON.parse(response)
return await provider?.pushPsbt(psbtHexs);
}}
/>
<ApiPayload
title="pushPsbt"
Expand Down
10 changes: 9 additions & 1 deletion packages/example/components/chains/btcBabylon/example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export default function BTCExample() {
title="connectWallet"
description="请求连接 Wallet 获取账户"
disableRequestContent
allowCallWithoutProvider
onExecute={async (request: string) => {
const res = await provider?.connectWallet();
console.log('connectWallet result:', res);
Expand Down Expand Up @@ -272,7 +273,6 @@ export default function BTCExample() {
const res = await provider?.signMessageBIP322(request);
return res;
}}
// @ts-expect-error
onValidate={async (request: string, response: string) => {
return Verifier.verifySignature(account.address, request, response);
}}
Expand Down Expand Up @@ -359,6 +359,10 @@ export default function BTCExample() {

return Promise.resolve(psbt);
}}
onValidate={async (request: string, response: string) => {
const res = await provider?.pushPsbt(response);
return JSON.stringify(res);
}}
/>
<ApiPayload
title="signPsbts"
Expand Down Expand Up @@ -423,6 +427,10 @@ export default function BTCExample() {
}),
);
}}
onValidate={async (request: string, response: string) => {
const [psbtHexs] = JSON.parse(response)
return await provider?.pushPsbt(psbtHexs);
}}
/>
<ApiPayload
title="pushPsbt"
Expand Down
6 changes: 5 additions & 1 deletion packages/example/components/chains/cardano/example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,9 @@ export default function Example() {
const signedTx = await lucid.fromTx(request).sign().complete();
return signedTx.toString();
}}
onValidate={async (request: string, response: string) => {
return await walletApi?.submitTx(response);
}}
generateRequestFrom={() => {
return (
<>
Expand Down Expand Up @@ -458,7 +461,8 @@ export default function Example() {
{
id: 'submitTx',
name: 'submitTx',
value: '复制 signTx 签名结果到这里',
value:
'复制 signTx 签名结果到这里、然后点击执行。\nsignTx 验证流程会自动广播交易。重复广播会报错。',
},
]}
onExecute={async (request: string) => {
Expand Down
82 changes: 45 additions & 37 deletions packages/example/components/chains/cosmos/example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,10 @@ export default function Example() {
msgs: obj.msgs,
};

const res = await provider?.signAmino(network.id, account.address, requestObj);
return JSON.stringify(res);
return await provider?.signAmino(network.id, account.address, requestObj);
}}
onValidate={async (request: string, response: string) => {
return await nodeClient.encodeAmino(response);
}}
/>
<ApiPayload
Expand All @@ -276,42 +278,42 @@ export default function Example() {

const msgs:
| {
typeUrl: string;
value: Uint8Array;
}[]
typeUrl: string;
value: Uint8Array;
}[]
| undefined = obj.msgs?.map((msg: { type: string; value: any }) => {
const value = msg.value;
if (msg.type === '/cosmos.bank.v1beta1.MsgSend') {
return {
typeUrl: '/cosmos.bank.v1beta1.MsgSend',
value: MsgSend.encode(
MsgSend.fromPartial({
fromAddress: value.from_address,
toAddress: value.to_address,
amount: value.amount?.map((amount: any) => ({
amount: amount.amount,
denom: amount.denom,
})),
}),
).finish(),
};
} else if (msg.type === '/cosmwasm.wasm.v1.MsgExecuteContract') {
return {
typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract',
value: MsgExecuteContract.encode(
MsgExecuteContract.fromPartial({
sender: value.sender,
contract: value.contract,
msg: Buffer.from(JSON.stringify(removeNull(value.msg))),
funds: value.funds?.map((amount: any) => ({
amount: amount.amount,
denom: amount.denom,
})),
}),
).finish(),
};
}
});
const value = msg.value;
if (msg.type === '/cosmos.bank.v1beta1.MsgSend') {
return {
typeUrl: '/cosmos.bank.v1beta1.MsgSend',
value: MsgSend.encode(
MsgSend.fromPartial({
fromAddress: value.from_address,
toAddress: value.to_address,
amount: value.amount?.map((amount: any) => ({
amount: amount.amount,
denom: amount.denom,
})),
}),
).finish(),
};
} else if (msg.type === '/cosmwasm.wasm.v1.MsgExecuteContract') {
return {
typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract',
value: MsgExecuteContract.encode(
MsgExecuteContract.fromPartial({
sender: value.sender,
contract: value.contract,
msg: Buffer.from(JSON.stringify(removeNull(value.msg))),
funds: value.funds?.map((amount: any) => ({
amount: amount.amount,
denom: amount.denom,
})),
}),
).finish(),
};
}
});

if (!msgs) return JSON.stringify({ error: 'msgs is null' });

Expand Down Expand Up @@ -359,6 +361,12 @@ export default function Example() {
});
return res;
}}
onValidate={async (request: string, response: string) => {
const tx = hexToBytes(response);
// @ts-expect-error
const res = await provider?.sendTx(network.id, tx, 'Sync');
return JSON.stringify(res);
}}
/>
<ApiPayload
title="sendTx"
Expand Down
Loading

0 comments on commit dda482c

Please sign in to comment.