ethereumjs-util#BN TypeScript Examples

The following examples show how to use ethereumjs-util#BN. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: util.ts    From remix-project with MIT License 7 votes vote down vote up
export function toBN (value) {
  if (value instanceof BN) {
    return value
  } else if (value.match && value.match(/^(0x)?([a-f0-9]*)$/)) {
    value = unpadHexString(value)
    value = new BN(value === '' ? '0' : value, 16)
  } else if (!isNaN(value)) {
    value = new BN(value)
  }
  return value
}
Example #2
Source File: util.ts    From remix-project with MIT License 7 votes vote down vote up
/*
    ints: list of BNs
  */
export function hexListFromBNs (bnList) {
  const ret = []
  for (const k in bnList) {
    const v = bnList[k]
    if (BN.isBN(v)) {
      ret.push('0x' + v.toString('hex', 64))
    } else {
      ret.push('0x' + (new BN(v)).toString('hex', 64)) // TEMP FIX TO REMOVE ONCE https://github.com/ethereumjs/ethereumjs-vm/pull/293 is released
    }
  }
  return ret
}
Example #3
Source File: DynamicByteArray.ts    From remix-project with MIT License 6 votes vote down vote up
async decodeFromStorage (location, storageResolver) {
    let value = '0x0'
    try {
      value = await extractHexValue(location, storageResolver, this.storageBytes)
    } catch (e) {
      console.log(e)
      return { error: '<decoding failed - ' + e.message + '>', type: this.typeName }
    }
    const length = new BN(value, 16)
    if (length.testn(0)) {
      let dataPos = new BN(sha3256(location.slot).replace('0x', ''), 16)
      let ret = ''
      let currentSlot = '0x'
      try {
        currentSlot = await readFromStorage(dataPos, storageResolver)
      } catch (e) {
        console.log(e)
        return { error: '<decoding failed - ' + e.message + '>', type: this.typeName }
      }
      while (length.gt(new BN(ret.length)) && ret.length < 32000) {
        currentSlot = currentSlot.replace('0x', '')
        ret += currentSlot
        dataPos = dataPos.add(new BN(1))
        try {
          currentSlot = await readFromStorage(dataPos, storageResolver)
        } catch (e) {
          console.log(e)
          return { error: '<decoding failed - ' + e.message + '>', type: this.typeName }
        }
      }
      return { value: '0x' + ret.replace(/(00)+$/, ''), length: '0x' + length.toString(16), type: this.typeName }
    } else {
      const size = parseInt(value.substr(value.length - 2, 2), 16) / 2
      return { value: '0x' + value.substr(0, size * 2), length: '0x' + size.toString(16), type: this.typeName }
    }
  }
Example #4
Source File: get-common.ts    From cloud-cryptographic-wallet with MIT License 6 votes vote down vote up
export async function getCommon(rpcUrl: string): Promise<CommonType> {
  const chainId = await query<string>(rpcUrl, "eth_chainId", []);

  if (!chainId) {
    throw new Error("getCommon: can't get result of eth_chainId");
  }

  return Common.custom({
    chainId: new BN(chainId.slice(2), "hex"),
    defaultHardfork: Hardfork.London,
  });
}
Example #5
Source File: global-variables.tsx    From remix-project with MIT License 6 votes vote down vote up
GlobalVariables = ({ block, receipt, tx }) => {
  // see https://docs.soliditylang.org/en/latest/units-and-global-variables.html#block-and-transaction-properties
  const globals = {
    'block.chainid': tx.chainId,
    'block.coinbase': block.miner,
    'block.difficulty': block.difficulty,
    'block.gaslimit': block.gasLimit,
    'block.number': block.number,
    'block.timestamp': block.timestamp,
    'msg.sender': tx.from,
    'msg.sig': tx.input.substring(0, 10),
    'msg.value': tx.value + ' Wei',
    'tx.origin': tx.from
  }
  if (block.baseFeePerGas) {
    globals['block.basefee'] = (new BN(block.baseFeePerGas.replace('0x', ''), 'hex')).toString(10) + ` Wei (${block.baseFeePerGas})`
  }

  return (
    <div id='globalvariable' data-id='globalvariable'>
      <DropdownPanel hexHighlight={false} bodyStyle={{ fontFamily: 'monospace' }} dropdownName='Global Variables' calldata={globals || {}} />
    </div>
  )
}
Example #6
Source File: transactions.ts    From remix-project with MIT License 6 votes vote down vote up
eth_getTransactionCount (payload, cb) {
    const address = payload.params[0]

    this.vmContext.vm().stateManager.getAccount(Address.fromString(address)).then((account) => {
      const nonce = new BN(account.nonce).toString(10)
      cb(null, nonce)
    }).catch((error) => {
      cb(error)
    })
  }
