-
Notifications
You must be signed in to change notification settings - Fork 154
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e0db15a
commit 0e8dbd8
Showing
9 changed files
with
368 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// /components/pay-button.tsx | ||
import React from 'react'; | ||
import { ConnectButton, Connector } from '@ant-design/web3'; | ||
import { MetaMask, WagmiWeb3ConfigProvider } from '@ant-design/web3-wagmi'; | ||
import { Button, Flex } from 'antd'; | ||
import { createConfig, http } from 'wagmi'; | ||
import { arbitrum, mainnet, optimism, polygon } from 'wagmi/chains'; | ||
import { injected } from 'wagmi/connectors'; | ||
|
||
import EvmSignTransaction from './send'; | ||
|
||
type PayButtonsProps = { | ||
setTokenEcosystem?: (token: string) => void; | ||
tokenEcosystem: string; | ||
signCallback: (signTransfer: (toAddress: string, amount: number) => void) => void; | ||
payCallback: (signTransfer: string, address: string) => void; | ||
onRejectSwitchChain?: (id: number) => void; | ||
}; | ||
|
||
const config = createConfig({ | ||
chains: [mainnet, polygon, arbitrum, optimism], | ||
transports: { | ||
[mainnet.id]: http(), | ||
[polygon.id]: http(), | ||
[arbitrum.id]: http(), | ||
[optimism.id]: http(), | ||
}, | ||
connectors: [ | ||
injected({ | ||
target: 'metaMask', | ||
}), | ||
], | ||
}); | ||
|
||
export const EvmPayButtons: React.FC<PayButtonsProps> = ({ | ||
setTokenEcosystem, | ||
tokenEcosystem, | ||
signCallback, | ||
payCallback, | ||
onRejectSwitchChain, | ||
}) => { | ||
return ( | ||
<div> | ||
<WagmiWeb3ConfigProvider | ||
config={config} | ||
eip6963={{ | ||
autoAddInjectedWallets: true, | ||
}} | ||
wallets={[MetaMask()]} | ||
chains={[mainnet, polygon, arbitrum, optimism]} | ||
> | ||
<Flex justify="space-between" style={{ width: 400, marginTop: 20 }}> | ||
<Connector | ||
modalProps={{ | ||
footer: ( | ||
<> | ||
Powered by{' '} | ||
<a href="https://web3.ant.design/" target="_blank" rel="noreferrer"> | ||
Ant Design Web3 | ||
</a> | ||
</> | ||
), | ||
}} | ||
> | ||
<ConnectButton showChainSelect={false} /> | ||
</Connector> | ||
<EvmSignTransaction | ||
setTokenEcosystem={setTokenEcosystem} | ||
tokenEcosystem={tokenEcosystem} | ||
signTransactionCallback={(signTransfer, address) => { | ||
payCallback(signTransfer, address); | ||
}} | ||
onRejectSwitchChain={onRejectSwitchChain} | ||
renderSignButton={(signTransfer, disabled, signLoading) => ( | ||
<Button | ||
type="primary" | ||
style={{ width: 200 }} | ||
loading={signLoading} | ||
disabled={disabled} | ||
onClick={() => { | ||
signCallback(signTransfer); | ||
}} | ||
> | ||
Pay | ||
</Button> | ||
)} | ||
/> | ||
</Flex> | ||
</WagmiWeb3ConfigProvider> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// /components/select.tsx | ||
import React from 'react'; | ||
import { Radio, Space } from 'antd'; | ||
|
||
import { TOKEN_PAY_ADDRESS } from '../constants/tokenPayAddress'; | ||
|
||
interface ChainSelectGroupProps { | ||
ecosystem: string; | ||
onChange: (ecosystem: string) => void; | ||
} | ||
|
||
const ChainSelect: React.FC<ChainSelectGroupProps> = (props) => { | ||
const chainList = TOKEN_PAY_ADDRESS.chains; | ||
|
||
return ( | ||
<Space size={16}> | ||
<Radio.Group | ||
onChange={(e) => { | ||
props.onChange(e.target.value); | ||
}} | ||
value={props.ecosystem} | ||
> | ||
{chainList.map((info) => { | ||
return ( | ||
<Radio key={info.ecosystem} value={info.ecosystem}> | ||
{info.name} | ||
</Radio> | ||
); | ||
})} | ||
</Radio.Group> | ||
</Space> | ||
); | ||
}; | ||
|
||
export default ChainSelect; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
// /components/send.tsx | ||
import React, { useEffect, useState } from 'react'; | ||
import { useAccount } from '@ant-design/web3'; | ||
import { parseAbi, parseUnits } from 'viem'; | ||
import { useChainId, useSwitchChain, useWriteContract } from 'wagmi'; | ||
|
||
import { TOKEN_PAY_ADDRESS } from '../constants/tokenPayAddress'; | ||
|
||
type SignTransactionProps = { | ||
setTokenEcosystem?: (token: string) => void; | ||
tokenEcosystem: string; | ||
signTransactionCallback?: (signTransfer: string, address: string) => void; | ||
renderSignButton: ( | ||
signTransfer: (toAddress: string, amount: number) => void, | ||
disabled: boolean, | ||
loading: boolean, | ||
) => React.ReactNode; | ||
onRejectSwitchChain?: (id: number) => void; | ||
}; | ||
|
||
const EvmSignTransaction: React.FC<SignTransactionProps> = ({ | ||
setTokenEcosystem, | ||
tokenEcosystem, | ||
signTransactionCallback, | ||
renderSignButton, | ||
onRejectSwitchChain, | ||
}) => { | ||
const [signLoading, setSignLoading] = useState<boolean>(false); | ||
const { writeContractAsync } = useWriteContract(); | ||
const { switchChain } = useSwitchChain(); | ||
const chainId = useChainId(); | ||
const { account } = useAccount(); | ||
|
||
useEffect(() => { | ||
if (account?.address) { | ||
const chainList = TOKEN_PAY_ADDRESS.chains; | ||
const changeChainId = chainList.find((item) => item.ecosystem === tokenEcosystem)?.id; | ||
if (changeChainId && changeChainId !== chainId) { | ||
switchChain?.( | ||
{ chainId: changeChainId }, | ||
{ | ||
onError: (error) => { | ||
if (error.message.includes('User rejected')) { | ||
onRejectSwitchChain?.(chainId); | ||
} | ||
}, | ||
}, | ||
); | ||
} | ||
} | ||
}, [tokenEcosystem, account]); | ||
|
||
useEffect(() => { | ||
if (chainId && !tokenEcosystem) { | ||
const chainList = TOKEN_PAY_ADDRESS.chains; | ||
const initTokenEcosystem = chainList.find((item) => item.id === chainId)?.ecosystem; | ||
if (initTokenEcosystem && account) { | ||
setTokenEcosystem?.(initTokenEcosystem); | ||
} else { | ||
setTokenEcosystem?.(chainList[0].ecosystem); | ||
} | ||
} | ||
}, [account]); | ||
|
||
const signTransfer = async (toAddress: string, amount: number) => { | ||
try { | ||
setSignLoading(true); | ||
// transfer ABI | ||
// { | ||
// "constant": false, | ||
// "inputs": [ | ||
// { "name": "_to", "type": "address" }, | ||
// { "name": "_value", "type": "uint256" } | ||
// ], | ||
// "name": "transfer", | ||
// "outputs": [], | ||
// "payable": false, | ||
// "stateMutability": "nonpayable", | ||
// "type": "function" | ||
// }, | ||
const decimals = TOKEN_PAY_ADDRESS.chains.find( | ||
(item) => item.ecosystem === tokenEcosystem, | ||
)?.decimals; | ||
const contractAddress = TOKEN_PAY_ADDRESS.chains.find( | ||
(item) => item.ecosystem === tokenEcosystem, | ||
)?.address; | ||
const signTransferHash = await writeContractAsync({ | ||
abi: parseAbi(['function transfer(address _to, uint256 _value)']), | ||
address: contractAddress as `0x${string}`, | ||
functionName: 'transfer', | ||
args: [ | ||
toAddress.toLocaleLowerCase() as `0x${string}`, | ||
parseUnits(amount.toString(), decimals!), | ||
], | ||
}); | ||
setSignLoading(false); | ||
signTransactionCallback?.(signTransferHash, account?.address || ''); | ||
} catch (error) { | ||
console.log('error', (error as any).message); | ||
setSignLoading(false); | ||
} | ||
}; | ||
|
||
return <div>{renderSignButton(signTransfer, !account, signLoading)}</div>; | ||
}; | ||
export default EvmSignTransaction; |
58 changes: 58 additions & 0 deletions
58
docs/guide/demos/best-practice/constants/tokenPayAddress.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// /constants/tokenPayAddress.ts | ||
interface TokenInfo { | ||
name: string; | ||
icon: string; | ||
symbol: string; | ||
chains: { | ||
name: string; | ||
id?: number; | ||
decimals: number; | ||
ecosystem: string; | ||
address: string; | ||
txScan?: string; | ||
network?: string; | ||
}[]; | ||
} | ||
export const TOKEN_PAY_ADDRESS: TokenInfo = { | ||
name: 'USDT', | ||
icon: 'https://mdn.alipayobjects.com/huamei_hsbbrh/afts/img/A*HkpaQoYlReEAAAAAAAAAAAAADiOMAQ/original', | ||
symbol: 'usdt', | ||
chains: [ | ||
{ | ||
name: 'Ethereum', | ||
id: 1, | ||
decimals: 6, | ||
ecosystem: 'ethereum', | ||
network: 'mainnet', | ||
txScan: 'https://etherscan.io/tx/', | ||
address: '0xdAC17F958D2ee523a2206206994597C13D831ec7', | ||
}, | ||
{ | ||
name: 'Polygon', | ||
id: 137, | ||
decimals: 6, | ||
ecosystem: 'polygon', | ||
network: 'polygon', | ||
txScan: 'https://polygonscan.com/tx/', | ||
address: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', | ||
}, | ||
{ | ||
name: 'Arbitrum', | ||
id: 42161, | ||
decimals: 6, | ||
ecosystem: 'arbitrum', | ||
network: 'arbitrum', | ||
txScan: 'https://arbiscan.io/tx/', | ||
address: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', | ||
}, | ||
{ | ||
name: 'Optimism', | ||
id: 10, | ||
decimals: 6, | ||
ecosystem: 'optimism', | ||
network: 'optimism', | ||
txScan: 'https://optimistic.etherscan.io/tx/', | ||
address: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58', | ||
}, | ||
], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// /usdt.tsx | ||
import React, { useState } from 'react'; | ||
import { Button, Card, Flex, message, Radio, Space, Typography } from 'antd'; | ||
|
||
import { EvmPayButtons } from './components/pay-button'; | ||
import ChainSelect from './components/select'; | ||
import { TOKEN_PAY_ADDRESS } from './constants/tokenPayAddress'; | ||
|
||
const { Title } = Typography; | ||
|
||
const PaymentInUSDT: React.FC = () => { | ||
// token ecosystem | ||
const [tokenEcosystem, setTokenEcosystem] = useState<string>(''); | ||
|
||
const onSubmitCashier = async (sign: (toAddress: string, amount: number) => void) => { | ||
// The address and amount are obtained from the backend service | ||
sign('0x35ceCD3d51Fe9E5AD14ea001475668C5A5e5ea76', 10); | ||
}; | ||
|
||
const runPay = async (sign: string, address: string) => { | ||
message.success('Pay success'); | ||
}; | ||
|
||
return ( | ||
<Card title="Payment in USDT"> | ||
<Title level={3}>Select Chain</Title> | ||
<ChainSelect ecosystem={tokenEcosystem} onChange={setTokenEcosystem} /> | ||
<EvmPayButtons | ||
setTokenEcosystem={setTokenEcosystem} | ||
tokenEcosystem={tokenEcosystem} | ||
signCallback={onSubmitCashier} | ||
payCallback={runPay} | ||
onRejectSwitchChain={(id) => { | ||
const oldTokenEcosystem = TOKEN_PAY_ADDRESS.chains.find( | ||
(item) => item.id === id, | ||
)?.ecosystem; | ||
setTokenEcosystem(oldTokenEcosystem || ''); | ||
}} | ||
/> | ||
</Card> | ||
); | ||
}; | ||
|
||
export default PaymentInUSDT; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
--- | ||
nav: Payment In USDT | ||
group: Best Practice | ||
--- | ||
|
||
# Payment In USDT | ||
|
||
当你的项目需要支持 `USDT` 付款的时候,并且需要支持多个链的 `USDT` / `USDC` 时,下边这些可以帮到你。 | ||
|
||
你可以通过我们官方提供的适配器配合 `@ant-design/web3` 使用,快速连接各类区块链,以便于同时支持这些链的 `USDT` / `USDC` 支付。 | ||
|
||
你可以这样做: | ||
|
||
<code compact src="./demos/best-practice/usdt.tsx"></code> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
--- | ||
nav: 用USDT支付 | ||
group: 最佳实践 | ||
--- | ||
|
||
# 用USDT支付 | ||
|
||
当你的项目需要支持 `USDT` 付款的时候,并且需要支持多个链的 `USDT` / `USDC` 时,下边这些可以帮到你。 | ||
|
||
你可以通过我们官方提供的适配器配合 `@ant-design/web3` 使用,快速连接各类区块链,以便于同时支持这些链的 `USDT` / `USDC` 支付。 | ||
|
||
你可以这样做: | ||
|
||
<code compact src="./demos/best-practice/usdt.tsx"></code> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters