Source: icon-js/wallet.js

/**
 * ICON wallet module for javascript
 * @module stayge-wallet/icon-js/wallet
*/

'use strict'

const key = require('./key.js');
const utils = require('./utils.js');
const jsonrpc = require('./jsonrpc.js');
const tx = require('./tx.js');

const DEFAULT_DEPLOY_STEP_LIMIT = 2000000000; // 20 ICX, step price : 0.00000001 ICX(10 Gloop)
const DEFAULT_UPDATE_STEP_LIMIT = 3000000000; // 30 ICX, step price : 0.00000001 ICX(10 Gloop)
const DEFAULT_TX_STEP_LIMIT = 500000; // 0.005 ICX, step price : 0.00000001 ICX(10 Gloop)

/**
 * Class representing a ICON Wallet
 */
class Wallet {


    /**
     * Factory method to create a new wallet with a newly generated private key
     * @return {Wallet}
     */
    static create() {
        return new Wallet(key.generatePrivateKey());
    }

    /**
     * Factory method to create a wallet from the private key
     * @param  {String} privateKeyString
     * @return {Wallet}
     */
    static fromPrivateKey(privateKeyString) {
        return new Wallet(Buffer.from(privateKeyString, 'hex'));
    }

    /**
     * Factory method to create a wallet from the keystore object
     * @param  {Object|string} keyStoreObj [description]
     * @param  {String} password    [description]
     * @return {Wallet}             [description]
     */
    static fromKeyStoreObj(keyStoreObj, password) {
        //console.log('typeof keyStoreObj:'+typeof keyStoreObj);
        const json = (typeof keyStoreObj === 'object') ? keyStoreObj : JSON.parse(keyStoreObj);

        return new Wallet(key.privateKeyFromKeyStoreObj(
            json,
            password
            ));
    }

    /**
     * Create a ICON Wallet
     * @param {Buffer} privateKey - private key for wallet
     */
    constructor(privateKey) {
        this._privateKey = privateKey;
        this._publicKey = key.privateToPublic(privateKey);
        this._address = key.publicToAddress(this._publicKey);
        this._endpoint = utils.getEndPointFromEnv();
    }


    /**
     * Get the private key of the wallet
     * @return {Buffer}
     */
    getPrivateKey() {
        return this._privateKey;
    }

    /**
     * Get the private key string of the wallet
     * @return {String}
     */
    getPrivateKeyString() {
        return this._privateKey.toString('hex');
    }


    /**
     * Get the public key of the wallet
     * @return {Buffer}
     */
    getPublicKey() {
        return this._publicKey;
    }


    /**
     * Get the public key string of the wallet
     * @return {String}
     */
    getPublicKeyString() {
        return this._publicKey.toString('hex');
    }

    /**
     * Get the address of the wallet
     * @return {Buffer}
     */
    getAddress() {
        return this._address;
    }

    /**
     * Get the address string of the wallet
     * @return {String}
     */
    getAddressString() {
        return 'hx' + this._address.toString('hex');
    }

    /**
     * Convert the wallet to the keystore object
     * @param  {String} password
     * @return {Object}
     */
    toKeyStoreObj(password) {
        return key.toKeyStoreObj(
            this.getPrivateKey(),
            this.getAddressString(),
            password
        );
    }

    /**
     * set the endpoint
     * @param {String} name 'mainnet' | 'testnet'
     */
    setEndPoint(name) {
        this._endpoint = utils.getEndPoint(name);
    }

    /**
     * get the endpoint
     * @return {String} uri of endpoint
     */
    getEndPoint() {
        return this._endpoint;
    }

    /**
     * Get the block information by height
     * @param  {Number|String} height
     * @return {Promise<Object>}
     */
    async getBlockByHeight(height) {
        return jsonrpc.getBlockByHeight(height, this.getEndPoint().url);
    }


    /**
     * Get the block information by hash
     * @param  {String} height
     * @return {Promise<Object>}
     */
    async getBlockByHash(hash) {
        return jsonrpc.getBlockByHash(hash, this.getEndPoint().url);
    }

    /**
     * Get the last block information
     * @return {Promise<Object>}
     */
    async getLastBlock() {
        return jsonrpc.getLastBlock(this.getEndPoint().url);
    }


    /**
     * Get balance of the wallet
     * @return {Promise<String>}
     */
    async getBalance() {
        return jsonrpc.getBalance(this.getAddressString(), this.getEndPoint().url);
    }

    /**
     * Get total supply of ICX
     * @return {Promise<String>}
     */
    async getTotalSupply() {
        return jsonrpc.getTotalSupply(this.getEndPoint().url);
    }


    /**
     * Transfer ICX coins
     * @param {String} to
     * @param {Number} value
     * @return {Promise<String>} txHash
     */
    async transferICX(to, value) {
        const data = {
            from: this.getAddressString(),
            to: to,
            stepLimit: DEFAULT_TX_STEP_LIMIT,
            value: value,
        };

        const rawTx = tx.makeIcxRawTx(data, this.getEndPoint().nid);
        const rawTxSigned = tx.signRawTx(this.getPrivateKey(), rawTx)
        const result = await jsonrpc.sendTransaction(
            rawTxSigned,
            this.getEndPoint().url
        );

        return result
    }


    /**
     * Transafer a message
     * @param  {String} to
     * @param  {String} msg
     * @return {Promise<String>} txHash
     */
    async transferMessage(to, msg) {
        const data = {
            from: this.getAddressString(),
            to: to,
            stepLimit: DEFAULT_TX_STEP_LIMIT,
            dataType: 'message',
            data: msg,
        };

        const rawTx = tx.makeIcxRawTx(data, this.getEndPoint().nid);
        const rawTxSigned = tx.signRawTx(this.getPrivateKey(), rawTx)
        const result = await jsonrpc.sendTransaction(
            rawTxSigned,
            this.getEndPoint().url
        );

        return result
    }


