• HOME
  • PRODUCT
  • DEVELOP
  • NEWS
  • CONSULTING
No Result
View All Result
illunex Blog
  • HOME
  • PRODUCT
  • DEVELOP
  • NEWS
  • CONSULTING
No Result
View All Result
일루넥스 블로그
No Result
View All Result

TRX(ERC20) 개발 Basic 4

4. 웹(ReactJS) 연동

박 진혁 by 박 진혁
2020년 9월 28일
in DEVELOP, 강의
TRX(ERC20) 개발 Basic 4

4. 웹(ReactJS) 연동

1. React 코드 수정

1.1. app.js

: contract 를 생성했던 address 를 contractAddress 변수에 활당해야한다.

import React from 'react';
import TronLinkGuide from 'components/TronLinkGuide';
import TronWeb from 'tronweb';
import Utils from 'utils';
import Swal from 'sweetalert2';
import Content from './Content';

import './App.scss';

// 창조자 주소
const FOUNDATION_ADDRESS = 'TCh7ZJM7mtxtDxfM6UwQrjBAFiqu1QCAqX';

// 받을 사람주소
const RECEIVER_ADDRESS = 'TZ9ZDkk2enDUzsnhpGHZS5mnuQeKemKUSe';
const RECEIVER_ADDRESS2 = 'TVLX75yPmRnJkE4sP6Sir5sPEaaKc6hMWz';

// contract 주소
const contractAddress = 'TDegrR2vLenMVvYYsd1FbYqUZoDUpksA7f';