Example #7
Source File: accounts.ts    From remix-project with MIT License 6 votes vote down vote up
eth_getBalance (payload, cb) {
    const address = payload.params[0]

    this.vmContext.vm().stateManager.getAccount(Address.fromString(address)).then((account) => {
      cb(null, new BN(account.balance).toString(10))
    }).catch((error) => {
      cb(error)
    })
  }
Example #8
Source File: accounts.ts    From remix-project with MIT License 6 votes vote down vote up
_addAccount (privateKey, balance) {
    return new Promise((resolve, reject) => {
      privateKey = Buffer.from(privateKey, 'hex')
      const address: Buffer = privateToAddress(privateKey)
      const addressStr = toChecksumAddress('0x' + address.toString('hex'))
      this.accounts[addressStr] = { privateKey, nonce: 0 }
      this.accountsKeys[addressStr] = '0x' + privateKey.toString('hex')

      const stateManager = this.vmContext.vm().stateManager
      stateManager.getAccount(Address.fromString(addressStr)).then((account) => {
        account.balance = new BN(balance.replace('0x', '') || 'f00000000000000001', 16)
        stateManager.putAccount(Address.fromString(addressStr), account).catch((error) => {
          reject(error)
        }).then(() => {
          resolve({})
        })
      }).catch((error) => {
        reject(error)
      })
    })
  }
Example #9
Source File: genesis.ts    From remix-project with MIT License 6 votes vote down vote up
export function generateBlock (vmContext) {
  return new Promise((resolve, reject) => {
    const block: Block = Block.fromBlockData({
      header: {
        timestamp: (new Date().getTime() / 1000 | 0),
        number: 0,
        coinbase: '0x0e9281e9c6a0808672eaba6bd1220e144c9bb07a',
        difficulty: new BN('69762765929000', 10),
        gasLimit: new BN('8000000').imuln(1)
      }
    }, { common: vmContext.vmObject().common })

    vmContext.vm().runBlock({ block: block, generate: true, skipBlockValidation: true, skipBalance: false }).then(() => {
      vmContext.addBlock(block)
      resolve({})
    }).catch((e) => reject(e))
  })
}
Example #10
Source File: VmProxy.ts    From remix-project with MIT License 6 votes vote down vote up
getSha3Input (stack, memory) {
    let memoryStart = stack[stack.length - 1]
    let memoryLength = stack[stack.length - 2]
    const memStartDec = (new BN(memoryStart.replace('0x', ''), 16)).toString(10)
    memoryStart = parseInt(memStartDec) * 2
    const memLengthDec = (new BN(memoryLength.replace('0x', ''), 16).toString(10))
    memoryLength = parseInt(memLengthDec) * 2

    let i = Math.floor(memoryStart / 32)
    const maxIndex = Math.floor(memoryLength / 32) + i
    if (!memory[i]) {
      return this.emptyFill(memoryLength)
    }
    let sha3Input = memory[i].slice(memoryStart - 32 * i)
    i++
    while (i < maxIndex) {
      sha3Input += memory[i] ? memory[i] : this.emptyFill(32)
      i++
    }
    if (sha3Input.length < memoryLength) {
      const leftSize = memoryLength - sha3Input.length
      sha3Input += memory[i] ? memory[i].slice(0, leftSize) : this.emptyFill(leftSize)
    }
    return sha3Input
  }
