# T-Swaps


# Get Started

T-Swaps is an innovative trading platform on Telos Native.&#x20;

## Features & Benefits

#### Fast & Affordable

Battle tested 10 000 transactions per second. No gas fees on Telos Native.

#### Easy to use

A trading platform that anyone can use.

#### Liquidity pools

Our pools have the most liquidity on Telos native.

#### Self-listing

You can list any native Telos token pair.

#### Eco-Friendly

Runs on the most energy efficient blockchain.

#### Curve Pools

Choose between the Bancor (Uniswap) or Curve algorithm during pool creation.

## STEP-BY-STEP GUIDE

1. Create a Telos Account - [How-to Guide](https://www.telos.net/signup)
2. Connect your Wallet - [How-to Guide](https://www.telos.net/#getting-started)
3. Get Telos native tokens - [How-to Guide](https://help.telos.net/en_US/getting-started/how-to-buy-tlos)


# Contact Us


# EVM Bridge

{% hint style="info" %}
This service is still under ongoing development.&#x20;
{% endhint %}

The EVM bridge allows native tokens to be bridged to and from BSC, Ethereum and Telos EVM. Project owners can make use of this service by following [Listing a token](/bridge/evm-bridge/listing-a-token).

The bridge is a modified version of the [alienworlds teleport bridge](https://github.com/Alien-Worlds/alienteleport) to allow for multiple tokens to be bridged.

If you are interested in bridging your token, let us know by **filling in this** [**form**](https://forms.gle/jtLeFtDsRfdUkJZv5).

## Audit report

[![SecureBlock Audit](https://secureblock.io/project/t-swaps-bridge/badge)](https://secureblock.io/project/t-swaps-bridge)

These contracts have been audited by [Secureblock](https://secureblock.io/)&#x20;

[Audit Report](https://secureblock.io/reports/c0279043-7d8f-4c89-88d9-5430ea0f57b4.pdf) - June 2022

## How does the bridge work?

![Bridge System Architecture](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2F6tDQfYSuiWhmYVMSaOIS%2Fimage.png?alt=media\&token=e3240462-4aef-4c47-9a6f-515255e1b328)

The bridge consists of 4 main parts:

* Telos Native Bridge Contract - Keeps record of transfers and bridgable tokens.
* Reporters - Facilitates secure communication between the two networks.
* Teleport Token Factory - Creates new Teleport Token Contracts
* Teleport Token - Is the modified ERC-20 Token Contract that allows claiming from Telos and bridging back to Telos.

The bridge works by transferring your listed token to the tport.start contract and specifying the network and address you're transferring to. The reporters will validate the transfer after 3 reporters have successfully reported. Once validated, the sent tokens will be claimable on the respective Token Contract. After claiming, the tokens are minted and sent to the address you specified originally.

To send tokens back to telos, the teleport action is called on the Teleport Token Contract with the amount and telos account. The reporters will validate. Once validated the tokens will be transferred from the tport.start contract back to you.

## Fees and related info

As it stands, there are no fees for users to bridge tokens other than gas costs. For project owners, the EVM token creation fee needs to be paid.&#x20;

A small fee is likely to be introduced in the near future to cover the costs of running the bridge.

For now, the best way to support future development is to [vote for our block producers](https://eosauthority.com/vote/producers?network=telos): bp.yknot & southafrica1.


# How to Bridge

Guide to bridging tokens using EVM Bridge

![From network selection](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2FJmZj7WHEWhEYuehBRsBm%2Fimage.png?alt=media\&token=d8bcf3ef-344b-4bd4-924b-c41823a224a6)

Once wallets have been created, they need to be connected. Clicking the "CONNECT WALLET" button on the Telos network bridge provides the user with the choice of using Anchor or Wombat.

![](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2FrWFFL9bg84yfqEINClKN%2Fimage.png?alt=media\&token=ca1038f0-5084-4cdb-a7e3-dfd5d9f61183)

After the user has connected Telos Account, they need to connect their Telos EVM Account through MetaMask. This can be done by clicking the "CONNECT WALLET" button on the Telos EVM network bridge.

![To network selection](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2Fgf4CAyuYDhUbgMIBBH5P%2Fimage.png?alt=media\&token=28d3e2f9-fc02-4a7f-87ce-2bde0a9ce552)

Once both accounts are connected, the user may select the "To" and "From" networks. The "To" and "From" networks can be switched using the switch networks button.

![Button that switches "To" and "From" networks.](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2FxPvdW30Vgnrcw5foVWH0%2Fimage.png?alt=media\&token=cedd5b3c-dd43-4181-a9ce-63adc7e53b14)

Once the user has selected the correct "To" and "From" networks, they make click next and select the token and amount of said token to be bridged.

![](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2FRMppXONzI607UAgGxYLp%2Fimage.png?alt=media\&token=723159ed-841c-457d-8045-32fcf0161d4e)

After selecting the token and amount, the next button takes the user to the "Confirm Transaction" panel.&#x20;

![](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2FVaIHjiz7xwtnSVekJVGM%2Fimage.png?alt=media\&token=09909383-a03a-4bff-8893-b52e3e80dcee)

Once confirmed, the user will need to sign their transaction. Once the transaction has been signed successfully, a popup with the transaction ID will be displayed. Clicking this ID will link the user to the corresponding block explorer for said transaction. Clicking "OK" closes the popup.

![](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2FgavzLuM0PIiubbxF1bXz%2Fimage.png?alt=media\&token=acf38423-c6db-4179-bcd6-186f99f20505)

The user will them be redirected to the network selection panel if they wish to bridge other tokens.


# Listing a token

Guide to bridging your token from Telos native to BSC, Ethereum and Telos EVM.

## Overview

Lising a token is done by creating a modified ERC-20 token contract on the EVM-side of the bridge. This is done through a Token Factory contract. Here is the current factory contracts deployed on the supported networks:

* Mainnet
  * BSC: [0x20c5bdabf14499234a4ec62b81145164f867da98](https://bscscan.com/address/0x20c5bdabf14499234a4ec62b81145164f867da98#writeContract)
  * TEVM: [0x7a82dE1B2159C33C8d93cd9Dbb06350820458E4f](https://www.teloscan.io/address/0x7a82dE1B2159C33C8d93cd9Dbb06350820458E4f/#contract)
* Testnet
  * BSC: [0xb945Dc9F48895F296eE30447A4dD603eaa2f3E72](https://testnet.bscscan.com/address/0xb945Dc9F48895F296eE30447A4dD603eaa2f3E72#code)
  * Goerli: [0xB4067e220966a41dd1694abAC422d6ca9cd2EC7D](https://goerli.etherscan.io/address/0xB4067e220966a41dd1694abAC422d6ca9cd2EC7D#code)&#x20;
  * TEVM: [0x6F174B0a2c6B6807CcCc18b6643dbf755E31400c](https://testnet.teloscan.io/address/0x6F174B0a2c6B6807CcCc18b6643dbf755E31400c/#contract)&#x20;

## Requirements

To bridge across to BSC/ETH/TEVM you will need to have:

* A token on Telos.
* A BSC/ETH/TEVM account. (BSC and TEVM has lower transactions fees)
* Have BNB/ETH/TLOS on the previous address. See specific amount table below

| Chain     | Amount (Mainnet) | Amount (Testnet) |
| --------- | ---------------- | ---------------- |
| BSC       | 0.3 BNB          | 0.01 BNB         |
| Ethereum  | 0.1 ETH          | 0.01 ETH         |
| Telos EVM | 100 TLOS         | 0.01 TLOS        |

{% hint style="info" %}
These values are subject to change.
{% endhint %}

## Steps

{% hint style="danger" %}
Interacting with the TeleportToken contract on [Teloscan](https://testnet.teloscan.io/) is known to have issues on Telos EVM testnet. We recommend using Remix for Telos EVM testnet instead.
{% endhint %}

1. Create token on BSC/ETH/TEVM using the teleport token factory contract. This can be done in one of two ways:
   * [Using Block Explorers](/bridge/evm-bridge/listing-a-token/using-block-explorers) - Recommended for most users
   * [Using Remix](/bridge/evm-bridge/listing-a-token/using-remix) - Requires more some knowledge of Solidity smart contracts.&#x20;
2. Send your newly created token details to us so that we can complete the process.
   * Fill in this form: <https://forms.gle/jtLeFtDsRfdUkJZv5>​
   * Send your token address to <https://t.me/+vuTCHwfB23wwYzU0>

As soon as we've received these details, we'll set up the bridge.To use the bridge, see [Sending tokens](https://app.gitbook.com/s/-MZmYa_En2H0T5iQjMMv/help/using-the-wallet#sending-tokens)​

​


# Using Block Explorers

Steps to creating your token using a block explorer

1. Go to the teleport token factory
   * See [here](/bridge/evm-bridge/listing-a-token#overview) for available the contract address
2. Connect your wallet
3. Insert the required information into the "**Create**" action.&#x20;

{% hint style="danger" %}
Be sure to set the "Threshold" to 3.
{% endhint %}

{% hint style="info" %}
The chain IDs are as follows:

ETH (mainnet & ropsten): 1

BSC (mainnet & testnet): 2

tEVM (mainnet & testnet): 3
{% endhint %}

![Token create example.](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2F3dUxz4oKndYsdruFPKAh%2Fteleportfac.png?alt=media\&token=c567f839-de00-49f4-aa77-550ead99407d)

4\. Then click the "write" button and confirm the transaction.

5\. Once the transactions is completed go the the created contract and call the accept ownership action.

You can find the created contract address by going to the transaction's internal transactions as shown below.

![​](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2FCu9TxFGrD65MjFZ0urfa%2Fimage.png?alt=media\&token=e4c0ff2d-5ea4-4257-b2df-d08ba8323fe5)

## &#x20;<a href="#interacting-with-your-contract-remix" id="interacting-with-your-contract-remix"></a>


# Using Remix

{% hint style="info" %}
It is recommended that you read through [Using Block Explorers](/bridge/evm-bridge/listing-a-token/using-block-explorers) before this one. The steps are very similar
{% endhint %}

## Steps <a href="#interacting-with-your-contract-remix" id="interacting-with-your-contract-remix"></a>

* Start creating a new blank project on Remix, then copy the `TeleportToken.sol` , `TeleportTokenFactory.sol` and `Owner.sol` (provided in [Solidity Contracts](/bridge/evm-bridge/solidity-contracts)) in the corresponding files as shown in the image below.

![ext you will go to deploy section and use the injected web3 environment. Make sure you selected the correct network in your metamask.](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2FncaDaKTUMpfTUj2mKwcw%2F1_1-contracts.png?alt=media\&token=0c8c0209-415a-4600-9e62-7d7cadcdaa7a)

* Compile the contracts using the compiler version 0.8.7.&#x20;

<img src="https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2FTLmZpAQavfbnBQX5VlDH%2F1_3-compile.png?alt=media&amp;token=c84545d9-b40e-45f4-b411-105cae516e95" alt="" data-size="original">

* Copy the token factory contract address to the `atAddress` field, select the `teleportTokenFactory` contract and click the `atAddress` button. This should show the callable actions of the contract.

![](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2FS1ySjv2RNpdhyqdyE0D8%2F3_1-deploy-address-v2.png?alt=media\&token=fdd95a56-3ca7-4f59-b866-ca687d63a2c1)

* You can now click on `create` and fill in your token details. Remember to set the amount of native tokens (eg. TLOS in the case of the Telos EVM) that you will be transferring to cover the creation fee in the `value` field. This amount can be found with the `creationFee` action. This value is in [wei](https://ethereum.org/en/glossary/#wei), so don't let the zero's startle you. Finally, click the transact button and sign the transaction.

<img src="https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2FBq1U7zbbnT2hcCKZ8Kbo%2F4_2-create-action.png?alt=media&amp;token=f0c979e9-8ad0-4190-964d-010266d7cd3f" alt="" data-size="original"><img src="https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2FjfuJOryP4Pjon2X1oLH5%2F4_1-create-fee-value-v2.png?alt=media&amp;token=36d5cdfd-7d89-4b81-bed6-e2e77fcb1482" alt="" data-size="original">

* To get your new token contract address, you have to inspect the internal transactions of the creation transaction (from the previous step).&#x20;
  * Navigate to the relavent block explorer. In this example we deployed the test token to the Telos EVM testnet, so we show our [transaction](https://testnet.teloscan.io/tx/0x07042b15be809382da3c63c207d9b859cca339093460811bae22e3f4f541a518#internal) on the testnet version of Teloscan.&#x20;
  * You will find your token address in the "to" value of the create call in one of the internal transactions.&#x20;

![](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2FTiUbw2dduwLIgOkPXryN%2Fimage.png?alt=media\&token=3e907b0b-636e-495e-93bc-a9e3559eea2f)

* Paste this address in the block explorer to view your contract. (You might need to prepend a "0x"). Here is our example's token contract: [0x980a232f66ccb9a005479784ae3a4f50818a5311](https://testnet.teloscan.io/address/0x980a232f66ccb9a005479784ae3a4f50818a5311/#contract)


# Solidity Contracts

The relavent Solidity smart contracts that are deployed on the EVM chains are listed here. Project owners can use these contracts to manually list their token on the bridge.

## Audit report

These contracts have been audited by [Secureblock](https://secureblock.io/)&#x20;

[Audit Report](https://secureblock.io/reports/c0279043-7d8f-4c89-88d9-5430ea0f57b4.pdf) - June 2022

## TeleportToken.sol

This is an extended ERC-20 token contract. This contract is the wrapped token contract on the EVM (Telos EVM, BSC, Ethereum etc.) side of the bridge.

```
pragma solidity ^0.8.6;
/*
 * SPDX-License-Identifier: MIT
 */
pragma experimental ABIEncoderV2;

// import "hardhat/console.sol";
import "./Owner.sol";
import {TeleportTokenFactory} from "./TeleportTokenFactory.sol";

contract Verify {
    function recoverSigner(bytes32 message, bytes memory sig)
        public
        pure
        returns (address)
    {
        uint8 v;
        bytes32 r;
        bytes32 s;

        (v, r, s) = splitSignature(sig);

        if (v != 27 && v != 28) {
            return (address(0));
        } else {
            // solium-disable-next-line arg-overflow
            return ecrecover(message, v, r, s);
        }
    }

    function splitSignature(bytes memory sig)
        public
        pure
        returns (
            uint8,
            bytes32,
            bytes32
        )
    {
        require(sig.length == 65);

        bytes32 r;
        bytes32 s;
        uint8 v;

        assembly {
            // first 32 bytes, after the length prefix
            r := mload(add(sig, 32))
            // second 32 bytes
            s := mload(add(sig, 64))
            // final byte (first byte of the next 32 bytes)
            v := byte(0, mload(add(sig, 96)))
        }

        if (v < 27) v += 27;

        return (v, r, s);
    }
}

library Endian {
    /* https://ethereum.stackexchange.com/questions/83626/how-to-reverse-byte-order-in-uint256-or-bytes32 */
    function reverse64(uint64 input) internal pure returns (uint64 v) {
        v = input;

        // swap bytes
        v = ((v & 0xFF00FF00FF00FF00) >> 8) | ((v & 0x00FF00FF00FF00FF) << 8);

        // swap 2-byte long pairs
        v = ((v & 0xFFFF0000FFFF0000) >> 16) | ((v & 0x0000FFFF0000FFFF) << 16);

        // swap 4-byte long pairs
        v = (v >> 32) | (v << 32);
    }

    function reverse32(uint32 input) internal pure returns (uint32 v) {
        v = input;

        // swap bytes
        v = ((v & 0xFF00FF00) >> 8) | ((v & 0x00FF00FF) << 8);

        // swap 2-byte long pairs
        v = (v >> 16) | (v << 16);
    }

    function reverse16(uint16 input) internal pure returns (uint16 v) {
        v = input;

        // swap bytes
        v = (v >> 8) | (v << 8);
    }
}

// ----------------------------------------------------------------------------
// Safe maths
// ----------------------------------------------------------------------------
library SafeMath {
    function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
        c = a + b;
        require(c >= a);
    }

    function sub(uint256 a, uint256 b) internal pure returns (uint256 c) {
        require(b <= a);
        c = a - b;
    }

    function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
        c = a * b;
        require(a == 0 || c / a == b);
    }

    function div(uint256 a, uint256 b) internal pure returns (uint256 c) {
        require(b > 0);
        c = a / b;
    }
}

// ----------------------------------------------------------------------------
// ERC Token Standard #20 Interface
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
// ----------------------------------------------------------------------------
abstract contract ERC20Interface {
    function totalSupply() public view virtual returns (uint256);

    function balanceOf(address tokenOwner)
        public
        view
        virtual
        returns (uint256 balance);

    function allowance(address tokenOwner, address spender)
        public
        view
        virtual
        returns (uint256 remaining);

    function transfer(address to, uint256 tokens)
        public
        virtual
        returns (bool success);

    function approve(address spender, uint256 tokens)
        public
        virtual
        returns (bool success);

    function transferFrom(
        address from,
        address to,
        uint256 tokens
    ) public virtual returns (bool success);

    event Transfer(address indexed from, address indexed to, uint256 tokens);
    event Approval(
        address indexed tokenOwner,
        address indexed spender,
        uint256 tokens
    );
}

// ----------------------------------------------------------------------------
// Contract function to receive approval and execute function in one call
//
// Borrowed from MiniMeToken
// ----------------------------------------------------------------------------
abstract contract ApproveAndCallFallBack {
    function receiveApproval(
        address from,
        uint256 tokens,
        address token,
        bytes memory data
    ) public virtual;
}

// ----------------------------------------------------------------------------
// ERC20 Token, with the addition of symbol, name and decimals and an
// initial fixed supply, added teleport method
// ----------------------------------------------------------------------------
contract TeleportToken is ERC20Interface, Owned, Verify {
    TeleportTokenFactory factory;

    using SafeMath for uint256;

    string public symbol;
    string public name;
    uint8 public decimals;
    uint256 public _totalSupply;
    uint8 public threshold;
    uint8 public thisChainId;

    mapping(address => uint256) balances;
    mapping(address => mapping(address => uint256)) allowed;

    mapping(uint64 => mapping(address => bool)) signed;
    mapping(uint64 => bool) public claimed;

    event Teleport(
        address indexed from,
        string to,
        uint256 tokens,
        uint256 chainId
    );
    event Claimed(
        uint64 id,
        address toAddress,
        address tokenAddress,
        uint256 amount
    );

    struct TeleportData {
        uint64 id;
        uint32 ts;
        uint64 fromAddr;
        uint256 quantity;
        uint64 symbolRaw;
        uint8 chainId;
        address toAddress;
        address tokenAddress;
        uint8 nativeDecimals;
    }

    // ------------------------------------------------------------------------
    // Constructor
    // ------------------------------------------------------------------------
    constructor(
        string memory _symbol,
        string memory _name,
        uint8 _decimals,
        uint256 __totalSupply,
        uint8 _threshold,
        uint8 _thisChainId
    ) {
        symbol = _symbol;
        name = _name;
        decimals = _decimals;
        _totalSupply = __totalSupply * 10**uint256(_decimals);
        balances[address(0)] = _totalSupply;
        threshold = _threshold;
        thisChainId = _thisChainId;
        factory = TeleportTokenFactory(payable(address(msg.sender)));
    }

    // ------------------------------------------------------------------------
    // Total supply
    // ------------------------------------------------------------------------
    function totalSupply() public view override returns (uint256) {
        return _totalSupply - balances[address(0)];
    }

    // ------------------------------------------------------------------------
    // Get the token balance for account `tokenOwner`
    // ------------------------------------------------------------------------
    function balanceOf(address tokenOwner)
        public
        view
        override
        returns (uint256 balance)
    {
        return balances[tokenOwner];
    }

    // ------------------------------------------------------------------------
    // Transfer the balance from token owner's account to `to` account
    // - Owner's account must have sufficient balance to transfer
    // - 0 value transfers are allowed
    // ------------------------------------------------------------------------
    function transfer(address to, uint256 tokens)
        public
        override
        returns (bool success)
    {
        balances[msg.sender] = balances[msg.sender].sub(tokens);
        balances[to] = balances[to].add(tokens);
        emit Transfer(msg.sender, to, tokens);
        return true;
    }

    // ------------------------------------------------------------------------
    // Token owner can approve for `spender` to transferFrom(...) `tokens`
    // from the token owner's account
    //
    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
    // recommends that there are no checks for the approval double-spend attack
    // as this should be implemented in user interfaces
    // ------------------------------------------------------------------------
    function approve(address spender, uint256 tokens)
        public
        override
        returns (bool success)
    {
        allowed[msg.sender][spender] = tokens;
        emit Approval(msg.sender, spender, tokens);
        return true;
    }

    // ------------------------------------------------------------------------
    // Transfer `tokens` from the `from` account to the `to` account
    //
    // The calling account must already have sufficient tokens approve(...)-d
    // for spending from the `from` account and
    // - From account must have sufficient balance to transfer
    // - Spender must have sufficient allowance to transfer
    // - 0 value transfers are allowed
    // ------------------------------------------------------------------------
    function transferFrom(
        address from,
        address to,
        uint256 tokens
    ) public override returns (bool success) {
        balances[from] = balances[from].sub(tokens);
        allowed[from][msg.sender] = allowed[from][msg.sender].sub(tokens);
        balances[to] = balances[to].add(tokens);
        emit Transfer(from, to, tokens);
        return true;
    }

    // ------------------------------------------------------------------------
    // Returns the amount of tokens approved by the owner that can be
    // transferred to the spender's account
    // ------------------------------------------------------------------------
    function allowance(address tokenOwner, address spender)
        public
        view
        override
        returns (uint256 remaining)
    {
        return allowed[tokenOwner][spender];
    }

    // ------------------------------------------------------------------------
    // Token owner can approve for `spender` to transferFrom(...) `tokens`
    // from the token owner's account. The `spender` contract function
    // `receiveApproval(...)` is then executed
    // ------------------------------------------------------------------------
    function approveAndCall(
        address spender,
        uint256 tokens,
        bytes memory data
    ) public returns (bool success) {
        allowed[msg.sender][spender] = tokens;
        emit Approval(msg.sender, spender, tokens);
        ApproveAndCallFallBack(spender).receiveApproval(
            msg.sender,
            tokens,
            address(this),
            data
        );
        return true;
    }

    // ------------------------------------------------------------------------
    // Moves tokens to the inaccessible account and then sends event for the oracles
    // to monitor and issue on other chain
    // to : EOS address
    // tokens : number of tokens in satoshis
    // chainId : The chain id that they will be sent to
    // ------------------------------------------------------------------------

    function teleport(
        string memory to,
        uint256 tokens,
        uint256 chainid
    ) public returns (bool success) {
        balances[msg.sender] = balances[msg.sender].sub(tokens);
        balances[address(0)] = balances[address(0)].add(tokens);

        emit Transfer(msg.sender, address(0), tokens);
        emit Teleport(msg.sender, to, tokens, chainid);

        return true;
    }

    // ------------------------------------------------------------------------
    // Claim tokens sent using signatures supplied to the other chain
    // ------------------------------------------------------------------------

    function stringToBytes32(string memory source)
        public
        pure
        returns (bytes32 result)
    {
        bytes memory tempEmptyStringTest = bytes(source);
        if (tempEmptyStringTest.length == 0) {
            return 0x0;
        }

        assembly {
            result := mload(add(source, 32))
        }
    }

    function verifySigData(bytes memory sigData)
        private
        returns (TeleportData memory)
    {
        TeleportData memory td;

        uint64 id;
        uint32 ts;
        uint64 fromAddr;
        uint64 quantity;
        uint64 symbolRaw;
        uint8 chainId;
        address toAddress;
        address tokenAddress;
        uint8 nativeDecimals;
        // uint64 requiredSymbolRaw;

        assembly {
            id := mload(add(add(sigData, 0x8), 0))
            ts := mload(add(add(sigData, 0x4), 8))
            fromAddr := mload(add(add(sigData, 0x8), 12))
            quantity := mload(add(add(sigData, 0x8), 20))
            symbolRaw := mload(add(add(sigData, 0x8), 29))
            chainId := mload(add(add(sigData, 0x1), 36))
            toAddress := mload(add(add(sigData, 0x14), 37))
            tokenAddress := mload(add(add(sigData, 0x14), 70))
            nativeDecimals := mload(add(add(sigData, 0x1), 90))
        }
        td.id = Endian.reverse64(id);
        td.ts = Endian.reverse32(ts);
        td.fromAddr = Endian.reverse64(fromAddr);
        td.symbolRaw = Endian.reverse64(symbolRaw);
        td.chainId = chainId;
        td.toAddress = toAddress;
        td.tokenAddress = tokenAddress;
        td.nativeDecimals = nativeDecimals;
        td.quantity =
            Endian.reverse64(quantity) *
            10**(decimals - nativeDecimals);

        // requiredSymbolRaw = uint64(
        //     bytes8(stringToBytes32(TeleportToken.symbol))
        // );
        // require(requiredSymbolRaw == symbolRaw - td.chainId, "Wrong symbol");
        require(address(this) == td.tokenAddress, "Invalid token address");
        require(thisChainId == td.chainId, "Invalid Chain ID");
        require(
            block.timestamp < SafeMath.add(td.ts, (60 * 60 * 24 * 30)),
            "Teleport has expired"
        );
        require(!claimed[td.id], "Already Claimed");

        claimed[td.id] = true;

        return td;
    }

    function claim(bytes memory sigData, bytes[] calldata signatures)
        public
        returns (address toAddress)
    {
        TeleportData memory td = verifySigData(sigData);

        // verify signatures
        require(sigData.length == 91, "Signature data is the wrong size");
        require(
            signatures.length <= 10,
            "Maximum of 10 signatures can be provided"
        );

        bytes32 message = keccak256(sigData);

        uint8 numberSigs = 0;

        for (uint8 i = 0; i < signatures.length; i++) {
            address potential = Verify.recoverSigner(message, signatures[i]);

            // console.log(potential);
            // console.log(oracles[potential]);
            // Check that they are an oracle and they haven't signed twice
            if (factory.isOracle(potential) && !signed[td.id][potential]) {
                signed[td.id][potential] = true;
                numberSigs++;

                if (numberSigs >= threshold) {
                    break;
                }
            }
        }

        require(
            numberSigs >= threshold,
            "Not enough valid signatures provided"
        );

        balances[address(0)] = balances[address(0)].sub(td.quantity);
        balances[td.toAddress] = balances[td.toAddress].add(td.quantity);

        emit Claimed(td.id, td.toAddress, td.tokenAddress, td.quantity);
        emit Transfer(address(0), td.toAddress, td.quantity);

        return td.toAddress;
    }

    function updateThreshold(uint8 newThreshold)
        public
        onlyOwner
        returns (bool success)
    {
        if (newThreshold > 0) {
            require(newThreshold <= 10, "Threshold has maximum of 10");

            threshold = newThreshold;

            return true;
        }

        return false;
    }

    function updateChainId(uint8 newChainId)
        public
        onlyOwner
        returns (bool success)
    {
        if (newChainId > 0) {
            require(newChainId <= 100, "ChainID is too big");
            thisChainId = newChainId;

            return true;
        }

        return false;
    }

    // ------------------------------------------------------------------------
    // Don't accept ETH
    // ------------------------------------------------------------------------
    receive() external payable {
        revert();
    }

    // ------------------------------------------------------------------------
    // Owner can transfer out any accidentally sent ERC20 tokens
    // ------------------------------------------------------------------------
    function transferAnyERC20Token(address tokenAddress, uint256 tokens)
        public
        onlyOwner
        returns (bool success)
    {
        return ERC20Interface(tokenAddress).transfer(owner, tokens);
    }
}
```

## TeleportTokenFactory.sol

```
pragma solidity ^0.8.6;
/*
 * SPDX-License-Identifier: MIT
 */
pragma experimental ABIEncoderV2;

// import "hardhat/console.sol";
import "./Owner.sol";
import "./TeleportToken.sol";

contract Oracled is Owned {
    mapping(address => bool) public oracles;
    address[] internal oraclesArr;

    modifier onlyOracle() {
        require(
            oracles[msg.sender] == true,
            "Account is not a registered oracle"
        );

        _;
    }

    function regOracle(address _newOracle) public onlyOwner {
        require(!oracles[_newOracle], "Oracle is already registered");
        oraclesArr.push(_newOracle);
        oracles[_newOracle] = true;
    }

    function unregOracle(address _remOracle) public onlyOwner {
        require(oracles[_remOracle] == true, "Oracle is not registered");

        delete oracles[_remOracle];
    }
}

contract TeleportTokenFactory is Owned, Oracled {
    TeleportToken[] public teleporttokens;
    uint256 public creationFee = 0.01 ether;

    // Payable constructor can receive Ether
    constructor() payable {}

    function isOracle(address _address) public view returns (bool) {
        return oracles[_address];
    }

    // Function to deposit Ether into this contract.
    // Call this function along with some Ether.
    // The balance of this contract will be automatically updated.
    function deposit() public payable {}

    // Call this function along with some Ether.
    // The function will throw an error since this function is not payable.
    function notPayable() public {}

    // Function to withdraw all Ether from this contract.
    function withdraw() public onlyOwner {
        // get the amount of Ether stored in this contract
        uint256 amount = address(this).balance;

        // send all Ether to owner
        // Owner can receive Ether since the address of owner is payable
        (bool success, ) = owner.call{value: amount}("");
        require(success, "Failed to send Ether");
    }

    // Function to receive Ether. msg.data must be empty
    receive() external payable {}

    // Fallback function is called when msg.data is not empty
    fallback() external payable {}

    function getBalance() public view returns (uint256) {
        return address(this).balance;
    }

    function create(
        string memory _symbol,
        string memory _name,
        uint8 _decimals,
        uint256 __totalSupply,
        uint8 _threshold,
        uint8 _thisChainId
    ) public payable {
        // correct fee
        require(msg.value == creationFee, "Wrong fee");
        TeleportToken tt = new TeleportToken(
            _symbol,
            _name,
            _decimals,
            __totalSupply,
            _threshold,
            _thisChainId
        );

        tt.transferOwnership(msg.sender);

        teleporttokens.push(tt);
    }

    function getTokenAddress(uint256 _index)
        public
        view
        returns (address ttAddress)
    {
        TeleportToken tt = teleporttokens[_index];

        return (address(tt));
    }

    function setFee(uint256 _fee) public onlyOwner {
        creationFee = _fee;
    }
}

```

## Owner.sol

```
pragma solidity ^0.8.6;

/*
 * SPDX-License-Identifier: MIT
 */

// ----------------------------------------------------------------------------
// Owned contract
// ----------------------------------------------------------------------------
contract Owned {
    address public owner;
    address public newOwner;

    event OwnershipTransferred(address indexed _from, address indexed _to);

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }

    function transferOwnership(address _newOwner) public onlyOwner {
        newOwner = _newOwner;
    }

    function acceptOwnership() public {
        require(msg.sender == newOwner);
        emit OwnershipTransferred(owner, newOwner);
        owner = newOwner;
        newOwner = address(0);
    }
}

```


# EOSIO Bridge


# How to Bridge

Guide to bridging tokens using EOSIO Bridge

Once wallets have been created, the user must select a network to bridge from. Once selected the user will be required to login using any of the available methods.

![](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2FIvtpEABcb8cG4barMwRu%2Fimage.png?alt=media\&token=478418a5-5cf9-4161-a72e-1bb754141560)

Note: If the user changes their from chain, they will need to login with an account on that network each time the from chain is changed.

![Network selection dropdown](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2FbvHFHOcOJ7cs3JUSM3B3%2Fimage.png?alt=media\&token=8601bbe0-47fd-4b5d-9c90-7a27d18f6d98)

![Available networks](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2F8nJPvLbllXxBbCLpZxkR%2Fimage.png?alt=media\&token=14a5b711-9fc0-44c3-8f4d-32771626ec4b)

After selecting a network, the user needs to select the token to bridge.

![Token selection dropdown](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2FmhmGrKL15aKTjx8x2NxP%2Fimage.png?alt=media\&token=77d40ad1-a86f-431c-8ce1-cb3d6f1c2cfa)

![A list of tokens and their balances](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2Fz1MeQh2xlKDJirvI8Wsj%2Fimage.png?alt=media\&token=192c2411-d4f8-40b0-91dd-4bd4f7916a81)

When the dropdown is clicked a list of available tokens to bridge as well as their balances are displayed for selection. Select a token and the quantity to be bridged.

![Token quantity field](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2FdD1icLcf1sFtOAJg9XZg%2Fimage.png?alt=media\&token=0fbb2a1a-e39a-415b-8325-56bfecaa174a)

Once a token, network and quantity have been selected, the to account field needs to be filled in with the 12-digit account name.

![To account field](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2FpJzfN77wP1JQhEt8Qskn%2Fimage.png?alt=media\&token=d5975e17-a756-4684-a77d-df42f32927da)

The next step is to select the chain where the to account resides.

![To network dropdown](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2FA8Asz3SHFPHLgLpeTKvn%2Fimage.png?alt=media\&token=ad85bd4f-8f2f-44a9-af5c-ddf3b2a31c2f)

The memo field can be filled in to add a memo to the bridging transaction. (Filling in this field is optional)

![Memo field](https://2545193999-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3T6MC6vcLf0IG8x4PYAz%2Fuploads%2FOU1IpGDBLkCHwC1ksbPN%2Fimage.png?alt=media\&token=16b87665-2f20-466d-b23e-9ec29794c2f8)

Once all required fields are filled in and all options selected, the user may click the send button to begin the transaction. The user's selected method of signing transactions should appear. The user need only sign the transaction to complete the bridging process.


# Exchange


# Token swapping


# Liquidity Pools


# Bridge


