# Hello world

Welcome to the most exciting and state-of-the-art platform to build your blockchain application on ThunderCore Blockchain. If you are an Ethereum developer, developing on ThunderCore should be seamless and smooth as ThunderCore is fully Ethereum Virtual Machine (EVM) compatible and inherits most of the tools and libraries from Ethereum.

This page acts as a quick guide into the ThunderCore developer platform. You will find links to some useful resources and websites to get you to start building applications on ThunderCore. Feel free to reach out to us on [Telegram](https://t.me/thunder_official) when you need any help!

### Developer quick start

Our blockchain natively supports EVM compatible smart contracts. The tools required to develop on ThunderCore includes:

* Setup Metamask Wallet or other web wallet
* Deploy your contracts on ThunderCore
  * [Using Foundry](/deploying-on-thundercore/using-foundry)
  * [Using Hardhat](/deploying-on-thundercore/using-hardhat-include-create-a-project-steps)
  * [Using Remix](/deploying-on-thundercore/using-remix)
  * [Using Truffle](/deploying-on-thundercore/using-truffle)
* Testnet faucet: [https://faucet-testnet.thundercore.com/](https://faucet-testnet.thundercore.com)
* Blockchain Explorers
  * Mainnet: [https://explorer-mainnet.thundercore.com/](https://explorer-testnet.thundercore.com)
  * Testnet: [https://explorer-testnet.thundercore.com/](https://explorer-testnet.thundercore.com)
* The ThunderCore's external protocol is compatible with Ethereum. Your existing code supporting Ethereum has a good chance to work as-is

| Item             | References                                                                           |
| ---------------- | ------------------------------------------------------------------------------------ |
| Official Website | <https://www.thundercore.com>                                                        |
| Block Explorer   | [https://explorer-mainnet.thundercore.com](https://explorer-testnet.thundercore.com) |
| JSON-RPC         | <https://mainnet-rpc.thundercore.com>                                                |
|                  | <https://mainnet-rpc.thundertoken.net>                                               |
|                  | <https://mainnet-rpc.thundercore.io>                                                 |
|                  | `wss://mainnet-ws.thundercore.com`                                                   |
| Chain ID         | thunder-mainnet: 108 (0x6c)                                                          |

#### How do I get a ThunderCore address? <a href="#how-do-i-get-a-thundercore-address" id="how-do-i-get-a-thundercore-address"></a>

ThunderCore is Ethereum (EVM) compatible. Any address created for Ethereum will work on ThunderCore. You can use MetaMask and/or any other popular Ethereum wallet to create ThunderCore address. To access the ThunderCore blockchain all you will need to do is to point network RPC to one of the following:

| RPC                                    |
| -------------------------------------- |
| <https://mainnet-rpc.thundercore.com>  |
| <https://mainnet-rpc.thundertoken.net> |
| <https://mainnet-rpc.thundercore.io>   |

For detailed instructions, please check out our tutorial on getting your own [wallet](https://help.thundercore.com/hc/en-us/articles/900006700223-ThunderCore-Hub).

**Already have a DApp?**

* Migrate from Ethereum chain or other EVM based chain

  As long as it’s EVM compatible, you are all set!

  * [Deploying your DApp on Thundercore](/deploying-on-thundercore)
  * [DApp example](/deploying-on-thundercore/deploy-a-dapp)

#### Learn the basics of development

* [What is Ethereum?](https://blockgeeks.com/guides/ethereum/)
* [Full stack DApp tutorial series](https://kauri.io/#collections/Full%20Stack%20dApp%20Tutorial%20Series/full-stack-dapp-tutorial-series-intro/)
* [cryptozombies tutorial](https://cryptozombies.io)
* [Truffle tutorial](https://www.trufflesuite.com/docs/truffle/quickstart)
* [Dapp University](https://www.dappuniversity.com)

#### &#x20;Popular development tools

* [Hardhat](https://hardhat.org/tutorial/)
* [Remix](https://remix.ethereum.org/#optimize=false\&runs=200\&evmVersion=null\&version=soljson-v0.8.7+commit.e28d00a7.js)
* [Truffle suite docs](https://www.trufflesuite.com/docs)
* [Truffle tutorial](https://www.trufflesuite.com/tutorial)

### :tada:Keeping up with ThunderCore:tada:

**Join our community and stay up to date with our latest news and announcements!**:smile:

Telegram: <https://t.me/thunder_official>

Twitter: <https://twitter.com/ThunderCoreLab>

ThunderCore Blog:  <https://news.thundercore.com/>

View all communities: <https://help.thundercore.com/hc/en-us/articles/4409279468313-Join-our-community->

####

***


# Network Details


# ThunderCore Mainnet

The following contains details for the RPC - HTTP, and WS. There is also a full node setup if you wish to setup your own full node.

| Network name   | ThunderCore Mainnet                                                                                                                                                                                                      |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Gas token      | TT token                                                                                                                                                                                                                 |
| ChainID        | 108                                                                                                                                                                                                                      |
| RPC            | <p>ThunderCore blockchain:<br><https://mainnet-rpc.thundercore.com><br><br>Use these alternative RPCs only if the above RPC fails:<br><https://mainnet-rpc.thundertoken.net><br><https://mainnet-rpc.thundercore.io></p> |
| Websocket      | <p><code>wss\://mainnet-ws.thundercore.com</code><br><code>wss\://mainnet-ws.thundertoken.net</code><br><code>wss\://mainnet-ws.thundercore.io</code></p>                                                                |
| Block Explorer | <https://explorer-mainnet.thundercore.com/>                                                                                                                                                                              |
| Faucet         | [https://faucet.thundercore.com](https://faucet.thundercore.com/)                                                                                                                                                        |

## Key info

<table><thead><tr><th width="472"></th><th></th></tr></thead><tbody><tr><td>Block time (sec)</td><td>1 sec</td></tr><tr><td>Number of blocks to transaction finality</td><td>1 block</td></tr><tr><td>Gas token symbol</td><td>TT</td></tr><tr><td>A canonical bridge for gas/stables</td><td><a href="https://bridge.thundercore.com/">ThunderCore Bridge</a></td></tr><tr><td>Chain permissions</td><td>Permissionless</td></tr><tr><td>Sources of purchasing gas tokens</td><td><a href="https://coinmarketcap.com/currencies/thundercore/markets/">CoinMarketCap</a></td></tr><tr><td>Pricing source of token</td><td><a href="https://coinmarketcap.com/currencies/thundercore/markets/">CoinMarketCap</a><br><a href="https://www.coingecko.com/en/coins/thundercore">CoinGecko</a></td></tr><tr><td>Block gas limit</td><td>100M</td></tr><tr><td>Transaction gas limit</td><td>100M, but code size or tx size will exceed the limit first</td></tr><tr><td>Transaction calldata size limit</td><td>40960</td></tr></tbody></table>

## How to get Mainnet tokens

1. Create a new Wallet on the ThunderCore Chain mainnet with MetaMask, Trust Wallet, MathWallet or any EVM compatible wallet.
2. Check out how you can get Mainnet tokens [here](https://help.thundercore.com/hc/en-us/articles/900006700383-Get-Tokens) and deposit them to your ThunderCore compatible wallet.

### Getting start

You can start the HTTP JSON-RPC with the --rpc flag

```
geth attach https://mainnet-rpc.thundercore.com
```

### JSON-RPC methods

Please refer to this [wiki page](https://documenter.getpostman.com/view/4117254/ethereum-json-rpc/RVu7CT5J?version=latest) or use [Postman](https://www.postman.com)

### Rate limit

The rate limit of ThunderCore endpoint Mainnet is *`10K/hr`*.

### Block range limit

You can make `eth_getLogs` requests with up to unlimit block range for now, But we're going change this limit to *`172800`* block range. If you need to pull logs frequently, we recommend using WebSockets to push new logs to you when they are available.

> Important: Thundercore network native token is TT, which will be used as gas fee


# ThunderCore Testnet

The ThunderCore testnet is an alternative to ThunderCore mainnet, which is used for testing and experimenting with smart contracts for developers. Testnet tokens are separated from the mainnet, and they should never have any value.

## What is the testnet good for?

* Create your test address and get your testnet funds.
* Develop applications and try tutorials on ThunderCore Chain without the potential to lose your own assets.
* Test your applications against new versions of ThunderCore Chain.
* Analyze blockchain data on a smaller, non-trivial data set compared to the public network.

The following contains details for the RPC - HTTP, and WS. There is also a full node setup if you wish to setup your own full node.

| Network name | ThunderCore Testnet                                                               |
| ------------ | --------------------------------------------------------------------------------- |
| Gas token    | TST token                                                                         |
| ChainID      | 18                                                                                |
| RPC          | <p>ThunderCore Testnet:</p><p><https://testnet-rpc.thundercore.com></p>           |
| Websocket    | `wss://testnet-ws.thundercore.com`                                                |
| Faucet       | [https://faucet-testnet.thundercore.com](https://faucet-testnet.thundercore.com/) |

## How to get Testnet Fund

Steps to claim testnet TST:

1. Create a new Wallet of ThunderCore Chain testnet with MetaMask or MathWallet
2. Get Testnet Fund: <https://faucet-testnet.thundercore.com>

## Getting start

You can start the HTTP JSON-RPC with the --rpc flag

```
geth attach https://testnet-rpc.thundercore.com
```

### JSON-RPC methods

Please refer to this [wiki page](https://documenter.getpostman.com/view/4117254/ethereum-json-rpc/RVu7CT5J?version=latest) or use [Postman](https://www.postman.com)

## Rate limit

The rate limit of ThunderCore endpoint Mainnet is *`10K/hr`*.

## Block range limit

You can make `eth_getLogs` requests with up to a *`172800`* block range. If you need to pull logs frequently, we recommend using WebSockets to push new logs to you when they are available.


# Token List

### **Mainnet**

-> Please see [here](https://github.com/thundercore/token-list/tree/master/assets/thundercore) to get the token icon assets

<table><thead><tr><th width="304">Token name</th><th width="228.66666666666666">ThunderCore Mainnet Address</th><th>Foreign Chain Address</th></tr></thead><tbody><tr><td>TT</td><td></td><td>Ethereum <a href="https://etherscan.io/address/0x1E053D89E08c24aA2CE5C5B4206744Dc2D7BD8F5">0x1E053D89E08c24aA2CE5C5B4206744Dc2D7BD8F5</a></td></tr><tr><td>TT-USDT (<a href="https://bridge.thundercore.com/eth/">ThunderCore Bridge</a>)</td><td><a href="https://explorer-mainnet.thundercore.com/address/0x4f3C8E20942461e2c3Bdd8311AC57B0c222f2b82/transactions">0x4f3c8e20942461e2c3bdd8311ac57b0c222f2b82</a></td><td>Ethereum <a href="https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7">0xdac17f958d2ee523a2206206994597c13d831ec7</a></td></tr><tr><td>TT-WBTC (<a href="https://bridge.thundercore.com/eth/">ThunderCore Bridge</a>)</td><td><a href="https://explorer-mainnet.thundercore.com/address/0x18fB0A62f207A2a082cA60aA78F47a1af4985190/transactions">0x18fB0A62f207A2a082cA60aA78F47a1af4985190</a></td><td>Ethereum <a href="https://etherscan.io/address/0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599">0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599</a></td></tr><tr><td>TT-USDC (<a href="https://bridge.thundercore.com/eth/">ThunderCore Bridge</a>)</td><td><a href="https://explorer-mainnet.thundercore.com/address/0x22e89898A04eaf43379BeB70bf4E38b1faf8A31e/transactions">0x22e89898A04eaf43379BeB70bf4E38b1faf8A31e</a></td><td>Ethereum <a href="https://etherscan.io/address/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48">0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48</a></td></tr><tr><td>TT-ETH (<a href="https://bridge.thundercore.com/eth/">ThunderCore Bridge</a>)</td><td><a href="https://explorer-mainnet.thundercore.com/address/0x6576Bb918709906DcbFDCeae4bB1e6df7C8a1077/transactions">0x6576Bb918709906DcbFDCeae4bB1e6df7C8a1077</a></td><td>Ethereum</td></tr><tr><td>TT (<a href="https://bridge.thundercore.com/bsc/">ThunderCore Bridge</a>)</td><td></td><td>BNB Chain <a href="https://bscscan.com/address/0x990E7154bB999FAa9b2fa5Ed29E822703311eA85">0x990E7154bB999FAa9b2fa5Ed29E822703311eA85</a></td></tr><tr><td>TT-BUSD (<a href="https://bridge.thundercore.com/bsc/">ThunderCore Bridge</a>)</td><td><a href="https://explorer-mainnet.thundercore.com/address/0xBEB0131D95AC3F03fd15894D0aDE5DBf7451d171/transactions">0xBEB0131D95AC3F03fd15894D0aDE5DBf7451d171</a></td><td>BNB Chain <a href="https://bscscan.com/address/0xe9e7cea3dedca5984780bafc599bd69add087d56">0xe9e7cea3dedca5984780bafc599bd69add087d56</a></td></tr><tr><td>TT-BNB (<a href="https://bridge.thundercore.com/bsc/">ThunderCore Bridge</a>)</td><td><a href="https://explorer-mainnet.thundercore.com/address/0x8EF1A1E0671Aa44852f4d87105eF482470bB3e69/transactions">0x8EF1A1E0671Aa44852f4d87105eF482470bB3e69</a></td><td>BNB Chain</td></tr><tr><td>BNB</td><td><a href="https://explorer-mainnet.thundercore.com/address/0xf390830DF829cf22c53c8840554B98eafC5dCBc2/transactions">0xf390830df829cf22c53c8840554b98eafc5dcbc2</a></td><td></td></tr><tr><td>ZIPPY</td><td><a href="https://explorer-mainnet.thundercore.com/address/0xD46d770b3032D92D9E1d4e5B925bB8840cDB4314/transactions">0xD46d770b3032D92D9E1d4e5B925bB8840cDB4314</a></td><td></td></tr><tr><td>RISER</td><td><a href="https://explorer-mainnet.thundercore.com/address/0xC1E7000f379f2247Ae930ba98d5568cd9D0b924b/transactions">0xc1e7000f379f2247ae930ba98d5568cd9d0b924b</a></td><td></td></tr><tr><td>RAM</td><td><a href="https://explorer-mainnet.thundercore.com/address/0xfE146D5710015d4075355fb7bE8d133346EC63c2/transactions">0xfE146D5710015d4075355fb7bE8d133346EC63c2</a></td><td></td></tr><tr><td>PUNCH</td><td><a href="https://explorer-mainnet.thundercore.com/address/0x8C2eeccd83752DB11594e699BBC8f756c4d03Cb9/transactions">0x8c2eeccd83752db11594e699bbc8f756c4d03cb9</a></td><td></td></tr><tr><td>OOL</td><td><a href="https://explorer-mainnet.thundercore.com/address/0x47fe33d321EEF4719FdFf38EA72B1dFC7f0cdf10/transactions">0x47fe33d321EEF4719FdFf38EA72B1dFC7f0cdf10</a></td><td></td></tr><tr><td>NICER</td><td><a href="https://explorer-mainnet.thundercore.com/address/0x1F489E0282cFA883A4224C91309bC4D4c062ed93/transactions">0x1F489E0282cFA883A4224C91309bC4D4c062ed93</a></td><td></td></tr><tr><td>HODLZ</td><td><a href="https://explorer-mainnet.thundercore.com/address/0x152FeA8177a31F4FE1cDe7AdaB12C744F1860166/transactions">0x152FeA8177a31F4FE1cDe7AdaB12C744F1860166</a></td><td></td></tr><tr><td>GuessToken</td><td><a href="https://explorer-mainnet.thundercore.com/address/0xe15c1cbF2de3fd15864F48A66b9da07736dAF578/transactions">0xe15c1cbF2de3fd15864F48A66b9da07736dAF578</a></td><td></td></tr><tr><td>FTT</td><td><a href="https://explorer-mainnet.thundercore.com/address/0xD441cD6eCfA027721B4d9ea5D9a6A9649ad8b3dA/transactions">0xD441cD6eCfA027721B4d9ea5D9a6A9649ad8b3dA</a></td><td></td></tr><tr><td>DICEZ</td><td><a href="https://explorer-mainnet.thundercore.com/address/0xFCDEa9f405bc6bd85C2e90c1DEbB9F3ca7a59D8f/transactions">0xFCDEa9f405bc6bd85C2e90c1DEbB9F3ca7a59D8f</a></td><td></td></tr><tr><td>ACORN</td><td><a href="https://explorer-mainnet.thundercore.com/address/0x6E690DaC861fE7441770f84146F263d1CFBE909C/transactions">0x6E690DaC861fE7441770f84146F263d1CFBE909C</a></td><td></td></tr></tbody></table>

### **Testnet**

***

| Token name          | ThunderCore Testnet Address                                                                                                           | Foreign Chain Address |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| Thunder Testnet USD | [0xf97B79eCE2F95e7B63a05F1FD73a59A1eF3E4fd7](https://scan-testnet.thundercore.com/address/0xf97B79eCE2F95e7B63a05F1FD73a59A1eF3E4fd7) |                       |


# Smart Contract Services

### **Mainnet**

| Contracts               | Contract Address                                                                                                                                       | Detail                                        |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------- |
| Random Number Generator | [0x8cC9C2e145d3AA946502964B1B69CE3cD066A9C7](https://explorer-mainnet.thundercore.com/address/0x8cC9C2e145d3AA946502964B1B69CE3cD066A9C7/transactions) | [Detail](/tool/tools/random-number-generator) |
| Price Oracles           | [0x7121aA94301048b0fF33173834bfA6d2f5D86fd7](https://viewblock.io/thundercore/address/0x7121aA94301048b0fF33173834bfA6d2f5D86fd7)                      | [Detail](/tool/tools/oracles)                 |


# Full Node Deployment

How to Run a Fullnode on ThunderCore Chain?

Building up your own Full Node. For more information please refer to [ThunderCore Github repository](https://github.com/thundercore/public-full).

***


# Develop on ThunderCore


# Migrate from Ethereum

ThunderCore is a scaling solution for public blockchain. ThunderCore supports all existing Ethereum tooling along with faster and much much much cheaper transactions.

If you are looking to integrate with ThunderCore, you are in the right place.

### Overview

Our blockchain natively supports EVM-compatible smart contracts. This following describes the steps required to port your existing Ethereum DApp to ThunderCore. If you haven't created a DApp before, checkout [Using Hardhat](/deploying-on-thundercore/using-hardhat-include-create-a-project-steps) tutorial.

#### Connecting to our network <a href="#connecting-to-our-network" id="connecting-to-our-network"></a>

To connect to our network, see the RPC endpoints below. You can perform any RPC operation available in Ethereum on these URLs.

| Network | RPC endpoint                                                              | Network ID |
| ------- | ------------------------------------------------------------------------- | ---------- |
| Mainnet | <https://mainnet-rpc.thundercore.com>                                     | 108        |
|         | <https://mainnet-rpc.thundertoken.net>                                    | 108        |
|         | [https://mainnet-rpc.thundercore.io/](https://mainnet-rpc.thundercore.io) | 108        |
| Testnet | <https://testnet-rpc.thundercore.com>                                     | 18         |

If you're using MetaMask, specify one of these URLs as a new, custom RPC.

If you're using Solidity, set the target `evmVersion` to `london.`

#### Yup, that's it <a href="#yup-thats-it" id="yup-thats-it"></a>

No need to rewrite your smart contracts or change any of your infrastructure code, you should be good to go! If you are facing any problems, please reach out on our [Teleram](https://t.me/thunder_official).


# Using Foundry

Foundry is a smart contract development toolchain that manages your dependencies, compiles your project, runs tests, deploys, and lets you interact with the chain from the CLI and via Solidity scripts.<br>

See the finished code at <https://github.com/thundercore/foundry-thundercore>

## One Time Setup <a href="#docs-internal-guid-576e8550-7fff-e213-0ee6-30645f6f0179" id="docs-internal-guid-576e8550-7fff-e213-0ee6-30645f6f0179"></a>

### Installing Foundry

See the [Installation](https://book.getfoundry.sh/getting-started/installation) chapter in the Foundry Book.

### Creating A Wallet <a href="#docs-internal-guid-347e2ee9-7fff-0b78-3071-e5ceb36ee85b" id="docs-internal-guid-347e2ee9-7fff-0b78-3071-e5ceb36ee85b"></a>

You can use "cast wallet new" to create a ThunderCore compatible wallet.

Here we name our newly created wallet deployer by moving the encrypted keystore file generated by "cast":

```
$ k=$(cast wallet new --json ~/.foundry/keystores | jq -r .[0].path)
Enter secret:
$ mv $k ~/.foundry/keystores/deployer
```

### Encrypted Keystores <a href="#docs-internal-guid-ecb06d1d-7fff-7593-6127-23484391c041" id="docs-internal-guid-ecb06d1d-7fff-7593-6127-23484391c041"></a>

Foundry generates standard encrypted Ethereum keystore files under $HOME/.foundry/keystores

* The format is [widely supported](https://ethereum.stackexchange.com/questions/12830/how-to-get-private-key-from-account-address-and-password)
* See [Web3 Secret Storage Definition](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition)

Private keys in the keystores can be exported with:

```
 ethkey inspect ~/.foundry/keystores/deployer
```

by using the \`ethkey\` utility from [go-ethereum](https://geth.ethereum.org/docs/getting-started/installing-geth).

### Obtaining Funds <a href="#docs-internal-guid-73c15ba0-7fff-ebf2-8be8-4979d115ce09" id="docs-internal-guid-73c15ba0-7fff-ebf2-8be8-4979d115ce09"></a>

* You'll need some gas tokens to deploy contracts.
* To test on ThunderCore testnet, you can get some testnet tokens from ThunderCore Testnet Faucet <https://faucet-testnet.thundercore.com>
* For ThunderCore mainnet, see <https://www.thundercore.com/buy-tt>

## Create A New Project <a href="#docs-internal-guid-1ad3df02-7fff-1fad-56da-bdead40937a4" id="docs-internal-guid-1ad3df02-7fff-1fad-56da-bdead40937a4"></a>

To start a new project with Foundry, use forge init:

```
$ forge init <project_name>
```

The src folder may already contain Counter.sol, a minimal Solidity contract.

## Setup Foundry For ThunderCore <a href="#docs-internal-guid-6c6bb751-7fff-7f53-89cc-445e88e1ee23" id="docs-internal-guid-6c6bb751-7fff-7f53-89cc-445e88e1ee23"></a>

```
$ cd <project_name>
$ EDIT foundry.toml
```

Edit foundry.toml to contain:

```
[profile.default]
evm_version = "london"

[rpc_endpoints]
thunder-mainnet = "https://mainnet-rpc.thundercore.com"
thunder-testnet = "https://testnet-rpc.thundercore.com"

# See more config options
# https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
```

## Compiling <a href="#docs-internal-guid-b0f8161f-7fff-5e73-6fcc-8f2f90d1f84d" id="docs-internal-guid-b0f8161f-7fff-5e73-6fcc-8f2f90d1f84d"></a>

Run the command forge build to build the project.

```
$ forge build
```

And test the build with "forge test".

```
$ forge test
```

### Deploy to ThunderCore Network <a href="#docs-internal-guid-2bfba379-7fff-fb8d-e762-ffa710db7615" id="docs-internal-guid-2bfba379-7fff-fb8d-e762-ffa710db7615"></a>

Edit script/Counter.s.sol and add "new Counter()" at the end of run():

```
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

import {Script, console} from "forge-std/Script.sol";
import "../src/Counter.sol";

contract CounterScript is Script {
	function setUp() public {}

	function run() public {
    		vm.broadcast();
    		new Counter();
	}
}

```

Use "forge script" to deploy your contract to ThunderCore:

```
$ forge script --rpc-url thunder-testnet --broadcast --account deployer ./script/Counter.s.sol
[⠰] Compiling...
No files changed, compilation skipped
Enter keystore password:
Script ran successfully.

## Setting up 1 EVM.

==========================

Chain 18

Estimated gas price: 2360 gwei

Estimated total gas used for script: 138734

Estimated amount required: 0.32741224 ETH

==========================
##
Sending transactions [0 - 0].
⠁ [00:00:00] [#] 1/1 txes (0.0s)##
Waiting for receipts.
⠉ [00:00:12] [#] 1/1 receipts (0.0s)
##### 18
✅  [Success]Hash: 0xe459d759617b8f6054646cd0aa37e2c14db66a051747b0c32609b2e3c87c3d78
Contract Address: 0x8133D6f94ae2cB864540BF9a3c736dd6f6F2E426
Block: 1754750
Paid: 0.2454537 ETH (106719 gas * 2300 gwei)



==========================

ONCHAIN EXECUTION COMPLETE & SUCCESSFUL.
Total Paid: 0.2454537 ETH (106719 gas * avg 2300 gwei)

Transactions saved to: (...)/broadcast/Counter.s.sol/18/run-latest.json

```

### Check the deployed contract in Explorer <a href="#docs-internal-guid-bea309e3-7fff-f192-baa0-ed2eb47129f2" id="docs-internal-guid-bea309e3-7fff-f192-baa0-ed2eb47129f2"></a>

Copy the address of your newly deployed contract from the output. Then go to the ThunderCore Blockchain Explorer, and paste the address in the Search by address field.

Mainnet: <https://explorer-mainnet.thundercore.com>

Testnet: <https://explorer-testnet.thundercore.com>

## Interact With The Counter Contract <a href="#docs-internal-guid-b0ef8ca9-7fff-0f45-30c3-0c59c1316c0c" id="docs-internal-guid-b0ef8ca9-7fff-0f45-30c3-0c59c1316c0c"></a>

We can read the Counter value via cast call:

```
$ cast call --rpc-url thunder-testnet <YOUR_CONTRACT_ADDR> 'number()'
0x0000000000000000000000000000000000000000000000000000000000000000
```

We can increment the Counter value via "cast send":

```
$ cast send --rpc-url thunder-testnet --account deployer <YOUR_CONTRACT_ADDR> 'increment()'
Enter keystore password:

blockHash           	0x03cdd8cb4bafb1028d3893ac34abd68b2f92a0b13c193dcf4b202812a4d2225d
(...)

```

After a successful transaction that calls increment , reading the counter value again should now return 1 instead of 0.

## Conclusion <a href="#docs-internal-guid-55b41487-7fff-adde-6ada-e1f85108fc43" id="docs-internal-guid-55b41487-7fff-adde-6ada-e1f85108fc43"></a>

In this guide, we've accomplished:

1. Created a new wallet in the Foundry keystore named deployer ($HOME/.foundry/deployer)
2. Obtained funds for gas to the deployer account
3. Created a new Foundry project
4. Configured that project for ThunderCore via foundry.toml
5. Deployed our contract to the ThunderCore blockchain
6. Interacted with our contract to read and write information

And that's the basics of how to develop on ThunderCore via Foundry! Remember the finished code is available at <https://github.com/thundercore/foundry-thundercore>


# Using Hardhat

> Hardhat is a development environment to compile, deploy, test, and debug your Ethereum software.

A sample project is available at <https://github.com/thundercore/hardhat-thunder-project>

#### Setting up Hardhat

Please follow [Hardhat offcial guide to prepare your environment](https://hardhat.org/tutorial/setting-up-the-environment.html).

Once your environment is ready, we can create an empty folder and init a Hardhat project in it.

```shell
$ mkdir my-thundercore-project && cd $_

# We choose a basic sample project and install its dependences here:
$ npx hardhat init

✔ What do you want to do? · Create a basic sample project

✔ Do you want to install this sample project's dependencies with npm (hardhat @nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers ethers)? (Y/n) · y
```

After initialization, we can test the project with the `hardhat compile` command:

{% tabs %}
{% tab title="npm" %}

```shell
$ npm exec -- hardhat compile
Downloading compiler 0.8.25
Compiling 2 files with 0.8.25
Compilation finished successfully
```

{% endtab %}

{% tab title="Yarn" %}

```shell
$ yarn hardhat compile
Compiling 2 files with 0.8.25
Compilation finished successfully
Done in 1.22s.
```

{% endtab %}
{% endtabs %}

#### Hardhat Config

To start developing on ThunderCore, we'll make some changes to the Hardhat config file. A great option is to use the [tt-hardhat plugin](https://github.com/thundercore/tt-hardhat#features).

```
yarn add -D tt-hardhat
```

Then, in hardhat.config, simply paste `import "tt-hardhat";` at the top. We'll now be able to use networks `thunder-testnet` and `thunder-mainnet`.

Alternatively, we can configure the network manually. Open and edit `hardhat.config.js` in the root directory of your project.

{% tabs %}
{% tab title="Use "tt-hardhat" plugin " %}

```
// hardhat.config.ts

import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";

// Add this
import "tt-hardhat";

const config: HardhatUserConfig = {
   solidity: "0.8.25",
   networks: {
    hardhat: {
      allowUnlimitedContractSize: true,
      blockGasLimit: 141438723,
    },
  }
};

export default config;
```

{% endtab %}

{% tab title="Manual hardhat.config.js" %}

```
// hardhat.config.js

// yarn add -D dotenv # install `dotenv`
imort * as dotenv from "dotenv";

dotenv.config();

module.exports = {
  solidity: {
    version: "0.8.25",
    settings: {
      evmVersion: "london",
    },
  },
  networks: {
    'thunder-testnet': {
      url: 'https://testnet-rpc.thundercore.com',
      chainId: 18,
      accounts: process.env.KEY ? [process.env.KEY] : [],
    },
    'thunder-mainnet': {
      url: 'https://mainnet-rpc.thundercore.com',
      chainId: 108,
      accounts: process.env.KEY ? [process.env.KEY] : [],
    },
  },
}
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
Never store your private key directly in `hardhat.config.js`

``Here we pass the its value on the command line or store it in `.env`.``
{% endhint %}

#### Deploy to ThunderCore Network

Let's deploy the first contract.

{% hint style="info" %}
You'll need some gas tokens to deploy contracts. To test on ThunderCore testnet, you can get some testnet tokens from [ThunderCore testnet Faucet](https://faucet-testnet.thundercore.com)
{% endhint %}

{% tabs %}
{% tab title="Unix-like system" %}

```shell
# Using NPM
KEY=0xPrivateKey npm exec -- hardhat run scripts/sample-script.js --network thunder-testnet
# or using Yarn
KEY=0xPrivateKey yarn hardhat run scripts/sample-script.js --network thunder-testnet
```

{% endtab %}

{% tab title="Windows CMD" %}

```shell
# Using NPM
set KEY=0xPrivateKey & npm exec -- hardhat run scripts/sample-script.js --network thunder-testnet
# or using Yarn
set KEY=0xPrivateKey & yarn hardhat run scripts/sample-script.js --network thunder-testnet
```

{% endtab %}

{% tab title="Windows Powershell" %}

```shell
# Using NPM
$env:KEY='0xPrivateKey';npm exec -- hardhat run scripts/sample-script.js --network thunder-testnet
# or using Yarn
$env:KEY='0xPrivateKey';yarn hardhat run scripts/sample-script.js --network thunder-testnet
```

{% endtab %}
{% endtabs %}

By using the `tt-hardhat` plugin, you can import `logDeployContracts` from hardhat to log your deployed contracts. [More info](https://github.com/thundercore/tt-hardhat#features)

**Congratulations!** You have successfully deployed a smart contract onto the ThunderCore network, you will find the deployed messages look like:

```
Greeter deployed to: 0xGreeterContractAddress
```

#### Verify contract by plugin

Once you deployed your contract, you might want to verify your contract code.

On ThunderCore testnet, we provide [Blockscout](https://explorer-testnet.thundercore.com) as our block explorer. You can use `hardhat-etherscan` plugin to verify your contract.

```bash
yarn add -D @nomiclabs/hardhat-etherscan
```

after installed the package, modify your `hardhat.config.js`

{% code title="hardhat.config.js" %}

```git
module.exports = {
  etherscan: {
    apiKey: {
      "thunder-testnet": "unused",
    },
    customChains: [
      {
        network: "thunder-testnet",
        chainId: 18,
        urls: {
          apiURL: "https://explorer-testnet.thundercore.com/api",
          browserURL: "https://explorer-testnet.thundercore.com",
        },
      },
    ],
  },
}
```

{% endcode %}

Now, you can verify your contract by command:

```
yarn hardhat verify --network thunder-testnet ADDRESS "CONSTRUCTOR_ARGUMENT"
```

For more details, you can check [hardhat-etherscan](https://github.com/NomicFoundation/hardhat/tree/master/packages/hardhat-etherscan) document.

Remember that a sample Hardhat project is available at <https://github.com/thundercore/hardhat-thunder-project>!


# Using Remix

> Remix is a web-based IDE for writing, compiling, and deploying contracts.

### Before Using Remix

Before using Remix to develop on ThunderCore testnet, we need to add ThunderCore testnet and get some testnet gas fee:

1. The fastest way to add ThunderCore networks is adding them by visit [Chainlist](https://chainlist.org/).
2. Search for `ThunderCore`:

   <img src="https://3880137760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHVry7OTN1UZzjjhTeYXg%2Fuploads%2Fgit-blob-5c3bd51b53739f97bbfcdf25610f37a56a1e2365%2Fchainlist-thundercore.png?alt=media" alt="Search ThunderCore" data-size="original">
3. Click connect, adding ThunderCore testnet and mainnet:

   <img src="https://3880137760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHVry7OTN1UZzjjhTeYXg%2Fuploads%2Fgit-blob-1ff5f5cfa72f725fc64a9c86b2bc35ca179162e4%2Fapprove-adding-testnet.png?alt=media" alt="Approve to add ThunderCore Testnet" data-size="original">
4. You can add [ThunderCore testnet explorer](https://explorer-testnet.thundercore.com/) to network settings from `Metamask Settings > Networks`:

   <img src="https://3880137760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHVry7OTN1UZzjjhTeYXg%2Fuploads%2Fgit-blob-084a6732357e1e4e67c707680d13563949ca022d%2Fsetup-testnet-explorer.png?alt=media" alt="Change block explorer URL to ThunderCore testnet explorer" data-size="original">
5. Now we need some gas fee to deploy. So we just visit [ThunderCore Faucet](https://faucet-testnet.thundercore.com/) and paste the public address to get some testnet TT:

   <img src="https://3880137760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHVry7OTN1UZzjjhTeYXg%2Fuploads%2Fgit-blob-c6f1431e29357074ca8bbb2dcdd6170815acb481%2Fget-testnet-tt-from-faucet.png?alt=media" alt="Copy and paste public address" data-size="original"><img src="https://3880137760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHVry7OTN1UZzjjhTeYXg%2Fuploads%2Fgit-blob-d048a4b78416505cebff360636db4630636d7b21%2Fgot-testnet-tt-from-faucet.png?alt=media" alt="Got some testnet TT" data-size="original">
6. Download the TT20 template contract if you need:

{% file src="/files/iwYBJ1UTZXLHEHsXg16O" %}
TT20 template contract
{% endfile %}

Great, we can work on Remix now.

### Setting up Remix IDE

Visit [Remix](https://remix.ethereum.org) to access the Remix IDE from your web browser.

1. Go to "File explorers"
2. Click `contracts` folder in your workspace, choose your prefered way to adding contracts. In here, we are using downloaded TT20 template contract in previous step. Click the "Load a local file into current workspace" icon and upload the file into `contracts` folder.
3. Rename the token name and symbol, and the initial total-supply amount which will mint to your account when deployment is done:

   <img src="https://3880137760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHVry7OTN1UZzjjhTeYXg%2Fuploads%2Fgit-blob-f1b67fcbd32dcc5f3c88476fda63f804781b7628%2Fupdate-token-name-and-symbol.png?alt=media" alt="" data-size="original">
4. You can choose to remove the `mint` function if you don't want your token being mintable.

   <img src="https://3880137760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHVry7OTN1UZzjjhTeYXg%2Fuploads%2Fgit-blob-d1c3ed6d8614be277f8297ed7cd70c4a47523641%2Fremove-mint-function.png?alt=media" alt="" data-size="original">

Okay, we are ready to compile it.

### Compile smart contract

1. Click TT20 contract, and go to "Solidity compiler" tab ![](https://3880137760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHVry7OTN1UZzjjhTeYXg%2Fuploads%2Fgit-blob-1c6c9a92cdc93858841082f4761166a91ae8da40%2Fsolidity_compiler.png?alt=media)
2. The compiler settings are:
   * **COMPILER:** 0.5.17+commit.d19bba13
   * **EVM VERSION:** EVM VERSION: london
   * **Auto compile:** clicked
   * **Enable optimization:** clicked and select `200`
3. Click on **Compile TT20** button. If the button doesn't display the right contract name, you'll need to go back to files tab and select the correct one.
4. After successful compilation, the tab will look like: ![](https://3880137760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHVry7OTN1UZzjjhTeYXg%2Fuploads%2Fgit-blob-7fb2a3d370364951c47295eb4c6c509edd688664%2Fsuccessful_solidity_compiler.png?alt=media)

Now we can deploy compiled contract to ThunderCore network.

### Deploy Contract to ThunderCore Testnet

1. Go to "Deploy & run transactions" tab.
2. In the "environment" selection, we choose "Injected Web3". It will connect to MetaMask to get network settings:

   <img src="https://3880137760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHVry7OTN1UZzjjhTeYXg%2Fuploads%2Fgit-blob-b6e901b2c055ca50e97bbbd66544238396f57735%2Fmetamask-as-injected-web3.png?alt=media" alt="" data-size="original">
3. You can change the "Gas Limit" to `90000000` which is ThunderCore network's limit. However in this contract, we don't need so much gas to deploy, so you can keep it as default.
4. In the "Contract" selection, choose the "TT20" contract:

   <img src="https://3880137760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHVry7OTN1UZzjjhTeYXg%2Fuploads%2Fgit-blob-a9655b0c2ed51b6b7e6de9a4aa787d1ab2f88527%2Fdeploy-tt20.png?alt=media" alt="" data-size="original">
5. Click on "Deploy" button and confirm the transation:

   <img src="https://3880137760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHVry7OTN1UZzjjhTeYXg%2Fuploads%2Fgit-blob-e1a73f2dfaf64b3db69eb4fb1d3a9b725c753963%2Fconfirm-deployment.png?alt=media" alt="" data-size="original">
6. You shall find the contract address display in "Deployed Contracts". You can open it and test around those functions:

   <img src="https://3880137760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHVry7OTN1UZzjjhTeYXg%2Fuploads%2Fgit-blob-aafa09bf8de002afff106af0e5a7649124be1394%2Ftest-deployed-tt20.png?alt=media" alt="" data-size="original">

**Congratulations!** You have successfully deployed a TT20 token on ThunderCore testnet. Keep developing more interesting contracts!


# Using Truffle

> Truffle is a development environment, testing framework and asset pipeline for Ethereum, aiming to make life as an Ethereum developer easier.

#### Adding Truffle to your project

You'll need [Node.js v8+](https://nodejs.org/en/) installed before we get started. And you can choose a preferred package management tool to begin with:

{% tabs %}
{% tab title="npm" %}

```bash
# To use truffle locally in your project, you must init a package.json file
$ npm init

# Install truffle and wallet-provider to your project
$ npm i -D truffle @truffle/hdwallet-provider

# Generate truffle configuation file and default folders
$ npm exec -- truffle init
```

{% endtab %}

{% tab title="Yarn" %}

```bash
# To use truffle locally in your project, you must init a package.json file
$ yarn init

# Install truffle and wallet-provider to your project
$ yarn add --dev truffle @truffle/hdwallet-provider

# Generate truffle configuation file and default folders
$ yarn truffle init
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
You can install global Truffle to your environment:

```bash
$ npm i -g truffle
```

Then, you can ignore `npm exec --` or `yarn` commands before `truffle`
{% endhint %}

#### Setup Truffle config file

We are going to edit `truffle-config.js`. First, we uncomment this line to import `@truffle/hdwallet-provider`:

{% code title="truffle-config.js" %}

```git
- // const HDWalletProvider = require('@truffle/hdwallet-provider');
+ const HDWalletProvider = require('@truffle/hdwallet-provider');
```

{% endcode %}

Then, we add ThunderCore network settings into your project.

{% code title="truffle-config.js" %}

```git
networks: {
  "thunder-mainnet": {
    provider: () => new HDWalletProvider([process.env.KEY], "https://mainnet-rpc.thundercore.com"),
    network_id: "108",
    gas: 90000000,
    gasPrice: 15e9
  },
  "thunder-testnet": {
    provider: () => new HDWalletProvider([process.env.KEY], "https://testnet-rpc.thundercore.com"),
    network_id: "18",
    gas: 90000000,
    gasPrice: 15e9
  }
}
```

{% endcode %}

{% hint style="danger" %}
Never store your private key directly in `truffle-config.js`
{% endhint %}

#### Deploy a Contract

{% hint style="info" %}
You'll need gas tokens to deploy contracts. To test on ThunderCore testnet, you can get testnet tokens from [ThunderCore testnet Faucet](https://faucet-testnet.thundercore.com)
{% endhint %}

Now, we can deploy the Migrator contract in the template to ThunderCore testnet.

{% tabs %}
{% tab title="Unix-like system" %}

```shell
# Using NPM
KEY=0xPrivateKey npm exec -- truffle migrate --network thunder-testnet --reset
# or using Yarn
KEY=0xPrivateKey yarn truffle migrate --network thunder-testnet --reset
```

{% endtab %}

{% tab title="Windows CMD" %}

```shell
# Using NPM
set KEY=0xPrivateKey & npm exec -- truffle migrate --network thunder-testnet --reset
# or using Yarn
set KEY=0xPrivateKey & yarn truffle migrate --network thunder-testnet --reset
```

{% endtab %}

{% tab title="Windows Powershell" %}

```shell
# Using NPM
$env:KEY='0xPrivateKey';npm exec -- truffle migrate --network thunder-testnet --reset
# or using Yarn
$env:KEY='0xPrivateKey';yarn truffle migrate --network thunder-testnet --reset
```

{% endtab %}
{% endtabs %}

When it's done, should show messages like this:

```
Starting migrations...
======================
> Network name:    'thunder-testnet'
> Network id:      18
> Block gas limit: 100000000 (0x5f5e100)


1_initial_migration.js
======================

   Deploying 'Migrations'
   ----------------------

   ...
   ...
   ...

   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:         0.000266154 ETH


Summary
=======
> Total deployments:   1
> Final cost:          0.000266154 ETH
```

**Congratulations!** You have successfully deployed a smart contract onto the ThunderCore network.

You can check the deployment status at:

* [**ThunderCore mainnet:**](https://viewblock.io/thundercore)
* [**ThunderCore testnet:**](https://explorer-testnet.thundercore.com/)


# Deploy TT20

## Deploy Your Own TT20

**ERC20** tokens are one of the most popular DApps in the blockchain community. This tutorial will guide you through deploying an TT20 smart contract on ThunderCore in 5 simple steps. It's super easy and fast!

#### Requirements

This tutorial expects you to have some basic knowledge of Truffle, Ethereum, Metamask and Solidity.

#### Install development tools

Please install the following:

```
Node.js v8+ LTS and npm (comes with Node)
Git
Yarn (optional)
```

Once we have those installed, we only need one command to install Truffle:

```
npm install -g truffle
# or
yarn global add truffle
```

To verify that Truffle is installed properly, type truffle version on a terminal.

#### Install MetaMask

MetaMask is a browser extension that serves as a “wallet” that safely stores your cryptocurrencies such as Ether (ETH) and ThunderCore (TT). It also serves as a “bridge” that connects the web application with the blockchain. You can download and learn more about [Metamask](https://metamask.io).

Get ThunderCore (TT) or ThunderCore Testnet Tokens to get started, you will need to get Thunder Token (Mainnet) or Thunder Testnet Token (Testnet) to deploy your smart contracts on ThunderCore. Please follow this instruction to get your tokens.

#### **Steps** in this tutorial we will be covering:

* Cloning tt20 repository and installing dependencies
* Updating config file of TT20 Token
* Compiling and deploying the smart contract on ThunderCore
* Transfering your TT20 to others

#### 1. Cloning TT20 repository and installing dependencies

To make it easier to get started with ThunderCore, we've created a ERC20 contract, TT20. You can download the contract with git command.​ On a terminal, input the following command to download the repository

> git clone <https://github.com/thundercore/tt20>

Next, we'll update the required dependencies for deploying the contract.

```
npm install
# or
yarn install
```

#### 2. Updating config file of ERC20 Token

Since we've finished the contract already, the only thing we need to do is to update the config file config.json in tt20 folder. The config.json should look like the following:

```
{
    "name": "SampleToken",
    "symbol": "SPT",
    "decimals": 9,
    "initialSupply": 1.5e9
}
```

Change these fields to whatever you want, for example:

```
{
    "name": "MyToken",
    "symbol": "MT",
    "decimals": 8,
    "initialSupply": 1.5e9
}
```

Things to note:

* The name and symbol fields give our token a unique identity.
* The decimals field determines the degree to which this token can be subdivided.
* The initialSupply field determines the number of tokens created when this contract is deployed. In this case, the number is arbitrary. Now, we have our own tokens!

#### 3. Compiling and deploying the smart contract

In the migrations/2\_deploy\_contracts.js, we load the configuration from config.js of ERC20 and deploy the contract. Before we compile and deploy our own ERC20, we can setup a local chain. By using a local blockchain, we can test our contract without consuming real tokens. We recommend using Ganache. Refer to thundercore/ganache and build the Ganache GUI or using the CLI tool thundercore/ganache-cli with the following command.

```
# in tt20 repository
npm install -g thundercore/ganache-cli#tt
```

After install the dependencies of ganache-cli, we can launch a local blockchain with the following command.

```
cd tt20
cd node_modules
cd / .bin
ganache-cli --networkId 5777 -p 9545
```

With our blockchain launched, run the following command to compile and deploy the contract

```
# deploy Token contract to network 'development'
./deploy-contracts --network development
```

You will see output that looks similar to this:

```
Command: [ 'truffle', 'migrate', '--network', 'development' ]
Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.


Starting migrations...
======================
> Network name:    'development'
> Network id:      5777
> Block gas limit: 6721975 (0x6691b7)


1_initial_migration.js
======================

   Replacing 'Migrations'
   ----------------------
   > transaction hash:    0x604136ec8bb8d95a819f6f1c962c622583a9c6f2bf91a7616e9a137ab278c6a6
   > Blocks: 0            Seconds: 0
   > contract address:    0xeae24EB27F866225cF6f29370054F7470A94417F
   > block number:        1
   > block timestamp:     1628560607
   > account:             0xa2b543E95EC730A61D40D1cCeb41C68aDe60072c
   > balance:             99.9967579
   > gas used:            162105 (0x27939)
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.0032421 ETH


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:           0.0032421 ETH


2_deploy_token.js
=================

   Replacing 'Token'
   -----------------
   > transaction hash:    0x737c5536c25c44c9cd8a40a8a0c0b25986e2d3d49a4823ea52e7d15c30f66e87
   > Blocks: 0            Seconds: 0
   > contract address:    0x0A7e26D081ffbe772791fC312101210c495b4550
   > block number:        3
   > block timestamp:     1628560608
   > account:             0xa2b543E95EC730A61D40D1cCeb41C68aDe60072c
   > balance:             99.9608271
   > gas used:            1739114 (0x1a896a)
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.03478228 ETH


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:          0.03478228 ETH


Summary
=======
> Total deployments:   2
> Final cost:          0.03802438 ETH
```

Now, your `MyToken` is deployed and mint to your first address in ganache.

With our blockchain launched, run the following command to compile and deploy the contract.

```
# deploy Token contract to network 'development'
./deploy-contracts --network development
```

You will see output that looks similar to this:

```
Command: [ 'truffle', 'migrate', '--network', 'development' ]


Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.


Starting migrations...
======================
> Network name:    'development'
> Network id:      5777
> Block gas limit: 6721975 (0x6691b7)


1_initial_migration.js
======================

   Replacing 'Migrations'
   ----------------------
   > transaction hash:    0x604136ec8bb8d95a819f6f1c962c622583a9c6f2bf91a7616e9a137ab278c6a6
   > Blocks: 0            Seconds: 0
   > contract address:    0xeae24EB27F866225cF6f29370054F7470A94417F
   > block number:        1
   > block timestamp:     1628560607
   > account:             0xa2b543E95EC730A61D40D1cCeb41C68aDe60072c
   > balance:             99.9967579
   > gas used:            162105 (0x27939)
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.0032421 ETH


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:           0.0032421 ETH


2_deploy_token.js
=================

   Replacing 'Token'
   -----------------
   > transaction hash:    0x737c5536c25c44c9cd8a40a8a0c0b25986e2d3d49a4823ea52e7d15c30f66e87
   > Blocks: 0            Seconds: 0
   > contract address:    0x0A7e26D081ffbe772791fC312101210c495b4550
   > block number:        3
   > block timestamp:     1628560608
   > account:             0xa2b543E95EC730A61D40D1cCeb41C68aDe60072c
   > balance:             99.9608271
   > gas used:            1739114 (0x1a896a)
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.03478228 ETH


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:          0.03478228 ETH


Summary
=======
> Total deployments:   2
> Final cost:          0.03802438 ETH
```

Now, your **MyToken** is deployed and mint to your first address in ganache.

#### 4. Deploy to the ThunderCore Testnet and Mainnet

Now, you can prepare to deploy your token to ThunderCore Testnet or Mainnet. Please make sure you have Thunder Testnet Token (TST) or Thunder Token (TT). First you set up the control of your account to truffle. You can set either by:

* Write your 12-word mnemonic (seed phrase) to a file named .mnemonic
* Export your account private keys, one per line, to a file named .private-keys

```
# If you use private keys
mv .private-keys.template .private-keys

# in .private-keys file, put your private keys
e59cb5e369b65eee650f90f3280cbe8039db81335943ac7a88df5f4df...
d92a96fa691a7c31b2e2891de05cacc85d562b128afa6bb8f7108aac7...

# If you prefer mnemonic
mv .mnemonic.template .mnemonic

# In .mnemonic file, put your mnemonic
dog cat apple bird ...
```

1. If you use metamask to control your address, you can check how to export the private key here. The address you used will be filled your `MyToken` .
2. Compile and migrate your contract for Thunder Testnet and Thunder Mainnet

```
# Deploy to testnet
./deploy-contracts --network thunder-testnet

# or Deploy to mainnet
./deploy-contracts --network thunder-mainnet
```

1. After deploying your own token, `totalSupply` will be added to your accounts. Check out MetaMask to see how to add custom token on MetaMask. The token contract address should be in the stdout after you executed the deployment command.

```
2_deploy_token.js
=================

   Replacing 'Token'
   -----------------
   > transaction hash:    0x737c5536c25c44c9cd8a40a8a0c0b25986e2d3d49a4823ea52e7d15c30f66e87
   > Blocks: 0            Seconds: 0
   > contract address:    0x0A7e26D081ffbe772791fC312101210c495b4550
   > block number:        3
   > block timestamp:     1628560608
   > account:             0xa2b543E95EC730A61D40D1cCeb41C68aDe60072c
   > balance:             99.9608271
   > gas used:            1739114 (0x1a896a)
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.03478228 ETH


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:          0.03478228 ETH
```

#### 5. Transferring your ERC20 token to others

If you have already added MyToken to your MetaMask, try to send your tokens to other accounts. See more detail on MetaMask doc Note If you try on your local ganache, make sure to set the custom network to your localchain. For exmaple, set rpc url to <http://localhost:9545> and chain id 5777. Then you can import private key from ganache to metamask or open a browser without MetaMask (such as incognito window) to see your tokens. Learning more about DApps It’s beyond the scope of this tutorial to go over the code, but if you’d like to learn more about smart contract programming and building DApps in general, we recommend the official Solidity documentation and truffle tutorial. For questions, please join to our Discord channel.&#x20;

Happy Coding! 😆

### Bridging your ERC20 Token to ThunderCore

For devs and projects with tokens deployed **one or more** chains, you may bridge your tokens over to ThunderCore via [Multichain](https://multichain.org/). Learn more by checking out their guide on [bridging your ERC20 tokens](https://docs.multichain.org/listing-and-integration/token-listing/erc20-cross-chain-options)!


# Deploy a DApp

### Overview

Let's use 5-10 minutes to deploy a complete game through ThunderCore that is easily accessible to your own friends and family -- accessible to anyone with internet access. We will release a simple coin toss game where players will receive twice as many bets if the coin is facing up. In the case of coins facing down, players will lose their bets, but still have a chance to double the bet.

#### Exploring the Game

To begin, we will obtain a wallet and gain access to the Thunder network. With either Metamask or TrustWallet pointed to the Thunder RPC, navigate [HERE](https://thundercore.github.io/DoubleOrNothing/) to play the game we will build in this tutorial!

![](https://i.imgur.com/IbBIWXd.png)

To make your own version of the page, just check out the [repo](https://github.com/thundercore/DoubleOrNothing) and follow the instructions in the readme.

At the end of those instructions, you should be able to access the game with either your mobile device through Metamask or any ThunderCore compatible mobile DApp browsers.

#### Deploying Your Own Contract

Now, let's get your game running on your own copy of the contract, so you can get started developing your own killer DApp!

First we will install all the dependencies.

```
node -v
# Let's make sure our node is v8 or v10
```

If you haven't downloaded node.js, go to [node.js](https://nodejs.org/en/download/) download the version 8 or version 10. If you have downloaded it before but your version is incompatible, install it with [nvm](https://github.com/nvm-sh/nvm), and follow the instructions below.

```
nvm install [v8 or v10]
nvm use [v8 or v10]

node -v  #Make double check our node is v8 or v10 (recommend node version:10.24.1)
```

* [references---how to change to an old version of node.js](https://stackoverflow.com/questions/7718313/how-to-change-to-an-older-version-of-node-js)

```
cd ./smart-contracts
yarn install

# or
npm install
```

Next grab your mnemonic or import your private key from metamask and create a file called .private-keys under “./smart-contracts ” or Trust Wallet and add it to the HDWallet in truffle-config.js

```
testnet
yarn migrate --network thunder-testnet --reset
# or
npm run migrate -- --network thunder-testnet --reset
```

```
mainnet
yarn migrate --network thunder-mainnet --reset
# or
npm run migrate -- --network thunder-mainnet --reset
```

In the console, you will see the price you've paid for its deployment, the contract address, and additional stats. Well done! Your contract is now up and running ready to be used by anyone. If the contract address of DoubleOrNothing didn’t show up in the console after the migration ,you can check the contract address by typing the command below.

```
mainnet
$ Truffle console --network thunder-mainnet
testnet
$ Truffle console --network thunder-mainnet

let contract = await DoubleOrNothing.deployed()
DoubleOrNothing.address
```

To make sure you've deployed doubleOrNothing smart contract successfully,you can double check the contract address and contract block number you've deployed lately.

#### Testnet

```
truffle(thunder-testnet)>let contract = await DoubleOrNothing.deployed()
truffle(thunder-testnet)> DoubleOrNothing.address
'0x48caD7fe30Fd1CA52EcBda9C82E398B0FFd321eE'
truffle(thunder-testnet)> n = web3.eth.getBlockNumber();
62591612
```

#### Mainnet

```
truffle(thunder-mainnet)>let contract = await DoubleOrNothing.deployed()
truffle(thunder-mainnet)> DoubleOrNothing.address
'0x8693A164EBC4429fCFF4461B481FCD4E60690fD3'
truffle(thunder-mainnet)> n = web3.eth.getBlockNumber();
83540251
```

We must now update our UI to use this contract address.

```
cd ./frontend
```

```
yarn install
# or
npm install
```

Find the .env file and change the **REACT\_APP\_CONTRACT\_ADDRESS** to your new address which you got by the command **DoubleOrNothing.address** above.

Meanwhile, you can start by deploying on testnet , change 'REACT\_APP\_TT\_USDT\_CONTRACT(testnet)' to `0xB1Fb0b14Ffea209ABa1e62ff3F2F3DFD2eaa9FE0`, and comment out another REACT\_APP\_TT\_USDT\_CONTRACT address. If you’re not sure of the REACT\_APP\_TT\_USDT\_CONTRACT testnet or mainet address, check out on [thundercore bridge](https://bridge-venus.thundercore.com/eth/).

Below are the specific steps we mentioned above.

First of all, click on the option above.Next, click the info symbol below.

![](https://3880137760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHVry7OTN1UZzjjhTeYXg%2Fuploads%2FWiN0YmQkbtBcwSvXVh0a%2F1%20\(1\).png?alt=media\&token=e9f5932e-d047-448d-b10c-9686ec52de84)

![](https://3880137760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHVry7OTN1UZzjjhTeYXg%2Fuploads%2Fyk4A5At4t4e7RSLEkWd8%2FFrame%203.png?alt=media\&token=3b3f0b56-6298-44ea-a53f-8f086a319a80)

![](https://3880137760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHVry7OTN1UZzjjhTeYXg%2Fuploads%2FjKpRHzf8GfyDMSbBMHG3%2F2.png?alt=media\&token=cb72bd70-51b5-407e-a43a-cd8f78a88d97)

You can see the **TT-USDT ADDRESS** ,which is **REACT\_APP\_TT\_USDT\_CONTRACT**=`0xB1Fb0b14Ffea209ABa1e62ff3F2F3DFD2eaa9FE0`

```
yarn start
# or
npm run start
```

This will start a local server with your changes. If you want to deploy this to your webpage run:

```
yarn build
# or
npm run build
```

```
git add -u

*Remember to not check in your mnemonic!!!!
```

```
git commit -m 'add my own contract address'
```

```
git push
```

Voila! In 5-10 seconds, your webpage will be running on your contract.Congratulations!

#### Debugging

Add a Console to display an Error Message in the DApp's UI when running in the Wallet tab of **TT Wallet** to display any error messages for problems/errors encountered while interacting with the chain.

Example 1: [TT20 Transactions](https://github.com/thundercore/hubbit-field-support/blob/c69d3798f77fd07d8b3f0381b5a0dc78addd0691/src/index.js#L172)

Example 2: [DoubleOrNothing](https://github.com/thundercore/DoubleOrNothing/commit/8d5e755876f77f309937b31791ae246b4826566a#diff-1a2294bec8f8b96cd516ecd00ef9f3c8R135)


# Deploy a NFT

> How to add rich metadata to your ERC721 or ERC1155 NFTs

## Implementing token URI

For pulling in off-chain metadata for ERC721 and ERC1155 assets, your contract will need to return a URI where we can find the metadata. To find this URI, we use the tokenURI method in ERC721 and the uri method in ERC1155. First, let's look closely at the tokenURI method in the Creature contract.

## ERC721

ref: [eip-721](https://eips.ethereum.org/EIPS/eip-721)

```
interface ERC721Metadata /* is ERC721 */ {
    /// @notice A descriptive name for a collection of NFTs in this contract
    function name() external view returns (string _name);

    /// @notice An abbreviated name for NFTs in this contract
    function symbol() external view returns (string _symbol);

    /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
    /// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC
    ///  3986. The URI may point to a JSON file that conforms to the "ERC721
    ///  Metadata JSON Schema".
    function tokenURI(uint256 _tokenId) external view returns (string);
}
```

## ERC1155

ref: [eip-1155](https://eips.ethereum.org/EIPS/eip-1155)

```
interface ERC1155Metadata_URI {
    /// @notice A descriptive name for a collection of NFTs in this contract
    function name() external view returns (string _name);

    /**
        @notice A distinct Uniform Resource Identifier (URI) for a given token.
        @dev URIs are defined in RFC 3986.
        The URI MUST point to a JSON file that conforms to the "ERC-1155 Metadata URI JSON Schema".        
        @return URI string
    */
    function uri(uint256 _id) external view returns (string memory);
}
```

## ERC1155 Metadata\_URI

The URI value allows for ID substitution by clients. If the string {id} exists in any URI, clients MUST replace this with the actual token ID in hexadecimal form. This allows for a large number of tokens to use the same on-chain string by defining a URI once, for that large number of tokens.\
The string format of the substituted hexadecimal ID MUST be lowercase alphanumeric: \[0-9a-f] with no 0x prefix. The string format of the substituted hexadecimal ID MUST be leading zero padded to 64 hex characters length if necessary.\
Example of such a URI: <https://token-cdn-domain/{id}.json> would be replaced with <https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json.\\>
if the client is referring to token ID 314592/0x4CCE0.

## Metadata

The tokenURI function in your ERC721 or the uri function in your ERC1155 contract should return an HTTP or IPFS URL. When queried, this URL should in turn return a JSON blob of data with the metadata for your token.

<img src="https://3880137760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHVry7OTN1UZzjjhTeYXg%2Fuploads%2Fgit-blob-992e49ecb0050ae33a1f98efb99200cc834f6367%2Fnft721_4.png?alt=media" alt="" data-size="original">

Here's main property definition

| Property    | Description                                                                                                                                                                                                   |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name        | Name of the item.                                                                                                                                                                                             |
| image       | <p>This is the URL to the image of the item. Can be just about any type of image , and can be IPFS URLs or paths.<br>If you use IPFS to host your metadata, your URL can be in the format ipfs\://{hash}.</p> |
| creator     | creator wallet address                                                                                                                                                                                        |
| description | A human readable description of the item. Markdown is supported.                                                                                                                                              |
| marketplace | marketplace if necessary                                                                                                                                                                                      |


# FAQs

## Technical FAQ <a href="#docusaurus" id="docusaurus"></a>

### Is ThunderCore compatible with Ethereum? <a href="#is-thundercore-compatible-with-ethereum" id="is-thundercore-compatible-with-ethereum"></a>

ThunderCore and Ethereum use the same virtual machine (EVM). As such, smart contracts that run on Ethereum can run on ThunderCore as well, which means that ThunderCore supports coding languages that Ethereum supports; including Solidity, Vyper, etc.

Furthermore, ThunderCore exposes Ethereum's [JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC), which makes it compatible with tools that use the JSON RPC, such as web3.js, MetaMask, Truffle, etc.

In general, any DApp that runs on Ethereum can be made to run on ThunderCore with very few or minor modifications. Visit the [tutorial](/deploying-on-thundercore/migrate-from-ethereum) to learn how to migrate from Ethereum to ThunderCore.

### Is ThunderCore decentralized? <a href="#is-thundercore-decentralized" id="is-thundercore-decentralized"></a>

Yes, ThunderCore is based on decentralized trust. Users have to trust neither the consensus nodes, nor the accelerator. Users only need to trust the honest majority for ThunderCore to be secure (which is the same for standard blockchains). To understand the consensus algorithm, see the [Whitepaper](https://docs.thundercore.com/thunder-whitepaper.pdf).

### How do I write smart contracts for ThunderCore? <a href="#how-do-i-write-smart-contracts-for-thundercore" id="how-do-i-write-smart-contracts-for-thundercore"></a>

Since ThunderCore is compatible with Ethereum smart contracts, you can write smart contracts the same way you would for Ethereum. Most people use Truffle, but other tools should work as well. Check out our tutorial to [deploy your own game](/deploying-on-thundercore/deploy-a-dapp).

### How do I deploy smart contracts on ThunderCore? <a href="#how-do-i-deploy-smart-contracts-for-thundercore" id="how-do-i-deploy-smart-contracts-for-thundercore"></a>

The process for deploying smart contracts on ThunderCoure would be the same way that you deploy them on Ethereum. Most people use Truffle, but other tools should work as well. See our tutorials on building and [migrating Ethereum DApps](/deploying-on-thundercore/migrate-from-ethereum) to ThunderCore.

### What if I already developed a DApp or smart contracts on Ethereum? <a href="#what-if-i-already-developed-a-dapp-or-smart-contracts-on-ethereum" id="what-if-i-already-developed-a-dapp-or-smart-contracts-on-ethereum"></a>

Since ThunderCore is compatible with Ethereum, it’s easy to migrate DApps and smart contracts to ThunderCore in just a few steps. Check out our [migrate Ethereum DApps to ThunderCore tutorial](/deploying-on-thundercore/migrate-from-ethereum).

### How much does it cost to use ThunderCore? <a href="#how-much-does-it-cost-to-use-thundercore" id="how-much-does-it-cost-to-use-thundercore"></a>

On the ThunderCore Mainnet, ThunderCore (TT) are used to pay for gas fees. ThunderCore doesn't rely on an expensive Proof-of-Work (PoW) algorithm and is therefore able to produce blocks at a lower cost.

Get ThunderCore (TT) and Testnet Tokens [here](https://help.thundercore.com/hc/en-us/articles/900006700383-Get-Tokens)

### Can I mine or stake ThunderCore (TT)? <a href="#can-i-mine-or-stake-thunder-tokens-tt" id="can-i-mine-or-stake-thunder-tokens-tt"></a>

Since ThunderCore utilizes Proof-of-Stake, as a result all ThunderCore (TT) are premined. No new tokens can be mined as we do not mint new tokens as part of our consensus process. ThunderCore validators, called committee node members, earn rewards through gas/txn fees. People can take part in the ThunderCore consensus mechanism and participate in securing the ThunderCore blockchain upon its public launch.

Read more about our Staking Pool Service [here](https://medium.com/thundercore/thundercore-super-node-staking-pool-service-launched-c391c1dbcaff)! Go [here](https://supernode.thundercore.com) now to stake your ThunderCore (TT) and earn up to 24% APY.

### How can I get access to ThunderCore?

ThunderCore is a public chain. The ThunderCore Mainnet is easily accessible via the published network addresses found [here](https://developers.thundercore.com/docs/migrate-to-thunder).

### Is ThunderCore available for DApp development? <a href="#is-thundercore-available-for-dapp-development" id="is-thundercore-available-for-dapp-development"></a>

Yes. We encourage DApp developers to experience a boost in performance while leveraging full EVM compatibility. DApps can be migrated to ThunderCore within as fast as five minutes.

ThunderCore (TT) are available to individuals and teams desiring to try the ThunderCore Mainnet. The ThunderCore Testnet has been running and available since February 2019 for DApp development. You can get started by obtaining Testnet Tokens from [here](https://help.thundercore.com/hc/en-us/articles/900006700383-Get-Tokens). Please also stay on the lookout for incentives to port your DApps to ThunderCore!

Right now you will have to configure most of the wallets to point to any one of the custom RPC url of ThunderCore:

| RPC                                    |
| -------------------------------------- |
| <https://mainnet-rpc.thundercore.com>  |
| <https://mainnet-rpc.thundertoken.net> |
| <https://mainnet-rpc.thundercore.io>   |

### Is ThunderCore(TT) an ERC-20 token? <a href="#is-thunder-token-an-erc-20-token" id="is-thunder-token-an-erc-20-token"></a>

No, ThunderCore (TT) is the native currency of an independent public blockchain, ThunderCore.

ThunderCore is an Ethereum Virtual Machine (EVM) compliant blockchain. Tokens based on the ERC-20 standard can be minted and deployed on ThunderCore.

### What can I do with ThunderCore (TT)? <a href="#what-can-i-do-with-thunder-tokens" id="what-can-i-do-with-thunder-tokens"></a>

ThunderCore (TT) is the native currency of an independent public blockchain, ThunderCore. ThunderCore (TT) can be used to build and monetize decentralized applications on the ThunderCore blockchain. ThunderCore (TT) can be used to pay for gas costs, execute transactions and underwrite smart contracts on the ThunderCore blockchain.

### Why is MetaMask showing my tokens as ETH and a large USD amount as its value? <a href="#why-is-metamask-showing-my-tokens-as-eth-and-a-large-usd-amount-as-its-value" id="why-is-metamask-showing-my-tokens-as-eth-and-a-large-usd-amount-as-its-value"></a>

When adding a custom RPC URL in MetaMask, MetaMask by default treats any token/coin as ETH and shows the portfolio value using the USD price of ETH.

To correct this, use the "Show Advanced Options" menu when adding the custom URL for Thunder Core (<https://mainnet-rpc.thundercore.com>). Add 108 (0x6c) as Chain ID and TT as the Symbol.

Once you do that your Thunder Tokens will appear as TT on you MetaMask wallet.

### Gas Fees <a href="#gas-fees" id="gas-fees"></a>

#### Gas Price <a href="#gas-price" id="gas-price"></a>

* Use the [eth\_gasPrice RPC](https://eth.wiki/json-rpc/API) call to get the moving average of recent price

#### Gas Limit <a href="#gas-limit" id="gas-limit"></a>

* Use the [eth\_estimateGas RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_estimategas) call to estimate the computation and storage cost required by the transaction. If you know for sure the destination address is a regular account and not a smart contract, you can use specify a gas limit of 21 K (21,000)

### How to Prevent Rate Limit? <a href="#how-to-prevent-rate-limit" id="how-to-prevent-rate-limit"></a>

* Optimize application program logic and reduce the frequency of query
* Use batch query

### The ability to query ancient states <a href="#the-ability-to-query-ancient-states" id="the-ability-to-query-ancient-states"></a>

* Balancing network performance by trading off the ability to query ancient states, such as account balances from months ago. Querying RPC with block numbers may fail if the timestamp of that block was processed a long time ago. Including:
  * eth\_getBalance
  * eth\_getCode
  * eth\_getTransactionCount
  * eth\_getStorage
  * eth\_call

### Address Generation <a href="#address-generation" id="address-generation"></a>

* ThunderCore addresses use the same format as Ethereum e.g. 0x519A3B21130Eb8496F7a8E4782fa3106aE4cFF27
* HD Wallet derivation path to obtain private keys from a 12-word mnemonic is (BIP32 Derivation Path): m/44'/1001'/0'/0

| Golang (go-ethereum)                                                                               | Javascript (web3.js)                                                                                                 |
| -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| [crtypo.GenerateKey()](https://github.com/ethereum/go-ethereum/blob/v1.9.12/crypto/crypto.go#L193) | [web3.eth.accounts.create()](https://github.com/thundercore/field-support/blob/private-key-to-address/src/key.js#L9) |
|                                                                                                    | [test](https://github.com/thundercore/field-support/blob/private-key-to-address/test/testPrivateKeyToAddress.js#L12) |

### Sending Transactions <a href="#sending-transactions" id="sending-transactions"></a>

| Protocol | Transfers                       | References                                                                                                                                                                                                  |
| -------- | ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| TT       | Native Cryptocurrency Transfers | See [submitTx()](https://github.com/thundercore/field-support/blob/transfer/src/transfer.js#L29) example [(test)](https://github.com/thundercore/field-support/blob/transfer/test/testTransfer.js#L11)      |
| TT20     | TT20 Token Transfers            | See [transferToken()](https://github.com/thundercore/field-support/blob/transfer/src/transfer.js#L54) example [(test)](https://github.com/thundercore/field-support/blob/transfer/test/testTransfer.js#L13) |

### Where to Ask Questions <a href="#where-to-ask-questions" id="where-to-ask-questions"></a>

* Join the ThunderCore [Telegram](https://t.me/thunder_official) to reach our developers and ask questions.

### Is your question still not answered? <a href="#is-your-question-still-not-answered" id="is-your-question-still-not-answered"></a>

Please get in touch with our team at the [Telegram](https://t.me/thunder_official). For urgent support, please [Submit a Request](https://help.thundercore.com/hc/en-us/requests/new) via our help center.


# Wallets

As an L1 blockchain, ThunderCore like Ethereum, Binance Chain, and other well-known public chains, also has many multi-chain wallets, custodial and non-custodial wallets in the ecosystem, such as [*imToken*](https://token.im/), [*MetaMask*](https://docs.developers.thundercore.com/product-protocol/wallets/configure-thundercore-on-metamask), [*Trust Wallet*](https://trustwallet.com/), and [*Bitkeep*](https://bitkeep.com/), etc.&#x20;

Users or developers can choose a suitable wallet according to their own preferences and needs.&#x20;


# MetaMask


# Create a MetaMask Wallet

If you are wondering how to create a new cryptocurrency wallet, consider creating one by installing the MetaMask extension.

Metamask is a free an secure browser that allows web applications to read and interact with the Ethereum blockchain.

### Install MetaMask on your browser

#### **Install MetaMask extension from Chrome, Firefox, Brave or Opera browsers.**

We will be using Google Chrome for the following tutorial.

1. Search MetaMask extension using your search engine.
2. Install MetaMask as a Google Chrome extension
3. Click add to Chrome
4. Click add extension

#### **Create an Account**

1. Click on the MetaMask icon in the upper right corner to open the extension 1.1 Install the latest version if there is any
2. Create an account by creating new password
3. Proceed by clicking Next, then accept Terms of Use
4. Click Reveal secret words
5. MetaMask will show 12 words seed phrase. Save seed words as a file to a save place and click Next
6. Verify your secret phrase by selecting the previously generated phrase. When done, click confirm By "solving this puzzle" you are confirming that you know your secret phrase

**Yay!** You have successfully created your MetaMask account.

### **Add ThunderCore Network**

To add ThunderCore's Mainnet, click on the Network selection dropdown and then click on Custom RPC

1. Open MetaMask and select custom RPC from the network dropdown
2. Go to Setting page ![](https://i.imgur.com/uPlP8V0.png)
3. Add a new network
4. Put in a Network name - "Thundercore Mainnet"
5. Put new RPC URL - "<https://mainnet-rpc.thundercore.com>"
6. Put chain ID - "108"
7. Put currency symbol - "TT"
8.
9. Click save, you will be directly switched to ThunderCore's Mainnet now in the network dropdown list. You can now close the dialog.

![](https://i.imgur.com/aAxfwf5.png)


# Create multiple accounts

To create multiple accounts,

1. Click on the Profile icon on MetaMask and then click on Create Account

![](https://i.imgur.com/dV7a9T5.png)

1. Add an account name and click on create

![](https://i.imgur.com/RRfpkqs.png)

To ceate more accounts by repeating step 1 and 2. When creating multiple accounts, your addresses will be different at your end.


# ThunderCore Bridge

## Intro

The ThunderCore bridge allows user to transfer assets between two chains in the ThunderCore ecosystem.

## Chain and Network Definitions

A bridge is created between 2 networks, referred to as a Native (or Home) Network and a Foreign Network.

* Home: A network with fast and inexpensive operations. All bridge operations to collect validator confirmations are performed on this side of the bridge, always refers to ThunderCore.
* Foreign: Can be one of Etheruem, and BNB chain
* ERC20: Refers to an ERC20 token created during the bridge process. In the ERC20-ERC20 bridge, ERC677 represent ERC20 tokens on one side of the bridge and are minted and burned accordingly.

## Bridge Components

A bridge is created between two networks, referred to as a Native (or Home) Network and Foreign Network.

* Token bridge: Listens to events and sends transactions to authorize asset transfers. Bridge UI Application: A DApp GUI to transfer tokens and coins between chains.
* Bridge UI Application. A DApp GUI to transfer tokens and coins between chains.
* Bridge smart contracts: Manages bridge validators, collects signatures, and confirms assets relay and disposal. Located at: <https://github.com/thundercore/thunder_bridge>

## Production Asset-transfer Bridges

The following bridges are fully functional in ThunderCore's production environments:

[**Ethereum**](https://bridge.thundercore.com/eth/) (Bridge between ThunderCore mainnet and Ethereum mainnet): Cost effective

[**BSC**](https://bridge.thundercore.com/bsc/) (Bridge between ThunderCore mainnet and BSC Network): A bridge service providing access to inter-blockchain liquidity for Binance Chain and Binance Smart Chain decentralized applications.

[**BSC testnet**](https://bridge-venus.thundercore.com/bsc/) (Bridge between ThunderCore testnet and BSC testnet)

## Resources

* [Architecture](/product-protocol/bridges/architecture)
* [Interact with bridge contract](/product-protocol/bridges/interact-with-thundercore-bridge)
* [Ethereum related contract address and information](/product-protocol/bridges/ethereum-contract-address)
* [BSC related contract address and information](/product-protocol/bridges/bsc-contract-address)


# Architecture

**ERC20-to-ERC20**

The entire process of bridging ERC20 tokens are shown on the diagram below

![](https://3880137760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHVry7OTN1UZzjjhTeYXg%2Fuploads%2Fgit-blob-ab4ba346a114e739fb8edae3d3a21c989c857745%2FERC20-to-ERC20.png?alt=media)

Bridge has a couple roles including:

* Administrators
* Validators
* Users

## Administrators

Administrators on the bridge manage the bridge smart contracts, add or remove validators, set minimum required signatures from validators in order to relay a user's transactions.

Administrators also can upgrade contracts in case of vulnerabilities.

## Validators

Validatdors do not manage smart contracts in the bridge setup, they are managed by Administrators. Validators in the network are responsible for:

* providing 100% uptime to relay transactions
* listening for `UserRequestForSignature` events on the ThunderCore and signing an approval to relay assets on foreign side
* listening for `CollectedSignatures` events on the ThunderCore. Once enough signatures are collected, transferring all collected signatures to the foreign side.
* listening for `UserRequestForAffirmation` or Transfer (depending on the bridge mode) events on the foreign side and sending approval to the ThunderCore to relay assets from foreign network to ThunderCore.

## Users

Users send assets to the bridge contracts and receive corresponding assets in return.

* `NATIVE-TO-ERC` mode: Send native coins to the ThunderCore Bridge contract to receive ERC20 tokens from the foreign bridge contract, and send TT20 tokens to the foreign bridge contract to unlock TT from the ThunderCore bridge contract.
* `ERC-TO-NATIVE` mode: Send ERC20 tokens to the foreign bridge contract to receive TT from the ThunderCore Bridge contract, and send TT to the ThunderCore Bridge contract to unlock ERC20 tokens from the Foreign bridge contract.
* `ERC-TO-ERC` mode: Transfer ERC20 tokens to the foreign bridge contract to mint TT20 tokens on the ThunderCore network, and transfer TT20 tokens to the ThunderCore Bridge contract to unlock ERC20 tokens on the foreign network;

For more information please refer to [Thunder Bridge](https://github.com/thundercore/thunder_bridge), and [TokenBridge](https://github.com/tokenbridge/docs/blob/master/SUMMARY.md)


# Ethereum <> ThunderCore

In Ethereum, we deployed two bridges one on mainnet and one on kovan testnet. The supported tokens can be found on this article.

## Ethereum mainnet

All information below can be found on [ThunderBridgeUI](https://bridge.thundercore.com/eth/)

### ERC20-USDT

* Token address: `0xdAC17F958D2ee523a2206206994597C13D831ec7`
* Foreign bridge contract address: `0x2E8a97c62Cc644aDCd108b9bEbCB9B32C9c58a1C`
* Corresponding token on ThunderCore: TT-USDT (`0x4f3C8E20942461e2c3Bdd8311AC57B0c222f2b82`)
* Home bridge contract address: `0x2C66e58c123fe807ef9c36682257fA6bfB4AFA52`
* Deposit minimum amount per transaction: `10` ERC20-USDT
* Withdraw Fee: `10` TT-USDT
* Withdraw minimum amount per transaction: `20` TT-USDT

### ERC20-USDC

* Token address: `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`
* Foreign bridge contract address: `0xC362bb39EC242aaF35446D00a18dF52321cBDd7D`
* Corresponding token on ThunderCore: TT-USDC (`0x22e89898A04eaf43379BeB70bf4E38b1faf8A31e`)
* Home bridge contract address: `0xc7E90D78c68D2a660141852bE8a5B678fCFB2896`
* Deposit minimum amount per transaction: `10` ERC20-USDC
* Withdraw Fee: `10` TT-USDC
* Withdraw minimum amount per transaction: `20` TT-USDC

### ERC20-WBTC

* Token address: `0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599`
* Foreign bridge contract address: `0x695D84E20613f30dCd2ce5C9428c9eD37A0137D2`
* Corresponding token on ThunderCore: TT-WBTC (`0x18fB0A62f207A2a082cA60aA78F47a1af4985190`)
* Home bridge contract address: `0x33c3bf851b50f3598E20B401f1de29ab24707b9C`
* Deposit minimum amount per transaction: `0` ERC20-WBTC
* Withdraw Fee: `0.00025` TT-WBTC
* Withdraw minimum amount per transaction: `0.001` TT-WBTC

### ETH

* Foreign bridge contract address: `0x48B884FE1b6F92Ca21646260001307b8E5B83e25`
* Corresponding token on ThunderCore: TT-ETH (`0x6576Bb918709906DcbFDCeae4bB1e6df7C8a1077`)
* Home bridge contract address: `0x09b122f3d3f971e8fb2e311135BE7E10513E0B0D`
* Deposit minimum amount per transaction: `0` ETH
* Withdraw Fee: `0.005` TT-ETH
* Withdraw minimum amount per transaction: `0.01` TT-ETH

### ERC20-TT

* Token address: `0x1E053D89E08c24aA2CE5C5B4206744Dc2D7BD8F5`
* Foreign bridge contract address: `0x49D267C36d25CDCD8E35c2fa3D6828552aaC19C8`
* Corresponding token on ThunderCore: TT
* Home bridge contract address: `0xf7BB8e8Bf385C9a3412F7F3762CA957F126992f9`
* Deposit minimum amount per transaction: `0` ERC20-TT
* Withdraw Fee: `500` TT
* Withdraw minimum amount per transaction: `1000` TT

### ERC20-NUM

* Token address: `0x3496B523e5C00a4b4150D6721320CdDb234c3079`
* Foreign bridge contract address: `0xDb4B8f08975a2cb4B1FfB6183C32bb0623Ef7E85`
* Corresponding token on ThunderCore: TT-NUM `0x9BAFB0Da04147276711721627Bf37b026dbfe10F`
* Home bridge contract address: `0x2938201EdC6E0BC92151622735E4ab90b8ae8B81`
* Deposit minimum amount per transaction: `0` ERC20-NUM
* Withdraw Fee: `0` NUM
* Withdraw minimum amount per transaction: `200` TT-NUM

## Kovan testnet

All information below can be found on [ThunderBridgeTestnetUI](https://bridge-venus.thundercore.com/eth/)

### ERC20-USDT

* Token address: `0x4B0b6E093a330c00fE614B804Ad59e9b0A4FE8A9`
* Foreign bridge contract address: `0x2eEeC8e67555846bbA37f28043Eb4f559C897Df2`
* Corresponding token on ThunderCore: TT-USDT (`0xB1Fb0b14Ffea209ABa1e62ff3F2F3DFD2eaa9FE0`)
* Home bridge contract address: `0xBF848476876fe698f4a92C2AD025D75C6A4e9a18`
* Deposit minimum amount per transaction: `0` ERC20-USDT
* Withdraw Fee: `5` TT-USDT
* Withdraw minimum amount per transaction: `10` TT-USDT

### ERC20-USDC

* Token address: `0x8C6B55324A8594F9D67A5Afb85bf0D63F1B7c0d3`
* Foreign bridge contract address: `0x9bd827619324409a2a9F96E5330F78F27c318Af5`
* Corresponding token on ThunderCore: TT-USDC (`0x1d8e61c62ceC1aabd2c36cd22E54Ba831c805f8B`)
* Home bridge contract address: `0x6e427b317C43400644d8d038BE89664B25C0BC81`
* Deposit minimum amount per transaction: `10` ERC20-USDC
* Withdraw Fee: `5` TT-USDC
* Withdraw minimum amount per transaction: `1` TT-USDC

### ERC20-WBTC

* Token address: `0xf68da3731aFF951882e845587011F76F37e5b64A`
* Foreign bridge contract address: `0xAfc9009b36221dFca8a285225E23911cd17f9A2f`
* Corresponding token on ThunderCore: TT-WBTC (`0xAb2b4a86a9d21AB43B3e2B4B29FF6b8616ED33B6`)
* Home bridge contract address: `0xc79Fa351ceAFDD4F509eb169315FB45d8e4857a7`
* Deposit minimum amount per transaction: `0` ERC20-WBTC
* Withdraw Fee: `0` TT-WBTC
* Withdraw minimum amount per transaction: `0.001` TT-WBTC

### ETH

* Foreign bridge contract address: `0x3F7162811FBc61Eb1Cb0A444c324aFd0F327f317`
* Corresponding token on ThunderCore: TT-ETH (`0x6757D10620c46219aF1E2f0E23144682d1aDBCC2`)
* Home bridge contract address: `0xbA7d144f75EA3240f82ddA53EE7DDede30C0f7B1`
* Deposit minimum amount per transaction: `0` ETH
* Withdraw Fee: `0.015` TT-ETH
* Withdraw minimum amount per transaction: `0.03` TT-ETH

### ERC20-TT

* Token address: `0xfdEB257d34B2cac7F9ab7A14C81d1A893D0746ee`
* Foreign bridge contract address: `0xfdEB257d34B2cac7F9ab7A14C81d1A893D0746ee`
* Corresponding token on ThunderCore: TT
* Home bridge contract address: `0x627a95f4eD7Fd4f58B037486307AA334e275b77B`
* Deposit minimum amount per transaction: `0` ERC20-TT
* Withdraw Fee: `0` TT
* Withdraw minimum amount per transaction: `1` TT

### ERC20-NUM

* Token address: `0x46C33cEeF4340D582d004ecaff21e35B464Cab21`
* Foreign bridge contract address: `0x8FFf76ED8C9DC4Ded0b4A065Ba977ec18DaF5214`
* Corresponding token on ThunderCore: TT-NUM `0x56D4Dc31042Fdb364076bbDb7D2Ad5F651102206`
* Home bridge contract address: `0xbbd40D44f16F629991d162305853FaF0434097BF`
* Deposit minimum amount per transaction: `0` ERC20-NUM
* Withdraw Fee: `100` NUM
* Withdraw minimum amount per transaction: `100` TT-NUM


# BNB chain <> ThunderCore

The BNB chain is also known as BSC, or the Binance Smart Chain.

## BNB chain Mainnet

All information can be found on [ThunderBridgeUI](https://bridge.thundercore.com/bsc/)

### BNB

* Foreign bridge contract address: `0x3E14602186DD9dE538F729547B3918D24c823546`
* Corresponding token on ThunderCore: TT-BNB (`0x8EF1A1E0671Aa44852f4d87105eF482470bB3e69`)
* Home bridge contract address: `0x777f993F9A11B401DFee1a86acBE6a67541E16E9`
* Deposit minimum amount per transaction: `0` BNB
* Withdrawal Fee: `0.003` TT-BNB
* Withdraw minimum amount per transaction: `0.03` TT-BNB

### BEP20-BUSD

* Token address: `0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56`
* Foreign bridge contract address: `0xe4a017b0B830f16969916b00efA4db4f4932565b`
* Corrosponding token on ThunderCore: TT-BUSD (`0xBEB0131D95AC3F03fd15894D0aDE5DBf7451d171`)
* Home bridge contract address: `0x840E8bE3Cf806ab0f0383c75f2033c5e4DD24af1`
* Deposit minimum amount per transaction: `0` BEP20-BUSD
* Withdraw Fee: `1` TT-BUSD
* Withdraw minimum amount per transaction: `10` TT-BUSD

### BEP20-TT

* Token address: `0x990E7154bB999FAa9b2fa5Ed29E822703311eA85`
* Foreign bridge contract address: `0xAD23b02673214973E354D41e19999D9E01F3Be58`
* Corresponding token on ThunderCore: TT
* Home bridge contract address: `0x2521D6b1F5350D5198e2A7A30FD6A23EE603B7aA`
* Deposit minimum amount per transaction: `0` BEP20-TT
* Withdraw Fee: `100` TT
* Withdraw minimum amount per transaction: `1000` TT

## BSC Testnet

All information can be found on [ThunderBridgeTestUI](https://bridge-venus.thundercore.com/bsc/)

### BNB

* Foreign bridge contract address: `0xBD49f5edE1DF5f39b075B2fE708c15187B2d7274`
* Corresponding token on ThunderCore: TT-BNB (`0xCFefA2AeA9f067A366Ab5c403DABe0139b5a5f15`)
* Home bridge contract address: `0xCCcef719feeD88E02A57b0ef25e2eC68b357E326`
* Deposit minimum amount per transaction: `0` BNB
* Withdraw Fee: `0` TT-BNB
* Withdraw minimum amount per transaction: `0.02` TT-BNB

### BEP20-BUSD

* Token address: `0x72Fb36B35E5323780634aB8532ffA9dfe731bA56`
* Foreign bridge contract address: `0x1E84c25d304050Fa4207301D1EE1a376289a8D65`
* Corresponding token on ThunderCore: TT-BUSD (`0x0538575FD08d69166AB528aA62C1ba46E3cA3Ae8`)
* Home bridge contract address: `0xA48613621c1b8c95fb2B96e4d3014FDa8aDCeF48`
* Deposit minimum amount per transaction: `0` BEP20-BUSD
* Withdraw Fee: `0` TT-BUSD
* Withdraw minimum amount per transaction: `5` TT-BUSD

### BEP20-TT

* Token address: `0xCB2Bf4F60072C6d198F878D9952AdDecB3211865`
* Foreign bridge contract address: `0xd399923bc73514DD5EbcF217DbA18dB0B7c7A936`
* Corresponding token on ThunderCore: TT
* Home bridge contract address: `0x360b04072749338Bc21391714Ec23D3d309AE1f2`
* Deposit minimum amount per transaction: `0` BEP20-TT
* Withdraw Fee: `0` TT
* Withdraw minimum amount per transaction: `0.1` TT


# Interact with ThunderCore Bridge

Since the main function of the bridge is to transfer assets across different networks, the way to interact with ThunderCore bridge is quite straightforward.

The only thing that you have to do is to transfer supported tokens to the bridge address directly.

Supported tokens can be found in the following documents:

* [Ethereum](/product-protocol/bridges/ethereum-contract-address)
* [BNB chain](/product-protocol/bridges/bsc-contract-address)

## Transfer Native Token to ThunderCore

In the ThunderCore Bridge, we currently support transfering ETH from Ethereum, BNB from BSC, and HT from HECO to ThunderCore. Here's an example how it works:

```js
let transaction = {
  to: FOREIGN_BRIDGE_ADDRESS,
  data: '',
  value: VALUE,
  gasPrice: GAS_PRICE,
  gas: GAS_LIMIT,
};

const result = await web3.eth.sendTransaction(transaction);
console.log(`transactionHash: ${result.transactionHash}`);
```

If you need to transfer tokens to a custom recipient in ThunderCore, replace the data part in transaction like as shown below

```js
const ERC20 = new web3.eth.Contract(ERC20ABI, FOREIGN_TOKEN_ADDRESS)
const data = await ERC20.methods.transfer(FOREIGN_BRIDGE_ADDRESS, VALUE).encodeABI({from: SENDER_ADDRESS});

// CUSTOM_RECIPIENT should start with 0x
data += `000000000000000000000000${CUSTOM_RECIPIENT.slice(2)}`;
```

## Transfer ERC20 to ThunderCore

To transfer ERC20 tokens to ThunderCore, try the example shown below

```js
const ERC20 = new web3.eth.Contract(ERC20ABI, FOREIGN_TOKEN_ADDRESS);
const data = await ERC20.methods.transfer(FOREIGN_BRIDGE_ADDRESS, VALUE).encodeABI({from: SENDER_ADDRESS})

const transaction = {
    gasPrice: GAS_PRICE,
    data,
    gas: GAS_LIMIT,
    from: SENDER_ADDRESS,
    to: FOREIGN_TOKEN_ADDRESS,
    value: '0',
};

await web3.eth.sendTransaction(transaction);
```

The corresponding tokens will be transfered to `SENDER_ADDRESS` in a while on foreign chain.

If you need to transfer tokens to a custom recipient in ThunderCore, add the recipient behind the data part before you send the transaction.

```js
// CUSTOM_RECIPIENT should start with 0x
data += `000000000000000000000000${CUSTOM_RECIPIENT.slice(2)}`;
```

## Transfer TT20 to Foreign

On ThunderCore, most of the bridge token are [ERC677](https://github.com/ethereum/EIPs/issues/677), we use `transferAndCall` function to call `onTokenTransfer` in bridge contract. Here's an example:

```js
const ERC677 = new web3.eth.Contract(ERC677ABI, HOME_TOKEN_ADDRESS);
let data = await ERC677.methods.transferAndCall(HOME_BRIDGE_ADDRESS, VALUE, "0x").encodeABI({from: SENDER_ADDRESS})

// if you want to send the token to custom address in foreign chain, CUSTOM_RECIPIENT should start with 0x
if (CUSTOM_RECIPIENT) {
    data += `000000000000000000000000${CUSTOM_RECIPIENT.slice(2)}`;
}

let transaction = {
  to: HOME_TOKEN_ADDRESS,
  data,
  value: "0",
  gasPrice: GAS_PRICE,
  gas: GAS_LIMIT,
};

await web3.eth.sendTransaction(transaction);
```

and part of `ERC677ABI` is

```json
[
  {
    "constant": false,
    "inputs": [
      {
        "name": "_to",
        "type": "address"
      },
      {
        "name": "_value",
        "type": "uint256"
      },
      {
        "name": "_data",
        "type": "bytes"
      }
    ],
    "name": "transferAndCall",
    "outputs": [
      {
        "name": "",
        "type": "bool"
      }
    ],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  }
]
```


# Game Development


# MetaFab

The free, end-to-end, self-serve solution for games and gamified apps to integrate powerful blockchain infrastructure in minutes.

ThunderCore has partnered with MetaFab to make building gaming or gamefi dapp easier than in the past. As a developer, you can now deploy your code via MetaFab in a super fast way. With lots of SDKs supported by MetaFab, developing an amazing gaming or gamefi dapp will not be a nightmare anymore.

To learn more about MetaFab, please refer to below links:

* [MetaFab Introduction](https://docs.trymetafab.com/docs/getting-started)
* [Language & Framework SDKs](https://docs.trymetafab.com/docs/language-framework-sdks)
* [Tutorials](https://docs.trymetafab.com/docs/first-steps-start-here)


# DApp Development


# Faucet

ThunderCore testnet faucet provides TST to developers to test DApps without using their own token. Currently you can get TST every 86400 seconds.

Before you begin, you'll need a wallet address that supports TST. Any address created for Ethereum will work on ThunderCore. You can use MetaMask and/or any other popular Ethereum wallet to create a ThunderCore address. To access the ThunderCore blockchain all you have to do is to point the network RPC to ThunderCore RPC url which can be found [here](/network-details/thundercore-testnet).

To get TST on testnet, please visit [ThunderCore testnet Faucet](https://faucet-testnet.thundercore.com).


# Random Number Generator

**Summary**

The ThunderCore blockchain supports generating cryptographically secure 256-bit random numbers through a Thunder trusted random number generating pre-compiled contract.

**Motivation**

When developing smart contracts for Ethereum, developers do not have built-in support for generating cryptographically secure random numbers. While there are some possible solutions (e.g. using Ethereum Alarm r Oraclize), these solutions often rely on external services and are not scalable. To address this need, ThunderCore has implemented built-in support to generate cryptographically secure random numbers through a pre-compiled contract.

**Specification** ThunderCore has implemented a pre-compiled contract which resides at address `0x8cC9C2e145d3AA946502964B1B69CE3cD066A9C7`. This address is the first 20 bytes of `sha256("Thunder_Random")`. Each invocation of fallback function of trusted random generator precompiled contract will return a 256-bit random number. The gas cost for each invocation is `1265040`. Below is an example which can be embedded into a smart contract. ThunderCore also provides a library which can be sued in Remix with `import "github.com/thundercore/RandomLibrary/RandomInterface.sol` from Github with URL in Remix. The random number generator will always return a `bytes32` value, so you will need to cast or convert this value as it suits your needs.

```
interface ThunderRandomLibraryInterface {
    function rand() external returns (uint256);
}
```

**Example** In the basic example shown below, a random number is used to determine whether the contract will pay the user. If the number is greater than the bet from the user, the contract takes the user's wager. If not, the contract pays the user their own bet plus 1.

> Note: the `require(msg.sender == tx.origin)` check in `bet()` is necessary for security and explained below.

```
pragma solidity ^0.8.9;

interface ThunderRandomLibraryInterface {
    function rand() external returns (uint256);
}

contract RandomExampleInterfaceVersion {
    event didWin(bool);
    uint256 public contractBalance;
    // Random precompiled contract address is 0x8cC9C2e145d3AA946502964B1B69CE3cD066A9C7
    address constant public randomNumberContractAddress = 0x8cC9C2e145d3AA946502964B1B69CE3cD066A9C7; 
    ThunderRandomLibraryInterface internal RNGLibrary;

    constructor() payable {
        contractBalance = uint256(msg.value);
        RNGLibrary = ThunderRandomLibraryInterface(randomNumberContractAddress);
    }

    function betNumber(uint256 bet) payable external returns (bool) {
        // block calls from other contracts to prevent "revert transaction unless I won" attacks
        require(msg.sender == tx.origin);
        
        if (msg.value < 5) {
            contractBalance = contractBalance + msg.value;

            emit didWin(false);
            return false;
        }

        uint256 randomNumber = RNGLibrary.rand();
        address payable sender = payable(msg.sender);
        if (bet < randomNumber) {
            sender.transfer(msg.value+1);
            emit didWin(true);

            contractBalance = contractBalance - 1;
            return true;
        }

        contractBalance = contractBalance + msg.value;
        emit didWin(false);
        return false;
    }
}
```

**How to prevent Revert the Transaction Unless I Won attacks** There's a conceptually simple approach to attack any game of chance on EVM compatible blockchains. The attacker would deploy a contract and do something like:

1. Play a game of chance
2. Check if the balance in the attacker's contract decreased after the game
3. Revert the transaction if the contract balance decreased

In Solidity, the attack would look like this:

```solidity
    function attack(uint256 v) public  {
        uint256 pool = this.balance;
        /* play game of chance ... */
        require(this.balance >= pool);
    }
```

Add a `require(msg.sender == tx.origin)` check at the beginning of your `bet` function prevents other contracts from calling your own and thus blocks the attack. See the [Block and Transaction Properties](https://docs.soliditylang.org/en/v0.4.25/units-and-global-variables.html#block-and-transaction-properties) section in [Solidity in Depth](https://docs.soliditylang.org/en/v0.4.25/solidity-in-depth.html) for details:

* `msg.sender (address)`: sender of the message (current call)
* `tx.origin (address)`: sender of the transaction (full call chain)


# Oracles

ThunderCore oracle provides a series of asset prices on the chain to make your smart contract connect with real world.

For projects already integrated with [Chainlink](https://chain.link) data feed , we are providing the same function interfaces to make your project cross-chain onto ThunderCore instantly.

{% hint style="danger" %}
**Pending for Review**

This is pre-release version section. Contents can be changed anytime, please use in your caution.
{% endhint %}

## Get Started

You can get the latest contract interfaces and ABIs through [npm](https://docs.npmjs.com):

```bash
$ npm install @thundercore/oracle
```

or [Yarn](https://yarnpkg.com/getting-started/install):

```bash
$ yarn add @thundercore/oracle
```

And just a few lines of code, so you can get the latest price:

{% tabs %}
{% tab title="New project" %}

```solidity
import { FeedRegistryConsumerInterface } from '@thundercore/oracle/TTOracle.sol';

contract MyProject {
    address public constant TT_ORACLE = 0xD477d4d8132C6fce38f0bf38f46FcB62D6c5ddaE;

    function getThunderTokenPrice() public view returns (int256) {
        (
            /* uint80 roundId */,
            int256 answer,
            /* uint256 startedAt */,
            /* uint256 updatedAt */,
            /* uint80 answeredInRound */
        ) = FeedRegistryConsumerInterface(TT_ORACLE)
                .latestRoundData('TT/USDT');

        return answer;
    }
}
```

{% endtab %}

{% tab title="Project integrated with Chainlink" %}

```solidity
import { FeedRegistryInterface } from "@chainlink/contracts/src/v0.8/interfaces/FeedRegistryInterface.sol";
import { Denominations } from '@thundercore/oracle/TTOracle.sol';

contract MyProject {
    address public constant TT_ORACLE = 0xD477d4d8132C6fce38f0bf38f46FcB62D6c5ddaE;

    function getThunderTokenPrice() public view returns (int256) {
        (
            /* uint80 roundId */,
            int256 answer,
            /* uint256 startedAt */,
            /* uint256 updatedAt */,
            /* uint80 answeredInRound */
        ) = FeedRegistryInterface(TT_ORACLE)
                .latestRoundData(
                    Denominations.TT,
                    Denominations.USDT
                );

        return answer;
    }
}
```

{% endtab %}

{% tab title="Truffle (web3.js)" %}

```bash
# npm exec -- truffle console --network thundercore
# or
# yarn truffle console --network thundrcore
truffle(thundercore)> const abi = require('@thundercore/oracle/abi/FeedRegistryConsumerInterface.json')

truffle(thundercore)> const oracle = new web3.eth.Contract(abi, TT_ORACLE)

truffle(thundercore)> oracle.methods.latestRoundData('TT/USDT').call().then(res => res.answer).then(web3.utils.fromWei)
'0.01663655'
```

{% endtab %}

{% tab title="Hardhat (ethers.js)" %}

```bash
# npm exec -- hardhat console --network thundercore
# or
# yarn truffle console --network thundrcore
> const abi = require('@thundercore/oracle/abi/FeedRegistryConsumerInterface.json')

> const oracle = new hre.ethers.Contract(TT_ORACLE, abi, hre.ethers.provider)

> await oracle.latestRoundData('TT/USDT').then(res => res.answer).then(hre.ethers.utils.formatEther)
'0.01663655'
```

{% endtab %}
{% endtabs %}

You can try it on ThunderCore testnet:

{% embed url="<https://codepen.io/o-p/pen/jOGLgbv>" %}
ThunderCore Testnet Oracle Example
{% endembed %}

## Using Data Feeds

Data Feeds are the quickest way to connect with the real-world asset prices.

{% hint style="info" %}
**Feed Registry**

You can use the [Feed Registry](#feed-registry) to reference data feed assets by pair name or currency identifier.
{% endhint %}

### Solidity

To consume price data, your smart contract should reference `DataFeedConsumerInterface`, which defines the external functions implemented by Data Feeds.

{% hint style="info" %}
If you've applied Chainlink aggregator in your service, i.e. [`AggregatorInterface`](https://github.com/smartcontractkit/chainlink/blob/d8982d45739a2157c3c5d73d2462b8b449165308/contracts/src/v0.8/interfaces/AggregatorInterface.sol), [`AggregatorV3Interface`](https://github.com/smartcontractkit/chainlink/blob/d8982d45739a2157c3c5d73d2462b8b449165308/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol), or [`AggregatorV2V3Interface`](https://github.com/smartcontractkit/chainlink/blob/d8982d45739a2157c3c5d73d2462b8b449165308/contracts/src/v0.8/interfaces/AggregatorV2V3Interface.sol), you don't have to change the interface. The only difference is the feed address, just change it and test the result on the fly.
{% endhint %}

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;

import { DataFeedConsumerInterface } from "@thundercore/oracle/TTOracle.sol";

contract PriceConsumer {

    DataFeedConsumerInterface internal priceFeed;

    /**
     * Network: ThunderCore testnet [18]
     * Pair: TT/USDT
     * Address: 0x1Ce18a95C56Db619C070AeF58918EaB09FE2634c
     */
    constructor() {
        priceFeed = DataFeedConsumerInterface(0x1Ce18a95C56Db619C070AeF58918EaB09FE2634c);
    }

    /**
     * Returns the latest price
     */
    function getLatestPrice() public view returns (int256) {
        (
            /* uint80 roundID */,
            int256 price,
            /* uint256 startedAt */,
            /* uint256 updatedAt */,
            /* uint80 answeredInRound */
        ) = priceFeed.latestRoundData();

        return price;
    }
}
```

The `latestRoundData` function returns five values representing information about the latest price data. See the [Data Feeds API Reference](#api-reference) for more details.

### ECMAScript (JavaScript)

{% tabs %}
{% tab title="web3.js (Node.js)" %}

```javascript
const Web3 = require('web3')
const web3 = new Web3('https://testnet-rpc.thundercore.com')
const abi = require('@thundercore/oracle/abi/DataFeedConsumerInterface.json')
const address = '0x1Ce18a95C56Db619C070AeF58918EaB09FE2634c'
const priceFeed = new web3.eth.Contract(abi, address)

priceFeed.methods.latestRoundData().call()
    .then(res => res.answer)
    .then(web3.utils.fromWei)
    .then((price) => { console.log(price) })
```

{% endtab %}

{% tab title="ethers.js (Node.js)" %}

```javascript
const { ethers } = require('ethers')
const provider = new ethers.providers.JsonRpcProvider('https://testnet-rpc.thundercore.com')
const abi = require('@thundercore/oracle/abi/DataFeedConsumerInterface.json')
const address = '0x1Ce18a95C56Db619C070AeF58918EaB09FE2634c'
const priceFeed = new ethers.Contract(address, abi, provider)

priceFeed.latestRoundData()
    .then(({ answer }) => { console.log(ethers.utils.formatEther(answer)) })
```

{% endtab %}
{% endtabs %}

### Python

This example uses [Web3.py](https://web3py.readthedocs.io/en/stable/) to retrieve feed data from the TT/USDT feed on the ThunderCore testnet network.

```python
from web3 import Web3
web3 = Web3(Web3.HTTPProvider('https://testnet-rpc.thundercore.com'))
abi = '[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"int256","name":"current","type":"int256"},{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"updatedAt","type":"uint256"}],"name":"AnswerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":true,"internalType":"address","name":"startedBy","type":"address"},{"indexed":false,"internalType":"uint256","name":"startedAt","type":"uint256"}],"name":"NewRound","type":"event"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"description","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint80","name":"roundId","type":"uint80"}],"name":"hasRoundData","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint80","name":"_roundId","type":"uint80"}],"name":"getRoundData","outputs":[{"internalType":"uint80","name":"roundId","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestRoundData","outputs":[{"internalType":"uint80","name":"roundId","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint80","name":"roundId","type":"uint80"}],"name":"getPreviousRoundId","outputs":[{"internalType":"uint80","name":"","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint80","name":"roundId","type":"uint80"}],"name":"getNextRoundId","outputs":[{"internalType":"uint80","name":"","type":"uint80"}],"stateMutability":"view","type":"function"}]'
addr = '0x1Ce18a95C56Db619C070AeF58918EaB09FE2634c'
contract = web3.eth.contract(address=addr, abi=abi)
latestData = contract.functions.latestRoundData().call()
print(latestData)
```

### Getting a different price denomination

If you require a denomination other than what we have provided, you can use two data feeds to derive the pair that you need. For example, if you need a `TT/ETH` price, you could take the `TT/USDT` feed and the `ETH/USDT` feed and derive `TT/ETH` using division.

$$
\frac{TT / USDT}{ETH / USDT} = \frac{TT / \sout{USDT}}{ETH / \sout{USDT}} = TT / ETH
$$

## Historical Price Data

The most common use case for data feeds is to get the latest price. However, we also exposes functions which can be used to retrieve price data of a previous round ID.

{% hint style="warning" %}
**Never over rely on previous round data of oracle**

If your project requires price before one week or longer ago, always store those prices inside your smart contract.

In ThunderCore oracle, we guarantee to keeps one recent week prices. And after one week, those data could be purged anytime.
{% endhint %}

### Solidity

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;

import { DataFeedConsumerInterface } from "@thundercore/oracle/TTOracle.sol";

contract HistoricalPriceConsumer {

    DataFeedConsumerInterface internal priceFeed;

    /**
     * Network: ThunderCore testnet [18]
     * Pair: TT/USDT
     * Address: 0x1Ce18a95C56Db619C070AeF58918EaB09FE2634c
     */
    constructor() {
        priceFeed = DataFeedConsumerInterface(0x1Ce18a95C56Db619C070AeF58918EaB09FE2634c);
    }

    /**
     * Returns historical price for a round id
     */
    function getHistoricalPrice(uint80 roundId) public view returns (int256) {
        require(priceFeed.hasRoundData(roundId), 'No this round data');

        (
            /* uint80 roundID */,
            int256 price,
            /* uint256 startedAt */,
            /* uint256 updatedAt */,
            /* uint80 answeredInRound */
        ) = priceFeed.getRoundData(roundId);

        return price;
    }
}
```

### ECMAScript (JavaScript)

{% tabs %}
{% tab title="web3.js (Node.js)" %}

```javascript
const Web3 = require('web3')
const web3 = new Web3('https://testnet-rpc.thundercore.com')
const abi = require('@thundercore/oracle/abi/DataFeedConsumerInterface.json')
const address = '0x1Ce18a95C56Db619C070AeF58918EaB09FE2634c'
const priceFeed = new web3.eth.Contract(abi, address)

priceFeed.methods.getRoundData(1).call()
    .then(res => res.answer)
    .then(web3.utils.fromWei)
    .then((price) => { console.log(price) })
```

{% endtab %}

{% tab title="ethers.js (Node.js)" %}

```javascript
const { ethers } = require('ethers')
const provider = new ethers.providers.JsonRpcProvider('https://testnet-rpc.thundercore.com')
const abi = require('@thundercore/oracle/abi/DataFeedConsumerInterface.json')
const address = '0x1Ce18a95C56Db619C070AeF58918EaB09FE2634c'
const priceFeed = new ethers.Contract(address, abi, provider)

priceFeed.getRoundData(1)
    .then(({ answer }) => { console.log(ethers.utils.formatEther(answer)) })
```

{% endtab %}
{% endtabs %}

### Python

```python
from web3 import Web3
web3 = Web3(Web3.HTTPProvider('https://testnet-rpc.thundercore.com'))
abi = '[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"int256","name":"current","type":"int256"},{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"updatedAt","type":"uint256"}],"name":"AnswerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":true,"internalType":"address","name":"startedBy","type":"address"},{"indexed":false,"internalType":"uint256","name":"startedAt","type":"uint256"}],"name":"NewRound","type":"event"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"description","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint80","name":"roundId","type":"uint80"}],"name":"hasRoundData","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint80","name":"_roundId","type":"uint80"}],"name":"getRoundData","outputs":[{"internalType":"uint80","name":"roundId","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestRoundData","outputs":[{"internalType":"uint80","name":"roundId","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint80","name":"roundId","type":"uint80"}],"name":"getPreviousRoundId","outputs":[{"internalType":"uint80","name":"","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint80","name":"roundId","type":"uint80"}],"name":"getNextRoundId","outputs":[{"internalType":"uint80","name":"","type":"uint80"}],"stateMutability":"view","type":"function"}]'
addr = '0x1Ce18a95C56Db619C070AeF58918EaB09FE2634c'
contract = web3.eth.contract(address=addr, abi=abi)
roundData = contract.functions.getRoundData(1).call()
print(roundData)
```

## Feed Registry

The Feed Registry is an on-chain mapping of assets to feeds. It enables you to query data feeds from asset addresses directly, without needing to know the feed contract addresses.

### Base and Quote

You are free to choose querying feeds from their pair names, e.g. `TT/USDT`; or you can keep Chainlink style by token addresses.

{% tabs %}
{% tab title="Query by pair name" %}

```solidity
registry.latestRoundData('TT/USDT');
```

{% endtab %}

{% tab title="Query by address" %}

```solidity
registry.latestRoundData(
    Denominations.TT,
    Denominations.USDT
);
```

{% endtab %}
{% endtabs %}

### Solidity example code

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;

import { FeedRegistryInterface } from '@thundercore/oracle/TTOracle.sol';

contract PriceConsumer {
    FeedRegistryInterface internal registry;

    /**
     * Network: ThunderCore testnet
     * Feed Registry: 0xD477d4d8132C6fce38f0bf38f46FcB62D6c5ddaE
     */
    constructor(address _registry) {
        registry = FeedRegistryInterface(_registry);
    }

    /**
     * Returns the TT / USDT price
     */
    function getTTPrice() public view returns (int) {
        (
            uint80 roundID,
            int256 price,
            uint256 startedAt,
            uint256 timeStamp,
            uint80 answeredInRound
        ) = registry.latestRoundData('TT/USDT');
        return price;
    }
}
```

### ECMAScript (JavaScript) example

```javascript
const Web3 = require('web3')
const web3 = new Web3('https://testnet-rpc.thundercore.com')
const abi = require('@thundercore/oracle/abi/FeedRegistryConsumerInterface.json')
const address = '0xD477d4d8132C6fce38f0bf38f46FcB62D6c5ddaE'
const registry = new web3.eth.Contract(abi, address)

registry.methods.latestRoundData('TT/USDT').call()
    .then(res => res.answer)
    .then(web3.utils.fromWei)
    .then((price) => { console.log(price) })
```

## API Reference

API reference for `DataFeedConsumerInterface`.

| Name                                        | Description                                  |
| ------------------------------------------- | -------------------------------------------- |
| [`decimals`](#decimals)                     | Decimals of "answer" in responsed round data |
| [`description`](#description)               | Feed pair name, format "${BASE}/${QUOTE}"    |
| [`version`](#version)                       | The code version of the feed proxy points to |
| [`hasRoundData`](#hasrounddata)             | Check if the round data existed              |
| [`getRoundData`](#getrounddata)             | Get data from a specific round               |
| [`latestRoundData`](#latestrounddata)       | Get data from the latest round               |
| [`getPreviousRoundId`](#getpreviousroundid) | Get previous data existed round ID           |
| [`getNextRoundId`](#getnextroundid)         | Get next data existed round ID               |

#### decimals

Get the decimals of "answer" in responsed round data

```solidity
function decimals() external view returns (uint8)
```

* `RETURN`: The number of decimals.

#### description

Get the feed pair name, format "${BASE}/${QUOTE}"

```solidity
function description() external view returns (string memory);
```

* `RETURN`: The pair name of data feed.

#### version

Get the code version of the feed proxy points to

```solidity
function version() external view returns (uint256);
```

* `RETURN`: The code version.

#### hasRoundData

Check if the round data existed

```solidity
function hasRoundData(uint80 roundId) external view returns (bool);
```

* **Petermeters**
  * `roundId`: The round ID to check if round data existed in data feed.
* **Return Values**
  * `RETURN`: Round data exists or not.

#### getRoundData

Get data from a specific round

```solidity
function getRoundData(uint80 _roundId)
    external
    view
    returns (
        uint80 roundId,
        int256 answer,
        uint256 startedAt,
        uint256 updatedAt,
        uint80 answeredInRound
    );
```

* **Petermeters**
  * `roundId`: The round ID
* **Return Values**
  * `roundId`: The round ID.
  * `answer`: The price.
  * `startedAt`: Timestamp of when the round started.
  * `updatedAt`: Timestamp of when the round was last updated.
  * `answeredInRound`: The round ID of the round in which the answer was computed.

#### latestRoundData

Get data from the latest round

```solidity
function latestRoundData()
    external
    view
    returns (
        uint80 roundId,
        int256 answer,
        uint256 startedAt,
        uint256 updatedAt,
        uint80 answeredInRound
    );
```

* **Return Values**
  * `roundId`: The round ID.
  * `answer`: The price.
  * `startedAt`: Timestamp of when the round started.
  * `updatedAt`: Timestamp of when the round was last updated.
  * `answeredInRound`: The round ID of the round in which the answer was computed.

#### getPreviousRoundId

Get previous data existed round ID

```solidity
function getPreviousRoundId(uint80 roundId) external view returns (uint80);
```

* **Petermeters**
  * `roundId`: The round ID to look up closest previous valid round ID.
* **Return Values**
  * `RETURN`: The previous valid round ID to parameter specified round ID; return 0 if no valid round ID before.

#### getNextRoundId

Get next data existed round ID

```solidity
function getNextRoundId(uint80 roundId) external view returns (uint80);
```

* **Petermeters**
  * `roundId`: The round ID to look up closest next valid round ID.
* **Return Values**
  * `RETURN`: The next valid round ID to parameter specified round ID; return 0 if no valid round ID after.

## Contract Addresses

{% tabs %}
{% tab title="ThunderCore mainnet (108)" %}
**FeedRegistry:** `0x70B3B30066b4F7B927f26C408461b3F176AA07Dc`

|     Pair     | Dec | Proxy                                        |
| :----------: | --: | -------------------------------------------- |
|   `TT/USDT`  |  18 | `0x0808Ac0b6f4B502C59e40D147dDA7Bfa1AE7BD6C` |
|  `ETH/USDT`  |  18 | `0x1Cc8dE741C6d32c321B46a23D8289F337aBEf4D9` |
|  `WBTC/USDT` |  18 | `0x632Ce66C7C973eE2662F207cBbA04A6E2d9B91bb` |
|  `BNB/USDT`  |  18 | `0xFB19d0dC0194A99913Daaa3d11f8d00ff4affa81` |
|   `HT/USDT`  |  18 | `0x53BD5eB3fF53F19F1eD7871D48B200f3312E8017` |
| {% endtab %} |     |                                              |

{% tab title="ThunderCore testnet (18)" %}
**FeedRegistry:** `0xD477d4d8132C6fce38f0bf38f46FcB62D6c5ddaE`

|      Pair     | Dec | Proxy                                        |
| :-----------: | --: | -------------------------------------------- |
|   `TT/USDT`   |  18 | `0x1Ce18a95C56Db619C070AeF58918EaB09FE2634c` |
|   `ETH/USDT`  |  18 | `0x555Ad57b0EA33e2ac49D267C96eF98aa254a54c4` |
|  `WBTC/USDT`  |  18 | `0x83Ac10Bc6dC02E07c71dfBF45ca7355675D340B5` |
|   `BNB/USDT`  |  18 | `0xcE6bd682263F58e1e2828ccA5AEc6A671FFfd739` |
|   `HT/USDT`   |  18 | `0xB6FEB586A86b4C542295E1232B45DE5F80961a16` |
|  {% endtab %} |     |                                              |
| {% endtabs %} |     |                                              |


# Referral Library

Referrals are one of the most effective forms of marketing to gain exposure and drive users to your DApp. Lots of popular DApps such as Fomo3d, MyCrypto Heroes, HyperSnake, as well as many others use referrals as a mechanism for success.

Hence, we've built a referral library: [Referral Solidity](https://github.com/thundercore/referral-solidity), to help DApp developers to quickly build their own referral mechanisms. In this document we will share how to use our library.

**Referral Solidity Library** Check out our basic multi-level referral: <https://github.com/thundercore/referral-solidity/>. With this library, you can gain the following features in minutes:

* Up to three levels of referral system with native token (ETH,TT...)
* Pay referral bonus based on referee amount
* Pay instantly when downline joins
* Ensure that only active users will get the referral bonus

**How to use** First, install our library with the following command.

```
npm install @thundercore/referral-solidity
```

Then, integrate referral solidity with your DApp by importing, initializing, binding referral relationship with `addReferrer` function and trigger referral payment by `payReferral`.

```
pragma solidity ^0.5.0;
import '@thundercore/referral-solidity/contracts/Referral.sol';

contracts YourGame is Referral {
  // Referral(decimals, referralBonus, secondsUntilInactive, onlyRewardActiveReferrers, levelRate, refereeBonusRateMap)
  constructor() Referral (10000, 500, 1 days, true, [6000, 3000, 1000], [1, 10000]) public {
  }

  // bind uplineAddr as msg.sender's referrer
  function addUpline(address payable uplineAddr) public {
    addReferrer(upline);
  }

  // trigger pay referral in your business logic
  function play() public payable {
    payReferral(msg.value);
  }
}
```

In the line of `constructor() Referral (10000, 500, 1 days, true, [6000, 3000, 1000], [1, 10000])`. You may be confused what these parameters mean, thus please refer to the explanation for the parameters below:

```
Referral(decimals, referralBonus, secondsUntilInactive, onlyRewardActiveReferrers, levelRate, refereeBonusRateMap)
```

**decimals** `<unit>` Base decimals for all rate calculation in referral. For example. if `decimals`equals to `10000`, and `referralBonus` is `500`, that means the referral bonus rate is `5%`.

**referralBonus**`<unit>` The total referral bonus rate, will be divided by `decimals`. For example, if you would like to set a rate of `5%`, then set `referralBonus` as `50` when `decimals` is `1000`.

**secondsUntilInactive**`<unit>` How long, in seconds, a user will be inactive. For example, `one days`.

**onlyRewardActiveReferrers**`<bool>` The flag to enable whether not to pay inactive uplines.

**levelRate**`<uint[]>` The bonus rate for each level, which will be divided by decimals. For example, if the max depth level is 3, then the set levelRate as `[6000,3000,1000]` when `decimals` is `10000` for the following case:

|      | Level 1 | Level 2 | Level 3 |
| ---- | ------- | ------- | ------- |
| Rate | 60%     | 30%     | 10%     |

**refereeBonusRateMap**`<uint[]>` The bonus rate mapping to each referree amount will be divided by decimals too. If the max depth is 3, the map should be passed as \[`<lower amount>`,`<rate>`,...]. For example, you should pass `[1, 2500,5,5000,10,10000]` when decimals is `10000` for the following case:

|      | 1-4 | 5-9 | 10+  |
| ---- | --- | --- | ---- |
| Rate | 25% | 50% | 100% |

Let's see an example to understand it better!

**Example - Integrate to DoubleOrNothing**

Let's add referrals to Double or Nothing! To do so we will need to set up the referral rules first:

* A user would pay 3% for referral, in different referral levels would get 60%, 30%, 10% of 3%
* A user gets 50% of referral bonus when they refer less than 5 people, 75% for less than 25 people, and 100% when over 25 people
* A user needs to play within 24 hours to remain an active user, which means that if a user does not play once a day, this user cannot get the referral

So, assume: The referral sequence A ← B ← C ← D A has referrerd 25 people, B has 6 people and C has 1 person. When D bets 1TT, 3% of bet will go to the referral pool (0.03TT). Then each upline will get:

* A: 1 \* 0.03 \* 0.1 \* 1 = 0.003
* B: 1 \* 0.03 \* 0.3 \* 0.75 = 0.00675
* C: 1 \* 0.03 \* 0.6 \* 0.5 = 0.009

So the parameters we pass to constructor will be:

|       | decimals | referralBonus | secondsUntilInactive |      | onlyRewardActiveReferrers | levelRate              | refereeBnusRateMap     |
| ----- | -------- | ------------- | -------------------- | ---- | ------------------------- | ---------------------- | ---------------------- |
| value | 1000     | 30            | 86400                | true | \[600,200,100]            | \[1,500,5,750,25,1000] | \[1,500,5,750,25,1000] |

Now let's enable the referral!

**Contract**

First import and pass parameters to our referral contract:

```
pragma solidity 0.5.0;

import '@thundercore/referral-solidity/contracts/Referral.sol';
...

contract DoubleOrNothing is Ownable, Referral {
  ...
  constructor(
      uint _decimals,
      uint _referralBonus,
      uint _secondsUntilInactive,
      bool _onlyRewardActiveReferrers,
      uint256[] memory _levelRate,
      uint256[] memory _refereeBonusRateMap
  ) Referral(
      _decimals,
      _referralBonus,
      _secondsUntilInactive,
      _onlyRewardActiveReferrers,
      _levelRate,
      _refereeBonusRateMap
  ) public {}
  ...
```

Then, add overload bet function to bind referral upline when bet with the address.

```
function bet(address payable _referrer) payable external {
    if(!hasReferrer(msg.sender)) {
      addReferrer(_referrer);
    }
    bet();
  }
```

Next, add payReferral in bet function

```
function bet() payable public {
    // msg.value is added to the balance to begin with so you need to double it
    require( address(this).balance >= msg.value * 2, 'Balance too low!');
    uint256 winnings = 0;

    // DO NOT USE THIS IN PRODUCTION, IT IS INSECURE
    if(uint256(blockhash(block.number -1)) % 2 == 0) {
      // 3% is deducted to cover the referral bonus
      winnings = msg.value * 197/100;
      address(msg.sender).transfer(winnings);
    }
    payReferral(msg.value);
    emit BetSettled(msg.sender, winnings);
  }
```

Finally, to deploy our DoubleOrNothing, we need to pass parameters in the migrations.

```
// migrations/1_initial_migration.js
module.exports = function(deployer) {
  deployer.deploy(Migrations);
  deployer.deploy(
    Double,
    1000,
    30,
    86400,
    true,
    [600, 200, 100],
    [1, 500, 5, 750, 25, 1000]
  );
};
```

**Frontend** Now, you can get the referral data from public accounts in the contract, including the total amount of referees and the total referral bonus of a user.

```
this.props.contract.accounts(this.props.address).then((info: any) => {
  this.setState({
    accountInfo: {
      reward: info.reward.toString(),
      referredCount: info.referredCount.toString()
    }
  });
});
```

Then, you can paste the URL to get referrer, like`https://thundercore.github.io/DoubleOrNothing?referrer=0x26b067f40696c97a058658949ec011ed6a84afe3`. Then, trigger the smart contract by `contract.bet(address)` to bind uplines and `contract.bet()` for normal bet. The referral will pay directly when they bet.

For more information, please refer [here](https://github.com/thundercore/DoubleOrNothing).


# TTSwap Resources

TT Swap is a decentralized token exchange service based on the open-source protocol [Uniswap](https://uniswap.org/) and is deployed on ThunderCore.

**Documents, ABI and source code** For more information please refer to [ThunderCore Github repository](https://github.com/thundercore/ttswap-contracts#function-tokentotokentransferoutput).

***


# Wrapped TT Addresses

Wrapped TT can be traded directly with alt tokens; wTT can also be converted back to TT.

## wTT Address:

{% tabs %}
{% tab title="Mainnet" %}
{% code title="wTT on ThunderCore Mainnet" %}

```
0x413cEFeA29F2d07B8F2acFA69d92466B9535f717
```

{% endcode %}

{% embed url="<https://wtt.thundercore.com>" %}
You can manually swap TT <=> wTT here
{% endembed %}
{% endtab %}

{% tab title="Testnet" %}
{% code title="wTT on ThunderCore Testnet" %}

```
0x390127E81EDe57CFa1e65eA9A96bD68A59D0a099
```

{% endcode %}

{% embed url="<https://wtt-testnet.thundercore.com>" %}
You can manually swap testnet TT <=> wTT here
{% endembed %}
{% endtab %}
{% endtabs %}


# Multicall

Multicall aggregates results from multiple contract constant function calls.

## Multicall Contract Addresses:

{% tabs %}
{% tab title="ThunderCore Mainnet" %}

<table><thead><tr><th width="163" align="center">Contract</th><th width="456">Address</th><th>Verified</th></tr></thead><tbody><tr><td align="center"><code>Multicall</code></td><td><code>0x3017086DeEf56679e267F67F66c4415109b7A97f</code></td><td><a href="https://viewblock.io/thundercore/address/0x3017086DeEf56679e267F67F66c4415109b7A97f?tab=code">✓</a></td></tr><tr><td align="center"><code>Multicall2</code></td><td><code>0xd1dC5CF410b227dFEeFEe8D3c1C9DB4FBE66d362</code></td><td><a href="https://viewblock.io/thundercore/address/0xd1dC5CF410b227dFEeFEe8D3c1C9DB4FBE66d362?tab=code">✓</a></td></tr><tr><td align="center"><a href="https://github.com/mds1/multicall"><code>Multicall3</code></a></td><td><code>0xcA11bde05977b3631167028862bE2a173976CA11</code></td><td><a href="https://viewblock.io/thundercore/address/0xd1dC5CF410b227dFEeFEe8D3c1C9DB4FBE66d362?tab=code">✓</a></td></tr></tbody></table>
{% endtab %}

{% tab title="ThunderCore Testnet" %}

<table><thead><tr><th width="154" align="center">Contract</th><th width="450">Address</th><th>Verified</th></tr></thead><tbody><tr><td align="center"><code>Multicall</code></td><td><code>0x7818a6A0fFe134b2aF30850DCE7c86A52eC6AC4F</code></td><td><a href="https://explorer-testnet.thundercore.com/address/0x7818a6A0fFe134b2aF30850DCE7c86A52eC6AC4F/contracts">✓</a></td></tr><tr><td align="center"><code>Multicall2</code></td><td><code>0x02C5503dd793cC457a1CE50d2d31a749cb5e9cB5</code></td><td><a href="https://explorer-testnet.thundercore.com/address/0x02C5503dd793cC457a1CE50d2d31a749cb5e9cB5/contracts">✓</a></td></tr><tr><td align="center"><code>Multicall3</code></td><td><code>0xcA11bde05977b3631167028862bE2a173976CA11</code></td><td><a href="https://explorer-testnet.thundercore.com/address/0x02C5503dd793cC457a1CE50d2d31a749cb5e9cB5/contracts">✓</a></td></tr></tbody></table>
{% endtab %}
{% endtabs %}


# Subgraph

ThunderCore subgraph provides developers to query some dapp blockchain data via GraphQL, which is a convenient choice for client applications based on web technologies that use HTTP/REST APIs to talk to other services.

## Official Subgraphs

| Name                                                                                        | Description                                                                                              |
| ------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| [`TT Mining(StableCoin)`](https://graph-node.thundercore.com/subgraphs/name/tt-mining/v5)   | A one-stop DeFi platform where you can earn profits in `stablecoins`.                                    |
| [`TT Mining(TT)`](https://graph-node.thundercore.com/subgraphs/name/tt-mining/tt-stakingv2) | A one-stop DeFi platform where you can earn profits in `TT`.                                             |
| [`TTSwap`](https://graph-node.thundercore.com/subgraphs/name/ttswap)                        | A DEX (decentralized exchange) on the ThunderCore blockchain based on the AMM model inspired by Uniswap. |

## GraphQL Query Example

#### TT Mining(StableCoin)

```
query tvlQuery {
  v5TotalValueLockeds {
    id
    amount
  }
}
```

#### TT Mining(TT)

```
query subscriptionV2 {
  ttsubscriptions(id: "", first: 10) {
    id
    plan {
      duration
      interestRate
      id
      subscribedCount
    }
    couponID
    amount
    interest
    starttime
    endtime
    redeemed
  }
}
```

#### TTSwap

```
query exchangesQuery {
  exchanges {
    tokenAddress
    tokenBalance
    tokenName
  }
}
```

## Third Party Sugbraphs

If you want to apply to deploy a subgraph using ThunderCore's infrastructure, please contact `support@thundercore.com`


# Auth Service

ThunderCore adopts MPC (Multi-Party Computation)-based threshold signatures from Particle Network.

If you think your project needs Auth Service, please refer to Particle Network's technical documentation [here](https://docs.particle.network/developers/auth-service).


# Wallet Service

You can easily plugging the wallet service into your dApp or wallet by Particle Wallet.

To learn more details about how to integrate, please refer to [here](https://docs.particle.network/developers/wallet-service).


# Node Service

Simplify scaling and powering your blockchain apps.

ThunderCore partners with Particle Network to make accessing ThunderCore blockchain easier, learn more [here](https://docs.particle.network/developers/node-service).


