How to Create NFT Staking Landing Page using ERC20, ERC721 in Next JS

NOTE: 
 

it's built on rinkeby ethereum testnet 
It's still on process.

what you can get from this project: 
 

  1. wallet integration with web3react
  2. erc721 staking
  3. erc20 coin to reward

Preparations 
 

  1. fullfill .env 
    NEXT_PUBLIC_ALCHEMY_RPC_URL
    NEXT_PUBLIC_ALCHEMY_API_KEY
    NEXT_PUBLIC_INFURA_API_KEY 
     

Images of The NFT Collection Website:

staking-dashboard unstaked-apes minting-dapp emergency-call wallet-connection

View Demo👇: 
https://nft-staking-master.netlify.app/ 

Download details:

Author: nft-utilz
Source code: https://github.com/nft-utilz/staking_boilerplate_frontend

#next #nextjs #react #javscript #nft #staking #erc20 #erc721 #web3 

How to Create NFT Staking Landing Page using ERC20, ERC721 in Next JS

A Collection of Vulnerabilities in ERC20 Smart Contracts

Awesome Buggy ERC20 Tokens

A Collection of Vulnerabilities in ERC20 Smart Contracts With Tokens Affected

Disclaimers

  • This repo is aimed to notify the community of development security by collecting reported smart contract issues
  • This repo collects all info from public resources and part of analysis is generated by script along with manual checking
  • This repo might not be perfectly accurate, please contact us or submit a pull request when you find something wrong
  • This repo contains no unreported issue
  • This repo might have duplicate names with popular projects, please do not over-decipher this
  • This repo includes some Token contracts without vulnerabilities, while they fail to satisfy specifications
  • This repo has a few problematic Token contracts that have already been fixed properly

Navigation

Recent Updates

Problems in ERC20 Token Contracts

ERC20 standard is one of the most popular Ethereum token standards [1]. As of June 26th, 2018, more than 95,000 ERC20 token smart contracts have been deployed according to statistics from Etherscan. Here is a daily trend chart of ERC20 contracts created according to our statistics:

ERC20 Contracts Created on main Ethereum network every day

Security Incidents in Smart Contracts

ERC20 Token specification has gone through challenges and improvements during its growth. Lots of critical security issues have been revealed, some of which have led to severe financial losses [2-11] for developers, investors, even Ethereum community as well.

On June 18th, 2016, the DAO hack caused a total loss of over 3,600,000 ethers(ETH) worth over a billion dollars, and the Ethereum hard-fork afterwards led to the Ethereum community breaking apart [2].

On April 22th, 2018, the attack on BeautyChain(BEC) contract hardly decreased the token price to zero via pouring astronomical tokens to exchanges through an integer overflow [3]. There are 10 other contracts at least containing this problem.

On April 25th, 2018, a similar integer overflow got uncovered in SMT. Hackers minted and dumped a tremendous amount of tokens, resulting in SMT's collapse [4]. There is one other contract at least containing this problem.

On May 20th, 2018, a critical logical flaw was found in EDU along with other three Token contracts (CVE-2018–11397, CVE-2018–11398), causing that users' balances could be transferred out randomly [5]. After further analysis, we caught this bug in at least 81 contracts [6].

On June 12, 2018, a series of overflow bug in ERC20 smart contracts got uncovered (CVE-2018-11687, CVE-2018-11809, CVE-2018-11810, CVE-2018-11811, CVE-2018-11812) [7]. We have revealed more than 800 contracts with the same problem after scanning over 20,000 contracts deployed on Etherscan [8].

Failure of Satisfying Specification in Many ERC20 contracts

Lots of ERC20 token contracts do not follow the ERC20 standard strictly, which is troublesome to developers of DApps on ERC20 tokens [12-14].

Thousands of deployed Token contracts referred to incorrect example code on Ethereum official website and OpenZeppelin, resulting in several functions failing to meet ERC20 standard. After upgrading Solidity compiler to 0.4.22, incompatibilities would arise and these contracts could not perform normal transactions on decentralized exchanges (DEX) or DApp in most cases [12], whereas a majority of DApp developing teams were off guard and unaware of such a problem.

Several Token contracts added redundant checks in standard approve(), requiring that the approved _amount smaller or equal to the current balance. However, it makes DEX employing protocols like 0x hard to finish approve() in advance, asking the Token developing team transfer a huge amount of tokens to the exchange's intermediate account ahead which violates the target of employing ERC20 standard and brings about inconvenience.

Since it is defined optional to set common querying interfaces like name(), symbol() and decimals() in ERC20 specification [1], many Token contracts left them out or named them differently, such as NAME(), SYMBOL() and DECIMALS(), making it harder for DEX and DApp developing.

Another point worth mentioning is that two events - Transfer and Approval should get fired under certain circumstances described by ERC20 specification [1]. In fact, many Token contracts left out Approval event referring to Ethereum official website [14]. This omission causes great difficulty for developers listening to relevant events, undermining the development of DApp ecosystem.

One Solution: Collecting Buggy Token Contracts

Statistical summaries from security organizations and experts indicate that critical vulnerabilities are hiding in smart contracts, taking the 'TOP 10 in 2018' by NCC group [15] as an example:

  • Reentrancy
  • Access Control
  • Integer Overflow
  • Unchecked Return Values For Low Level Calls
  • Denial of Service
  • Bad Randomness
  • Front-Running
  • Time manipulation
  • Short Address Attack
  • Unknown Unknowns

This might be just the tip of an iceberg. Recent research together with the aforementioned point of view state clearly that the scale of problems in smart contracts deployed on Ethereum may go beyond our imagination.

We made a collection of past bugs and vulnerabilities, including:

  1. vulnerabilities in Token contracts
  2. incompatibilities due to inconsistency with ERC20
  3. excessive authorities of Token administrators [16]

Why This Repo?

There are many projects in Ethereum community contributing to the ecosystem of smart contracts, such as 'A guide to smart contract security best practices' [17] maintained by Consensys and 'OpenZeppelin, a framework to build secure smart contracts on Ethereum' [18] developed by OpenZeppelin.

Also, we found the fact that a majority of issues in buggy Token contracts come from referring, copying and modifying others' code without caution. Also, using incorrect sample code is an origin of bugs. It is difficult for beginners and developers of smart contracts to determine whether a contract snippet from main net contains bugs and identify these issues in seconds.

We would maintain this collection to:

  • provide a reference and learning materials of common bugs in ERC20 token contracts
  • help ERC20 token contract developers to develop correct and secure contracts
  • notice DApp developers of incompatible/buggy/vulnerable ERC20 token contracts
  • warn exchanges and investors of potential risks in incompatible/buggy/insecure ERC20 tokens

What We Collect?

  • Descriptions of common vulnerabilities
  • List of deployed buggy token contracts
  • List of nonstandard token contracts

Repo Structure

awesome-buggy-erc20-tokens
├── token_dict.json
├── token_detail_dict.json
├── ERC20_token_issue_list_CN.md
├── issues.json
├── bad_tokens.all.csv
├── bad_tokens.all.json
├── bad_tokens.top.csv
├── bad_tokens.top.json
├── raw/
├── csv/
├── json/
├── gen_token_detail_dict.py
└── gen_list_from_raw.py

As shown below, lists in CSV and JSON help developers to browse and search for addresses of given contracts with reported vulnerabilities.

addr,category,name,symbol,exchanges,totalSupply,decimals,info
0x014B50466590340D41307Cc54DCee990c8D58aa8,[B6],ICOS,ICOS,@HitBTC@Tidex,560417,6,_
0x093e5C256Ff8B32c7F1377f4C20e331674C77F00,[A2],Dignity,DIG,@Livecoin,3000000000,8,_
{
    "0x014B50466590340D41307Cc54DCee990c8D58aa8": {
        "decimals": 6,
        "exchanges": [
            "HitBTC",
            "Tidex"
        ],
        "info": "_",
        "issues": {
            "no-symbol": true
        },
        "name": "ICOS",
        "rank": 316,
        "symbol": "ICOS",
        "totalSupply": 560417
    },
    "0x093e5C256Ff8B32c7F1377f4C20e331674C77F00": {
        "decimals": 8,
        "exchanges": [
            "Livecoin"
        ],
        "info": "_",
        "issues": {
            "totalsupply-overflow": true
        },
        "name": "Dignity",
        "rank": 613,
        "symbol": "DIG",
        "totalSupply": 3000000000
    }
}

How to Contribute

We hope this collection can contribute to the Ethereum ecosystem by maintaining and updating in a long period and definitely welcome contributions to this collection.

For now we only maintain detailed information of token contracts (totalSupply, decimals, exchanges) that have market caps on CoinMarketCap. If you find any other incompatible/buggy/vulnerable ERC20 token contracts, please update token_dict.json and run script gen_token_detail_dict.py.