Example #11
Source File: txResultHelper.ts    From remix-project with MIT License 6 votes vote down vote up
VM_RESULT = {
  receipt: {
    amountSpent: new BN(1),
    contractAddress: CONTRACT_ADDRESS_BUFFER,
    gasRefund: new BN(0),
    gasUsed: new BN(GAS_USED_INT),
    status: STATUS_OK,
  },
  transactionHash: TRANSACTION_HASH
}
Example #12
Source File: typeConversion.ts    From remix-project with MIT License 6 votes vote down vote up
function convertToString (v) {
  try {
    if (v instanceof Array) {
      const ret = []
      for (const k in v) {
        ret.push(convertToString(v[k]))
      }
      return ret
    } else if (BN.isBN(v) || (v.constructor && v.constructor.name === 'BigNumber')) {
      return v.toString(10)
    } else if (v._isBuffer) {
      return bufferToHex(v)
    } else if (typeof v === 'object') {
      const retObject = {}
      for (const i in v) {
        retObject[i] = convertToString(v[i])
      }
      return retObject
    } else {
      return v
    }
  } catch (e) {
    console.log(e)
    return v
  }
}
Example #13
Source File: util.ts    From remix-project with MIT License 6 votes vote down vote up
export function decodeIntFromHex (value, byteLength, signed) {
  let bigNumber = new BN(value, 16)
  if (signed) {
    bigNumber = bigNumber.fromTwos(8 * byteLength)
  }
  return bigNumber.toString(10)
}
Example #14
Source File: Mapping.ts    From remix-project with MIT License 6 votes vote down vote up
function getMappingLocation (key, position) {
  // mapping storage location decribed at http://solidity.readthedocs.io/en/develop/miscellaneous.html#layout-of-state-variables-in-storage
  // > the value corresponding to a mapping key k is located at keccak256(k . p) where . is concatenation.

  // key should be a hex string, and position an int
  const mappingK = toBuffer(addHexPrefix(key))
  let mappingP = toBuffer(addHexPrefix(position))
  mappingP = setLengthLeft(mappingP, 32)
  const mappingKeyBuf = concatTypedArrays(mappingK, mappingP)
  const mappingStorageLocation: Buffer = keccak(mappingKeyBuf)
  const mappingStorageLocationinBn: BN = new BN(mappingStorageLocation, 16)
  return mappingStorageLocationinBn
}
Example #15
Source File: txResultHelper.ts    From remix-project with MIT License 5 votes vote down vote up
EXEC_RESULT = {
  exceptionError: null,
  gasRefund: new BN(0),
  gasUsed: new BN(GAS_USED_INT),
  returnValue: RETURN_VALUE_BUFFER
}
Example #16
Source File: typeConversion.ts    From remix-project with MIT License 5 votes vote down vote up
export function toInt (h) {
  if (h.indexOf && h.indexOf('0x') === 0) {
    return (new BN(h.replace('0x', ''), 16)).toString(10)
  } else if ((h.constructor && h.constructor.name === 'BigNumber') || BN.isBN(h)) {
    return h.toString(10)
  }
  return h
}
Example #17
Source File: solidityTypeFormatter.ts    From remix-project with MIT License 5 votes vote down vote up
// eslint-disable-line

