Skip to content
This repository has been archived by the owner on Jul 19, 2024. It is now read-only.

Commit

Permalink
Merge pull request #81 from klaytn/develop
Browse files Browse the repository at this point in the history
Add Soulbound NFT, Canonical WKLAY, and Multicall pages to Misc menu.
  • Loading branch information
edwin082 authored Jan 25, 2023
2 parents 9f7b8ad + 9fac5dc commit 5e86606
Show file tree
Hide file tree
Showing 13 changed files with 3,023 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/consts/urlMap.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
const network = {
testnet: {
rpc: 'https://public-node-api.klaytnapi.com/v1/baobab',
scope: 'https://baobab.scope.klaytn.com/tx/',
finder: 'https://baobab.klaytnfinder.io/tx/',
finderToken: 'https://baobab.klaytnfinder.io/token/',
finderNFT: 'https://baobab.klaytnfinder.io/nft/',
},
mainnet: {
rpc: 'https://public-node-api.klaytnapi.com/v1/cypress',
scope: 'https://scope.klaytn.com/tx/',
finder: 'https://www.klaytnfinder.io/tx/',
finderToken: 'https://www.klaytnfinder.io/token/',
finderNFT: 'https://www.klaytnfinder.io/nft/',
Expand Down
24 changes: 24 additions & 0 deletions src/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import CheckAccountKey from './views/Miscellaneous/CheckAccountKey'
import GenerateKeystore from './views/Miscellaneous/GenerateKeystore'
import KeccakFromString from './views/Miscellaneous/KeccakFromString'
import LoadKeystore from './views/Miscellaneous/LoadKeystore'
import SoulboundNFT from './views/Miscellaneous/SoulboundNFT'
import WKLAY from './views/Miscellaneous/WKLAY'
import Multicall from './views/Miscellaneous/Multicall'

import Web3modalExample from './views/Web3modal'
import Web3modalNFT from './views/Web3modal/web3modalNFT'
Expand Down Expand Up @@ -259,6 +262,27 @@ const routes: RouteType[] = [
component: CheckAccountKey,
description: 'Returns account key type of the given address',
},
{
path: '/soulboundNFT',
name: 'Soulbound NFT',
component: SoulboundNFT,
description:
'Deploys Soulbound NFT contract and tests functions: Mint, Transfer, and Burn',
},
{
path: '/WKLAY',
name: 'Canonical WKLAY',
component: WKLAY,
description:
'Interact with canonical-WKLAY contract and tests functions: Deposit, Withdraw, Approve, and Transfer',
},
{
path: '/multicall',
name: 'Multicall',
component: Multicall,
description:
'Aggregates results from multiple contract constant function calls',
},
],
},
]
Expand Down
286 changes: 286 additions & 0 deletions src/views/Miscellaneous/Multicall.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,286 @@
import { ReactElement, useMemo, useState } from 'react'
import Caver from 'caver-js'
import _ from 'lodash'

import { URLMAP, COLOR } from 'consts'
import {
Button,
Card,
CardHeader,
CardBody,
Container,
Text,
CardSection,
CodeBlock,
View,
Label,
FormInput,
LinkA,
} from 'components'

import { exWKLAYAbi } from './constants/exWKLAYAbi'
import { exMulticallAbi } from './constants/exMulticallAbi'
import {
exposureTime,
contractAddress,
wklayContractAddress,
exAddress1,
exAddress2,
exAddress3,
exAddress4,
exAddress5,
} from './constants/exMulticallData'

type Res = {
success: boolean
returnData: string
}

