logo

Integration Guide

Introduction#

aelf-web-login: Modular React wallet collection and components for aelf applications.

website: https://aelf-web-login.vercel.app/

Install#

1
yarn add @aelf-web-login/wallet-adapter-night-elf @aelf-web-login/wallet-adapter-portkey-aa @aelf-web-login/wallet-adapter-portkey-discover @aelf-web-login/wallet-adapter-react @aelf-web-login/wallet-adapter-base @aelf-web-login/wallet-adapter-bridge

Then the package.json will be like this

1
"dependencies": {
2
"@aelf-web-login/wallet-adapter-night-elf": "^0.0.2-alpha.7",
3
"@aelf-web-login/wallet-adapter-portkey-aa": "^0.0.2-alpha.7",
4
"@aelf-web-login/wallet-adapter-portkey-discover": "^0.0.2-alpha.7",
5
"@aelf-web-login/wallet-adapter-react": "^0.0.2-alpha.7",
6
"@aelf-web-login/wallet-adapter-base": "^0.0.2-alpha.7",
7
"@aelf-web-login/wallet-adapter-bridge": "^0.0.2-alpha.7",
8
}

Config#

  • Import PortkeyDiscoverWallet, PortkeyAAWallet and NightElfWallet and generate instance
  • Create didConfig (internal invoke: ConfigProvider.setGlobalConfig(didConfig))
  • Create baseConfig for SignIn component
  • Create wallets by wallet instance
  • Combine them into a whole as config
  • 1
    import { PortkeyDiscoverWallet } from '@aelf-web-login/wallet-adapter-portkey-discover';
    2
    import { PortkeyAAWallet } from '@aelf-web-login/wallet-adapter-portkey-aa';
    3
    import { NightElfWallet } from '@aelf-web-login/wallet-adapter-night-elf';
    4
    import { IConfigProps } from '@aelf-web-login/wallet-adapter-bridge';
    5
    import { TChainId, SignInDesignEnum, NetworkEnum } from '@aelf-web-login/wallet-adapter-base';
    6
    7
    const APP_NAME = 'explorer.aelf.io';
    8
    const WEBSITE_ICON = 'https://explorer.aelf.io/favicon.main.ico';
    9
    const CHAIN_ID = 'AELF' as TChainId;
    10
    const NETWORK_TYPE = NetworkEnum.TESTNET;
    11
    const RPC_SERVER_AELF = 'https://aelf-test-node.aelf.io';
    12
    const RPC_SERVER_TDVV = 'https://tdvv-public-node.aelf.io';
    13
    const RPC_SERVER_TDVW = 'https://tdvw-test-node.aelf.io';
    14
    const GRAPHQL_SERVER = 'https://dapp-aa-portkey-test.portkey.finance/Portkey_DID/PortKeyIndexerCASchema/graphql';
    15
    const CONNECT_SERVER = 'https://auth-aa-portkey-test.portkey.finance';
    16
    17
    const didConfig = {
    18
    graphQLUrl: GRAPHQL_SERVER,
    19
    connectUrl: CONNECT_SERVER,
    20
    requestDefaults: {
    21
    baseURL: 'https://aa-portkey-test.portkey.finance',
    22
    timeout: 30000,
    23
    },
    24
    socialLogin: {
    25
    Portkey: {
    26
    websiteName: APP_NAME,
    27
    websiteIcon: WEBSITE_ICON,
    28
    },
    29
    },
    30
    };
    31
    32
    const baseConfig = {
    33
    networkType: NETWORK_TYPE,
    34
    chainId: CHAIN_ID,
    35
    keyboard: true,
    36
    noCommonBaseModal: false,
    37
    design: SignInDesignEnum.CryptoDesign, // "SocialDesign" | "CryptoDesign" | "Web2Design"
    38
    titleForSocialDesign: 'Crypto wallet',
    39
    iconSrcForSocialDesign: 'url or base64',
    40
    };
    41
    42
    const wallets = [
    43
    new PortkeyAAWallet({
    44
    appName: APP_NAME,
    45
    chainId: CHAIN_ID,
    46
    autoShowUnlock: true,
    47
    }),
    48
    new PortkeyDiscoverWallet({
    49
    networkType: NETWORK_TYPE,
    50
    chainId: CHAIN_ID,
    51
    autoRequestAccount: true,
    52
    autoLogoutOnDisconnected: true,
    53
    autoLogoutOnNetworkMismatch: true,
    54
    autoLogoutOnAccountMismatch: true,
    55
    autoLogoutOnChainMismatch: true,
    56
    }),
    57
    new NightElfWallet({
    58
    chainId: CHAIN_ID,
    59
    appName: APP_NAME,
    60
    connectEagerly: true,
    61
    defaultRpcUrl: RPC_SERVER_AELF,
    62
    nodes: {
    63
    AELF: {
    64
    chainId: 'AELF',
    65
    rpcUrl: RPC_SERVER_AELF,
    66
    },
    67
    tDVW: {
    68
    chainId: 'tDVW',
    69
    rpcUrl: RPC_SERVER_TDVW,
    70
    },
    71
    tDVV: {
    72
    chainId: 'tDVV',
    73
    rpcUrl: RPC_SERVER_TDVV,
    74
    },
    75
    },
    76
    }),
    77
    ]
    78
    79
    const config: IConfigProps = {
    80
    didConfig,
    81
    baseConfig,
    82
    wallets
    83
    };

    Usage#

  • Import WebLoginProvider, init and useConnectWallet
  • invoke init with upper config as params
  • pass the return value bridgeAPI to WebLoginProvider
  • use useConnectWallet to consume bridgeAPI
  • 1
    import { WebLoginProvider, init, useConnectWallet } from '@aelf-web-login/wallet-adapter-react';
    2
    3
    const App = () => {
    4
    const bridgeAPI = init(config); // upper config
    5
    return (
    6
    <WebLoginProvider bridgeAPI={bridgeAPI}>
    7
    <Demo />
    8
    </WebLoginProvider>
    9
    );
    10
    };
    11
    const Demo = () => {
    12
    const {
    13
    connectWallet,
    14
    disConnectWallet,
    15
    walletInfo,
    16
    lock,
    17
    isLocking,
    18
    isConnected,
    19
    loginError,
    20
    walletType,
    21
    getAccountByChainId,
    22
    getWalletSyncIsCompleted,
    23
    getSignature,
    24
    callSendMethod,
    25
    callViewMethod
    26
    } = useConnectWallet();
    27
    }

    API#

    connectWallet#

    1
    connectWallet: () => Promise<TWalletInfo>

    Connect wallet and return walletInfo

    1
    import { Button } from 'aelf-design';
    2
    3
    const Demo = () => {
    4
    const { connectWallet } = useConnectWallet();
    5
    const onConnectBtnClickHandler = async() => {
    6
    try {
    7
    const rs = await connectWallet();
    8
    } catch (e: any) {
    9
    console.log(e.message)
    10
    }
    11
    }
    12
    return (
    13
    <Button onClick={onConnectBtnClickHandler}>connect</Button>
    14
    )
    15
    }

    disConnectWallet#

    1
    disConnectWallet: () => Promise<void>

    Disconnect wallet

    1
    import { Button } from 'aelf-design';
    2
    3
    const Demo = () => {
    4
    const { disConnectWallet } = useConnectWallet();
    5
    const onDisConnectBtnClickHandler = () => {
    6
    disConnectWallet()
    7
    }
    8
    return (
    9
    <Button onClick={onDisConnectBtnClickHandler}>disConnect</Button>
    10
    )
    11
    }

    lock#

    1
    lock: () => void

    Lock wallet, only portkeyAA wallet take effect

    1
    import { Button } from 'aelf-design';
    2
    3
    const Demo = () => {
    4
    const { lock } = useConnectWallet();
    5
    return (
    6
    <Button onClick={lock}>lock</Button>
    7
    )
    8
    }

    getAccountByChainId#

    1
    getAccountByChainId: (chainId: TChainId) => Promise<string>

    Get account address of designative chainId

    1
    import { Button } from 'aelf-design';
    2
    3
    const Demo = () => {
    4
    const { getAccountByChainId } = useConnectWallet();
    5
    6
    const getAelfAccountHandler = async() => {
    7
    const address = await getAccountByChainId('AELF')
    8
    console.log(address)
    9
    }
    10
    const getTdvwAccountHandler = async() => {
    11
    const address = await getAccountByChainId('tDVW')
    12
    console.log(address)
    13
    }
    14
    return (
    15
    <Button onClick={getAelfAccountHandler}>account-AELF</Button>
    16
    <Button onClick={getTdvwAccountHandler}>account-tDVW</Button>
    17
    )
    18
    }

    getWalletSyncIsCompleted#

    1
    getWalletSyncIsCompleted: (chainId: TChainId) => Promise<string | boolean>

    Return account address of designative chainId if sync is competed, otherwise return false

    1
    import { Button } from 'aelf-design';
    2
    3
    const Demo = () => {
    4
    const { getWalletSyncIsCompleted } = useConnectWallet();
    5
    6
    const getAelfSyncIsCompletedHandler = async() => {
    7
    const address = await getWalletSyncIsCompleted('AELF')
    8
    console.log(address)
    9
    }
    10
    const getTdvwSyncIsCompletedHandler = async() => {
    11
    const address = await getWalletSyncIsCompleted('tDVW')
    12
    console.log(address)
    13
    }
    14
    return (
    15
    <Button onClick={getAelfSyncIsCompletedHandler}>sync-AELF</Button>
    16
    <Button onClick={getTdvwSyncIsCompletedHandler}>sync-tDVW</Button>
    17
    )
    18
    }

    getSignature#

    1
    const getSignature: (params: TSignatureParams) => Promise<{ `` error: number; `` errorMessage: string; `` signature: string; `` from: string; ``} | null>

    Get signature message

    1
    import { Button, Input } from 'aelf-design';
    2
    3
    type TSignatureParams = {
    4
    appName: string;
    5
    address: string;
    6
    signInfo: string;
    7
    hexToBeSign?: string;
    8
    };
    9
    10
    const Demo = () => {
    11
    const { getSignature } = useConnectWallet();
    12
    const [signInfo, setSignInfo] = useState('');
    13
    const [signedMessage, setSignedMessage] = useState('');
    14
    15
    const signHandler = async () => {
    16
    const sign = await getSignature({
    17
    signInfo,
    18
    appName: '',
    19
    address: '',
    20
    });
    21
    setSignedMessage(sign.signature);
    22
    };
    23
    24
    return (
    25
    div>
    26
    <div>
    27
    <Button onClick={signHandler}>
    28
    Sign
    29
    </Button>
    30
    <Input value={signInfo} onChange={(e) => setSignInfo(e.target.value)} />
    31
    <div>{signedMessage}</div>
    32
    </div>
    33
    </div>
    34
    )
    35
    }

    callSendMethod#

    1
    callSendMethod: <T, R>(props: ICallContractParams<T>) => Promise<R>

    Call contract's send method

    1
    import { Button } from 'aelf-design';
    2
    3
    interface ICallContractParams<T> {
    4
    contractAddress: string;
    5
    methodName: string;
    6
    args: T;
    7
    chainId?: TChainId;
    8
    sendOptions?: SendOptions;
    9
    }
    10
    11
    const Demo = () => {
    12
    const { callSendMethod } = useConnectWallet();
    13
    const [result, setResult] = useState({});
    14
    15
    const onApproveHandler = async() => {
    16
    const res = await callSendMethod({
    17
    chainId: 'tDVW',
    18
    contractAddress: 'JRmBduh4nXWi1aXgdUsj5gJrzeZb2LxmrAbf7W99faZSvoAaE',
    19
    methodName: 'Approve',
    20
    args: {
    21
    symbol: 'ELF',
    22
    spender: 'JRmBduh4nXWi1aXgdUsj5gJrzeZb2LxmrAbf7W99faZSvoAaE',
    23
    amount: '100000000',
    24
    },
    25
    });
    26
    setResult(res);
    27
    }
    28
    29
    return (
    30
    <div>
    31
    <Button onClick={onApproveHandler}>Approve in tDVW</Button>
    32
    <div>
    33
    <h4>Result</h4>
    34
    <pre className="result">{JSON.stringify(result, null, ' ')}</pre>
    35
    </div>
    36
    </div>
    37
    )
    38
    }

    callViewMethod#

    1
    callViewMethod: <T, R>(props: ICallContractParams<T>) => Promise<R>

    Call contract's view method

    1
    import { Button } from 'aelf-design';
    2
    3
    interface ICallContractParams<T> {
    4
    contractAddress: string;
    5
    methodName: string;
    6
    args: T;
    7
    chainId?: TChainId;
    8
    sendOptions?: SendOptions; // only send method use, ignore in view method
    9
    }
    10
    11
    const Demo = () => {
    12
    const { callViewMethod, getAccountByChainId } = useConnectWallet();
    13
    const [result, setResult] = useState({});
    14
    15
    const onGetBalanceHandler = async() => {
    16
    const res = await callViewMethod({
    17
    chainId: 'tDVW',
    18
    contractAddress: 'ASh2Wt7nSEmYqnGxPPzp4pnVDU4uhj1XW9Se5VeZcX2UDdyjx',
    19
    methodName: 'GetBalance',
    20
    args: {
    21
    symbol: 'ELF',
    22
    owner: await getAccountByChainId('tDVW'),
    23
    },
    24
    });
    25
    setResult(res);
    26
    }
    27
    28
    return (
    29
    <div>
    30
    <Button onClick={onGetBalanceHandler}>GetBalance in tDVW</Button>
    31
    <div>
    32
    <h4>Result</h4>
    33
    <pre className="result">{JSON.stringify(result, null, ' ')}</pre>
    34
    </div>
    35
    </div>
    36
    )
    37
    }

    walletInfo#

    1
    const walletInfo: TWalletInfo

    Wallet information after connecting wallet, can import TWalletInfo from @aelf-web-login/wallet-adapter-base

    1
    type TWalletInfo =
    2
    | {
    3
    name?: string;
    4
    address: string;
    5
    extraInfo?: {
    6
    [key: string]: any;
    7
    };
    8
    }
    9
    | undefined;
    10
    11
    // walletInfo returned by nightElf
    12
    {
    13
    name,
    14
    address,
    15
    extraInfo: {
    16
    publicKey,
    17
    nightElfInfo: {
    18
    name,
    19
    appPermission,
    20
    defaultAElfBridge: bridge,
    21
    aelfBridges: bridges,
    22
    nodes,
    23
    },
    24
    },
    25
    }
    26
    27
    // walletInfo returned by portkeyAA
    28
    import { DIDWalletInfo } from '@portkey/did-ui-react';
    29
    {
    30
    name,
    31
    address,
    32
    extraInfo: {
    33
    publicKey,
    34
    portkeyInfo: {
    35
    ...DIDWalletInfo
    36
    accounts: {
    37
    [chainId]: didWalletInfo.caInfo?.caAddress,
    38
    },
    39
    nickName,
    40
    },
    41
    },
    42
    }
    43
    44
    // walletInfo returned by portkeyDiscover
    45
    import type { Accounts, IPortkeyProvider } from '@portkey/provider-types';
    46
    {
    47
    address,
    48
    extraInfo: {
    49
    accounts: Accounts,
    50
    nickName,
    51
    provider: IPortkeyProvider,
    52
    },
    53
    }
    54
    55
    const Demo = () => {
    56
    const { walletInfo } = useConnectWallet();
    57
    console.log(walletInfo)
    58
    return null
    59
    }

    walletType#

    1
    const walletType: WalletTypeEnum

    The currently connected wallet type, can import WalletTypeEnum from @aelf-web-login/wallet-adapter-base

    1
    enum WalletTypeEnum {
    2
    unknown = 'Unknown',
    3
    elf = 'NightElf',
    4
    aa = 'PortkeyAA',
    5
    discover = 'PortkeyDiscover',
    6
    }
    7
    8
    const Demo = () => {
    9
    const { walletType } = useConnectWallet();
    10
    console.log(walletType)
    11
    return null
    12
    }

    isLocking#

    1
    const isLocking: boolean

    indicate whether the current state is locked, only portkeyAA wallet take effect, other wallets always return false

    1
    import { Button } from 'aelf-design';
    2
    3
    const Demo = () => {
    4
    const { isLocking } = useConnectWallet();
    5
    6
    return (
    7
    <Button>
    8
    {isLocking ? 'unlock' : 'connect'}
    9
    </Button>
    10
    )
    11
    }

    isConnected#

    1
    const isConnected: boolean

    indicate whether the current state is connected

    1
    import { Button } from 'aelf-design';
    2
    3
    const Demo = () => {
    4
    const { isConnected } = useConnectWallet();
    5
    6
    return (
    7
    <div>
    8
    <Button disabled={isConnected}>connect</Button>
    9
    <Button disabled={!isConnected}>disConnect</Button>
    10
    </div>
    11
    )
    12
    }

    loginError#

    1
    const loginError: TWalletError | null

    indicate are there any errors during the login/logout/unlock process

    1
    type TWalletError = {
    2
    name: string;
    3
    code: number;
    4
    message: string;
    5
    nativeError?: any;
    6
    }
    7
    8
    const Demo = () => {
    9
    const { loginError } = useConnectWallet();
    10
    11
    useEffect(() => {
    12
    if (!loginError) {
    13
    return;
    14
    }
    15
    console.log(loginError.message);
    16
    }, [loginError]);
    17
    18
    return null
    19
    }

    Development#

  • Install dependencies in the project root directory
  • 1
    pnpm install
  • cd to demo directory and execute dev command
  • 1
    cd packages/starter
    2
    pnpm dev

    Publish#

  • Upgrade the version numbers of each sub package
  • execute release command in the project root directory
  • 1
    pnpm release

    Edited on: 11 July 2024 04:33:40 GMT+0