If you find other bugs not listed in this collection, please update in the following process.

  • Add the name and description of the bug with reference to ERC20_token_issue_list.md
  • Create a new file with the bug name in raw directory and fill in the address of affected contracts
  • Add the name and index of the new bug to issues.json
  • Run python3 gen_list_from_raw.py -i raw/* -o bad_tokens in the repo root
  • Check the update and send us a pull request

If you have any questions or ideas, please join our discussion on Gitter.

TODO

  •  Add more 'Excessive Authorities' issues:
    •  Minting tokens
    •  Setting trading price
    •  Manipulate other accounts

Technical Partnership

References

Download details:
Author: sec-bit
Source code: https://github.com/sec-bit/awesome-buggy-erc20-tokens
License: CC0-1.0 license

#solidity #smartcontract #blockchain #ethereum #erc20

A Collection of Vulnerabilities in ERC20 Smart Contracts

ERC20 Library with Staking Functionality Written in Solidity & Python

ERC20Stakeable Smart Contract.

The goal is to create a ERC20 Stakeable library easy to implement for any token.

This Smart Contract is not Audited!

Created using OpenZeppelin ERC20 Smart Contract and ERC20Burnable extension.

Inspired by Patrick Collins' DeFi-minimal Staking.sol.

Features for users:

  1. Deposit the ERC20 Token and gain a fixed APR calculated hourly.
  2. Compound your rewards.
  3. Claim your rewards.
  4. Withdraw a part of deposit.
  5. Withdraw all(your deposit + rewards).

Features for owner:

  1. Set a fixed APR.
  2. Set a minimum stake amount.
  3. Set compounding frequency limit.

How to use?

Prerequisites:

Rinkeby deployment

python3 -m pip install --user pipx
python3 -m pipx ensurepath
# restart terminal
pipx install eth-brownie
  • Brownie
  • A free Infura Project Id key for Rinkeby Network

Installation

Clone this repo:

git clone https://github.com/andreitoma8/ERC20-Staking
cd ERC20-Staking

Deploy to Rinkeby

  • Add a .env file with the same contents of .env.example, but replaced with your variables.
  • Run the command:
brownie run scripts/deploy.py --network rinkeby

The script will deploy the token, mint 1.000.000 for yourself and verify the Smart Contract on .rinkeby.etherscan.io

Any feedback is much apreciated!

If this was helpful please consider donating:

0xA4Ad17ef801Fa4bD44b758E5Ae8B2169f59B666F

Run test locally on Ganache

For unning local tests you also need:

npm install -g ganache-cli

or, if you are using Yarn

yarn global add ganache-cli
  • NodeJS. To verify NodeJS installation run
node --version

Test scripts

  • Run the command:
brownie test testes/test.py

The test will assert the following:

  1. Contract deployment
  2. Initial staking transaction
  3. Rewards calculation in 100 H
  4. Compound rewards transaction
  5. Withdraw rewards transaction
  6. Withdraw all transaction

Download Details:
Author: andreitoma8
Source Code: https://github.com/andreitoma8/ERC20-Staking
License:

#blockchain #solidity #smartcontract #erc20 #staking

ERC20 Library with Staking Functionality Written in Solidity & Python

Implementation Of ERC20 token for The CasperLabs Platform

Casper Fungible Tokens (ERC-20 Standard)

A library for developing fungible tokens (ERC-20 Tokens) tokens for the Casper Network.

The main functionality is provided via the ERC-20 struct, and is intended to be consumed by a smart contract written to be deployed on the Casper Network.

Usage

To create an example fungible token contract which uses this library, use the cargo-casper tool:

cargo install cargo-casper
cargo casper --erc20 <PATH TO NEW PROJECT>

This command will generate a new project structure with an example token contract based on an example project.

Development

Make sure the wasm32-unknown-unknown Rust target is installed.

make prepare

Build Smart Contracts

To build the example fungible token contract and supporting test contracts:

make build-contracts

Test

make test

JavaScript Client SDK

A JavaScript client SDK can be used to interact with the fungible token contract.

Documentation

For more information, visit the below guides:

Download Details:
Author: casper-ecosystem
Source Code: https://github.com/casper-ecosystem/erc20
License: Apache-2.0 license

#casper #blockchain #smartcontract #erc20 #rust 

Implementation Of ERC20 token for The CasperLabs Platform
Best of Crypto

Best of Crypto

1655106180

Optimistic Ethereum ERC20 Waffle Example

Getting Started with the Optimistic Ethereum: Simple ERC20 Token Waffle Tutorial

Hi there! Welcome to our Optimistic Ethereum ERC20 Waffle example!

If your preferred smart contract testing framework is Truffle, see our Optimistic Ethereum ERC20 Truffle tutorial here.

If you're interested in writing your first L2-compatible smart contract using Waffle as your smart contract testing framework, then you've come to the right place! This repo serves as an example for how go through and compile & test your contracts on both Ethereum and Optimistic Ethereum.

Let's begin!

Prerequisites

Please make sure you've installed the following before continuing:

Setup

To start, clone this Waffle-ERC20-Example repo, enter it, and install all of its dependencies:

git clone https://github.com/ethereum-optimism/Waffle-ERC20-Example.git
cd Waffle-ERC20-Example
yarn install

Step 1: Compile your contracts for Optimistic Ethereum

Compiling a contract for Optimistic Ethereum is pretty easy! First we'll need to install the @eth-optimism/solc and solc packages. Since we currently only support solc versions 0.5.16, 0.6.12, and 0.7.6 for Optimistic Ethereum contracts, we'll be using version 0.7.6 in this example. Let's add these two packages:

yarn add @eth-optimism/solc@0.7.6-alpha.1
yarn add solc@0.7.6

Next we just need to add a new Waffle config to compile our contracts. Create waffle-ovm.json and add this to it:

{
  "compilerVersion": "./node_modules/@eth-optimism/solc",
  "sourceDirectory": "./contracts",
  "outputDirectory": "./build-ovm"
}

Here, we specify the new custom Optimistic Ethereum compiler we just installed and the new build path for our compiled contracts.

And we're ready to compile! All you have to do is specify the waffle-ovm.json config in your waffle command:

yarn waffle waffle-ovm.json

Our waffle-ovm.json config file tells Waffle that we want to use the Optimistic Ethereum solidity compiler.

Yep, it's that easy. You can verify that everything went well by looking for the build-ovm directory.

Here, build-ovm signifies that the contracts contained in this directory have been compiled for the OVM, the Optimistic Virtual Machine, as opposed to the Ethereum Virtual Machine. Now let's move on to testing!

Step 2: Testing your Optimistic Ethereum contracts

Testing with Waffle is easy. We've included a simple set of ERC20 tests inside Waffle-ERC20-Example/test/erc20.spec.js. Let's run these tests with waffle:

yarn mocha 'test/*.spec.js' --timeout 10000

If everything went well, you should see a bunch of green checkmarks.

Testing an Optimistic Ethereum contract

Woot! It's finally time to test our contract on top of Optimistic Ethereum. But first we'll need to get a local version of an Optimistic Ethereum node running...

Fortunately, we have some handy dandy tools that make it easy to spin up a local Optimistic Ethereum node!

Since we're going to be using Docker, make sure that Docker is installed on your machine prior to moving on (info on how to do that here). We recommend opening up a second terminal for this part. This way you'll be able to keep the Optimistic Ethereum node running so you can execute some contract tests.

Now we just need to download, build, and install our Optimistic Ethereum node by running the following commands. Please note that docker-compose build will take a while. We're working on improving this (sorry)!

git clone git@github.com:ethereum-optimism/optimism.git
cd optimism
yarn install
yarn build
cd ops
docker-compose build
docker-compose up

You now have your very own locally deployed instance of Optimistic Ethereum! 🙌

With your local instance of Optimistic Ethereum up and running, let's test your contracts! Since the two JSON RPC provider URLs (one for your local instance Ethereum and Optimistic Ethereum) have already been specified in your .env file, all we need to do next is run the test command.

To do that, run:

yarn TARGET=OVM mocha 'test/*.spec.js' --timeout 50000

Notice that we use the TARGET=OVM flag to let mocha know that we want to use the build-ovm folder as our path to our JSON files. (Remember that these JSON files were compiled using the Optimistic Ethereum solidity compiler!)

You should see a set of passing tests for your ERC20 contract. If so, congrats! You're ready to deploy an application to Optimistic Ethereum. It really is that easy.

And uh... yeah. That's pretty much it. Tutorial complete. Hopefully now you know the basics of working with Optimistic Ethereum! 🅾️

Further Reading

OVM vs. EVM Incompatibilities

Our goal is to bring the OVM as close to 100% compatibility with all existing Ethereum projects, but our software is still in an early stage. Our community hub docs will maintain the most up to date list of known incompatibilities between the OVM and EVM, along with our plans to fix them.

Wasn't that easy?

The OVM provides a fresh new take on layer 2 development: it's mostly identical to layer 1 development. However, there are a few differences that are worth noting, which you can read more about in our EVM comparison documentation. No hoops, no tricks--the Ethereum you know and love, ready to scale up with L2. For more info on our progress and what's going on behind the scenes, you can follow us on Twitter.

Want to try deploying contracts to the Optimistic Ethereum testnet next? Check out the full integration guide on the Optimism community hub.

Troubleshooting

Example project not working? Create a Github Issue, or hop in our Discord channel and ask away.

Download Details:
Author: ethereum-optimism
Source Code: https://github.com/ethereum-optimism/Waffle-ERC20-Example
License: MIT license

#optimism  #blockchain  #smartcontract  #ethereum #solidity #javascript #erc20 

Optimistic Ethereum ERC20 Waffle Example

Token Contract in AssemblyScript For Near Blockchain

Token Contract in AssemblyScript

This project contains an implementation of a token contract similar to ERC20 but simpler. We'll visit a page, sign in and use your browser's console to run commands to initialize, send, and get the balance of a custom token.

Note: this example uses a basic version of a token. It is not the supported token contract laid out in the NEAR Enhancement Proposal for non-fungible tokens. Visit this example illustrating implementations of the non-fungible token in Rust and AssemblyScript. It is not recommended to deploy non-fungible tokens written in AssemblyScript for financial use cases.

Getting started

There's a button at the top of this file that says "Open in Gitpod." If you want to try out this project as fast as possible, that's what you want. It will open the project in your browser with a complete integrated development environment configured for you. If you want to run the project yourself locally, read on.

There are two ways to run this project locally. The first is quick, and a good way to instantly become familiar with this example. Once familiar, the next step is to create your own NEAR account and deploy the contract to testnet.

Quick option

  1. Install dependencies:

yarn

2.   Build and deploy this smart contract to a development account. This development account will be created automatically and is not intended for reuse:

yarn dev

Standard deploy option

In this second option, the smart contract will get deployed to a specific account created with the NEAR Wallet.

  1. Ensure near-cli is installed by running:
near --version

If needed, install near-cli:

npm install near-cli -g

2.   If you do not have a NEAR account, please create one with NEAR Wallet. Then, in the project root, login with near-cli by following the instructions after this command:

near login

3.   Modify the top of src/config.js, changing the CONTRACT_NAME to be the NEAR account that you just used to log in.

const CONTRACT_NAME = process.env.CONTRACT_NAME || 'YOUR_ACCOUNT_NAME_HERE'; /* TODO: fill this in! */

4.   Start the example!

yarn start

Exploring The Code

  1. The backend code lives in the /assembly folder. This code gets deployed to the NEAR blockchain when you run yarn deploy:contract. This sort of code-that-runs-on-a-blockchain is called a "smart contract" – learn more about NEAR smart contracts.
  2. The frontend code lives in the /src folder. /src/index.html is a great place to start exploring. Note that it loads in /src/main.js, where you can learn how the frontend connects to the NEAR blockchain.
  3. Tests: there are different kinds of tests for the frontend and backend. The backend code gets tested with the asp command for running the backend AssemblyScript tests, and jest for running frontend tests. You can run both of these at once with yarn test.

Both contract and client-side code will auto-reload as you change source files.

Download Details:
Author: near-examples
Source Code: https://github.com/near-examples/token-contract-as
License: View license

#blockchain  #smartcontract  #near #erc20 

Token Contract in AssemblyScript For Near Blockchain
Best of Crypto

Best of Crypto

1651586480

BUSD Contract: Solidity Smart Contracts for The Binance USD

Binance USD (BUSD)

Paxos-issued USD-collateralized ERC20 stablecoin public smart contract repository.

https://www.paxos.com/busd

ABI, Address, and Verification

The contract abi is in BUSD.abi. It is the abi of the implementation contract. Interaction with Binance USD is done at the address of the proxy at 0x4Fabb145d64652a948d72533023f6E7A623C7C5. See https://etherscan.io/token/0x4Fabb145d64652a948d72533023f6E7A623C7C53 for live on-chain details, and the section on bytecode verification below.

The BUSD contract is based upon the PAX Standard smart contract which was audited by three third-party specialists (Nomic Labs, ChainSecurity, and Trail of Bits) in September-October 2018. In January 2019, Trail of Bits performed an additional audit for a potential upgrade to the PAX USD smart contract.