const Multicall = (): ReactElement => {
const caver = useMemo(() => new Caver(URLMAP.network['testnet']['rpc']), [])

const [multicallMsg, setMulticallMsg] = useState('')
const [multicallButtonDisabled, setMulticallButtonDisabled] = useState(false)
const [multicallSuccess, setMulticallSuccess] = useState(false)

const [address1, setAddress1] = useState(exAddress1)
const [address2, setAddress2] = useState(exAddress2)
const [address3, setAddress3] = useState(exAddress3)
const [address4, setAddress4] = useState(exAddress4)
const [address5, setAddress5] = useState(exAddress5)

const [outputArray, setOuputArray] = useState(Array<string>)

const multicall = async (): Promise<void> => {
try {
setMulticallButtonDisabled(true)

const wklay = new caver.contract(
JSON.parse(JSON.stringify(exWKLAYAbi)),
wklayContractAddress
)

const multicall = new caver.contract(
JSON.parse(JSON.stringify(exMulticallAbi)),
contractAddress
)

const calls = [
wklay.methods.balanceOf(address1),
wklay.methods.balanceOf(address2),
wklay.methods.balanceOf(address3),
wklay.methods.balanceOf(address4),
wklay.methods.balanceOf(address5),
]

const callRequests = calls.map((call) => ({
target: call._parent._address,
callData: call.encodeABI(),
}))

const { returnData } = await multicall.call(
'tryBlockAndAggregate',
false,
callRequests
)
let output = returnData.map((data: Res, index: number) => {
const types = calls[index]._method.outputs
const { __length__, ...result } = caver.abi.decodeParameters(
types,
data.returnData
)
return Object.values(result)
})

output = output.map((elem: Array<string>) =>
caver.utils.fromPeb(elem[0], 'KLAY')
)
setOuputArray(output)

if (output.length === 5) {
setMulticallMsg('Multicall is successfully called.')
setMulticallButtonDisabled(false)
setMulticallSuccess(true)
} else {
throw Error('Multicall is failed')
}
} catch (err) {
setMulticallMsg(_.toString(err))
setMulticallButtonDisabled(false)
setMulticallSuccess(false)

setTimeout(() => {
setMulticallMsg('')
}, exposureTime)
}
}

return (
<Container>
<Card>
<CardHeader>
<h3 className="title">Multicall - Check the WKLAY Balance at Once</h3>
<Text>
Multicall aggregates result from multiple smart contract constant
function calls in a single call. It reduces several JSON RPC
requests while guaranteeing that all returned values are from the
same block, like an atomic read. The following example comes from
the 'Miscellaneous menu - Canonical WKLAY page'. You can deposit or
transfer the WKLAY to other addresses on that page. After it, change
the account addresses as you like and check the results here at
once. You are able to find more information about Multicall:{' '}
<LinkA link="https://github.com/inevitable-dao/klaytn-multicall">
Multicall Github Repository1
</LinkA>{' '}
and{' '}
<LinkA link="https://github.com/makerdao/multicall.js">
Multicall Github Repository2
</LinkA>
.
</Text>
</CardHeader>
<CardBody>
<CardSection>
<View style={{ marginBottom: 10 }}>
<Label>Address1</Label>
<View style={{ paddingBottom: 10 }}>
<FormInput
type="text"
placeholder="Address1"
onChange={setAddress1}
value={address1}
/>
</View>
<Label>Address2</Label>
<View style={{ paddingBottom: 10 }}>
<FormInput
type="text"
placeholder="Address2"
onChange={setAddress2}
value={address2}
/>
</View>
<Label>Address3</Label>
<View style={{ paddingBottom: 10 }}>
<FormInput
type="text"
placeholder="Address3"
onChange={setAddress3}
value={address3}
/>
</View>
<Label>Address4</Label>
<View style={{ paddingBottom: 10 }}>
<FormInput
type="text"
placeholder="Address4"
onChange={setAddress4}
value={address4}
/>
</View>
<Label>Address5</Label>
<View style={{ paddingBottom: 10 }}>
<FormInput
type="text"
placeholder="Address5"
onChange={setAddress5}
value={address5}
/>
</View>
<Button disabled={multicallButtonDisabled} onClick={multicall}>
Multicall
</Button>
</View>
<CodeBlock
title="caver-js code"
text={`const wklay = new caver.contract(
JSON.parse(JSON.stringify(exWKLAYAbi)),
wklayContractAddress
)
const multicall = new caver.contract(
JSON.parse(JSON.stringify(exMulticallAbi)),
contractAddress
)
const calls = [
wklay.methods.balanceOf(address1),
wklay.methods.balanceOf(address2),
wklay.methods.balanceOf(address3),
wklay.methods.balanceOf(address4),
wklay.methods.balanceOf(address5),
]
const callRequests = calls.map((call) => ({
target: call._parent._address,
callData: call.encodeABI(),
}))
const { returnData } = await multicall.call(
'tryBlockAndAggregate',
false,
callRequests
)
let output = returnData.map((data: Res, index: number) => {
const types = calls[index]._method.outputs
const { __length__, ...result } = caver.abi.decodeParameters(
types,
data.returnData
)
return Object.values(result)
})
output = output.map((elem: Array<string>) =>
caver.utils.fromPeb(elem[0], 'KLAY')
)
setOuputArray(output)`}
/>
</CardSection>
{!!multicallMsg && (
<CardSection>
{multicallSuccess ? (
<>
<Text>{multicallMsg}</Text>
<Text>
{'\n'}
Balance of {address1}
{`\n-> `}
{outputArray[0]} WKLAY
</Text>
<Text>
{'\n'}
Balance of {address2}
{`\n-> `}
{outputArray[1]} WKLAY
</Text>
<Text>
{'\n'}
Balance of {address3}
{`\n-> `}
{outputArray[2]} WKLAY
</Text>
<Text>
{'\n'}
Balance of {address4}
{`\n-> `}
{outputArray[3]} WKLAY
</Text>
<Text>
{'\n'}
Balance of {address5}
{`\n-> `}
{outputArray[4]} WKLAY
</Text>
</>
) : (
<Text style={{ color: COLOR.error }}> {multicallMsg} </Text>
)}
</CardSection>
)}
</CardBody>
</Card>
</Container>
)
}

export default Multicall
Loading

0 comments on commit 5e86606

Please sign in to comment.