Skip to content

Commit

Permalink
Add FeeDelegate tool
Browse files Browse the repository at this point in the history
  • Loading branch information
nujabes403 committed Apr 14, 2019
1 parent 3501f83 commit 2f60575
Show file tree
Hide file tree
Showing 11 changed files with 265 additions and 7 deletions.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"dependencies": {
"bignumber.js": "^8.0.2",
"bs58": "^4.0.1",
"caver-js": "0.0.2-r",
"caver-js": "0.0.2-u",
"classnames": "^2.2.5",
"dotenv": "^6.0.0",
"dotenv-webpack": "^1.5.7",
Expand Down
203 changes: 203 additions & 0 deletions src/components/FeeDelegate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
import React, { Component } from 'react'
import { Subject, fromEvent, of } from 'rxjs'
import { map, tap, take, takeUntil, catchError } from 'rxjs/operators'
import { ajax } from 'rxjs/ajax'

import KlayRawTransactionDecoder from 'components/KlayRawTransactionDecoder'
import { feeDelegateLambdaURL } from 'constants/url'
import { caver } from 'utils/caver'

import './FeeDelegate.scss'

type Props = {

}

const generateRandomFeeDelegatedRawTx = (feedAddress, toAddress) => {
const rawTxcandidate = [randomTxType1, randomTxType2, randomTxType3, randomTxType4]
const idx = parseInt((Math.random() * 1000) % rawTxcandidate.length)

return rawTxcandidate[idx](feedAddress, toAddress)
}

const randomTxType1 = (feedAddress, toAddress) => ({
type: 'FEE_DELEGATED_SMART_CONTRACT_DEPLOY',
from: feedAddress,
to: toAddress,
data: `0x608060405234801561001057600080fd5b506101de806100206000396000f3006080604052600436106100615763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631a39d8ef81146100805780636353586b146100a757806370a08231146100ca578063fd6b7ef8146100f8575b3360009081526001602052604081208054349081019091558154019055005b34801561008c57600080fd5b5061009561010d565b60408051918252519081900360200190f35b6100c873ffffffffffffffffffffffffffffffffffffffff60043516610113565b005b3480156100d657600080fd5b5061009573ffffffffffffffffffffffffffffffffffffffff60043516610147565b34801561010457600080fd5b506100c8610159565b60005481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604081208054349081019091558154019055565b60016020526000908152604090205481565b336000908152600160205260408120805490829055908111156101af57604051339082156108fc029083906000818181858888f193505050501561019c576101af565b3360009081526001602052604090208190555b505600a165627a7a72305820627ca46bb09478a015762806cc00c431230501118c7c26c30ac58c4e09e51c4f0029`,
gas: '3000000',
})

const randomTxType2 = (feedAddress, toAddress) => ({
type: 'FEE_DELEGATED_VALUE_TRANSFER',
from: feedAddress,
to: toAddress,
value: 10,
gas: '3000000',
})

const randomTxType3 = (feedAddress, toAddress) => ({
type: 'FEE_DELEGATED_VALUE_TRANSFER_MEMO',
from: feedAddress,
to: toAddress,
value: 20,
data: '0xdeadbeef',
gas: '3000000',
})

const randomTxType4 = (feedAddress, toAddress) => ({
type: 'FEE_DELEGATED_SMART_CONTRACT_DEPLOY_WITH_RATIO',
from: feedAddress,
to: toAddress,
feeRatio: 10,
data: `0x608060405234801561001057600080fd5b506101de806100206000396000f3006080604052600436106100615763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631a39d8ef81146100805780636353586b146100a757806370a08231146100ca578063fd6b7ef8146100f8575b3360009081526001602052604081208054349081019091558154019055005b34801561008c57600080fd5b5061009561010d565b60408051918252519081900360200190f35b6100c873ffffffffffffffffffffffffffffffffffffffff60043516610113565b005b3480156100d657600080fd5b5061009573ffffffffffffffffffffffffffffffffffffffff60043516610147565b34801561010457600080fd5b506100c8610159565b60005481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604081208054349081019091558154019055565b60016020526000908152604090205481565b336000908152600160205260408120805490829055908111156101af57604051339082156108fc029083906000818181858888f193505050501561019c576101af565b3360009081526001602052604090208190555b505600a165627a7a72305820627ca46bb09478a015762806cc00c431230501118c7c26c30ac58c4e09e51c4f0029`,
gas: '3000000',
})

class FeeDelegate extends Component<Props> {
destroy$ = new Subject()

state = {
rawTx: '',
receipt: null,
isLoading: false,
isGenerating: false,
errorMessage: '',
}

componentDidMount() {
fromEvent(this.decoderComp.$rawTransactionHex, 'input').pipe(
tap((e) => {
this.setState({
rawTx: e.target.value,
hasError: false,
errorMessage: '',
})
}),
takeUntil(this.destroy$),
).subscribe()
}

requestFeeDelegate = () => {
const { rawTx } = this.state
if (!rawTx) return

this.setState({
isLoading: true,
receipt: null,
})

try {
ajax.getJSON(feeDelegateLambdaURL + '/' + rawTx).pipe(
map((receipt) => {
console.log(receipt, 'receipt')
this.setState({
receipt: receipt,
isLoading: false,
hasError: false,
errorMessage: '',
})
}),
catchError((err) => {
console.log(err, 'err')
this.setState({
receipt: null,
isLoading: false,
hasError: true,
errorMessage: err && JSON.stringify(err.response),
})

return of('no more request')
}),
take(1),
).subscribe()
} catch (e) {
console.log(e, 'e')
this.setState({
receipt: null,
isLoading: false,
hasError: true,
})
}
}

genRandomFeeDelegateRawTx = async () => {
this.setState({
receipt: null,
hasError: false,
errorMessage: '',
isGenerating: true,
})
const { address: feedAddress, privateKey } = caver.klay.accounts.create()
const { address: toAddress } = caver.klay.accounts.create()

await fetch(`https://baobab.klaytnwallet.com/api/faucet/?address=${feedAddress}`)

const senderTransaction = generateRandomFeeDelegatedRawTx(feedAddress, toAddress)

const { rawTransaction } = await caver.klay.accounts.signTransaction(senderTransaction, privateKey)

this.decoderComp.$rawTransactionHex.value = rawTransaction
this.decoderComp.$rawTransactionHex.dispatchEvent(new Event('input'))

setTimeout(() => {
this.setState({
isGenerating: false,
})
}, 0)
}

render() {
const { errorMessage, rawTx, receipt, hasError, isGenerating, isLoading } = this.state

return (
<div className="FeeDelegate">
<p className="FeeDelegate__notice">Note: "FEE DELEGATE" tool only works when Klaytn baobab network is online.</p>
<button
className="FeeDelegate__genButton"
onClick={this.genRandomFeeDelegateRawTx}
disabled={isGenerating}
>
Generate random FEE_DELEGATED_XXX Raw Transaction
</button>
<button
className="FeeDelegate__requestButton"
onClick={this.requestFeeDelegate}
disabled={isLoading}
>
Request fee delegate
</button>
{(isGenerating || isLoading) && (
<img
className="FeeDelegate__loading"
src="/static/images/network-indicator.svg"
/>
)}
{hasError && <div className="FeeDelegate__error">Error occurred. {errorMessage}</div>}
{!hasError && receipt && (
<div className="FeeDelegate__receipt">
<p className="FeeDelegate__receiptHeader">Receipt: </p>
{Object.entries(receipt).map(([fieldName, fieldValue]) => {
return (
<div className="FeeDelegate__receiptField">
{fieldName}: {fieldValue} {fieldName === 'txHash' && (
<a
target="_blank"
className="FeeDelegate__scopeLink"
href={`https://baobab.klaytnscope.com/tx/${fieldValue}`}
>
Check Detail
</a>
)}
</div>
)
})}
</div>
)}
<KlayRawTransactionDecoder title="Sender's rawTx" ref={(comp) => this.decoderComp = comp} />
</div>
)
}
}

export default FeeDelegate
45 changes: 45 additions & 0 deletions src/components/FeeDelegate.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
.FeeDelegate {
padding-bottom: 100px;
}

.FeeDelegate__receipt {
font-size: 12px;
word-break: break-all;
border: 2px solid #eeeeee;
border-radius: 3px;
padding: 8px;
margin-bottom: 4px;
}

.FeeDelegate__error {
color: red;
font-size: 14px;
margin-bottom: 4px;
}

.FeeDelegate__receiptHeader {
font-size: 14px;
margin-bottom: 2px;
}

.FeeDelegate__loading {
display: inline-block;
vertical-align: middle;
width: 20px;
height: 20px;
}

.FeeDelegate__genButton, .FeeDelegate__requestButton {
display: inline-block;
vertical-align: middle;
margin-left: 4px;
}

.FeeDelegate__notice {
margin-bottom: 4px;
}

.FeeDelegate__scopeLink {
color: #6A8DDA;
text-decoration: underline;
}
3 changes: 2 additions & 1 deletion src/components/KlayRawTransactionDecoder.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,12 @@ class KlayRawTransactionDecoder extends Component<Props> {

render() {
const { result } = this.state
const { title } = this.props

return (
<div className="KlayRawTransactionDecoder">
<div className="KlayRawTransactionDecoder__inputWrapper">
<label className="KlayRawTransactionDecoder__label">Raw Tx:</label>
<label className="KlayRawTransactionDecoder__label">{title || 'Raw Tx:'}</label>
<textarea
className="KlayRawTransactionDecoder__rawTxInput"
ref={($rawTransactionHex) => this.$rawTransactionHex = $rawTransactionHex}
Expand Down
4 changes: 4 additions & 0 deletions src/constants/linkToDescription.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ const linkToDescription = {
title: 'RAW TX DECODER',
markdown: RawTransactionDecoderMarkdown,
},
'/feeDelegate': {
title: 'FEE DELEGATE',
markdown: RawTransactionDecoderMarkdown,
},
}

export default linkToDescription
1 change: 1 addition & 0 deletions src/constants/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const menuItems = {
{ title: 'PRIVATEKEY TO ADDRESS', link: '/key?l=KLAY' },
{ title: 'KECCAK256', link: '/keccak256?l=KLAY' },
{ title: 'RAW TRANSACTION DECODER', link: '/klayRawTransactionDecoder?l=KLAY' },
{ title: '(EXPERIMENTAL) FEE DELEGATE', link: '/feeDelegate?l=KLAY' },
]
}

Expand Down
1 change: 1 addition & 0 deletions src/constants/url.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const feeDelegateLambdaURL = 'https://brq3fas44k.execute-api.us-east-1.amazonaws.com/dev/feeDelegate'
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import WeiConverter from 'components/WeiConverter'
import PebConverter from 'components/PebConverter'
import HumanreadableAddress from 'components/HumanreadableAddress'
import KlayRawTransactionDecoder from 'components/KlayRawTransactionDecoder'
import FeeDelegate from 'components/FeeDelegate'

window.isMobile = isMobile

Expand Down Expand Up @@ -66,6 +67,7 @@ export const renderRoutes = (rootComponent) => (
<Route path="/pebConverter" component={PebConverter} />
<Route path="/humanreadableAddress" component={HumanreadableAddress} />
<Route path="/klayRawTransactionDecoder" component={KlayRawTransactionDecoder} />
<Route path="/feeDelegate" component={FeeDelegate} />
</Route>
</Router>
)
Expand Down
4 changes: 2 additions & 2 deletions src/utils/caver.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Caver from 'caver-js'
// caver is imported only for using helpers, utils function.
export const caver = new Caver()

export const caver = new Caver('https://api.baobab.klaytn.net:8651')

export default caver
1 change: 1 addition & 0 deletions static/images/network-indicator.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 2f60575

Please sign in to comment.