caver-js
Version:
caver-js is a JavaScript API library that allows developers to interact with a Klaytn node
272 lines (236 loc) • 7.52 kB
JavaScript
/*
Modifications copyright 2018 The caver-js Authors
This file is part of web3.js.
web3.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
web3.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
This file is derived from web3.js/packages/web3-eth-abi/src/index.js (2019/06/12).
Modified and improved for the caver-js development.
*/
/**
* @file iban.js
*
* Details: https://github.com/ethereum/wiki/wiki/ICAP:-Inter-exchange-Client-Address-Protocol
*
* @author Marek Kotewicz <marek@parity.io>
* @date 2015
*/
const BigNumber = require('bn.js')
const utils = require('../../src/index')
const leftPad = function(string, bytes) {
let result = string
while (result.length < bytes * 2) {
result = `0${result}`
}
return result
}
/**
* Prepare an IBAN for mod 97 computation by moving the first 4 chars to the end and transforming the letters to
* numbers (A = 10, B = 11, ..., Z = 35), as specified in ISO13616.
*
* @method iso13616Prepare
* @param {String} iban the IBAN
* @returns {String} the prepared IBAN
*/
const iso13616Prepare = function(iban) {
const A = 'A'.charCodeAt(0)
const Z = 'Z'.charCodeAt(0)
iban = iban.toUpperCase()
iban = iban.substr(4) + iban.substr(0, 4)
return iban
.split('')
.map(function(n) {
const code = n.charCodeAt(0)
if (code >= A && code <= Z) {
// A = 10, B = 11, ... Z = 35
return code - A + 10
}
return n
})
.join('')
}
/**
* Calculates the MOD 97 10 of the passed IBAN as specified in ISO7064.
*
* @method mod9710
* @param {String} iban
* @returns {Number}
*/
const mod9710 = function(iban) {
let remainder = iban
let block
while (remainder.length > 2) {
block = remainder.slice(0, 9)
remainder = (parseInt(block, 10) % 97) + remainder.slice(block.length)
}
return parseInt(remainder, 10) % 97
}
/**
* This prototype should be used to create iban object from iban correct string
*
* @param {String} iban
*/
class Iban {
constructor(iban) {
this._iban = iban
}
/**
* This method should be used to create an ethereum address from a direct iban address
*
* @method toAddress
* @param {String} iban address
* @return {String} the ethereum address
*/
static toAddress(ib) {
ib = new Iban(ib)
if (!ib.isDirect()) {
throw new Error("IBAN is indirect and can't be converted")
}
return ib.toAddress()
}
/**
* This method should be used to create iban address from an ethereum address
*
* @method toIban
* @param {String} address
* @return {String} the IBAN address
*/
static toIban(address) {
return Iban.fromAddress(address).toString()
}
/**
* This method should be used to create iban object from an ethereum address
*
* @method fromAddress
* @param {String} address
* @return {Iban} the IBAN object
*/
static fromAddress(address) {
if (!utils.isAddress(address)) {
throw new Error(`Provided address is not a valid address: ${address}`)
}
address = address.replace('0x', '').replace('0X', '')
const asBn = new BigNumber(address, 16)
const base36 = asBn.toString(36)
const padded = leftPad(base36, 15)
return Iban.fromBban(padded.toUpperCase())
}
/**
* Convert the passed BBAN to an IBAN for this country specification.
* Please note that <i>"generation of the IBAN shall be the exclusive responsibility of the bank/branch servicing the account"</i>.
* This method implements the preferred algorithm described in http://en.wikipedia.org/wiki/International_Bank_Account_Number#Generating_IBAN_check_digits
*
* @method fromBban
* @param {String} bban the BBAN to convert to IBAN
* @returns {Iban} the IBAN object
*/
static fromBban(bban) {
const countryCode = 'XE'
const remainder = mod9710(iso13616Prepare(`${countryCode}00${bban}`))
const checkDigit = `0${98 - remainder}`.slice(-2)
return new Iban(countryCode + checkDigit + bban)
}
/**
* Should be used to create IBAN object for given institution and identifier
*
* @method createIndirect
* @param {Object} options, required options are "institution" and "identifier"
* @return {Iban} the IBAN object
*/
static createIndirect(options) {
return Iban.fromBban(`ETH${options.institution}${options.identifier}`)
}
/**
* This method should be used to check if given string is valid iban object
*
* @method isValid
* @param {String} iban string
* @return {Boolean} true if it is valid IBAN
*/
static isValid(iban) {
const i = new Iban(iban)
return i.isValid()
}
/**
* Should be called to check if iban is correct
*
* @method isValid
* @returns {Boolean} true if it is, otherwise false
*/
isValid() {
return /^XE[0-9]{2}(ETH[0-9A-Z]{13}|[0-9A-Z]{30,31})$/.test(this._iban) && mod9710(iso13616Prepare(this._iban)) === 1
}
/**
* Should be called to check if iban number is direct
*
* @method isDirect
* @returns {Boolean} true if it is, otherwise false
*/
isDirect() {
return this._iban.length === 34 || this._iban.length === 35
}
/**
* Should be called to check if iban number if indirect
*
* @method isIndirect
* @returns {Boolean} true if it is, otherwise false
*/
isIndirect() {
return this._iban.length === 20
}
/**
* Should be called to get iban checksum
* Uses the mod-97-10 checksumming protocol (ISO/IEC 7064:2003)
*
* @method checksum
* @returns {String} checksum
*/
checksum() {
return this._iban.substr(2, 2)
}
/**
* Should be called to get institution identifier
* eg. XREG
*
* @method institution
* @returns {String} institution identifier
*/
institution() {
return this.isIndirect() ? this._iban.substr(7, 4) : ''
}
/**
* Should be called to get client identifier within institution
* eg. GAVOFYORK
*
* @method client
* @returns {String} client identifier
*/
client() {
return this.isIndirect() ? this._iban.substr(11) : ''
}
/**
* Should be called to get client direct address
*
* @method toAddress
* @returns {String} ethereum address
*/
toAddress() {
if (this.isDirect()) {
const base36 = this._iban.substr(4)
const asBn = new BigNumber(base36, 36)
return utils.toChecksumAddress(asBn.toString(16, 20))
}
return ''
}
toString() {
return this._iban
}
}
module.exports = Iban