export function extractData (item, parent): ExtractData {
  const ret: ExtractData = {}

  if (item.isProperty || !item.type) {
    return item
  }
  try {
    if (item.type.lastIndexOf(']') === item.type.length - 1) {
      ret.children = (item.value || []).map(function (item, index) {
        return { key: index, value: item }
      })
      ret.children.unshift({
        key: 'length',
        value: {
          self: (new BN(item.length.replace('0x', ''), 16)).toString(10),
          type: 'uint',
          isProperty: true
        }
      })
      ret.isArray = true
      ret.self = parent.isArray ? '' : item.type
      ret.cursor = item.cursor
      ret.hasNext = item.hasNext
    } else if (item.type.indexOf('struct') === 0) {
      ret.children = Object.keys((item.value || {})).map(function (key) {
        return { key: key, value: item.value[key] }
      })
      ret.self = item.type
      ret.isStruct = true
    } else if (item.type.indexOf('mapping') === 0) {
      ret.children = Object.keys((item.value || {})).map(function (key) {
        return { key: key, value: item.value[key] }
      })
      ret.isMapping = true
      ret.self = item.type
    } else {
      ret.children = null
      ret.self = item.value
      ret.type = item.type
    }
  } catch (e) {
    console.log(e)
  }
  return ret
}
Example #18
Source File: value.tsx    From remix-project with MIT License 5 votes vote down vote up
export function ValueUI (props: ValueProps) {
  const [sendValue, setSendValue] = useState<string>(props.sendValue)
  const inputValue = useRef<HTMLInputElement>({} as HTMLInputElement)

  useEffect(() => {
    (sendValue !== props.sendValue) && props.setSendValue(sendValue)
  }, [sendValue])

  const validateInputKey = (e) => {
    // preventing not numeric keys
    // preventing 000 case
    if (!isNumeric(e.key) ||
      (e.key === '0' && !parseInt(inputValue.current.value) && inputValue.current.value.length > 0)) {
      e.preventDefault()
    }
  }

  const validateValue = (e) => {
    const value = e.target.value

    if (!value) {
      // assign 0 if given value is
      // - empty
      return setSendValue('0')
    }

    let v
    try {
      v = new BN(value, 10)
      setSendValue(v.toString(10))
    } catch (e) {
      // assign 0 if given value is
      // - not valid (for ex 4345-54)
      // - contains only '0's (for ex 0000) copy past or edit
      setSendValue('0')
    }

    // if giveen value is negative(possible with copy-pasting) set to 0
    if (v.lt(0)) setSendValue('0')
  }

  return (
    <div className="udapp_crow">
      <label className="udapp_settingsLabel" data-id="remixDRValueLabel">Value</label>
      <div className="udapp_gasValueContainer">
        <input
          ref={inputValue}
          type="number"
          min="0"
          pattern="^[0-9]"
          step="1"
          className="form-control udapp_gasNval udapp_col2"
          id="value"
          data-id="dandrValue"
          title="Enter the value and choose the unit"
          onKeyPress={validateInputKey}
          onChange={validateValue}
          value={props.sendValue}
        />
        <select name="unit" value={props.sendUnit} className="form-control p-1 udapp_gasNvalUnit udapp_col2_2 custom-select" id="unit" onChange={(e) => { props.setUnit((e.target.value) as 'ether' | 'finney' | 'gwei' | 'wei') }}>
          <option data-unit="wei" value='wei'>Wei</option>
          <option data-unit="gwei" value="gwei">Gwei</option>
          <option data-unit="finney" value="finney">Finney</option>
          <option data-unit="ether" value="ether">Ether</option>
        </select>
      </div>
    </div>
  )
}
Example #19
Source File: ArrayType.ts    From remix-project with MIT License 5 votes vote down vote up
async decodeFromStorage (location, storageResolver) {
    const ret = []
    let size = null
    let slotValue
    try {
      slotValue = await extractHexValue(location, storageResolver, this.storageBytes)
    } catch (e) {
      console.log(e)
      return {
        error: '<decoding failed - ' + e.message + '>',
        type: this.typeName
      }
    }
    const currentLocation = {
      offset: 0,
      slot: location.slot
    }
    if (this.arraySize === 'dynamic') {
      size = toBN('0x' + slotValue)
      currentLocation.slot = sha3256(location.slot)
    } else {
      size = new BN(this.arraySize)
    }
    const k = toBN(0)
    for (; k.lt(size) && k.ltn(300); k.iaddn(1)) {
      try {
        ret.push(await this.underlyingType.decodeFromStorage(currentLocation, storageResolver))
      } catch (e) {
        return {
          error: '<decoding failed - ' + e.message + '>',
          type: this.typeName
        }
      }
      if (this.underlyingType.storageSlots === 1 && location.offset + this.underlyingType.storageBytes <= 32) {
        currentLocation.offset += this.underlyingType.storageBytes
        if (currentLocation.offset + this.underlyingType.storageBytes > 32) {
          currentLocation.offset = 0
          currentLocation.slot = '0x' + add(currentLocation.slot, 1).toString(16)
        }
      } else {
        currentLocation.slot = '0x' + add(currentLocation.slot, this.underlyingType.storageSlots).toString(16)
        currentLocation.offset = 0
      }
    }
    return { value: ret, length: '0x' + size.toString(16), type: this.typeName }
  }
