DApp(PC Web): Anchor使用说明

安装依赖

yarn @amax/anchor-link @amax/anchor-link-browser-transport

初始化

 const transport = new AnchorLinkBrowserTransport();
 const link = new AnchorLink({
      transport,
      service: "https://fwd.aplink.app",
      chains: [
        {
          chainId:
            "208dacab3cd2e181c86841613cf05d9c60786c677e4ce86b266d0a58884968f7",
          nodeUrl: "https://test-chain.ambt.art",
        },
      ],
    });

登录

anchor-link-demo既是scope,也是session_name,可以通过这个关键字取出session信息。session存在则是在登录状态。 注:scope的类型为Name,所以符合Name规范,长度最好不要超过12位,如果输入不合法的字符串,系统会自动处理成合法(Name),比如:anchor-link-demo => anchor.link.d,不合法的字符全部处理成"."符号

    const identity = await link.login("anchor-link-demo");
    const { account, proof, proofKey, proofValid } = await verifyProof(
      link,
      identity,
    );
    setAccount(account);
    setSession(identity.session);

验证

export async function verifyProof(link, identity) {
  // Generate an array of valid chain IDs from the demo configuration
  const chains = blockchains.map(chain => chain.chainId);


  // Create a proof helper based on the identity results from anchor-link
  const proof = IdentityProof.from(identity.proof);


  // Check to see if the chainId from the proof is valid for this demo
  const chain = chains.find(id => ChainId.from(id).equals(proof.chainId));
  if (!chain) {
    throw new Error("Unsupported chain supplied in identity proof");
  }


  // Load the account data from a blockchain API
  let account: API.v1.AccountObject;
  try {
    account = await link.client.v1.chain.get_account(proof.signer.actor);
  } catch (error) {
    if (error instanceof APIError && error.code === 0) {
      throw new Error("No such account");
    } else {
      throw error;
    }
  }

获取登录状态

在页面刷新后,如何重新获取登录状态。anchor-link-demo是登录时设置的关键字,即session名。如果session存在,说明是在登录状态下。

    const session = await link.restoreSession(
      "anchor-link-demo"
    );

    if (session) {
      const { actor } = session.auth;
      const account = await link.client.v1.chain.get_account(actor);
      setSession(session);
      setAccount(account);
    }

退出登录

  async function doLogout() {
    await link.current.clearSessions("anchor-link-demo");
    setAccount(undefined);
    setSession(undefined);
  }

侦听退出登录

aplink断开连接时会触发session.onAppRemoveSession操作

export async function onAppRemoveSession() {
  if (!window.__LINK__) {
    return;
  }
  const session: LinkSession = await window.__LINK__.restoreSession(scope);
  if (session) {
    (session as LinkChannelSession).onAppRemoveSession(() => {
      eventBus.trigger('logout');
    });
  }
}

如何与后端进行登录验证?

export async function login(dispatch) {
  const link = initLink();
  const identity = await link.login(scope);
  const { account, proof, proofKey, proofValid } = await verifyProof(
    link,
    identity,
  );


  const walletAddress = proof.signer.actor.toString();
  const authority = proof.signer.permission.toString();
  const chainId = network.chainId;


  storage.set('walletAddress', walletAddress);
  storage.set('authority', authority);
  storage.set('chainId', chainId);

  // proof信息传给后端进行签名校验,成功返回token,失败则退出link登录。
  await dispatch({
    type: 'login/login',
    params: {
      signature: proof.signature.toString(),
      message: '',
      wallet_address: walletAddress,
      authority,
      scope: proof.scope.toString(),
      expiration: proof.expiration.toString(),
    },
    callback: async ({ data, code }) => {
      if (code === 200) {
        updateToken(data.token);
        await dispatch({
          type: 'global/updateState',
          state: {
            isLogin: true,
            walletAddress,
            chainId,
          },
        });
        setTimeout(eventBus.trigger, 400, 'getBalance');
      } else {
        await link.clearSessions(scope);
        storage.remove('walletAddress');
        storage.remove('authority');
        storage.remove('chainId');
      }
    },
  });
}

发起交易

单个交易,给testuser1帐号转0.000001 MUSDT

注意: broadcast设置,如果为truepush_transaction动作与web发起,即app只负责生成交易签名。如果为false,则由app发起最终交易。

  async function doTransact() {
    if (session) {
      const action = {
        account: "amax.mtoken",
        name: "transfer",
        authorization: [session.auth],
        data: {
          "from": session.auth.actor,
          "to": "testuser1",
          "quantity": "0.000001 MUSDT",
          "memo": "",
        },
      }
      session.transact({ action }, { broadcast: false }).then((data) => {
        setTransaction(data);
      })
    } else {
      message.warn("请登录");
    }
  }

多个交易

生成一个NFT,执行了两个动作createissue

async function createrNFT() {
    if (session) {
      const symbol = {
        id: 19999,
        parent_id: 0,
      };
      const quantity = 1000;
      const createParams = {
        issuer: session.auth.actor,
        maximum_supply: quantity,
        token_uri: "https://kverso.mypinata.cloud/ipfs/QmUVVg7V3a9MBuxpQboc67HEhTX6hDZEunZ1Tm5Gucb6BW/1471",
        ipowner: session.auth.actor,
        symbol,
      };
      const issueParams = {
        to: session.auth.actor,
        quantity: {
          amount: quantity,
          symbol,
        },
        memo: "",
      };


      const actions = [{
        account: "amax.ntoken",
        name: "create",
        authorization: [session.auth],
        data: createParams,
      }, {
        account: "amax.ntoken",
        name: "issue",
        authorization: [session.auth],
        data: issueParams,
      }]

      session.transact({ actions }, { broadcast: true }).then((data) => {
        setTransaction(data);
      })


    } else {
      message.warn("请登录");
    }
  }

相关文档

https://www.npmjs.com/package/@amax/anchor-link

https://github.com/greymass/anchor-link-demo-multipass

最后更新于