Contract Specification

Binance USD(BUSD) is an ERC20 token that is Centrally Minted and Burned by Paxos, representing the trusted party backing the token with USD.

ERC20 Token

The public interface of Binance USD is the ERC20 interface specified by EIP-20.

  • name()
  • symbol()
  • decimals()
  • totalSupply()
  • balanceOf(address who)
  • transfer(address to, uint256 value)
  • approve(address spender, uint256 value)
  • allowance(address owner, address spender)
  • transferFrom(address from, address to, uint256 value)

And the usual events.

  • event Transfer(address indexed from, address indexed to, uint256 value)
  • event Approval(address indexed owner, address indexed spender, uint256 value)

Typical interaction with the contract will use transfer to move the token as payment. Additionally, a pattern involving approve and transferFrom can be used to allow another address to move tokens from your address to a third party without the need for the middleperson to custody the tokens, such as in the 0x protocol.

Warning about ERC20 approve front-running

There is a well known gotcha involving the ERC20 approve method. The problem occurs when the owner decides to change the allowance of a spender that already has an allowance. If the spender sends a transferFrom transaction at a similar time that the owner sends the new approve transaction and the transferFrom by the spender goes through first, then the spender gets to use the original allowance, and also get approved for the intended new allowance.

The recommended mitigation in cases where the owner does not trust the spender is to first set the allowance to zero before setting it to a new amount, checking that the allowance was not spent before sending the new approval transaction. Note, however, that any allowance change is subject to front-running, which is as simple as watching the mempool for certain transactions and then offering a higher gas price to get another transaction mined onto the blockchain more quickly.

Controlling the token supply

The total supply of BUSD is backed by fiat held in reserve at Paxos. There is a single supplyController address that can mint and burn the token based on the actual movement of cash in and out of the reserve based on requests for the purchase and redemption of BUSD.

The supply control interface includes methods to get the current address of the supply controller, and events to monitor the change in supply of BUSD.

  • supplyController()

Supply Control Events

  • SupplyIncreased(address indexed to, uint256 value)
  • SupplyDecreased(address indexed from, uint256 value)
  • SupplyControllerSet(address indexed oldSupplyController, address indexed newSupplyController)

Pausing the contract

In the event of a critical security threat, Paxos has the ability to pause transfers and approvals of the BUSD token. The ability to pause is controlled by a single owner role, following OpenZeppelin's Ownable. The simple model for pausing transfers following OpenZeppelin's Pausable.

Asset Protection Role

As required by our regulators, we have introduced a role for asset protection to freeze or seize the assets of a criminal party when required to do so by law, including by court order or other legal process.

The assetProtectionRole can freeze and unfreeze the BUSD balance of any address on chain. It can also wipe the balance of an address after it is frozen to allow the appropriate authorities to seize the backing assets.

Freezing is something that Paxos will not do on its own accord, and as such we expect to happen extremely rarely. The list of frozen addresses is available in isFrozen(address who).

BetaDelegateTransfer

In order to allow for gas-less transactions we have implemented a variation of EIP-865. The public function betaDelegatedTransfer and betaDelegatedTransferBatch allow an approved party to transfer BUSD on the end user's behalf given a signed message from said user. Because EIP-865 is not finalized, all methods related to delegated transfers are prefixed by Beta. Only approved parties are allowed to transfer BUSD on a user's behalf because of potential attacks associated with signing messages. To mitigate some attacks, EIP-712 is implemented which provides a structured message to be displayed for verification when signing.

function betaDelegatedTransfer(
   bytes sig, address to, uint256 value, uint256 fee, uint256 seq, uint256 deadline
) public returns (bool) {

Upgradeability Proxy

To facilitate upgradeability on the immutable blockchain we follow a standard two-contract delegation pattern: a proxy contract represents the token, while all calls not involving upgrading the contract are delegated to an implementation contract.

The delegation uses delegatecall, which runs the code of the implementation contract in the context of the proxy storage. This way the implementation pointer can be changed to a different implementation contract while still keeping the same data and BUSD contract address, which are really for the proxy contract.

The proxy used here is AdminUpgradeabilityProxy from ZeppelinOS.

Upgrade Process

The implementation contract is only used for the logic of the non-admin methods. A new implementation contract can be set by calling upgradeTo() or upgradeToAndCall() on the proxy, where the latter is used for upgrades requiring a new initialization or data migration so that it can all be done in one transaction. You must first deploy a copy of the new implementation contract, which is automatically paused by its constructor to help avoid accidental calls directly to the proxy contract.

Bytecode verification

The proxy contract and implementation contracts are verified on etherscan at the following links: https://etherscan.io/token/0x4Fabb145d64652a948d72533023f6E7A623C7C53 https://etherscan.io/token/0x5864c777697Bf9881220328BF2f16908c9aFCD7e

Because the implementation address in the proxy is a private variable, verifying that this is the proxy being used requires reading contract storage directly. This can be done using a mainnet node, such as infura, by pasting the network address in truffle-config.js and running

truffle exec ./getImplementationAddress.js --network mainnet

Contract Tests

To run smart contract tests first start

ganache-cli

in another terminal

Then run

make test-contracts

You can also run make test-contracts-coverage to see a coverage report.

Download Details:
Author: paxosglobal
Source Code: https://github.com/paxosglobal/busd-contract
License: MIT License

#blockchain  #stablecoin  #busd #cryptocurrency #solidity #javascript #smartcontract #erc20 

 BUSD Contract: Solidity Smart Contracts for The Binance USD

Cómo construir una plataforma de intercambio ERC-20

Aprenda a crear una plataforma de intercambio ERC-20 donde los usuarios puedan acuñar, comprar y vender tokens ERC-20 en este completo tutorial.

Las aplicaciones de tokens y NFT aumentan cada día. Traen muchas nuevas posibilidades a la mesa. Desde usarlos en juegos hasta crear su propia moneda virtual para un evento, puede hacer muchas cosas usando las tecnologías Web3.

Hoy vamos a crear una plataforma de intercambio de tokens, donde los usuarios pueden comprar y vender un token específico. El tipo de token que vamos a usar aquí es ERC-20 y los vamos a implementar en la red de Polygon Mumbai.

El enfoque que vamos a seguir es primero crear un contrato inteligente, que acuñará nuestros tokens, y luego otro contrato inteligente para facilitar su compra y venta. Luego usaremos ambos contratos inteligentes en nuestra aplicación Next.js para que los usuarios puedan comprar y vender.

requisitos previos

  • Conocimiento práctico de React
  • Conocimiento práctico de Next.js
  • Conocimiento práctico de Solidity
  • Node.js instalado
  • Un editor de código: prefiero Visual Studio Code
  • Extensión MetaMask instalada con al menos una billetera
  • MetaMask conectado a la red de prueba Polygon Mumbai

Si siente que está atascado en el tutorial, no dude en consultar el repositorio de GitHub .

Contenido

  • Crear el contrato inteligente de token
  • Crear el contrato de proveedor
  • Configuración del contrato inteligente del proveedor
  • Configurando nuestra aplicación Next.js
  • Configuración de variables de entorno
  • Trabajando en la autenticación
  • Implementación de la funcionalidad de compra y venta.

Crear el contrato inteligente de token

El contrato inteligente de tokens nos ayudará a acuñar tokens. Abra Remix IDE y cree un nuevo archivo llamado TestToken.soldebajo de la contractscarpeta. Use el siguiente código en el archivo:

// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract TestToken is ERC20 {
    constructor() ERC20("TestToken", "TEST"){
        _mint(msg.sender, 10000 * 10 ** 18);
    }
}

En el código anterior, usamos plantillas de contrato de OpenZeppelin para crear un token ERC-20. Estas plantillas nos brindan las funciones mínimas requeridas por los tokens ERC-20, y son seguras y optimizadas, por lo que no debe preocuparse por reforzar la seguridad de su token. En el constructor de nuestro contrato, especificamos el nombre y el símbolo de nuestro token y acuñamos 10,000 tokens en la billetera del creador del contrato.

Ahora, compile el contrato presionando Ctrl + S (o Cmd + S para Mac). Asegúrese de haber conectado MetaMask a Polygon Mumbai. Vaya a la pestaña Implementar en la barra lateral y configure el entorno en Inyectado Web3 , para que Remix IDE use MetaMask para implementar su contrato.

Asegúrate de que tus otras configuraciones sean similares a esta:

 

Después de verificar todas las configuraciones, haga clic en Implementar . Esto debería abrir la ventana emergente de autorización de MetaMask. Haga clic en Confirmar .

 

Si no tiene fondos en su billetera de Polygon Mumbai, puede obtener algunos a través de un faucet . Después de confirmar la transacción, espere unos segundos hasta que vea su contrato desplegado en la barra lateral izquierda.

Copie la dirección del contrato, ya que la necesitaremos al configurar el contrato del proveedor.

Crear el contrato de proveedor

Cree un nuevo archivo llamado TestTokenVendor.soldebajo de la contractscarpeta. Utilice el siguiente código para el contrato:

// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.4;
import "./TestToken.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract Vendor is Ownable {
  TestToken yourToken;
  uint256 public tokensPerMatic = 100;
  event BuyTokens(address buyer, uint256 amountOfMATIC, uint256 amountOfTokens);
  constructor(address tokenAddress) {
    yourToken = TestToken(tokenAddress);
  }

  function buyTokens() public payable returns (uint256 tokenAmount) {
    require(msg.value > 0, "You need to send some MATIC to proceed");
    uint256 amountToBuy = msg.value * tokensPerMatic;

    uint256 vendorBalance = yourToken.balanceOf(address(this));
    require(vendorBalance >= amountToBuy, "Vendor has insufficient tokens");

    (bool sent) = yourToken.transfer(msg.sender, amountToBuy);
    require(sent, "Failed to transfer token to user");

    emit BuyTokens(msg.sender, msg.value, amountToBuy);
    return amountToBuy;
  }
  function sellTokens(uint256 tokenAmountToSell) public {

    require(tokenAmountToSell > 0, "Specify an amount of token greater than zero");

    uint256 userBalance = yourToken.balanceOf(msg.sender);
    require(userBalance >= tokenAmountToSell, "You have insufficient tokens");

    uint256 amountOfMATICToTransfer = tokenAmountToSell / tokensPerMatic;
    uint256 ownerMATICBalance = address(this).balance;
    require(ownerMATICBalance >= amountOfMATICToTransfer, "Vendor has insufficient funds");
    (bool sent) = yourToken.transferFrom(msg.sender, address(this), tokenAmountToSell);
    require(sent, "Failed to transfer tokens from user to vendor");

    (sent,) = msg.sender.call{value: amountOfMATICToTransfer}("");
    require(sent, "Failed to send MATIC to the user");
  }

  function withdraw() public onlyOwner {
    uint256 ownerBalance = address(this).balance;
    require(ownerBalance > 0, "No MATIC present in Vendor");
    (bool sent,) = msg.sender.call{value: address(this).balance}("");
    require(sent, "Failed to withdraw");
  }
}

