Skip to content

omni/tokenbridge-burner-wallet-plugin

Repository files navigation

TokenBridge Burner Wallet 2 Plugin Sample

This sample plugin defines a mediator extension exchange pair to be used in the Exchange Plugin in the burner wallet. It uses the resources from the @poanet/tokenbridge-bw-exchange npm package to define new assets and exchange pairs.

Introduction

The Burner Wallet 2.0 is a modular, extendable and customizable web application. It provides a set of packages and plugins that allow you to extend the basic functionality. Here we will focus on the Assets package and the Exchange Plugin.

Assets

You can add any native or ERC20 token to track its balance and send transactions. For example you can define a new ERC20 and add it to the wallet:

import { xdai, dai, eth, ERC20Asset } from '@burner-wallet/assets';

const test = new ERC20Asset({
  id: 'tst', // The internal ID used by the wallet.
  name: 'Test Token', // The display name that will be displayed to the user.
  network: '1', // The chain ID of the chain the token is deployed to.
  address: '0x52ad726d80dbb4A9D4430d03657467B99843406b' // Address where the token contract is deployed
});

const core = new BurnerCore({
  assets: [test, xdai, dai, eth],
});

The ERC20Asset class extends from the Asset class. The Asset class provides several methods to allow the wallet interact with the token. The following are the most important to pay attention and that could be overridden if your token behaves differently.

  • getBalance: Indicates how to get the balance of your asset.
  • startWatchingAddress: Indicates how to listen to value transfers incoming into your account.
  • _send: Indicates how to send value to another account.

Gateways

Gateways can be thought of as “wrapped RPC providers”, as they transmit data from the wallet to endpoints such as Infura. Gateways use the network id from the assets to select the correct endpoints.

The @burner-wallet/core module contains some standard gateways:

  • InfuraGateway
  • XDaiGateway
  • InjectedGateway (which transmits messages through an injected Web3 provider such as Metamask).

Exchange Plugin

The @burner-wallet/exchange package is an extendable plugin for implementing asset exchanges and bridges. The exchange module accepts an array of trading pairs.

const exchange = new Exchange({
  pairs: [new Pair1(), new Pair2()]
})

Pair is an abstract class that defines the interface for trading pairs. If you would like to add custom trading functionality, you can extend this class and implement it's methods:

  • estimateAtoB: Indicates how to estimate the B Asset the user will receive for the amount of A Asset. For example Fees could be considered here. This method returns the amount to be received, and a custom message to display in UI.
  • estimateBtoA: Indicates how to estimate the A Asset the user will receive for the amount of B Asset. For example Fees could be considered here. This method returns the amount to be received, and a custom message to display in UI.
  • exchangeAtoB: Indicates how to send A Asset to be exchanged for B Asset. Here you can add logic to detect exchange finalization for example for a more complex exchange operation like bridges.
  • exchangeBtoA: Indicates how to send B Asset to be exchanged for A Asset. Here you can add logic to detect exchange finalization for example for a more complex exchange operation like bridges.

Exchange pairs examples:

  • XDAIBridge: It allows the user to exchange the pair DAI <> xDAI. Since validators need to verify the transaction, and release the tokens on the other network, this pair detects the exchange finalization by listening to events on the bridge contracts.
  • Uniswap: It allows the user to exchange the pair DAI <> ETH by using Uniswap. In this case, exchangeAtoB is extended for converting DAI to ETH, since it requires performing two transactions. First calling approve on the token contract and then calling the method from the Uniswap contract.

TokenBridge Plugin

The TokenBridge Burner Wallet 2 Plugin provides some generic resources that can be used and extended:

  • ERC677Asset - A representation of an Erc677 token
  • BridgeableERC20Asset - A representation of an Erc20 token with a possibility of bridging it through token bridges.
  • NativeMediatorAsset - Represents a native token that interacts with a Mediator extension.
  • Mediator Pair - Represents an Exchange Pair that interacts with mediators extensions.
  • MediatorErcToNative Pair - Represents a modified Mediator Pair that interacts with a tokenbridge erc-to-native mediators contracts.
  • TokenBridgeGateway - A gateway to operate with ETC, POA Sokol, POA Core and qDAI networks.

The asset ERC677Asset extends from ERC20Asset and overrides some methods:

  • _send: In this case the method transferAndCall is used instead of the transfer method.
  • startWatchingAddress: Add logic to correctly track the transfer events related to the wallet account.
  • getTx: Overrides the logic to return the stored information about a transfer transaction to avoid errors on the information displayed.

The asset BridgeableERC20Asset extends from ERC20Asset and overrides some methods:

  • _send: If the asset detects that receiver is a bridge/mediator contract and it has on of the supported bridge modes, the tokens are sent using approve() + relayTokens, otherwise, regular ERC20 transfer() is used.

The asset NativeMediatorAsset extends from the NativeAsset of the burner wallet core. It extends the functionality with the following method:

  • scanMediatorEvents: Add logic to watch transfer from mediator contracts to the wallet account to display it in the activity list.
  • getTx: Overrides the logic to return the stored information about a transfer transaction to avoid errors on the information displayed.