Example #20
Source File: abi-coder.ts    From ethereum-sdk with MIT License 5 votes vote down vote up
function formatParam(type: any, param: any) {
	const paramTypeBytes = new RegExp(/^bytes([0-9]*)$/)
	const paramTypeBytesArray = new RegExp(/^bytes([0-9]*)\[\]$/)
	const paramTypeNumber = new RegExp(/^(u?int)([0-9]*)$/)
	const paramTypeNumberArray = new RegExp(/^(u?int)([0-9]*)\[\]$/)

	// Format BN to string
	if (BN.isBN(param) || (param && param.constructor && param.constructor.name === "BigNumber")) {
		return (param as number | BN).toString(10)
	}

	if (type.match(paramTypeBytesArray) || type.match(paramTypeNumberArray)) {
		return param.map((p: any) => formatParam(type.replace("[]", ""), p))
	}

	// Format correct width for u?int[0-9]*
	let match = type.match(paramTypeNumber)
	if (match) {
		let size = parseInt(match[2] || "256")
		if (size / 8 < param.length) {
			// pad to correct bit width
			param = ethers.utils.hexZeroPad(param, size)
		}
	}

	// Format correct length for bytes[0-9]+
	match = type.match(paramTypeBytes)
	if (match) {
		if (Buffer.isBuffer(param)) {
			param = ethers.utils.hexlify(param)
		}

		// format to correct length
		let size = parseInt(match[1])
		if (size) {
			let maxSize = size * 2
			if (param.substring(0, 2) === "0x") {
				maxSize += 2
			}
			if (param.length < maxSize) {
				// pad to correct length
				const rightPad = function (string: string | number, chars: number) {
					const hasPrefix = typeof string === "number" || /^0x/i.test(string)
					string = string.toString(16).replace(/^0x/i, "")

					const padding = (chars - string.length + 1 >= 0) ? chars - string.length + 1 : 0

					return (hasPrefix ? "0x" : "") + string + (new Array(padding).join("0"))
				}
				param = rightPad(param, size * 2)
			}
		}

		// format odd-length bytes to even-length
		if (param.length % 2 === 1) {
			param = "0x0" + param.substring(2)
		}
	}

	return param
}
Example #21
Source File: prepare-fee-for-exchange-wrapper.ts    From ethereum-sdk with MIT License 5 votes vote down vote up
export function prepareForExchangeWrapperFees(fees: Part[]): string[] {
	return fees.map(fee => {
		const addr = stripHexPrefix(fee.account)
		const preparedFee = new BN(fee.value, 10).toString(16).padStart(24, "0")
		return new BN(preparedFee + addr, 16).toString(10)
	})
}
Example #22
Source File: provider.ts    From hardhat-kms-signer with MIT License 5 votes vote down vote up
private async _getNonce(address: Buffer): Promise<BN> {
    const response = (await this._wrappedProvider.request({
      method: "eth_getTransactionCount",
      params: [bufferToHex(address), "pending"],
    })) as string;

    return rpcQuantityToBN(response);
  }