En el código anterior, estamos creando un Ownablecontrato, que es una plantilla de OpenZeppelin. Esto significa que podemos transferir la propiedad de este contrato a alguna otra billetera, si así lo deseamos.

Estamos importando nuestro contrato de token y brindándole la dirección a través del constructor (proporcionaremos la dirección como argumento al implementar el contrato). También estamos estableciendo un precio general del token dentro de la tokensPerMaticvariable. Este valor se utilizará para calcular la cantidad de tokens a comprar en función de la cantidad de MATIC enviada al contrato.

En la buyTokens()función, primero verificamos si se envió algún MATIC y si el contrato del proveedor tiene suficientes tokens en el saldo o no. Luego, estamos yourToken.transfer()enviando nuestros tokens desde el contrato del proveedor a la billetera que envió la llamada del contrato. Finalmente, estamos emitiendo un evento y devolviendo la cantidad de tokens comprados.

La sellTokens()función no es tan sencilla como la buyTokens()función. Verificamos si el usuario tiene la cantidad especificada de tokens o no, calculamos la cantidad de MATIC que se devolverá al usuario y verificamos si el contrato del proveedor tiene una cantidad suficiente de MATIC en el saldo.

Sin embargo, aquí viene la parte divertida: no podemos simplemente transferir tokens de la billetera del usuario al saldo de nuestro contrato de proveedor. Primero debemos solicitar la aprobación del usuario para permitirnos administrar sus tokens y enviarnos estos tokens. Este método es seguro porque necesitamos establecer el límite de la cantidad de tokens para los que solicitamos aprobación. La autorización está en MetaMask y el usuario puede ver claramente qué cantidad de tokens puede manejar el contrato.

Este procedimiento de aprobación tiene lugar en el front-end (de una aplicación Next.js, en este caso). Una vez que se otorga la aprobación, realizamos la transferFrom()función de transferir los fondos del usuario a la billetera del contrato del proveedor. Y finalmente, enviamos MATIC al usuario.

La withdraw()función sólo puede ser ejecutada por el titular del contrato. Esta función le permite enviar todo el MATIC almacenado en el contrato inteligente a la billetera del propietario.

Finalmente, implemente el contrato y pase la dirección del contrato del token como parámetro.

Configuración del contrato inteligente del proveedor

Ahora que hemos implementado el contrato inteligente del proveedor, debemos enviarle algunos tokens para que funcione.

Abra el contrato de token en la pestaña Implementar . En la sección de transferencia , pegue la dirección del contrato del proveedor y la cantidad total de tokens (que se pueden obtener haciendo clic en totalSupply.

Haga clic en transacción para aprobar la transacción de MetaMask, y todos los tokens se enviarán desde su billetera al saldo del contrato del proveedor. Ahora su contrato de proveedor puede facilitar la compra y venta de tokens.

Ahora, vaya a la pestaña de compilación y copie el ABI de los dos contratos (así como las direcciones del token y del proveedor), ya que los necesitaremos en nuestro archivo Next.js.

Configurando nuestra aplicación Next.js

Navegue a un directorio seguro y ejecute el siguiente comando en la terminal para crear su aplicación Next.js:

npx create-next-app erc20-exchange-platform

Úselo --use-npmal final si desea instalar dependencias usando npm( create-next-apprecientemente se ha predeterminado a yarn). Navegue a la carpeta del proyecto y ejecute el siguiente comando para instalar algunas dependencias requeridas:

#npm npm install @thirdweb-dev/sdk @thirdweb-dev/react web3 #yarn hilo añadir @thirdweb-dev/sdk @thirdweb-dev/react web3

Estamos instalando @thirdweb-dev/sdkpara ayudar con la autenticación y conectando nuestra aplicación a MetaMask. De esta forma, no dedicamos mucho tiempo a la autenticación.

También estamos instalando @thirdweb-dev/reactpara proporcionarnos Hooks que funcionarán @thirdweb-dev/sdkpara brindarnos información útil sobre el estado del usuario. Estamos instalando web3para interactuar con nuestros tokens y contratos inteligentes de proveedores.

Como no cubriremos el estilo en este tutorial, lo dejaré aquí sin centrarme demasiado en los detalles. Abra globals.cssdebajo de la stylescarpeta y use los siguientes estilos:

html,
body {
  padding: 0;
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
    Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}
a {
  color: inherit;
  text-decoration: none;
}
* {
  box-sizing: border-box;
}
.home__container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
}
.home__button {
  background-color: #2ecc71;
  border: none;
  border-radius: 5px;
  font-size: 20px;
  padding: 15px;
  margin: 10px;
  cursor: pointer;
}
.exchange__container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
}
.exchange__textBox {
  width: 300px;
  height: 50px;
  border: 1px solid #c4c4c4;
  border-radius: 5px;
  font-size: 20px;
  padding: 15px;
  margin: 10px;
  cursor: pointer;
}
.exchange__button {
  width: 300px;
  height: 50px;
  border: 1px solid #2ecc71;
  background-color: #2ecc71;
  border-radius: 5px;
  font-size: 20px;
  padding: 15px;
  margin: 10px;
  cursor: pointer;
}

Configuración de variables de entorno y otros datos

Cree un nuevo archivo llamado .env.localen el directorio del proyecto, este contendrá nuestras direcciones de contrato:

NEXT_PUBLIC_TOKEN_CONTRACT_ADDRESS=(dirección del token aquí) NEXT_PUBLIC_VENDOR_CONTRACT_ADDRESS=(dirección del proveedor aquí)

Ahora, cree un nuevo archivo llamado contracts.jsen el directorio del proyecto. En este archivo, guardaremos y exportaremos las ABI del contrato para ambos contratos:

export const tokenABI = [
  {
    inputs: [],
    stateMutability: "nonpayable",
    type: "constructor",
  },
  {
    anonymous: false,
    inputs: [
      {
        indexed: true,
        internalType: "address",
        name: "owner",
        type: "address",
      },
      {
        indexed: true,
        internalType: "address",
        name: "spender",
        type: "address",
      },
      {
        indexed: false,
        internalType: "uint256",
        name: "value",
        type: "uint256",
      },
    ],
    name: "Approval",
    type: "event",
  },
  {
    anonymous: false,
    inputs: [
      {
        indexed: true,
        internalType: "address",
        name: "from",
        type: "address",
      },
      {
        indexed: true,
        internalType: "address",
        name: "to",
        type: "address",
      },
      {
        indexed: false,
        internalType: "uint256",
        name: "value",
        type: "uint256",
      },
    ],
    name: "Transfer",
    type: "event",
  },
  {
    inputs: [
      {
        internalType: "address",
        name: "owner",
        type: "address",
      },
      {
        internalType: "address",
        name: "spender",
        type: "address",
      },
    ],
    name: "allowance",
    outputs: [
      {
        internalType: "uint256",
        name: "",
        type: "uint256",
      },
    ],
    stateMutability: "view",
    type: "function",
  },
  {
    inputs: [
      {
        internalType: "address",
        name: "spender",
        type: "address",
      },
      {
        internalType: "uint256",
        name: "amount",
        type: "uint256",
      },
    ],
    name: "approve",
    outputs: [
      {
        internalType: "bool",
        name: "",
        type: "bool",
      },
    ],
    stateMutability: "nonpayable",
    type: "function",
  },
  {
    inputs: [
      {
        internalType: "address",
        name: "account",
        type: "address",
      },
    ],
    name: "balanceOf",
    outputs: [
      {
        internalType: "uint256",
        name: "",
        type: "uint256",
      },
    ],
    stateMutability: "view",
    type: "function",
  },
  {
    inputs: [],
    name: "decimals",
    outputs: [
      {
        internalType: "uint8",
        name: "",
        type: "uint8",
      },
    ],
    stateMutability: "view",
    type: "function",
  },
  {
    inputs: [
      {
        internalType: "address",
        name: "spender",
        type: "address",
      },
      {
        internalType: "uint256",
        name: "subtractedValue",
        type: "uint256",
      },
    ],
    name: "decreaseAllowance",
    outputs: [
      {
        internalType: "bool",
        name: "",
        type: "bool",
      },
    ],
    stateMutability: "nonpayable",
    type: "function",
  },
  {
    inputs: [
      {
        internalType: "address",
        name: "spender",
        type: "address",
      },
      {
        internalType: "uint256",
        name: "addedValue",
        type: "uint256",
      },
    ],
    name: "increaseAllowance",
    outputs: [
      {
        internalType: "bool",
        name: "",
        type: "bool",
      },
    ],
    stateMutability: "nonpayable",
    type: "function",
  },
  {
    inputs: [],
    name: "name",
    outputs: [
      {
        internalType: "string",
        name: "",
        type: "string",
      },
    ],
    stateMutability: "view",
    type: "function",
  },
  {
    inputs: [],
    name: "symbol",
    outputs: [
      {
        internalType: "string",
        name: "",
        type: "string",
      },
    ],
    stateMutability: "view",
    type: "function",
  },
  {
    inputs: [],
    name: "totalSupply",
    outputs: [
      {
        internalType: "uint256",
        name: "",
        type: "uint256",
      },
    ],
    stateMutability: "view",
    type: "function",
  },
  {
    inputs: [
      {
        internalType: "address",
        name: "to",
        type: "address",
      },
      {
        internalType: "uint256",
        name: "amount",
        type: "uint256",
      },
    ],
    name: "transfer",
    outputs: [
      {
        internalType: "bool",
        name: "",
        type: "bool",
      },
    ],
    stateMutability: "nonpayable",
    type: "function",
  },
  {
    inputs: [
      {
        internalType: "address",
        name: "from",
        type: "address",
      },
      {
        internalType: "address",
        name: "to",
        type: "address",
      },
      {
        internalType: "uint256",
        name: "amount",
        type: "uint256",
      },
    ],
    name: "transferFrom",
    outputs: [
      {
        internalType: "bool",
        name: "",
        type: "bool",
      },
    ],
    stateMutability: "nonpayable",
    type: "function",
  },
];
export const vendorABI = [
  {
    inputs: [
      {
        internalType: "address",
        name: "tokenAddress",
        type: "address",
      },
    ],
    stateMutability: "nonpayable",
    type: "constructor",
  },
  {
    anonymous: false,
    inputs: [
      {
        indexed: false,
        internalType: "address",
        name: "buyer",
        type: "address",
      },
      {
        indexed: false,
        internalType: "uint256",
        name: "amountOfETH",
        type: "uint256",
      },
      {
        indexed: false,
        internalType: "uint256",
        name: "amountOfTokens",
        type: "uint256",
      },
    ],
    name: "BuyTokens",
    type: "event",
  },
  {
    anonymous: false,
    inputs: [
      {
        indexed: true,
        internalType: "address",
        name: "previousOwner",
        type: "address",
      },
      {
        indexed: true,
        internalType: "address",
        name: "newOwner",
        type: "address",
      },
    ],
    name: "OwnershipTransferred",
    type: "event",
  },
  {
    inputs: [],
    name: "buyTokens",
    outputs: [
      {
        internalType: "uint256",
        name: "tokenAmount",
        type: "uint256",
      },
    ],
    stateMutability: "payable",
    type: "function",
  },
  {
    inputs: [],
    name: "owner",
    outputs: [
      {
        internalType: "address",
        name: "",
        type: "address",
      },
    ],
    stateMutability: "view",
    type: "function",
  },
  {
    inputs: [],
    name: "renounceOwnership",
    outputs: [],
    stateMutability: "nonpayable",
    type: "function",
  },
  {
    inputs: [
      {
        internalType: "uint256",
        name: "tokenAmountToSell",
        type: "uint256",
      },
    ],
    name: "sellTokens",
    outputs: [],
    stateMutability: "nonpayable",
    type: "function",
  },
  {
    inputs: [],
    name: "tokensPerEth",
    outputs: [
      {
        internalType: "uint256",
        name: "",
        type: "uint256",
      },
    ],
    stateMutability: "view",
    type: "function",
  },
  {
    inputs: [
      {
        internalType: "address",
        name: "newOwner",
        type: "address",
      },
    ],
    name: "transferOwnership",
    outputs: [],
    stateMutability: "nonpayable",
    type: "function",
  },
  {
    inputs: [],
    name: "withdraw",
    outputs: [],
    stateMutability: "nonpayable",
    type: "function",
  },
];