class App extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            balance: 0,
            getbalanceaddress: '',
            transferaddress: '',
            transferamount: '',
            contractAddress: '',
            tokenname: '',
            tokensymbol: '',
            tronwebaddress: '',
            totalSupply: '',
            burnamount: '',
            transferfromfromaddress: '',
            transferfromtoaddress: '',
            transferfromamount: '',
            approvespender: '',
            approveamount: '',
            burnfromfrom: '',
            burnfromamount: '',

            tronWeb: {
                installed: false,
                loggedIn: false
            },
        }

        this.updateGetBalanceInputValue = this.updateGetBalanceInputValue.bind(this)
        this.updateTransferInputValue = this.updateTransferInputValue.bind(this)
        this.updateTransferAmountInputValue = this.updateTransferAmountInputValue.bind(this)
        this.updateContractAddressInput = this.updateContractAddressInput.bind(this)
        this.updateBurnAmountInputValue = this.updateBurnAmountInputValue.bind(this)
        this.updateTansferFromFromInputValue = this.updateTansferFromFromInputValue.bind(this)
        this.updateTansferFromToInputValue = this.updateTansferFromToInputValue.bind(this)
        this.updateTansferFromAmountInputValue = this.updateTansferFromAmountInputValue.bind(this)
        this.updateApproveSpender = this.updateApproveSpender.bind(this)
        this.updateApproveValue = this.updateApproveValue.bind(this)
        this.updateBurnFromFromValue = this.updateBurnFromFromValue.bind(this)
        this.updateBurnFromAmountValue = this.updateBurnFromAmountValue.bind(this)
    }

    async componentDidMount() {
        this.setState({loading: true})

        await new Promise(resolve => {

            console.log('window.tronWeb===>' + window.tronWeb);

            const tronWebState = {
                installed: !!window.tronWeb,
                loggedIn: window.tronWeb && window.tronWeb.ready
            };

            if (tronWebState.installed) {
                this.setState({
                    tronWeb: tronWebState
                });

                return resolve();
            }

            let tries = 0;
            const timer = setInterval(() => {
                if (tries >= 10) {
                    const TRONGRID_API = 'https://api.trongrid.io';

                    window.tronWeb = new TronWeb(
                        TRONGRID_API,
                        TRONGRID_API,
                        TRONGRID_API
                    );

                    this.setState({
                        tronWeb: {
                            installed: false,
                            loggedIn: false
                        }
                    });

                    clearInterval(timer);
                    return resolve();
                }
                tronWebState.installed = !!window.tronWeb;
                tronWebState.loggedIn = window.tronWeb && window.tronWeb.ready;

                if (!tronWebState.installed)
                    return tries++;

                this.setState({
                    tronWeb: tronWebState
                });

                resolve();

            }, 100);

        })

        if (!this.state.tronWeb.loggedIn) {
            // Set default address (foundation address) used for contract calls
            // Directly overwrites the address object as TronLink disabled the
            // function call


            window.tronWeb.defaultAddress = {
                hex: window.tronWeb.address.toHex(FOUNDATION_ADDRESS),
                base58: FOUNDATION_ADDRESS
            };

            window.tronWeb.on('addressChanged', () => {
                if (this.state.tronWeb.loggedIn)
                    return;

                this.setState({
                    tronWeb: {
                        installed: true,
                        loggedIn: true
                    }
                });
            });
        }

        /*
        await Utils.setTronWeb(window.tronWeb, contractAddress);
        // 창조자 주소
        //console.log(Utils.tronWeb.address.fromHex((((await Utils.tronWeb.trx.getAccount()).address).toString())));
        const tronwebaddress = Utils.tronWeb.address.fromHex((((await Utils.tronWeb.trx.getAccount()).address).toString()))
        // 창조자 가진 금액
        console.log("contract token total money : " + await Utils.tronWeb.trx.getBalance());

        await this.setState({tronwebaddress : tronwebaddress})
        */

        //await this.updateContractAddressInput();
    }

    //--------------------------------------------------------------------------------------------
    // DYNAMIC CONTRACT ADDRESS
    //--------------------------------------------------------------------------------------------
    async updateContractAddressInput(evt) {
        await this.setState({
            contractAddress: evt.target.value
            //contractAddress: 'TPHeKw1nmDgAC6FiHS7v5VGSEnQ3d4WjJ7'
        });
        console.log('contractAddress : ', this.state.contractAddress);
        await Utils.setTronWeb(window.tronWeb, this.state.contractAddress);
        //const tmp_name = await Utils.contract.name().call();
        const tmp_tronwebaddress = Utils.tronWeb.address.fromHex((((await Utils.tronWeb.trx.getAccount()).address).toString()));
        await this.setState({
            tokenname: await Utils.contract.name().call(),
            tokensymbol: await Utils.contract.symbol().call(),
            totalSupply: ((await Utils.contract.totalSupply().call()).toNumber()) / 100000000,
            tronwebaddress: tmp_tronwebaddress
        });


        // const testValue =await Utils.hexAddressToBase58('41a2726afbecbd8e936000ed684cef5e2f5cf43008');
        // console.log(testValue);
    }

    //--------------------------------------------------------------------------------------------
    // GET BALANCE
    //--------------------------------------------------------------------------------------------
    async getBalance(_getbalanceaddress) {
        const balance = ((await Utils.contract.balanceOf(_getbalanceaddress).call()).toNumber()) / 100000000;
        //const balance = await Utils.contract.decimals().call();
        console.log('balance', balance);

        this.setState({balance: balance})

    }

    updateGetBalanceInputValue(evt) {
        console.log('getbalanceaddress : ', this.state.getbalanceaddress);
        this.setState({
            getbalanceaddress: evt.target.value
        });
    }


    //--------------------------------------------------------------------------------------------
    // TRANSFER
    //--------------------------------------------------------------------------------------------
    Transfer(_to, _amount) {

        Utils.contract.transfer(_to, _amount).send({
            shouldPollResponse: true,
            callValue: 0
        }).then(res => Swal({
            title: 'Transfer Successful',
            type: 'success'
        })).catch(err => Swal({
            title: 'Transfer Failed',
            type: 'error'

        }));

    }

    updateTransferInputValue(evt) {
        this.setState({
            transferaddress: evt.target.value
        });
        console.log('transferaddress : ', this.state.transferaddress);
    }

    updateTransferAmountInputValue(evt) {
        console.log('transferamount : ', this.state.transferamount);
        this.setState({
            transferamount: evt.target.value
        });
    }

    //--------------------------------------------------------------------------------------------
    // TRANSFER FROM
    //--------------------------------------------------------------------------------------------
    async TransferFrom(_from, _to, _amount) {
        const allowance = await Utils.contract.allowance(_from, this.state.tronwebaddress).call();
        console.log('allowance : ', allowance);

        Utils.contract.transferFrom(_from, _to, _amount).send({
            shouldPollResponse: true,
            callValue: 0
        }).then(res => Swal({
            title: 'Transfer Successful',
            type: 'success'
        })).catch(err => Swal({
            title: 'Transfer Failed',
            type: 'error'

        }));
    }

    updateTansferFromFromInputValue(evt) {
        this.setState({
            transferfromfromaddress: evt.target.value
        });
        console.log('transferfromfromaddress : ', this.state.transferfromfromaddress);
    }

    updateTansferFromToInputValue(evt) {
        this.setState({
            transferfromtoaddress: evt.target.value
        });
        console.log('transferfromtoaddress : ', this.state.transferfromtoaddress);
    }

    updateTansferFromAmountInputValue(evt) {
        this.setState({
            transferfromamount: evt.target.value
        });
        console.log('transferfromamount : ', this.state.transferfromamount);

    }

    //--------------------------------------------------------------------------------------------
    // APPROVE
    //--------------------------------------------------------------------------------------------
    Approve(_spender, _amount) {
        Utils.contract.approve(_spender, _amount).send({
            shouldPollResponse: true,
            callValue: 0
        }).then(res => Swal({
            title: 'Approval Successful',
            type: 'success'
        })).catch(err => {
                Swal({
                    title: 'Approval Failed',
                    type: 'error'
                })
                console.log('err ==> ' + JSON.stringify(err));
            }
        );
    }

    updateApproveValue(evt) {
        this.setState({
            approveamount: evt.target.value
        });
        console.log('approveamount : ', this.state.approveamount);
    }

    updateApproveSpender(evt) {
        this.setState({
            approvespender: evt.target.value
        });
        console.log('approvespender : ', this.state.approvespender);
    }

    //--------------------------------------------------------------------------------------------
    // BURN
    //--------------------------------------------------------------------------------------------
    Burn(_amount) {
        Utils.contract.burn(_amount).send({
            shouldPollResponse: true,
            callValue: 0
        }).then(res => Swal({
            title: 'Burn Successful',
            type: 'success'
        })).catch(err => Swal({
            title: 'Burn Failed',
            type: 'error'

        }));
    }

    updateBurnAmountInputValue(evt) {
        console.log('burnamount : ', this.state.burnamount);
        this.setState({
            burnamount: evt.target.value
        });
    }

    //--------------------------------------------------------------------------------------------
    // BURN FROM
    //--------------------------------------------------------------------------------------------
    BurnFrom(_from, _amount) {
        Utils.contract.burnFrom(_from, _amount).send({
            shouldPollResponse: true,
            callValue: 0
        }).then(res => Swal({
            title: 'Burn Successful',
            type: 'success'
        })).catch(err => Swal({
            title: 'Burn Failed',
            type: 'error'

        }));
    }

    updateBurnFromAmountValue(evt) {
        console.log('burnfromamount : ', this.state.burnfromamount);
        this.setState({
            burnfromamount: evt.target.value
        });
    }

    updateBurnFromFromValue(evt) {
        console.log('burnfromfrom : ', this.state.burnfromfrom);
        this.setState({
            burnfromfrom: evt.target.value
        });
    }


    render() {
        if (!this.state.tronWeb.installed)
            return <TronLinkGuide/>;

        if (!this.state.tronWeb.loggedIn)
            return <TronLinkGuide installed/>;


        return (
            <div className='row'>
                <div className='col-lg-12 text-center'>
                    <hr/>

                    <div className="topnav">
                        <img src={'CodeXpert.png'} width="200px"/>
                    </div>
                    <hr style={{color: 'black', backgroundColor: 'black', height: 0.5}}/>
                    <h1 style={{color: 'black'}}>Tron TRC20 Token Management Platform</h1>
                    <hr style={{color: 'black', backgroundColor: 'black', height: 0.5}}/>
                    <p> Your Address : {this.state.tronwebaddress} </p>
                    <br/>
                    <br/>
                    {/* ---------------------------------------------------------------------------------------------- */}
                    {/* 컨태랙트 주소 복사 */}
                    {/* ---------------------------------------------------------------------------------------------- */}
                    <p> Paste your contract address here : </p>
                    <input style={{width: "400px"}} value={this.state.contractAddress}
                           onChange={this.updateContractAddressInput}/>
                    <br/>
                    <p> Token name : {this.state.tokenname}</p>
                    <p> Token Symbol : {this.state.tokensymbol}</p>
                    <p> Total Supply : {this.state.totalSupply}</p>
                    <hr style={{color: 'white', backgroundColor: 'white', height: 0.5}}/>
                    <br/>
                    <br/>

                    {/* ---------------------------------------------------------------------------------------------- */}
                    {/* 잔액 가져오기 */}
                    {/* ---------------------------------------------------------------------------------------------- */}
                    <h1>잔액 보기</h1>
                    <br/>
                    <input style={{width: "400px"}} value={this.state.getbalanceaddress}
                           onChange={this.updateGetBalanceInputValue}/>
                    <br/>
                    <br/>
                    <button className='btn btn-primary' onClick={(event) => {
                        event.preventDefault()
                        this.getBalance(this.state.getbalanceaddress)
                    }}>Get Balance
                    </button>
                    <br/>
                    <br/>
                    <p>Your balance is : {this.state.balance}</p>
                    <br/>


                    {/* ---------------------------------------------------------------------------------------------- */}
                    {/* 금액 보내기 */}
                    {/* ---------------------------------------------------------------------------------------------- */}
                    <hr style={{color: 'white', backgroundColor: 'white', height: 0.5}}/>
                    <h1>금액 보내기</h1>
                    <br/>
                    <br/>
                    <p> To : </p>
                    <input style={{width: "400px"}} value={this.state.transferaddress}
                           onChange={this.updateTransferInputValue}/>
                    <p> Amount : </p>
                    <input style={{width: "200px"}} value={this.state.transferamount}
                           onChange={this.updateTransferAmountInputValue}/>
                    <br/>
                    <br/>
                    <button className='btn btn-primary' onClick={(event) => {
                        event.preventDefault()
                        this.Transfer(this.state.transferaddress, this.state.transferamount * 100000000)
                    }}>Transfer
                    </button>
                    <br/>

                    {/* ---------------------------------------------------------------------------------------------- */}
                    {/* 3자 이체 */}
                    {/* ---------------------------------------------------------------------------------------------- */}
                    <hr style={{color: 'white', backgroundColor: 'white', height: 0.5}}/>
                    <h1>3자이체</h1>
                    <br/>
                    <p> From : </p>
                    <input style={{width: "400px"}} value={this.state.transferfromfromaddress}
                           onChange={this.updateTansferFromFromInputValue}/>
                    <p> To : </p>
                    <input style={{width: "400px"}} value={this.state.transferfromtoaddress}
                           onChange={this.updateTansferFromToInputValue}/>
                    <p> Amount : </p>
                    <input style={{width: "200px"}} value={this.state.transferfromamount}
                           onChange={this.updateTansferFromAmountInputValue}/>
                    <br/>
                    <br/>
                    <button className='btn btn-primary' onClick={(event) => {
                        event.preventDefault()
                        this.TransferFrom(this.state.transferfromfromaddress, this.state.transferfromtoaddress, this.state.transferfromamount * 100000000)
                    }}>Transfer From
                    </button>
                    <br/>
                    <br/>

                    {/* ---------------------------------------------------------------------------------------------- */}
                    {/* APPROVE 하기 */}
                    {/* ---------------------------------------------------------------------------------------------- */}
                    <hr style={{color: 'white', backgroundColor: 'white', height: 0.5}}/>
                    <h1>승인받기(APPROVE)</h1>
                    <br/>
                    <p> Spender : </p>
                    <input style={{width: "400px"}} value={this.state.approvespender}
                           onChange={this.updateApproveSpender}/>
                    <p> Amount : </p>
                    <input style={{width: "400px"}} value={this.state.approveamount}
                           onChange={this.updateApproveValue}/>
                    <br/>
                    <br/>
                    <button className='btn btn-primary' onClick={(event) => {
                        event.preventDefault()
                        this.Approve(this.state.approvespender, this.state.approveamount * 100000000)
                    }}>Approve
                    </button>
                    <br/>


                    {/* ---------------------------------------------------------------------------------------------- */}
                    {/* burn 하기 */}
                    {/* ---------------------------------------------------------------------------------------------- */}
                    <hr style={{color: 'white', backgroundColor: 'white', height: 0.5}}/>
                    <h1>태우기(burn)</h1>
                    <br/>
                    <p> Amount to burn : </p>
                    <input style={{width: "200px"}} value={this.state.burnamount}
                           onChange={this.updateBurnAmountInputValue}/>
                    <br/>
                    <br/>
                    <button className='btn btn-primary' onClick={(event) => {
                        event.preventDefault()
                        this.Burn(this.state.burnamount * 100000000)
                    }}>Burn
                    </button>
                    <br/>
                    <br/>
                    <br/>
                    {/* ---------------------------------------------------------------------------------------------- */}
                    {/* 3자 태우기 이체 */}
                    {/* ---------------------------------------------------------------------------------------------- */}

                    <hr style={{color: 'white', backgroundColor: 'white', height: 0.5}}/>
                    <h1>3자 태우기(burn)</h1>
                    <br/>
                    <p> From : </p>
                    <input style={{width: "200px"}} value={this.state.burnfromfrom}
                           onChange={this.updateBurnFromFromValue}/>
                    <p> Amount to burn : </p>
                    <input style={{width: "200px"}} value={this.state.burnfromamount}
                           onChange={this.updateBurnFromAmountValue}/>

                    <br/>
                    <br/>
                    <button className='btn btn-primary' onClick={(event) => {
                        event.preventDefault()
                        this.BurnFrom(this.state.burnfromfrom, this.state.burnfromamount * 100000000)
                    }}>Burn From
                    </button>
                    <br/>
                    <br/>

                    <br/>
                    <br/>
                </div>
            </div>
        );
    }
}