Example #23
Source File: txRunnerVM.ts    From remix-project with MIT License 4 votes vote down vote up
runInVm (from, to, data, value, gasLimit, useCall, timestamp, callback) {
    const self = this
    let account
    if (!from && useCall && Object.keys(self.vmaccounts).length) {
      from = Object.keys(self.vmaccounts)[0]
      account = self.vmaccounts[from]
    } else account = self.vmaccounts[from] 
    
    if (!account) {
      return callback('Invalid account selected')
    }
    if (Number.isInteger(gasLimit)) {
      gasLimit = '0x' + gasLimit.toString(16)
    }

    this.getVMObject().stateManager.getAccount(Address.fromString(from)).then((res) => {
      // See https://github.com/ethereumjs/ethereumjs-tx/blob/master/docs/classes/transaction.md#constructor
      // for initialization fields and their types
      if (!value) value = 0
      if (typeof value === 'string') {
        if (value.startsWith('0x')) value = new BN(value.replace('0x', ''), 'hex')
        else {
          try {
            value = new BN(value, 10)
          } catch (e) {
            return callback('Unable to parse the value ' + e.message)
          }
        }
      }

      const EIP1559 = this.commonContext.hardfork() !== 'berlin' // berlin is the only pre eip1559 fork that we handle.
      let tx
      if (!EIP1559) {
        tx = Transaction.fromTxData({
          nonce: useCall ? this.nextNonceForCall : new BN(res.nonce),
          gasPrice: '0x1',
          gasLimit: gasLimit,
          to: to,
          value: value,
          data: Buffer.from(data.slice(2), 'hex')
        }, { common: this.commonContext }).sign(account.privateKey)
      } else {
        tx = FeeMarketEIP1559Transaction.fromTxData({
          nonce: useCall ? this.nextNonceForCall : new BN(res.nonce),
          maxPriorityFeePerGas: '0x01',
          maxFeePerGas: '0x1',
          gasLimit: gasLimit,
          to: to,
          value: value,
          data: Buffer.from(data.slice(2), 'hex')
        }).sign(account.privateKey)
      }
      if (useCall) this.nextNonceForCall++

      const coinbases = ['0x0e9281e9c6a0808672eaba6bd1220e144c9bb07a', '0x8945a1288dc78a6d8952a92c77aee6730b414778', '0x94d76e24f818426ae84aa404140e8d5f60e10e7e']
      const difficulties = [new BN('69762765929000', 10), new BN('70762765929000', 10), new BN('71762765929000', 10)]

      const block = Block.fromBlockData({
        header: {
          timestamp: timestamp || (new Date().getTime() / 1000 | 0),
          number: self.blockNumber,
          coinbase: coinbases[self.blockNumber % coinbases.length],
          difficulty: difficulties[self.blockNumber % difficulties.length],
          gasLimit: new BN(gasLimit.replace('0x', ''), 16).imuln(2),
          baseFeePerGas: EIP1559 ? '0x1' : undefined
        },
        transactions: [tx]
      }, { common: this.commonContext })

      if (!useCall) {
        ++self.blockNumber
        this.runBlockInVm(tx, block, callback)
      } else {
        this.getVMObject().stateManager.checkpoint().then(() => {
          this.runBlockInVm(tx, block, (err, result) => {
            this.getVMObject().stateManager.revert().then(() => {
              callback(err, result)
            })
          })
        })
      }
    }).catch((e) => {
      callback(e)
    })
  }