Trabajando en la autenticación

Ir al _app.jsarchivo debajo de la pagescarpeta. Aquí, incluiremos nuestra aplicación con ThirdwebProvider, lo que nos ayudará a implementar la autenticación.

Tu _app.jsdebería verse así:

import { ThirdwebProvider, ChainId } from "@thirdweb-dev/react";
import "../styles/globals.css";
function MyApp({ Component, pageProps }) {
  return (
    <ThirdwebProvider desiredChainId={ChainId.Mumbai}>
      <Component {...pageProps} />
    </ThirdwebProvider>
  );
}
export default MyApp;

Aquí, proporcionamos el desiredChainIdID de cadena de Polygon Mumbai. Ahora ve a index.jsy copia el siguiente código en él:

import { useAddress, useMetamask } from "@thirdweb-dev/react";
import Head from "next/head";
import Image from "next/image";
import styles from "../styles/Home.module.css";
import { useEffect } from "react";
import { useRouter } from "next/router";
export default function Home() {
  const connectWithMetamask = useMetamask();
  const router = useRouter();
  const address = useAddress();
  useEffect(() => {
    if (address) router.replace("/exchange");
  }, [address]);
  return (
    <div>
      <Head>
        <title>Exchange TEST tokens</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <div className="home__container">
        <h1>Sign in to exchange</h1>
        <button className="home__button" onClick={connectWithMetamask}>
          Sign in using MetaMask
        </button>
      </div>
    </div>
  );
}

Arriba, estamos usando Hooks de Thirdweb para realizar la autenticación mediante un botón y realizar un seguimiento de la dirección de la billetera del usuario. También estamos comprobando si el usuario está autenticado en un useEffect()correo electrónico y redireccionando al usuario en consecuencia.

Ahora cree un nuevo archivo llamado exchange.jsen el pagesdirectorio. Tener el siguiente diseño en el archivo:

import { useAddress } from "@thirdweb-dev/react";
import Head from "next/head";
import { useRouter } from "next/router";
import React, { useEffect, useState } from "react";
import Web3 from "web3";
import { tokenABI, vendorABI } from "../contracts";
const web3 = new Web3(Web3.givenProvider);
function Exchange() {
  const [tokens, setTokens] = useState();
  const [matic, setMatic] = useState(0);
  const address = useAddress();
  const router = useRouter();
  const purchase = async () => {};
  const sell = async () => {};
  useEffect(() => {
    if (!address) router.replace("/");
  }, [address]);
  useEffect(() => {
    setMatic(tokens / 100);
  }, [tokens]);
  return (
    <div>
      <Head>
        <title>Exchange TEST tokens</title>
      </Head>
      <div className="exchange__container">
        <h1>Purchase TEST Tokens</h1>
        <input
          type="number"
          placeholder="Amount of tokens"
          className="exchange__textBox"
          value={tokens}
          onChange={(e) => setTokens(e.target.value)}
        />
        <div>MATIC equivalent: {matic}</div>
        <button className="exchange__button" onClick={purchase}>
          Purchase
        </button>
        <button className="exchange__button" onClick={sell}>
          Sell
        </button>
      </div>
    </div>
  );
}
export default Exchange;

El código anterior verifica si el usuario está autenticado o no, y calcula cuántos MATIC se requieren para comprar tokens. El código debe proporcionar un resultado de la siguiente manera:

 

A medida que ingresa la cantidad de tokens, se actualizará la cantidad de MATIC requerida. También inicializamos el web3paquete antes que el componente, por lo que ahora podemos usar operaciones basadas en contratos.

Implementación de la funcionalidad de compra y venta.

Ahora, trabajemos en la funcionalidad real de compra y venta. En el código anterior, no tenemos código para la purchase()función. Aquí está el código para ello:

const purchase = async () => {
  try {
    const accounts = await web3.eth.getAccounts();
    const vendor = new web3.eth.Contract(
      vendorABI,
      process.env.NEXT_PUBLIC_VENDOR_CONTRACT_ADDRESS
    );
    const request = await vendor.methods.buyTokens().send({
      from: accounts[0],
      value: web3.utils.toWei(matic.toString(), "ether"),
    });
    alert("You have successfully purchased TEST tokens!");
    console.log(request);
  } catch (err) {
    console.error(err);
    alert("Error purchasing tokens");
  }
};

En el código anterior, primero conectamos las cuentas con MetaMask. Luego, inicializamos nuestro contrato de proveedor proporcionando el contrato ABI y la dirección en los parámetros del constructor.

Luego, llamamos a la buyTokens()función de nuestro contrato y enviamos la cantidad requerida de MATIC junto con la solicitud. Ahora, cuando intente comprar tokens, debería aparecer la autorización de MetaMask y, al aceptarla, debería ver los tokens en sus activos de MetaMask en breve:

 

El código para sell()es el siguiente:

const sell = async () => {
  try {
    const accounts = await web3.eth.getAccounts();
    const tokenContract = new web3.eth.Contract(
      tokenABI,
      process.env.NEXT_PUBLIC_TOKEN_CONTRACT_ADDRESS
    );
    // Approve the contract to spend the tokens
    let request = await tokenContract.methods
      .approve(
        process.env.NEXT_PUBLIC_VENDOR_CONTRACT_ADDRESS,
        web3.utils.toWei(tokens, "ether")
      )
      .send({
        from: accounts[0],
      });
    // Trigger the selling of tokens
    const vendor = new web3.eth.Contract(
      vendorABI,
      process.env.NEXT_PUBLIC_VENDOR_CONTRACT_ADDRESS
    );
    request = await vendor.methods
      .sellTokens(web3.utils.toWei(tokens, "ether"))
      .send({
        from: accounts[0],
      });
    alert("You have successfully sold TEST tokens!");
    console.log(request);
  } catch (err) {
    console.error(err);
    alert("Error selling tokens");
  }
};

En el código anterior, nos comunicamos con el contrato de token para aprobar el contrato del proveedor para gastar los tokens requeridos en nuestro nombre. Luego, nos ponemos en contacto con nuestro contrato de proveedor para iniciar el proceso de venta. Luego, los tokens se transferirán al proveedor y MATIC se enviará a la billetera del usuario.

Conclusión

¡Felicidades! Ha creado con éxito su propia plataforma de intercambio de tokens ERC-20. Aquí está el repositorio de GitHub si siente que está atascado en alguna parte del tutorial.

Fuente https://blog.logrocket.com

#blockchain #nft #web3 #erc20 #solidity #smartcontract #eth

Cómo construir una plataforma de intercambio ERC-20
Blockchain Dev

Blockchain Dev

1651212843

How to Created Your Own ERC-20 Token Exchange Platform

Learn how to build an ERC-20 exchange platform where users can mint, buy, and sell ERC-20 tokens in this comprehensive tutorial.

Applications of tokens and NFTs are increasing everyday. They bring a lot of new possibilities to the table. From using them in games to creating your own virtual currency for an event, you can do many things using Web3 technologies.

Today, we are going to make a token exchange platform, where users can buy and sell a specific token. The token type we’re going to use here is ERC-20, and we are going to deploy them on the Polygon Mumbai network.

The approach we are going to follow is first creating a smart contract, which will mint our tokens, and then another smart contract to facilitate buying and selling them. We will then use both of the smart contracts in our Next.js application in order to make buying and selling accessible to the users.

Prerequisites

  • Working knowledge of React
  • Working knowledge of Next.js
  • Working knowledge of Solidity
  • Node.js installed
  • A code editor – I prefer Visual Studio Code
  • MetaMask extension installed with at least one wallet
  • MetaMask connected to Polygon Mumbai testnet

If you feel you’re stuck in the tutorial, feel free to refer to the GitHub repository.

Contents

  • Creating the token smart contract
  • Creating the vendor contract
  • Configuring the vendor smart contract
  • Setting up our Next.js app
  • Setting up environment variables
  • Working on authentication
  • Implementing purchasing and selling functionality

Creating the token smart contract

The token smart contract will help us mint tokens. Open Remix IDE and create a new file called TestToken.sol under the contracts folder. Use the following code in the file:

// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract TestToken is ERC20 {
    constructor() ERC20("TestToken", "TEST"){
        _mint(msg.sender, 10000 * 10 ** 18);
    }
}

In the above code, we are using OpenZeppelin contract templates to create an ERC-20 token. These templates provide us with bare minimum functions required by an ERC-20 tokens, and are secure and optimized, so you don’t need to worry about using tightening the security of your token. In the constructor of our contract, we are specifying the name and the symbol of our token and minting 10,000 tokens into the contract creator’s wallet.

Now, compile the contract by pressing Ctrl + S (or Cmd + S for Mac). Make sure you have connected MetaMask to Polygon Mumbai. Go to the Deploy tab in the sidebar, and set the environment to Injected Web3, so that Remix IDE uses MetaMask to deploy your contract.

Make sure your other settings are similar to this:

metamask settings

After verifying all the settings, click on Deploy. This should open up MetaMask authorization popup. Click on Confirm.

 

If you don’t have funds in your Polygon Mumbai wallet, you can get some through a faucet. After confirming the transaction, wait for a few seconds until you see your contract deployed on the left sidebar.

Copy the contract address, as we will need it when configuring the vendor contract.

Creating the vendor contract