    /**
     * Send a transaction for calling a SCORE'S method
     * @param  {String} scoreAddress
     * @param  {String} scoreMethod
     * @param  {Object} methodParams
     * @return {Promise<String>} txHash
     */
    async callScoreTx(scoreAddress, scoreMethod, methodParams) {
        const data = {
            from: this.getAddressString(),
            to: scoreAddress,
            stepLimit: DEFAULT_TX_STEP_LIMIT,
            dataType: 'call',
            data: {
                method: scoreMethod
            },
        };

        if (methodParams) {
            data.data.params = methodParams;
        }

        const rawTx = tx.makeIcxRawTx(data, this.getEndPoint().nid);
        const rawTxSigned = tx.signRawTx(this.getPrivateKey(), rawTx)
        const result = await jsonrpc.sendTransaction(
            rawTxSigned,
            this.getEndPoint().url
        );

        return result
    }

    /**
     * Install a SCORE on the ICON blockchain
     * @param  {String} scoreContent
     * @param  {Object} installParams
     * @return {Promise<String>} txHash
     */
    async installScore(scoreContent, installParams) {
        const data = {
            from: this.getAddressString(),
            to: 'cx0000000000000000000000000000000000000000',   // address 0 means SCORE install
            stepLimit: DEFAULT_DEPLOY_STEP_LIMIT,
            dataType: 'deploy',
            data: {
                contentType: 'application/zip',
                content: scoreContent,
            },
        };

        if (installParams) {
            data.data.params = installParams;
        }

        const rawTx = tx.makeIcxRawTx(data, this.getEndPoint().nid);
        const rawTxSigned = tx.signRawTx(this.getPrivateKey(), rawTx)
        const result = await jsonrpc.sendTransaction(
            rawTxSigned,
            this.getEndPoint().url
        );

        return result
    }


    /**
     * Update the SCORE on the ICON blockchain
     * @param  {String} scoreAddress address of score
     * @param  {String} scoreContent score contents of hexstring format
     * @param  {Object} updateParams parameter for update
     * @return {Promise<String>}
     */
    async updateScore(scoreAddress, scoreContent, updateParams) {
        const data = {
            from: this.getAddressString(),
            to: scoreAddress,
            stepLimit: DEFAULT_UPDATE_STEP_LIMIT,
            dataType: 'deploy',
            data: {
                contentType: 'application/zip',
                content: scoreContent,
            },
        };

        if (updateParams) {
            data.data.params = updateParams;
        }

        const rawTx = tx.makeIcxRawTx(data, this.getEndPoint().nid);
        const rawTxSigned = tx.signRawTx(this.getPrivateKey(), rawTx)
        const result = await jsonrpc.sendTransaction(
            rawTxSigned,
            this.getEndPoint().url
        );

        return result
    }

    /**
     * Call SCORE's external function
     * @param  {String} to
     * @param  {String} method
     * @param  {Object} params
     * @return {Promise<String>}
     */
    async call(to, method, params) {
        const data = {
            from: this.getAddressString(),
            to: to,
            dataType: 'call',
            data: {
                method: method,
                params: params
            }
        };

        const result = await jsonrpc.call(
            data,
            this.getEndPoint().url
        );

        return result
    }

    /**
     * Get the SCORE's external API list
     * @param  {String} address
     * @return {Promise<Object>}
     */
    async getScoreApi(address) {
        return jsonrpc.getScoreApi(address, this.getEndPoint().url);
    }

    /**
     * Get the transaction result with the specified txHash
     * @param  {String} txHash
     * @return {Promise<Object>}
     */
    async getTransactionResult(txHash) {
        return jsonrpc.getTransactionResult(txHash, this.getEndPoint().url);
    }

    /**
     * Get the transaction information by txHash
     * @param  {String} txHash
     * @return {Promise<Object>}
     */
    async getTransactionByHash(txHash) {
        return jsonrpc.getTransactionByHash(txHash, this.getEndPoint().url);
    }


    /**
     * deposit to the score for virtual step
     * @param  {String} scoreAddress
     * @param  {Number} amt
     * @return {Promise<String>} txHash
     */
    async depositFeeSharing(scoreAddress, amt) {
        const data = {
            from: this.getAddressString(),
            to: scoreAddress,
            value: amt,
            stepLimit: DEFAULT_TX_STEP_LIMIT,
            dataType: 'deposit',
            data: {
                action: 'add'
            },
        };

        const rawTx = tx.makeIcxRawTx(data, this.getEndPoint().nid);
        const rawTxSigned = tx.signRawTx(this.getPrivateKey(), rawTx)
        const result = await jsonrpc.sendTransaction(
            rawTxSigned,
            this.getEndPoint().url
        );

        return result
    }

    /**
     * withdraw the deposit for virtual step
     * @param  {String} scoreAddress
     * @param  {Number} amt
     * @return {Promise<String>} txHash
     */
    async withdrawFeeSharing(scoreAddress, depositId) {
        const data = {
            from: this.getAddressString(),
            to: scoreAddress,
            stepLimit: DEFAULT_TX_STEP_LIMIT,
            dataType: 'deposit',
            data: {
                action: 'withdraw',
                id: depositId
            },
        };

        const rawTx = tx.makeIcxRawTx(data, this.getEndPoint().nid);
        const rawTxSigned = tx.signRawTx(this.getPrivateKey(), rawTx)
        const result = await jsonrpc.sendTransaction(
            rawTxSigned,
            this.getEndPoint().url
        );

        return result
    }

}



/** @type {Wallet} */
module.exports = Wallet;