/* eslint-disable */
import {
IconService,
Wallet,
HttpProvider,
SignedTransaction,
DeployTransaction,
ScoreApiList,
Call,
DeployTransactionBuilder,
CallBuilder,
CallTransactionBuilder
} from 'icon-sdk-js';
const { IconAmount, IconConverter, IconWallet } = IconService;
import MockData from '../../mockData/index.js';
import BigNumber from "bignumber.js";
let deployAndTransferTokenExample;
class DeployAndTransferTokenExample {
private iconService: IconService;
private readonly wallet: Wallet;
private deployTxHash: string;
private content: string;
private transactionTxHash: string;
private scoreAddress: string;
constructor() {
// HttpProvider is used to communicate with http.
const provider: HttpProvider = new HttpProvider(MockData.NODE_URL);
// Create IconService instance
this.iconService = new IconService(provider);
// Load wallet
this.wallet = IconWallet.loadPrivateKey(MockData.PRIVATE_KEY_1);
this.deployTxHash = '';
this.transactionTxHash = '';
this.content = '';
this.scoreAddress = '';
this.addListener();
}
addListener() {
// 1. Upload Score File
document.getElementById('D01').addEventListener('click', async () => {
await this.readFile();
});
// 2. Check Score Deployment TX Status
document.getElementById('D02').addEventListener('click', async () => {
await this.checkDeployTxStatus();
});
// 3. Send ST Token
document.getElementById('D03').addEventListener('click', async () => {
await this.sendTransaction();
});
// 4. Check ST Token Balance
document.getElementById('D04').addEventListener('click', async () => {
await this.getTokenBalance(MockData.WALLET_ADDRESS_1);
await this.getTokenBalance(MockData.WALLET_ADDRESS_2);
});
// 5. Check ST Token Transaction TX Status
document.getElementById('D05').addEventListener('click', async () => {
await this.checkTransactionTxStatus();
});
}
async readFile() {
let input, file, fr;
const self = this;
if (typeof window.FileReader !== 'function') {
document.getElementById('D01-1').innerHTML = "The file API isn't supported on this browser yet.";
return;
}
try {
input = document.getElementById('fileinput');
file = input.files[0];
fr = new FileReader();
fr.onload = async () => {
self.content = showResult(fr);
await self.deployScore();
};
fr.readAsBinaryString(file);
function showResult (fr) {
let markup, result, n, aByte, byteStr;
markup = [];
result = fr.result;
for (n = 0; n < result.length; ++n) {
aByte = result.charCodeAt(n);
byteStr = aByte.toString(16);
if (byteStr.length < 2) {
byteStr = "0" + byteStr;
}
markup.push(byteStr);
}
return markup.join("");
}
} catch (e) {
document.getElementById('D01-1').innerHTML = e.message;
}
}
async deployScore() {
// Build raw transaction object
const transaction: DeployTransaction = await this.buildDeployTransaction();
// Create signature of the transaction
const signedTransaction: SignedTransaction = new SignedTransaction(transaction, this.wallet);
// Read params to transfer to nodes
const signedTransactionProperties = JSON.stringify(signedTransaction.getProperties()).split(",").join(", \n")
document.getElementById('D01-2').innerHTML = `Signed Transaction: ${signedTransactionProperties}`;
// Send transaction
this.deployTxHash = await this.iconService.sendTransaction(signedTransaction).execute();
document.getElementById('D02-1').innerHTML = this.deployTxHash;
// Print transaction hash
document.getElementById('D01-3').innerHTML = `Transfer Request Complete. Tx hash is ${this.deployTxHash}`;
}
async buildDeployTransaction() {
const initialSupply = IconConverter.toBigNumber("100000000000");
const decimals = IconConverter.toBigNumber("18");
const tokenName = "StandardToken";
const tokenSymbol = "ST";
const contentType = "application/zip";
// Enter token information
// key name ("initialSupply", "decimals", "name", "symbol")
// You must enter the given values. Otherwise, your transaction will be rejected.
const params = {
initialSupply: IconConverter.toHex(initialSupply),
decimals: IconConverter.toHex(decimals),
name: tokenName,
symbol: tokenSymbol
}
const installScore = MockData.SCORE_INSTALL_ADDRESS;
const stepLimit = await this.getMaxStepLimit();
const walletAddress = this.wallet.getAddress();
// networkId of node 1:mainnet, 2~:etc
const networkId = IconConverter.toBigNumber(3);
const version = IconConverter.toBigNumber(3);
// Timestamp is used to prevent the identical transactions. Only current time is required (Standard unit : us)
// If the timestamp is considerably different from the current time, the transaction will be rejected.
const timestamp = (new Date()).getTime() * 1000;
//Enter transaction information
const deployTransactionBuilder = new DeployTransactionBuilder();
return deployTransactionBuilder
.nid(networkId)
.from(walletAddress)
.to(installScore)
.stepLimit(stepLimit)
.timestamp(timestamp)
.contentType(contentType)
.content(`0x${this.content}`)
.params(params)
.version(version)
.build();
}
async getMaxStepLimit(): Promise {
const governanceApi: ScoreApiList = await this.iconService.getScoreApi(MockData.GOVERNANCE_ADDRESS).execute();
// "getMaxStepLimit" : the maximum step limit value that any SCORE execution should be bounded by.
const methodName = 'getMaxStepLimit';
// Check input and output parameters of api if you need
const getMaxStepLimitApi = governanceApi.getMethod(methodName);
const getMaxStepLimitApiInputs = getMaxStepLimitApi.inputs.length > 0 ? JSON.stringify(getMaxStepLimitApi.inputs) : 'none';
const getMaxStepLimitApiOutputs = getMaxStepLimitApi.outputs.length > 0 ? JSON.stringify(getMaxStepLimitApi.outputs) : 'none';
console.log(`[getMaxStepLimit]\n inputs: ${getMaxStepLimitApiInputs} \n outputs: ${getMaxStepLimitApiOutputs}`);
const params = {};
params[getMaxStepLimitApi.inputs[0].name] = 'invoke';
// Get max step limit by iconService.call
const callBuilder = new CallBuilder();
const call: Call = callBuilder
.to(MockData.GOVERNANCE_ADDRESS)
.method(methodName)
.params(params)
.build();
const maxStepLimit = await this.iconService.call(call).execute();
return IconConverter.toBigNumber(maxStepLimit as string)
}
async checkDeployTxStatus() {
if (!this.deployTxHash) {
document.getElementById('D02-1').innerHTML = 'Deploy ST Token first.';
}
const transactionResult = await this.iconService.getTransactionResult(this.deployTxHash).execute();
const status = transactionResult.status === 1 ? 'success' : 'failure';
this.scoreAddress = transactionResult.scoreAddress;
document.getElementById('D02-2').innerHTML = `tx status : ${status}`;
if (this.scoreAddress) {
document.getElementById('D02-3').innerHTML = `Your score address : ${this.scoreAddress}`;
this.getTokenBalance(MockData.WALLET_ADDRESS_1);
this.getTokenBalance(MockData.WALLET_ADDRESS_2);
}
}
async sendTransaction() {
if (!this.scoreAddress) {
document.getElementById('D03-1').innerHTML = 'Deploy ST Token and check deployment transaction first.';
return;
}
// Build raw transaction object
const transaction = await this.buildTokenTransaction();
// Create signature of the transaction
const signedTransaction = new SignedTransaction(transaction, this.wallet);
// Read params to transfer to nodes
const signedTransactionProperties = JSON.stringify(signedTransaction.getProperties()).split(",").join(", \n")
document.getElementById('D03-1').innerHTML = `Signed Transaction: ${signedTransactionProperties}`;
// Send transaction
this.transactionTxHash = await this.iconService.sendTransaction(signedTransaction).execute();
document.getElementById('D05-1').innerHTML = this.transactionTxHash;
// Print transaction hash
document.getElementById('D03-2').innerHTML = `Transfer Request Complete. Tx hash is ${this.transactionTxHash}`;
}
async buildTokenTransaction() {
const walletAddress = this.wallet.getAddress();
// You can use "governance score apis" to get step costs.
const value = IconAmount.of(1, IconAmount.Unit.ICX).toLoop();
const stepLimit = await this.getDefaultStepCost();
// networkId of node 1:mainnet, 2~:etc
const networkId = IconConverter.toBigNumber(3);
const version = IconConverter.toBigNumber(3);
// Timestamp is used to prevent the identical transactions. Only current time is required (Standard unit : us)
// If the timestamp is considerably different from the current time, the transaction will be rejected.
const timestamp = (new Date()).getTime() * 1000;
// SCORE name that send transaction is “transfer”.
const methodName = "transfer";
// Enter receiving address and the token value.
// You must enter the given key name("_to", "_value"). Otherwise, the transaction will be rejected.
const params = {
_to: MockData.WALLET_ADDRESS_2,
_value: IconConverter.toHex(value)
}
//Enter transaction information
return new CallTransactionBuilder()
.nid(networkId)
.from(walletAddress)
.to(this.scoreAddress)
.stepLimit(stepLimit)
.timestamp(timestamp)
.method(methodName)
.params(params)
.version(version)
.build();
}
async getDefaultStepCost(): Promise {
// Get governance score api list
const governanceApi = await this.iconService.getScoreApi(MockData.GOVERNANCE_ADDRESS).execute();
console.log(governanceApi)
const methodName = 'getStepCosts';
// Check input and output parameters of api if you need
const getStepCostsApi = governanceApi.getMethod(methodName);
const getStepCostsApiInputs = getStepCostsApi.inputs.length > 0 ? JSON.stringify(getStepCostsApi.inputs) : 'none';
const getStepCostsApiOutputs = getStepCostsApi.outputs.length > 0 ? JSON.stringify(getStepCostsApi.outputs) : 'none';
console.log(`[getStepCosts]\n inputs: ${getStepCostsApiInputs} \n outputs: ${getStepCostsApiOutputs}`);
// Get step costs by iconService.call
const callBuilder = new CallBuilder();
const call = callBuilder
.to(MockData.GOVERNANCE_ADDRESS)
.method(methodName)
.build();
const stepCosts = await this.iconService.call(call).execute();
// For sending token, it is about twice the default value.
return IconConverter.toBigNumber(stepCosts["default"]).times(2)
}
async getTokenBalance(address) {
if (!this.scoreAddress) {
document.getElementById('D04-1').innerHTML = 'Deploy ST Token and check deployment transaction first.';
}
const tokenAddress = this.scoreAddress;
// Method name to check the balance
const methodName = "balanceOf";
// You must enter the given key name (“_owner”).
const params = {
_owner: address
}
const callBuilder = new CallBuilder();
const call = callBuilder
.to(tokenAddress)
.method(methodName)
.params(params)
.build();
// Check the wallet balance
const balance = await this.iconService.call(call).execute();
const htmlId = address === MockData.WALLET_ADDRESS_1 ? 'D04-2' : 'D04-3';
document.getElementById(htmlId).innerHTML = `${IconAmount.of(balance, IconAmount.Unit.LOOP).convertUnit(IconAmount.Unit.ICX)}`;
}
async checkTransactionTxStatus() {
if (!this.transactionTxHash) {
document.getElementById('D05-1').innerHTML = 'Make token transaction first.';
}
if (!this.scoreAddress) {
document.getElementById('D05-1').innerHTML = 'Deploy ST Token and check deployment transaction first.';
}
const transactionResult = await this.iconService.getTransactionResult(this.transactionTxHash).execute();
const status = transactionResult.status === 1 ? 'success' : 'failure';
document.getElementById('D05-2').innerHTML = `tx status: ${status}`;
}
}
if (document.getElementById('D01')) {
deployAndTransferTokenExample = new DeployAndTransferTokenExample();
}
export default DeployAndTransferTokenExample;