Create a new file called TestTokenVendor.sol under the contracts folder. Use the following code for the contract:

// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.4;
import "./TestToken.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract Vendor is Ownable {
  TestToken yourToken;
  uint256 public tokensPerMatic = 100;
  event BuyTokens(address buyer, uint256 amountOfMATIC, uint256 amountOfTokens);
  constructor(address tokenAddress) {
    yourToken = TestToken(tokenAddress);
  }

  function buyTokens() public payable returns (uint256 tokenAmount) {
    require(msg.value > 0, "You need to send some MATIC to proceed");
    uint256 amountToBuy = msg.value * tokensPerMatic;

    uint256 vendorBalance = yourToken.balanceOf(address(this));
    require(vendorBalance >= amountToBuy, "Vendor has insufficient tokens");

    (bool sent) = yourToken.transfer(msg.sender, amountToBuy);
    require(sent, "Failed to transfer token to user");

    emit BuyTokens(msg.sender, msg.value, amountToBuy);
    return amountToBuy;
  }
  function sellTokens(uint256 tokenAmountToSell) public {

    require(tokenAmountToSell > 0, "Specify an amount of token greater than zero");

    uint256 userBalance = yourToken.balanceOf(msg.sender);
    require(userBalance >= tokenAmountToSell, "You have insufficient tokens");

    uint256 amountOfMATICToTransfer = tokenAmountToSell / tokensPerMatic;
    uint256 ownerMATICBalance = address(this).balance;
    require(ownerMATICBalance >= amountOfMATICToTransfer, "Vendor has insufficient funds");
    (bool sent) = yourToken.transferFrom(msg.sender, address(this), tokenAmountToSell);
    require(sent, "Failed to transfer tokens from user to vendor");

    (sent,) = msg.sender.call{value: amountOfMATICToTransfer}("");
    require(sent, "Failed to send MATIC to the user");
  }

  function withdraw() public onlyOwner {
    uint256 ownerBalance = address(this).balance;
    require(ownerBalance > 0, "No MATIC present in Vendor");
    (bool sent,) = msg.sender.call{value: address(this).balance}("");
    require(sent, "Failed to withdraw");
  }
}

In the above code, we are creating an Ownable contract, which is an OpenZeppelin template. This means that we can transfer the ownership of this contract to some other wallet, if we wish to do so.

We are importing our token contract and providing the address to it through the constructor (we will provide the address as an argument while deploying the contract). We are also setting a general price of the token inside the tokensPerMatic variable. This value will be used to calculate the amount of tokens to purchase based on the amount of MATIC sent to the contract.

In the buyTokens() function, we are firstly checking if any MATIC was sent and if the vendor contract has sufficient tokens in balance or not. Then we are doing yourToken.transfer() to send our tokens from the vendor contract to the wallet that sent the contract call. Finally, we are emitting an event and returning the number of tokens purchased.

The sellTokens() function is not as straightforward as the buyTokens() function. We perform checks on whether user has the specified number of tokens or not, calculate the amount of MATIC to be sent back to the user, and check whether the vendor contract has sufficient amount of MATIC in balance.

However, here comes the fun part: we can’t just transfer tokens from user’s wallet to our vendor contract’s balance. We first need to ask for approval from the user to let us manage their tokens and send these tokens back to us. This method is secure because we need to set the limit of number of tokens we are asking approval for. The authorization is on MetaMask and the user can clearly see what amount of tokens is the contract allowed to handle.

This approval procedure takes place on the front end (of a Next.js application, in this case). After the approval is granted, we perform the transferFrom() function to transfer the user’s funds to vendor contract’s wallet. And finally, we send MATIC to the user.

The withdraw() function can only be run by the owner of the contract. This function allows you to send all the MATIC stored in the smart contract into the owner’s wallet.

Finally, deploy the contract and pass the token contract’s address as a parameter.

Configuring the vendor smart contract

Now that we have deployed the vendor smart contract, we need to send it some tokens to work.

Open the token contract in the Deploy tab. Under the transfer section, paste the vendor contract’s address and the total amount of tokens (which can be obtained by clicking totalSupply.

Click on transact to approve the MetaMask transaction, and all the tokens will be sent from your wallet to the vendor contract balance. Now your vendor contract is able to facilitate buying and selling of tokens.

Now, go to the compile tab, and copy the ABI of the two contracts (as well as token and vendor addresses), as we will need them in our Next.js file.

Setting up our Next.js app

Navigate to a safe directory and run the following command in the terminal to create your Next.js app:

npx create-next-app erc20-exchange-platform

Use --use-npm at the end if you wish to install dependencies using npm (create-next-app has recently defaulted to yarn). Navigate to the project folder and run the following command to install some required dependencies:

#npm npm install @thirdweb-dev/sdk @thirdweb-dev/react web3 #yarn yarn add @thirdweb-dev/sdk @thirdweb-dev/react web3

We are installing @thirdweb-dev/sdk to help with authentication and connecting our application to MetaMask. This way, we don’t spend a lot of time in authentication.

We are also installing @thirdweb-dev/react to provide us Hooks that will work with @thirdweb-dev/sdk to give us useful information about the state of the user. We are installing web3 to interact with our token and vendor smart contracts.

As we won’t be covering styling in this tutorial, I’ll just leave it here without focusing too much on the details. Open globals.css under the styles folder and use the following styles:

html,
body {
  padding: 0;
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
    Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}
a {
  color: inherit;
  text-decoration: none;
}
* {
  box-sizing: border-box;
}
.home__container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
}
.home__button {
  background-color: #2ecc71;
  border: none;
  border-radius: 5px;
  font-size: 20px;
  padding: 15px;
  margin: 10px;
  cursor: pointer;
}
.exchange__container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
}
.exchange__textBox {
  width: 300px;
  height: 50px;
  border: 1px solid #c4c4c4;
  border-radius: 5px;
  font-size: 20px;
  padding: 15px;
  margin: 10px;
  cursor: pointer;
}
.exchange__button {
  width: 300px;
  height: 50px;
  border: 1px solid #2ecc71;
  background-color: #2ecc71;
  border-radius: 5px;
  font-size: 20px;
  padding: 15px;
  margin: 10px;
  cursor: pointer;
}

Setting up environment variables and other data

Create a new file called .env.local in the project directory, this will hold our contract addresses:

NEXT_PUBLIC_TOKEN_CONTRACT_ADDRESS=(token address here) NEXT_PUBLIC_VENDOR_CONTRACT_ADDRESS=(vendor address here)

Now, create a new file called contracts.js in the project directory. In this file, we will save and export the contract ABIs for both contracts:

export const tokenABI = [
  {
    inputs: [],
    stateMutability: "nonpayable",
    type: "constructor",
  },
  {
    anonymous: false,
    inputs: [
      {
        indexed: true,
        internalType: "address",
        name: "owner",
        type: "address",
      },
      {
        indexed: true,
        internalType: "address",
        name: "spender",
        type: "address",
      },
      {
        indexed: false,
        internalType: "uint256",
        name: "value",
        type: "uint256",
      },
    ],
    name: "Approval",
    type: "event",
  },
  {
    anonymous: false,
    inputs: [
      {
        indexed: true,
        internalType: "address",
        name: "from",
        type: "address",
      },
      {
        indexed: true,
        internalType: "address",
        name: "to",
        type: "address",
      },
      {
        indexed: false,
        internalType: "uint256",
        name: "value",
        type: "uint256",
      },
    ],
    name: "Transfer",
    type: "event",
  },
  {
    inputs: [
      {
        internalType: "address",
        name: "owner",
        type: "address",
      },
      {
        internalType: "address",
        name: "spender",
        type: "address",
      },
    ],
    name: "allowance",
    outputs: [
      {
        internalType: "uint256",
        name: "",
        type: "uint256",
      },
    ],
    stateMutability: "view",
    type: "function",
  },
  {
    inputs: [
      {
        internalType: "address",
        name: "spender",
        type: "address",
      },
      {
        internalType: "uint256",
        name: "amount",
        type: "uint256",
      },
    ],
    name: "approve",
    outputs: [
      {
        internalType: "bool",
        name: "",
        type: "bool",
      },
    ],
    stateMutability: "nonpayable",
    type: "function",
  },
  {
    inputs: [
      {
        internalType: "address",
        name: "account",
        type: "address",
      },
    ],
    name: "balanceOf",
    outputs: [
      {
        internalType: "uint256",
        name: "",
        type: "uint256",
      },
    ],
    stateMutability: "view",
    type: "function",
  },
  {
    inputs: [],
    name: "decimals",
    outputs: [
      {
        internalType: "uint8",
        name: "",
        type: "uint8",
      },
    ],
    stateMutability: "view",
    type: "function",
  },
  {
    inputs: [
      {
        internalType: "address",
        name: "spender",
        type: "address",
      },
      {
        internalType: "uint256",
        name: "subtractedValue",
        type: "uint256",
      },
    ],
    name: "decreaseAllowance",
    outputs: [
      {
        internalType: "bool",
        name: "",
        type: "bool",
      },
    ],
    stateMutability: "nonpayable",
    type: "function",
  },
  {
    inputs: [
      {
        internalType: "address",
        name: "spender",
        type: "address",
      },
      {
        internalType: "uint256",
        name: "addedValue",
        type: "uint256",
      },
    ],
    name: "increaseAllowance",
    outputs: [
      {
        internalType: "bool",
        name: "",
        type: "bool",
      },
    ],
    stateMutability: "nonpayable",
    type: "function",
  },
  {
    inputs: [],
    name: "name",
    outputs: [
      {
        internalType: "string",
        name: "",
        type: "string",
      },
    ],
    stateMutability: "view",
    type: "function",
  },
  {
    inputs: [],
    name: "symbol",
    outputs: [
      {
        internalType: "string",
        name: "",
        type: "string",
      },
    ],
    stateMutability: "view",
    type: "function",
  },
  {
    inputs: [],
    name: "totalSupply",
    outputs: [
      {
        internalType: "uint256",
        name: "",
        type: "uint256",
      },
    ],
    stateMutability: "view",
    type: "function",
  },
  {
    inputs: [
      {
        internalType: "address",
        name: "to",
        type: "address",
      },
      {
        internalType: "uint256",
        name: "amount",
        type: "uint256",
      },
    ],
    name: "transfer",
    outputs: [
      {
        internalType: "bool",
        name: "",
        type: "bool",
      },
    ],
    stateMutability: "nonpayable",
    type: "function",
  },
  {
    inputs: [
      {
        internalType: "address",
        name: "from",
        type: "address",
      },
      {
        internalType: "address",
        name: "to",
        type: "address",
      },
      {
        internalType: "uint256",
        name: "amount",
        type: "uint256",
      },
    ],
    name: "transferFrom",
    outputs: [
      {
        internalType: "bool",
        name: "",
        type: "bool",
      },
    ],
    stateMutability: "nonpayable",
    type: "function",
  },
];
export const vendorABI = [
  {
    inputs: [
      {
        internalType: "address",
        name: "tokenAddress",
        type: "address",
      },
    ],
    stateMutability: "nonpayable",
    type: "constructor",
  },
  {
    anonymous: false,
    inputs: [
      {
        indexed: false,
        internalType: "address",
        name: "buyer",
        type: "address",
      },
      {
        indexed: false,
        internalType: "uint256",
        name: "amountOfETH",
        type: "uint256",
      },
      {
        indexed: false,
        internalType: "uint256",
        name: "amountOfTokens",
        type: "uint256",
      },
    ],
    name: "BuyTokens",
    type: "event",
  },
  {
    anonymous: false,
    inputs: [
      {
        indexed: true,
        internalType: "address",
        name: "previousOwner",
        type: "address",
      },
      {
        indexed: true,
        internalType: "address",
        name: "newOwner",
        type: "address",
      },
    ],
    name: "OwnershipTransferred",
    type: "event",
  },
  {
    inputs: [],
    name: "buyTokens",
    outputs: [
      {
        internalType: "uint256",
        name: "tokenAmount",
        type: "uint256",
      },
    ],
    stateMutability: "payable",
    type: "function",
  },
  {
    inputs: [],
    name: "owner",
    outputs: [
      {
        internalType: "address",
        name: "",
        type: "address",
      },
    ],
    stateMutability: "view",
    type: "function",
  },
  {
    inputs: [],
    name: "renounceOwnership",
    outputs: [],
    stateMutability: "nonpayable",
    type: "function",
  },
  {
    inputs: [
      {
        internalType: "uint256",
        name: "tokenAmountToSell",
        type: "uint256",
      },
    ],
    name: "sellTokens",
    outputs: [],
    stateMutability: "nonpayable",
    type: "function",
  },
  {
    inputs: [],
    name: "tokensPerEth",
    outputs: [
      {
        internalType: "uint256",
        name: "",
        type: "uint256",
      },
    ],
    stateMutability: "view",
    type: "function",
  },
  {
    inputs: [
      {
        internalType: "address",
        name: "newOwner",
        type: "address",
      },
    ],
    name: "transferOwnership",
    outputs: [],
    stateMutability: "nonpayable",
    type: "function",
  },
  {
    inputs: [],
    name: "withdraw",
    outputs: [],
    stateMutability: "nonpayable",
    type: "function",
  },
];