export default App; 

1.2. utils/index.js

//const contractAddress = 'TA2zHDeqLw5DUd8FrRjP7Zn3FV64S3wj6K'
//const contractAddress = 'TGNN7ZgoqGNTqkBmtumY1BioSmZGtsWKbR'

const HEX_PREFIX = '41';

const utils = {
    tronWeb: false,
    contract: false,

    async setTronWeb(tronWeb, contractAddress) {
        this.tronWeb = tronWeb;
        this.contract = await tronWeb.contract().at(contractAddress)
    },

    async hexAddressToBase58 (hexAddress) {
        let retval = hexAddress;
        try {
            let tronWeb = this.tronWeb;
            if (hexAddress.startsWith("0x")) {
                hexAddress = HEX_PREFIX + hexAddress.substring(2);
            }
            let bArr = tronWeb.utils['code'].hexStr2byteArray(hexAddress);
            retval = tronWeb.utils['crypto'].getBase58CheckAddress(bArr);
        } catch (e) {
            //Handle
        }
        return retval;
    }

};

export default utils; 

→ hexAddressToBase58 는 핵사주소를 기본 값으로 변경시키는 로직 부분이다.

2. 실행

→ yarn start

2.1. Contract 링크

: contract 주소를 넣는다.
: 주소를 입력하면 바로 Token 정보를 가져온다.