The pair Mediator extend from some other classes that has Pair as base. It implements the previous mentioned methods to estimate and exchange the assets. It also implements some methods to detect the exchange finalization. Here are some details of the implemented methods:

  • estimateAtoB: Gets the fee, calculates the amount of B Asset the user will receive and sets a custom message to be displayed mentioning the fee charges.
  • estimateBtoA: Gets the fee, calculates the amount of A Asset the user will receive and sets a custom message to be displayed mentioning the fee charges.
  • exchangeAtoB: Sends A Asset to the mediator contract. Then it calls detectExchangeAToBFinished.
  • exchangeBtoA: Sends B Asset to the mediator contract. Then it calls detectExchangeBToAFinished.
  • detectExchangeAToBFinished: Wait for events emitted by the mediator contract to detect the exchange finalization.
  • detectExchangeBToAFinished: Wait for events emitted by the mediator contract to detect the exchange finalization.

The pair MediatorErcToNative extend from Mediator as base. It overrides estimateAtoB and estimateBtoA to use a different manner of retrieving bridging fees that are specific for erc-to-native mediator.

The gateway TokenBridgeGateway extends from the Gateway class of the burner wallet core. It provides access from the wallet to the following networks:

  • ETC
  • POA Sokol
  • POA Core
  • qDAI

Project structure

There are three main folders in the project:

  • wallet - is a burner wallet instance ready to use your plugin
  • test-wallet - is a burner wallet instance ready to test your plugin and resources in testnets
  • my-plugin - is the folder where the plugin code is located. To change the name of the plugin it is necessary to update the folder name my-plugin and all mentions to my-plugin to the new name of your plugin.

Inside my-plugin you can find the files that defines the resources to be exposed by the plugin to be used by the burner wallet in order to interact with the ERC677 to ERC677 bridge extension:

  • Stake - extends from ERC677Asset defined in @poanet/tokenbridge-bw-exchange
  • xStake - extends from ERC677Asset defined in @poanet/tokenbridge-bw-exchange
  • StakeBridge - extends from Mediator defined in @poanet/tokenbridge-bw-exchange

In this repo example case, the class StakeBridge extends the Mediator class but has some differences on how to estimate the values and calculate the transfers fees. That's why it overrides the methods:

  • estimateAtoB: To add specific logic to get the fee from the A to B exchange and estimate the value that will be received.
  • estimateBtoA: To avoid fee calculations since there are no fees for B to A exchange.

You can extend or replace these resources based on your use case.

Inside the wallet folder, the file wallet/src/index.tsx integrates the plugin into the wallet by importing the resources in the following line:

import { Stake, xStake, StakeBridge } from 'my-plugin'

To be able to use and to display the balances for Stake and xStake it is necessary to list them in the list of assets as follow:

const core = new BurnerCore({
    ...
  assets: [Stake, xStake]
})

Then, in order to perform exchange operations between the assets it is needed that the defined pair is included in the Exchange plugin as follows:

const exchange = new Exchange({
  pairs: [new StakeBridge()]
})

Clone the sample repo

Clone the sample repo to create a plugin project that uses the TokenBridge plugin. This sample repo contains a ready to publish plugin for a ERC677 to ERC677 bridge extension, but you can later modify it to define your own resources.

Install dependencies

Run yarn install. This repo uses Lerna and Yarn Workspaces, so yarn install will install all dependencies and link modules in the repo.

Build

To build the plugin package, from the root folder of project, you need to run the following command:

yarn build

Test plugin and resources in testnets

The project includes a burner wallet instance where you can test the implementation of the plugin in testnet. For that, you have to make sure that the build step was performed and that the plugin resources you modified are correctly imported and used in the src/index.tsx file of the test-wallet folder.

  1. Create .env file in test-wallet folder from .env.example and set the required parameters for the ERC677 to ERC677 bridge extension:
REACT_APP_INFURA_KEY=<your key from infura.com>
REACT_APP_HOME_NETWORK=
REACT_APP_HOME_TOKEN_NAME=
REACT_APP_HOME_TOKEN_ADDRESS=
REACT_APP_HOME_MEDIATOR_ADDRESS=

REACT_APP_FOREIGN_NETWORK=
REACT_APP_FOREIGN_TOKEN_NAME=
REACT_APP_FOREIGN_TOKEN_ADDRESS=
REACT_APP_FOREIGN_MEDIATOR_ADDRESS=
  1. To start the burner wallet instance run:
yarn start-test-wallet

Run plugin in Mainnet

The project includes a burner wallet instance where you can use the implementation of the plugin. For that, you have to make sure that the build step was performed and that the plugin resources you modified are correctly imported and used in the src/index.tsx file of the wallet folder.

  1. Create .env file in wallet folder and set:
REACT_APP_INFURA_KEY=<your key from infura.com>
  1. To start the burner wallet instances run:
yarn start-wallet

Publish to npm

In order to make the plugin accessible it needs to be published in the npm registry. For that, you can follow these steps:

  1. Create account in https://www.npmjs.com/

  2. Go to my-plugin folder

  3. Run yarn build. Make sure it generates the dist folder

  4. Update version in my-plugin/package.json

  5. Run yarn publish and fill login information if required. The prompt will ask for the new version, complete it with the version from my-plugin/package.json

More information in https://classic.yarnpkg.com/en/docs/publishing-a-package/