Working on authentication

Go to _app.js file under the pages folder. Here, we will enclose our app with ThirdwebProvider, which will help us implement authentication.

Your _app.js should look like this:

import { ThirdwebProvider, ChainId } from "@thirdweb-dev/react";
import "../styles/globals.css";
function MyApp({ Component, pageProps }) {
  return (
    <ThirdwebProvider desiredChainId={ChainId.Mumbai}>
      <Component {...pageProps} />
    </ThirdwebProvider>
  );
}
export default MyApp;

Here, we are providing the desiredChainId as the chain ID of Polygon Mumbai. Now go to index.js and copy the following code in it:

import { useAddress, useMetamask } from "@thirdweb-dev/react";
import Head from "next/head";
import Image from "next/image";
import styles from "../styles/Home.module.css";
import { useEffect } from "react";
import { useRouter } from "next/router";
export default function Home() {
  const connectWithMetamask = useMetamask();
  const router = useRouter();
  const address = useAddress();
  useEffect(() => {
    if (address) router.replace("/exchange");
  }, [address]);
  return (
    <div>
      <Head>
        <title>Exchange TEST tokens</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <div className="home__container">
        <h1>Sign in to exchange</h1>
        <button className="home__button" onClick={connectWithMetamask}>
          Sign in using MetaMask
        </button>
      </div>
    </div>
  );
}

Above, we are using Hooks from Thirdweb to perform authentication using a button and keeping track of the address of the user’s wallet. We are also checking if the user is authenticated in an useEffect() and redirecting the user accordingly.

Now create a new file called exchange.js in the pages directory. Have the following layout in the file:

import { useAddress } from "@thirdweb-dev/react";
import Head from "next/head";
import { useRouter } from "next/router";
import React, { useEffect, useState } from "react";
import Web3 from "web3";
import { tokenABI, vendorABI } from "../contracts";
const web3 = new Web3(Web3.givenProvider);
function Exchange() {
  const [tokens, setTokens] = useState();
  const [matic, setMatic] = useState(0);
  const address = useAddress();
  const router = useRouter();
  const purchase = async () => {};
  const sell = async () => {};
  useEffect(() => {
    if (!address) router.replace("/");
  }, [address]);
  useEffect(() => {
    setMatic(tokens / 100);
  }, [tokens]);
  return (
    <div>
      <Head>
        <title>Exchange TEST tokens</title>
      </Head>
      <div className="exchange__container">
        <h1>Purchase TEST Tokens</h1>
        <input
          type="number"
          placeholder="Amount of tokens"
          className="exchange__textBox"
          value={tokens}
          onChange={(e) => setTokens(e.target.value)}
        />
        <div>MATIC equivalent: {matic}</div>
        <button className="exchange__button" onClick={purchase}>
          Purchase
        </button>
        <button className="exchange__button" onClick={sell}>
          Sell
        </button>
      </div>
    </div>
  );
}
export default Exchange;

The above code is checking if the user is authenticated or not, and calculating how many MATIC is required to purchase tokens. The code should provide a result as follows:

Purchase test tokens screen

As you type in the number of tokens, the amount of MATIC required will be updated. We also have initialized the web3 package before the component, so we can use contract-based operations now.

Implementing purchasing and selling functionality

Now, let’s work on the actual functionality of purchasing and selling. In the above code, we have no code for purchase() function. Here’s the code for it:

const purchase = async () => {
  try {
    const accounts = await web3.eth.getAccounts();
    const vendor = new web3.eth.Contract(
      vendorABI,
      process.env.NEXT_PUBLIC_VENDOR_CONTRACT_ADDRESS
    );
    const request = await vendor.methods.buyTokens().send({
      from: accounts[0],
      value: web3.utils.toWei(matic.toString(), "ether"),
    });
    alert("You have successfully purchased TEST tokens!");
    console.log(request);
  } catch (err) {
    console.error(err);
    alert("Error purchasing tokens");
  }
};

In the above code, we first get the accounts connected with MetaMask. Then, we initialize our vendor contract by providing the contract ABI and address in the parameters of the constructor.

Then, we call the buyTokens() function of our contract and send the required amount of MATIC along with the request. Now when you attempt to purchase tokens, MetaMask authorization should pop up and, upon accepting it, you should see tokens in your MetaMask assets shortly:

number of test tokens

The code for sell() is as follows:

const sell = async () => {
  try {
    const accounts = await web3.eth.getAccounts();
    const tokenContract = new web3.eth.Contract(
      tokenABI,
      process.env.NEXT_PUBLIC_TOKEN_CONTRACT_ADDRESS
    );
    // Approve the contract to spend the tokens
    let request = await tokenContract.methods
      .approve(
        process.env.NEXT_PUBLIC_VENDOR_CONTRACT_ADDRESS,
        web3.utils.toWei(tokens, "ether")
      )
      .send({
        from: accounts[0],
      });
    // Trigger the selling of tokens
    const vendor = new web3.eth.Contract(
      vendorABI,
      process.env.NEXT_PUBLIC_VENDOR_CONTRACT_ADDRESS
    );
    request = await vendor.methods
      .sellTokens(web3.utils.toWei(tokens, "ether"))
      .send({
        from: accounts[0],
      });
    alert("You have successfully sold TEST tokens!");
    console.log(request);
  } catch (err) {
    console.error(err);
    alert("Error selling tokens");
  }
};

In the above code, we are contacting the token contract to approve the vendor contract to spend required tokens on our behalf. Then, we are contacting our vendor contract to initiate the selling process. The tokens will then be transferred to the vendor and MATIC will be sent to the user’s wallet.

Conclusion

Congratulations! You’ve successfully created your own ERC-20 token exchange platform. Here’s the GitHub repository if you feel you’re stuck somewhere in the tutorial.

Original article source at https://blog.logrocket.com

#blockchain #nft #web3 #erc20 #solidity #smartcontract #eth

How to Created Your Own ERC-20 Token Exchange Platform

Solidity Tutorial: ERC20 Tokens & Creating your own Crypto Currency

The Ethereum blockchain allows you to create your own cryptocurrency, or token, that can be purchased with Ether, the native cryptocurrency of the Ethereum blockchain. ERC-20 is simply a standard that specifies how these tokens behave, so that they are compatible with other platforms like cryptocurrency exchanges.

#ethereum  #solidity  #blockchain  #smartcontract #erc20 #crypto 

Solidity Tutorial: ERC20 Tokens & Creating your own Crypto Currency
Best of Crypto

Best of Crypto

1647418620

Gravity Bridge: A CosmosSDK for Moving Assets on & Off Of EVM Based

Gravity bridge is Cosmos <-> Ethereum bridge designed to run on the Cosmos Hub focused on maximum design simplicity and efficiency.

Gravity can transfer ERC20 assets originating on Ethereum to a Cosmos based chain and back to Ethereum.

The ability to transfer assets originating on Cosmos to an ERC20 representation on Ethereum is coming within a few months.

Status

Gravity bridge is under development and will be undergoing audits soon. Instructions for deployment and use are provided in the hope that they will be useful.

It is your responsibility to understand the financial, legal, and other risks of using this software. There is no guarantee of functionality or safety. You use Gravity entirely at your own risk.

You can keep up with the latest development by watching our public standups feel free to join yourself and ask questions.

  • Solidity Contract
    •  Multiple ERC20 support
    •  Tested with 100+ validators
    •  Unit tests for every throw condition
    •  Audit for assets originating on Ethereum
    •  Support for issuing Cosmos assets on Ethereum
  • Cosmos Module
    •  Basic validator set syncing
    •  Basic transaction batch generation
    •  Ethereum -> Cosmos Token issuing
    •  Cosmos -> Ethereum Token issuing
    •  Bootstrapping
    •  Genesis file save/load
    •  Validator set syncing edge cases
    •  Slashing
    •  Relaying edge cases
    •  Transaction batch edge cases
    •  Support for issuing Cosmos assets on Ethereum
    •  Audit
  • Orchestrator / Relayer
    •  Validator set update relaying
    •  Ethereum -> Cosmos Oracle
    •  Transaction batch relaying
    •  Tendermint KMS support
    •  Audit

The design of Gravity Bridge

  • Trust in the integrity of the Gravity bridge is anchored on the Cosmos side. The signing of fraudulent validator set updates and transaction batches meant for the Ethereum contract is punished by slashing on the Cosmos chain. If you trust the Cosmos chain, you can trust the Gravity bridge operated by it, as long as it is operated within certain parameters.
  • It is mandatory for peg zone validators to maintain a trusted Ethereum node. This removes all trust and game theory implications that usually arise from independent relayers, once again dramatically simplifying the design.