2.2. 잔액 확인

: contract 주소를 넣는다.
: 주소를 입력하면 바로 Token 정보를 가져온다.

2.3. 금액보내기

: 임의로 계정 2개를 생성해놓자.( 나는 이전에 이미 생성을 해놓은 상태였다.)

TONLINK 계정은 contract 로 만들어놓은 계정을 선택해 놓은 상태에서 jin2 계정으로 보내본다.

5000개 토큰을 보내고 확인해보자.

“Transfer” 를 클릭하면 Request Signature 창이 뜨게 되고 계약 내용을 확인하고 Accept 를 눌러주면된다.

오류가 났나? 재밌는 건 어쩌다가 몇 번 오류가 날 수도 있다. 이는 shouldPollResponse: true 가 설정되어 있을 때 네트워크 또는 기타 이유로 인해 발생될 수도 있다고 한다. 아직 Tron Shasta 가 불안한가? 어쨋든 이러한 것이 귀찮다면 이부분을 주석 처리해서 해보면.. 잘 보내질 것 이다.

제대로 Token이 보내졌다면 TronLinK 해당 게정에 토큰이 들어와있는지 확인해보자. 아래와 같이 제대로 500 Token 이 들어가있는 걸 확인할 수 있다.

2.4. 3자 이체

: 내가 누군가에게 단순히 Token 을 보내는 것은 위의 Transfer 기능을 활용하면 된다.
하지만 우리가 살고 있는 실세계의 은행을 생각해보면.. 내 돈을 제 3자(곧 은행) 에게 이체를 하고
내 돈을 활용 할 권한을 주는것이라고 생각해본 적은 없는가?