Example #24
Source File: universalDappUI.tsx    From remix-project with MIT License 4 votes vote down vote up
export function UniversalDappUI (props: UdappProps) {
  const [toggleExpander, setToggleExpander] = useState<boolean>(true)
  const [contractABI, setContractABI] = useState<FuncABI[]>(null)
  const [address, setAddress] = useState<string>('')
  const [expandPath, setExpandPath] = useState<string[]>([])
  const [llIError, setLlIError] = useState<string>('')
  const [calldataValue, setCalldataValue] = useState<string>('')
  const [evmBC, setEvmBC] = useState(null)

  useEffect(() => {
    if (!props.instance.abi) {
      const abi = txHelper.sortAbiFunction(props.instance.contractData.abi)

      setContractABI(abi)
    } else {
      setContractABI(props.instance.abi)
    }
  }, [props.instance.abi])

  useEffect(() => {
    if (props.instance.address) {
      // @ts-ignore
      let address = (props.instance.address.slice(0, 2) === '0x' ? '' : '0x') + props.instance.address.toString('hex')

      address = ethJSUtil.toChecksumAddress(address)
      setAddress(address)
    }
  }, [props.instance.address])

  useEffect(() => {
    if (props.instance.contractData) {
      setEvmBC(props.instance.contractData.bytecodeObject)
    }
  }, [props.instance.contractData])

  const sendData = () => {
    setLlIError('')
    const fallback = txHelper.getFallbackInterface(contractABI)
    const receive = txHelper.getReceiveInterface(contractABI)
    const args = {
      funcABI: fallback || receive,
      address: address,
      contractName: props.instance.name,
      contractABI: contractABI
    }
    const amount = props.sendValue

    if (amount !== '0') {
      // check for numeric and receive/fallback
      if (!isNumeric(amount)) {
        return setLlIError('Value to send should be a number')
      } else if (!receive && !(fallback && fallback.stateMutability === 'payable')) {
        return setLlIError("In order to receive Ether transfer the contract should have either 'receive' or payable 'fallback' function")
      }
    }
    let calldata = calldataValue

    if (calldata) {
      if (calldata.length < 4 && is0XPrefixed(calldata)) {
        return setLlIError('The calldata should be a valid hexadecimal value with size of at least one byte.')
      } else {
        if (is0XPrefixed(calldata)) {
          calldata = calldata.substr(2, calldata.length)
        }
        if (!isHexadecimal(calldata)) {
          return setLlIError('The calldata should be a valid hexadecimal value.')
        }
      }
      if (!fallback) {
        return setLlIError("'Fallback' function is not defined")
      }
    }

    if (!receive && !fallback) return setLlIError('Both \'receive\' and \'fallback\' functions are not defined')

    // we have to put the right function ABI:
    // if receive is defined and that there is no calldata => receive function is called
    // if fallback is defined => fallback function is called
    if (receive && !calldata) args.funcABI = receive
    else if (fallback) args.funcABI = fallback

    if (!args.funcABI) return setLlIError('Please define a \'Fallback\' function to send calldata and a either \'Receive\' or payable \'Fallback\' to send ethers')
    runTransaction(false, args.funcABI, null, calldataValue)
  }

  const toggleClass = () => {
    setToggleExpander(!toggleExpander)
  }

  const remove = () => {
    props.removeInstance(props.index)
  }

  const runTransaction = (lookupOnly, funcABI: FuncABI, valArr, inputsValues, funcIndex?: number) => {
    const functionName = funcABI.type === 'function' ? funcABI.name : `(${funcABI.type})`
    const logMsg = `${lookupOnly ? 'call' : 'transact'} to ${props.instance.name}.${functionName}`

    props.runTransactions(
      props.index,
      lookupOnly,
      funcABI,
      inputsValues,
      props.instance.name,
      contractABI,
      props.instance.contractData,
      address,
      logMsg,
      props.logBuilder,
      props.mainnetPrompt,
      props.gasEstimationPrompt,
      props.passphrasePrompt,
      funcIndex)
  }

  const extractDataDefault = (item, parent?) => {
    const ret: any = {}

    if (BN.isBN(item)) {
      ret.self = item.toString(10)
      ret.children = []
    } else {
      if (item instanceof Array) {
        ret.children = item.map((item, index) => {
          return { key: index, value: item }
        })
        ret.self = 'Array'
        ret.isNode = true
        ret.isLeaf = false
      } else if (item instanceof Object) {
        ret.children = Object.keys(item).map((key) => {
          return { key: key, value: item[key] }
        })
        ret.self = 'Object'
        ret.isNode = true
        ret.isLeaf = false
      } else {
        ret.self = item
        ret.children = null
        ret.isNode = false
        ret.isLeaf = true
      }
    }
    return ret
  }

  const handleExpand = (path: string) => {
    if (expandPath.includes(path)) {
      const filteredPath = expandPath.filter(value => value !== path)

      setExpandPath(filteredPath)
    } else {
      setExpandPath([...expandPath, path])
    }
  }

  const handleCalldataChange = (e) => {
    const value = e.target.value

    setCalldataValue(value)
  }

  const label = (key: string | number, value: string) => {
    return (
      <div className="d-flex mt-2 flex-row label_item">
        <label className="small font-weight-bold mb-0 pr-1 label_key">{key}:</label>
        <label className="m-0 label_value">{value}</label>
      </div>
    )
  }

  const renderData = (item, parent, key: string | number, keyPath: string) => {
    const data = extractDataDefault(item, parent)
    const children = (data.children || []).map((child) => {
      return (
        renderData(child.value, data, child.key, keyPath + '/' + child.key)
      )
    })

    if (children && children.length > 0) {
      return (
        <TreeViewItem id={`treeViewItem${key}`} key={keyPath} label={label(key, data.self)} onClick={() => handleExpand(keyPath)} expand={expandPath.includes(keyPath)}>
          <TreeView id={`treeView${key}`} key={keyPath}>
            {children}
          </TreeView>
        </TreeViewItem>
      )
    } else {
      return <TreeViewItem id={key.toString()} key={keyPath} label={label(key, data.self)} onClick={() => handleExpand(keyPath)} expand={expandPath.includes(keyPath)} />
    }
  }

  return (
    <div className={`instance udapp_instance udapp_run-instance border-dark ${toggleExpander ? 'udapp_hidesub' : 'bg-light'}`} id={`instance${address}`} data-shared="universalDappUiInstance">
      <div className="udapp_title alert alert-secondary">
        <button data-id={`universalDappUiTitleExpander${props.index}`} className="btn udapp_titleExpander" onClick={toggleClass}>
          <i className={`fas ${toggleExpander ? 'fa-angle-right' : 'fa-angle-down'}`} aria-hidden="true"></i>
        </button>
        <div className="input-group udapp_nameNbuts">
          <div className="udapp_titleText input-group-prepend">
            <span className="input-group-text udapp_spanTitleText">
              {props.instance.name} at {shortenAddress(address)} ({props.context})
            </span>
          </div>
          <div className="btn-group">
            <button className="btn p-1 btn-secondary"><CopyToClipboard content={address} direction={'top'} /></button>
          </div>
        </div>
        <button
          className="udapp_udappClose mr-1 p-1 btn btn-secondary align-items-center"
          data-id="universalDappUiUdappClose"
          onClick={remove}
          title="Remove from the list"
        >
          <i className="udapp_closeIcon fas fa-times" aria-hidden="true"></i>
        </button>
      </div>
      <div className="udapp_cActionsWrapper" data-id="universalDappUiContractActionWrapper">
        <div className="udapp_contractActionsContainer">
          {
            contractABI && contractABI.map((funcABI, index) => {
              if (funcABI.type !== 'function') return null
              const isConstant = funcABI.constant !== undefined ? funcABI.constant : false
              const lookupOnly = funcABI.stateMutability === 'view' || funcABI.stateMutability === 'pure' || isConstant
              const inputs = props.getFuncABIInputs(funcABI)

              return <>
                <ContractGUI
                  funcABI={funcABI}
                  clickCallBack={(valArray: { name: string, type: string }[], inputsValues: string) => {
                    runTransaction(lookupOnly, funcABI, valArray, inputsValues, index)
                  }}
                  inputs={inputs}
                  evmBC={evmBC}
                  lookupOnly={lookupOnly}
                  key={index}
                />
                <div className="udapp_value" data-id="udapp_value">
                  <TreeView id="treeView">
                    {
                      Object.keys(props.instance.decodedResponse || {}).map((key) => {
                        const funcIndex = index.toString()
                        const response = props.instance.decodedResponse[key]

                        return key === funcIndex ? Object.keys(response || {}).map((innerkey) => {
                          return renderData(props.instance.decodedResponse[key][innerkey], response, innerkey, innerkey)
                        }) : null
                      })
                    }
                  </TreeView>
                </div>
              </>
            })
          }
        </div>
        <div className="d-flex flex-column">
          <div className="d-flex flex-row justify-content-between mt-2">
            <div className="py-2 border-top d-flex justify-content-start flex-grow-1">
              Low level interactions
            </div>
            <a
              href="https://solidity.readthedocs.io/en/v0.6.2/contracts.html#receive-ether-function"
              title="check out docs for using 'receive'/'fallback'"
              target="_blank" rel="noreferrer"
            >
              <i aria-hidden="true" className="fas fa-info my-2 mr-1"></i>
            </a>
          </div>
          <div className="d-flex flex-column align-items-start">
            <label className="">CALLDATA</label>
            <div className="d-flex justify-content-end w-100 align-items-center">
              <input id="deployAndRunLLTxCalldata" onChange={handleCalldataChange} className="udapp_calldataInput form-control" title="The Calldata to send to fallback function of the contract." />
              <button id="deployAndRunLLTxSendTransaction" data-id="pluginManagerSettingsDeployAndRunLLTxSendTransaction" className="udapp_instanceButton p-0 w-50 btn border-warning text-warning" title="Send data to contract." onClick={sendData}>Transact</button>
            </div>
          </div>
          <div>
            <label id="deployAndRunLLTxError" className="text-danger my-2">{ llIError }</label>
          </div>
        </div>
      </div>
    </div>
  )
}