Key design Components

  • A highly efficient way of mirroring Cosmos validator voting onto Ethereum. The Gravity solidity contract has validator set updates costing ~500,000 gas ($2 @ 20gwei), tested on a snapshot of the Cosmos Hub validator set with 125 validators. Verifying the votes of the validator set is the most expensive on chain operation Gravity has to perform. Our highly optimized Solidity code provides enormous cost savings. Existing bridges incur more than double the gas costs for signature sets as small as 8 signers.
  • Transactions from Cosmos to ethereum are batched, batches have a base cost of ~500,000 gas ($2 @ 20gwei). Batches may contain arbitrary numbers of transactions within the limits of ERC20 sends per block, allowing for costs to be heavily amortized on high volume bridges.

Operational parameters ensuring security

  • There must be a validator set update made on the Ethereum contract by calling the updateValset method at least once every Cosmos unbonding period (usually 2 weeks). This is because if there has not been an update for longer than the unbonding period, the validator set stored by the Ethereum contract could contain validators who cannot be slashed for misbehavior.
  • Cosmos full nodes do not verify events coming from Ethereum. These events are accepted into the Cosmos state based purely on the signatures of the current validator set. It is possible for the validators with >2/3 of the stake to put events into the Cosmos state which never happened on Ethereum. In this case observers of both chains will need to "raise the alarm". We have built this functionality into the relayer.

Run Gravity bridge right now using docker

We provide a one button integration test that deploys a full arbitrary validator Cosmos chain and testnet Geth chain for both development + validation. We believe having a in depth test environment reflecting the full deployment and production-like use of the code is essential to productive development.

Currently on every commit we send hundreds of transactions, dozens of validator set updates, and several transaction batches in our test environment. This provides a high level of quality assurance for the Gravity bridge.

Because the tests build absolutely everything in this repository they do take a significant amount of time to run. You may wish to simply push to a branch and have Github CI take care of the actual running of the tests.

To run the test simply have docker installed and run.

bash tests/all-up-test.sh

There are optional tests for specific features

Valset stress changes the validating power randomly 25 times, in an attempt to break validator set syncing

bash tests/all-up-test.sh VALSET_STRESS

Batch stress sends 300 transactions over the bridge and then 3 batches back to Ethereum. This code can do up to 10k transactions but Github Actions does not have the horsepower.

bash tests/all-up-test.sh BATCH_STRESS

Validator out tests a validator that is not running the mandatory Ethereum node. This validator will be slashed and the bridge will remain functioning.

bash tests/all-up-test.sh VALIDATOR_OUT

Developer guide

Solidity Contract

in the solidity folder

Run HUSKY_SKIP_INSTALL=1 npm install, then npm run typechain.

Run npm run evm in a separate terminal and then

Run npm run test to run tests.

After modifying solidity files, run npm run typechain to recompile contract typedefs.

The Solidity contract is also covered in the Cosmos module tests, where it will be automatically deployed to the Geth test chain inside the development container for a micro testnet every integration test run.

Cosmos Module

We provide a standard container-based development environment that automatically bootstraps a Cosmos chain and Ethereum chain for testing. We believe standardization of the development environment and ease of development are essential so please file issues if you run into issues with the development flow.

Go unit tests

These do not run the entire chain but instead test parts of the Go module code in isolation. To run them, go into /module and run make test

To hand test your changes quickly

This method is dictinct from the all up test described above. Although it runs the same components it's much faster when editing individual components.

  1. run ./tests/build-container.sh
  2. run ./tests/start-chains.sh
  3. switch to a new terminal and run ./tests/run-tests.sh
  4. Or, docker exec -it gravity_test_instance /bin/bash should allow you to access a shell inside the test container

Change the code, and when you want to test it again, restart ./tests/start-chains.sh and run ./tests/run-tests.sh.

Explanation:

./tests/build-container.sh builds the base container and builds the Gravity test zone for the first time. This results in a Docker container which contains cached Go dependencies (the base container).

./tests/start-chains.sh starts a test container based on the base container and copies the current source code (including any changes you have made) into it. It then builds the Gravity test zone, benefiting from the cached Go dependencies. It then starts the Cosmos chain running on your new code. It also starts an Ethereum node. These nodes stay running in the terminal you started it in, and it can be useful to look at the logs. Be aware that this also mounts the Gravity repo folder into the container, meaning changes you make will be reflected there.

./tests/run-tests.sh connects to the running test container and runs the integration test found in ./tests/integration-tests.sh

Tips for IDEs:

  • Launch VS Code in /solidity with the solidity extension enabled to get inline typechecking of the solidity contract
  • Launch VS Code in /module/app with the go extension enabled to get inline typechecking of the dummy cosmos chain

Working inside the container

It can be useful to modify, recompile, and restart the testnet without restarting the container, for example if you are running a text editor in the container and would not like it to exit, or if you are editing dependencies stored in the container's /go/ folder.

In this workflow, you can use ./tests/reload-code.sh to recompile and restart the testnet without restarting the container.

For example, you can use VS Code's "Remote-Container" extension to attach to the running container started with ./tests/start-chains.sh, then edit the code inside the container, restart the testnet with ./tests/reload-code.sh, and run the tests with ./tests/integration-tests.sh.

Debugger

To use a stepping debugger in VS Code, follow the "Working inside the container" instructions above, but set up a one node testnet using ./tests/reload-code.sh 1. Now kill the node with pkill gravityd. Start the debugger from within VS Code, and you will have a 1 node debuggable testnet.

Download Details:
Author: cosmos
Source Code: https://github.com/cosmos/gravity-bridge
License: Apache-2.0 License

#blockchain  #cosmos  #cryptocurrency #evm #ethereum #POW #erc20 

Gravity Bridge: A CosmosSDK for Moving Assets on & Off Of EVM Based
Token Center

Token Center

1645903047

How to Create BEP20 Token? BEP20 Token Create Tool

If you would like to create BEP20 token under Binance Smart Chain without any coding skills, you are invited to use the BEP20 Token Generator which is free and easy to use with its user friendly interface.

Bep20 Token Generator

BEP20 Token Generator: https://tokencenter.github.io/bep20-generator/

BEP20 Token Generator is a free DApp which allows you to create your own BEP20 token in less than a minute.

What is BEP20 token?

A Token is a Smart Contract that represents digital assets that may be sent and received and have value. Smart Contracts are programs that function precisely as they are planned, with no downtime, censorship, fraud, or third-party influence. These apps are built on a Blockchain, a massively powerful shared global infrastructure that can move value and reflect property ownership.

BEP20 specifies how APIs for token smart contracts should be implemented. It is based on Ethereum's ERC20 protocol and offers the fundamental functionality of transferring tokens, approving tokens so they may be spent by another on-chain third party, and transferring between Binance Chain and Binance Smart Chain.

How to code BEP20 token?

Solidity is the most often used programming language for smart contracts.

Solidity is a high-level object-oriented programming language for creating Smart Contracts. Solidity is statically typed and, among other things, enables inheritance, libraries, and sophisticated user-defined types. Solidity allows you to design contracts for voting, crowdfunding, blind auctions, and multi-signature wallets, among other things.

There are several libraries and tools that give implementations of standards such as ERC20 and ERC721 that you may use as-is or modify to fit your needs, as well as Solidity components for creating bespoke contracts and more complicated decentralized systems.

How to create ERC20 token by using TokenCenter?

It is super easy to use the tool

  1. To to BEP20 Token Generator
  2. Install Metamask and login.
  3. Enter your token details such as name, symbol, decimals and supply.
  4. Create your token.

Your Token will be completely compliant with the BEP20 specification and will work with any BEP20 wallet anywhere on the planet. It will have a Name, a Symbol, and a quantity in decimals.

#bep20tokens  #solidity #metamask #erc20  #bep20  #bep20tokengenerator  #bep20token  #bep20generator  #bsc #bep20token 

How to Create BEP20 Token? BEP20 Token Create Tool
Token Center

Token Center

1645902188

How to Create ERC20 Token? ERC20 Token Create Tool

If you would like to create ERC20 token under Ethereum network without any coding skills, you are invited to use the ERC20 Token Generator which is free and easy to use with its user friendly interface.

ERC20 Token Generator: https://tokencenter.github.io/erc20-generator/

ERC20 Token Generator is a free DApp which allows you to create your own ERC20 token in less than a minute.

What is ERC20 Token?

A Token is a Smart Contract that represents digital assets that may be sent and received and have value. Smart Contracts are programs that function precisely as they are planned, with no downtime, censorship, fraud, or third-party influence. These apps are built on a Blockchain, a massively powerful shared global infrastructure that can move value and reflect property ownership.

The Ethereum Blockchain is used to operate ERC20 Tokens. The ERC20 Token protocol gained popularity through initial coin offerings (ICOs) among crowdfunding businesses, and it is now being used in DeFi initiatives like Uniswap.

The ERC20 interface defines a set of functions to be implemented to allow integration with other Smart Contracts, Wallets or Marketplaces.

How to code ERC20 Tokens

Solidity is the most often used programming language of smart contracts.

Solidity is a high-level object-oriented programming language for creating Smart Contracts. Solidity is statically typed and, among other things, enables inheritance, libraries, and sophisticated user-defined types. Solidity allows you to design contracts for voting, crowdfunding, blind auctions, and multi-signature wallets, among other things.

There are several libraries and tools that give implementations of standards such as ERC20 and ERC721 that you may use as-is or modify to fit your needs, as well as Solidity components for creating bespoke contracts and more complicated decentralized systems.

How to create ERC20 token by using TokenCenter?

It is super easy to use the tool

  1. Install Metamask and login.
  2. Enter your token details such as name, symbol, decimals and supply.
  3. Create your token.

Your Token will be completely compliant with the ERC20 specification and will work with any ERC20 wallet anywhere on the planet. It will have a Name, a Symbol, and a quantity in decimals.

#eth #erc20 #token #erc20 token create #solidity #metamask

How to Create ERC20 Token? ERC20 Token Create Tool
Arden  Keebler

Arden Keebler

1645717260

How to Sell any NFT for ERC-20 Tokens in NFT Marketplaces

Learn how to use Tatum's NFT marketplace smart contract to sell any ERC-721 or ERC-1155 NFT (from Tatum, from OpenSea, from your own smart contract, etc.) for any custom ERC-20 token.

#nft #blockchain #erc20 #token #nftmarketplace #smartcontract 

How to Sell any NFT for ERC-20 Tokens in NFT Marketplaces
Arden  Keebler

Arden Keebler

1645695420

How to Use NFT Marketplaces To Sell Tatum Royalty NFTs for ERC20 Token

Learn how to use Tatum's NFT marketplace smart contract to sell Tatum royalty NFTs for any custom ERC-20 token.

#erc20 #blockchain #nft #nfts #nftmarketplace #smartcontract 

How to Use NFT Marketplaces To Sell Tatum Royalty NFTs for ERC20 Token