제3자(은행)에게 내 돈을 사용할 수 있는 특정 권한을 줌으로써 은행은 여러 대출 상품을 만들고 보험도 만들고,
때로는 해당 돈을 직원들 월급을 주기도한다. 물론 내돈을 사용해서 – 가 나게 하면 소송감이기하지만
은행은 정해진 틀안에서 내 돈을 활용하고 이자까지 주고있다.

어찌됐든 우리는 권한을 주었고 은행은 우리가 허용한 권한 안에서 우리의 돈을 자알~ 굴리고 있는 것이다.
그러면 블록체인에서의 3자 이체 권한을 주는 방법을 살펴보자.

우리가 현재 등록한 계정을 다시 한 번 살펴보자

TronlInk 의 주체를 devdevil0625 로 지정 된 상태에서 park2213 에게 1000 개의 Token 을 jin2 가 보낼 수 있는 권한을 줄 수 있도록 테스트 해본다.
이번 테스트에서 주목할 점은 jin2 가 devdevil0625의 토큰을 park2213 에게 보내는 것이다.

2.4. 승인받기

TronLink → devdevil0625의 주소 (TCh7ZJM7mtxtDxfM6UwQrjBAFiqu1QCAqX)

Spender → jin2 의 주소 (TVLX75yPmRnJkE4sP6Sir5sPEaaKc6hMWz)

Amount → 1000

위처럼 샛팅한 뒤에 Request Signature 창이 팝업 되면 Accept를 클릭 한

3자 이체 수행을 해본다.

park2213의 토큰 1000개가 모두 보내어졋다.

2.5. 태우기 (burn)

현재 devdevil0625 의 토큰 잔액 확인

→ 998500

park2213의 토큰 1000개가 모두 보내어졋다.

최종 확인

→ 993500

2.6. 3자 태우기

먼저 승인받기 (5000 개를 태울 수 있는 권한을 jin2 에게 준다.)

TronLink 지갑 소유자를 jin2 로 변경한 뒤

3자 태우기 실행

최종 확인

Tags: TRX(ERC20)개발실전강의
ShareTweet
Previous Post

CSS에 날개, Sass (SCSS)

Next Post

MiniKube를 사용해서 로컬용 오케스트레이션 확인하기

Next Post
CSS에 날개, Sass (SCSS)

MiniKube를 사용해서 로컬용 오케스트레이션 확인하기

  • Copyright © 2020 illunex., Inc., All Rights Reserved.
  • 개인정보보호정책
No Result
View All Result
  • HOME
  • PRODUCT
  • DEVELOP
  • NEWS
  • CONSULTING