Home Reference Source

packages/oo7-parity/src/index.js

  1. // (C) Copyright 2016-2017 Parity Technologies (UK) Ltd.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14.  
  15. /* eslint-disable no-return-assign */
  16. /* eslint-disable no-proto */
  17.  
  18. // TODO [Document auxilary types]
  19.  
  20. const oo7 = require('oo7');
  21. const ParityApi = require('@parity/api');
  22.  
  23. const {
  24. asciiToHex,
  25. bytesToHex,
  26. hexToAscii,
  27. isAddressValid,
  28. toChecksumAddress,
  29. sha3,
  30. capitalizeFirstLetter,
  31. singleton,
  32. denominations,
  33. denominationMultiplier,
  34. interpretRender,
  35. combineValue,
  36. defDenom,
  37. formatValue,
  38. formatValueNoDenom,
  39. formatToExponential,
  40. interpretQuantity,
  41. splitValue,
  42. formatBalance,
  43. formatBlockNumber,
  44. isNullData,
  45. splitSignature,
  46. removeSigningPrefix,
  47. cleanup
  48. } = require('./utils');
  49.  
  50. const {
  51. abiPolyfill,
  52. RegistryABI,
  53. RegistryExtras,
  54. GitHubHintABI,
  55. OperationsABI,
  56. BadgeRegABI,
  57. TokenRegABI,
  58. BadgeABI,
  59. TokenABI
  60. } = require('./abis');
  61.  
  62. function defaultProvider () {
  63. if (typeof window !== 'undefined' && window.ethereum) {
  64. return window.ethereum;
  65. }
  66.  
  67. try {
  68. if (typeof window !== 'undefined' && window.parent && window.parent.ethereum) {
  69. return window.parent.ethereum;
  70. }
  71. } catch (e) {}
  72.  
  73. return new ParityApi.Provider.Http('http://localhost:8545');
  74. }
  75.  
  76. class Bonds {
  77. /**
  78. * Creates a new oo7-parity bonds aggregate object with given ethereum provider.
  79. *
  80. * Additional documentation can be found at https://wiki.parity.io/oo7-Parity-Reference.html
  81. *
  82. * @param {?Provider} provider Web3-compatible transport Provider (i.e. `window.ethereum`). Uses a sane default if not provided.
  83. * @returns {Bonds}
  84. */
  85. constructor (provider = defaultProvider()) {
  86. if (!this) {
  87. return createBonds({ api: new ParityApi(provider) });
  88. }
  89.  
  90. /**
  91. *
  92. * A {@link Bond} representing latest time. Updated every second.
  93. *
  94. * @type {TimeBond}
  95. *
  96. * @example
  97. * const { bonds } = require('oo7-parity')
  98. *
  99. * bonds
  100. * .time
  101. * .tie(console.log) // prints time periodically
  102. */
  103. this.time = null;
  104.  
  105. /**
  106. * A {@link Bond} representing latest block number.
  107. * Alias for {@link Bonds.blockNumber}
  108. *
  109. * @type {Bond.<Number>}
  110. */
  111. this.height = null;
  112.  
  113. /**
  114. * A {@link Bond} representing latest block number.
  115. *
  116. * @type {Bond.<Number>}
  117. *
  118. * @example
  119. * const { bonds } = require('oo7-parity')
  120. *
  121. * bonds
  122. * .blockNumber
  123. * .tie(console.log) // prints latest block number when it changes
  124. */
  125. this.blockNumber = null;
  126.  
  127. /**
  128. * A function returning bond that represents given block content.
  129. *
  130. * @param {string|number|Bond} number block number
  131. * @returns {Bond.<Block>} block bond
  132. *
  133. * @example
  134. * const { bonds } = require('oo7-parity')
  135. *
  136. * bonds
  137. * .blockByNumber(bonds.height)
  138. * .tie(console.log) // prints latest block
  139. */
  140. this.blockByNumber = null;
  141.  
  142. /**
  143. * A function returning bond that represents given block content.
  144. *
  145. * @param {string|number|Bond} hash block hash
  146. * @returns {Bond.<Block>} block bond
  147. *
  148. * @example
  149. * const { bonds } = require('oo7-parity')
  150. *
  151. * bonds
  152. * .blockByHash('0x2b23d04567313fa141ca396f1e2620b62ab0c5d69f8c77157118f8d7671e1f4d')
  153. * .tie(console.log) // prints block with given hash
  154. */
  155. this.blockByHash = null;
  156.  
  157. /**
  158. * Similar to {@link Bonds.blockByNumber} and {@link Bonds.blockByHash},
  159. * but accepts both hashes and numbers as arguments.
  160. *
  161. * @param {string|number|Bond} hashOrNumber block hash or block number
  162. * @returns {Bond.<Block>} block bond
  163. *
  164. * @example
  165. * const { bonds } = require('oo7-parity')
  166. *
  167. * bonds
  168. * .findBlock('0x2b23d04567313fa141ca396f1e2620b62ab0c5d69f8c77157118f8d7671e1f4d')
  169. * .tie(console.log) // prints block with given hash
  170. */
  171. this.findBlock = null;
  172.  
  173. /**
  174. * A subscriptable version of {@link Bonds.findBlock}
  175. *
  176. * You can retrieve bonds given block numbers or hashes or other Bonds.
  177. *
  178. * @type {Object.<string|number|Bond, Bond>}
  179. *
  180. * @example
  181. * const { bonds } = require('oo7-parity')
  182. *
  183. * bonds
  184. * .blocks['0x2b23d04567313fa141ca396f1e2620b62ab0c5d69f8c77157118f8d7671e1f4d']
  185. * .tie(console.log) // prints block with given hash
  186. *
  187. * bonds
  188. * .blocks[bonds.height]
  189. * .tie(console.log) // prints latest block every time it changes
  190. */
  191. this.blocks = null;
  192.  
  193. /**
  194. * A {@link Bond} for latest block.
  195. *
  196. * @type {Bond.<Block>}
  197. *
  198. * @example
  199. * const { bonds } = require('oo7-parity')
  200. *
  201. * bonds
  202. * .head
  203. * .tie(console.log) // prints latest block every time it changes
  204. *
  205. */
  206. this.head = null;
  207.  
  208. /**
  209. * A {@link Bond} for currently set block author.
  210. * Represents a result of `eth_coinbase` RPC call.
  211. *
  212. * @type {Bond.<Address>}
  213. *
  214. * @example
  215. * const { bonds } = require('oo7-parity')
  216. *
  217. * bonds
  218. * .author
  219. * .tie(console.log) // prints currently set block author (coinbase/miner) every time it changes
  220. *
  221. */
  222. this.author = null;
  223.  
  224. /**
  225. * List of accounts managed by the node.
  226. *
  227. * @type {Bond.<Address[]>}
  228. *
  229. * @example
  230. * const { bonds } = require('oo7-parity')
  231. *
  232. * bonds
  233. * .accounts
  234. * .tie(console.log) // prints accounts list every time it changes
  235. *
  236. */
  237. this.accounts = null;
  238.  
  239. /**
  240. * User-selected default account for this dapp.
  241. *
  242. * @type {Bond.<Address>}
  243. *
  244. * @example
  245. * const { bonds } = require('oo7-parity')
  246. *
  247. * bonds
  248. * .defaultAccount
  249. * .tie(console.log) // prints default account every time it changes
  250. *
  251. */
  252. this.defaultAccount = null;
  253.  
  254. /**
  255. * Alias for {@link Bonds.defaultAccount}
  256. *
  257. * @type {Bond.<Address>}
  258. *
  259. * @example
  260. * const { bonds } = require('oo7-parity')
  261. *
  262. * bonds
  263. * .me
  264. * .tie(console.log) // prints default account every time it changes
  265. *
  266. */
  267. this.me = null;
  268. /**
  269. * Posts a transaction to the network.
  270. *
  271. * @param {TransactionRequest} tx Transaction details
  272. * @returns {ReactivePromise.<TransactionStatus>}
  273. * @example
  274. * const { bonds } = require('oo7-parity')
  275. *
  276. * bonds
  277. * .post({ to: bonds.me, value: 0 })
  278. * .tie(console.log) // Reports transaction progress
  279. */
  280. this.post = null;
  281. /**
  282. * Returns a signature of given message
  283. *
  284. * @param {Hash|Bond} hash Hash to sign
  285. * @param {?Address|Bond} from Optional account that should be used for signing.
  286. * @returns {ReactivePromise.<SignStatus>}
  287. * @example
  288. * const { bonds } = require('oo7-parity')
  289. *
  290. * bonds
  291. * .sign('0x2ea2e504d09c458dbadc703112125564d53ca03c27a5b28e7b3e2b5804289c45')
  292. * .tie(console.log) // Reports signing progress
  293. */
  294. this.sign = null;
  295.  
  296. /**
  297. * Returns balance of given address.
  298. *
  299. * @param {string|Bond.<Address>} address
  300. * @returns {Bond.<BigNumber>}
  301. *
  302. * @example
  303. * const { bonds } = require('oo7-parity')
  304. *
  305. * bonds
  306. * .balance(bonds.me)
  307. * .tie(console.log) // prints default account balance every time any of them changes
  308. *
  309. */
  310. this.balance = null;
  311.  
  312. /**
  313. * Returns code of given address.
  314. *
  315. * @param {string|Bond.<Address>} address
  316. * @returns {Bond.<Bytes>}
  317. *
  318. * @example
  319. * const { bonds } = require('oo7-parity')
  320. *
  321. * bonds
  322. * .code(bonds.me)
  323. * .tie(console.log) // prints default account code every time any of them changes
  324. *
  325. */
  326. this.code = null;
  327.  
  328. /**
  329. * Returns the nonce of given address.
  330. *
  331. * @param {string|Bond.<Address>} address
  332. * @returns {Bond.<BigNumber>}
  333. *
  334. * @example
  335. * const { bonds } = require('oo7-parity')
  336. *
  337. * bonds
  338. * .nonce(bonds.me)
  339. * .tie(console.log) // prints default account nonce every time any of them changes
  340. *
  341. */
  342. this.nonce = null;
  343.  
  344. /**
  345. * Returns storage at given index of an address.
  346. *
  347. * @param {string|Bond.<Address>} address Contract address
  348. * @param {string|number|Bond.<H256>} storageIdx Contract storage index
  349. * @returns {Bond.<BigNumber>}
  350. *
  351. * @example
  352. * const { bonds } = require('oo7-parity')
  353. *
  354. * bonds
  355. * .storageAt(bonds.me, 0)
  356. * .tie(console.log) // prints default account storage at position 0 every time any of them changes
  357. *
  358. */
  359. this.storageAt = null;
  360.  
  361. /**
  362. * Returns node's syncing status.
  363. * If the node is fully synced this will return `false`.
  364. *
  365. * @type {Bond.<bool>}
  366. *
  367. * @example
  368. * const { bonds } = require('oo7-parity')
  369. *
  370. * bonds
  371. * .syncing
  372. * .tie(console.log) // prints sync status every time it changes
  373. *
  374. */
  375. this.syncing = null;
  376. /**
  377. * Returns node's authoring status.
  378. * If the node is not authoring blocks this will return `false`.
  379. *
  380. * @type {Bond.<bool>}
  381. *
  382. * @example
  383. * const { bonds } = require('oo7-parity')
  384. *
  385. * bonds
  386. * .authoring
  387. * .tie(console.log) // prints authoring status every time it changes
  388. *
  389. */
  390. this.authoring = null;
  391. /**
  392. * Reported hashrate.
  393. * If there is an external miner connected to the node it will return reported values.
  394. *
  395. * @type {Bond.<BigNumber>}
  396. *
  397. * @example
  398. * const { bonds } = require('oo7-parity')
  399. *
  400. * bonds
  401. * .hashrate
  402. * .tie(console.log) // prints current average hashrate
  403. *
  404. */
  405. this.hashrate = null;
  406. this.ethProtocolVersion = null;
  407. /**
  408. * Suggested gas price value. (Gas Price Oracle)
  409. * This returns a suggested gas price for next transaction. The estimation is based on statistics from last blocks.
  410. *
  411. * @type {Bond.<BigNumber>}
  412. *
  413. * @example
  414. * const { bonds } = require('oo7-parity')
  415. *
  416. * bonds
  417. * .gasPrice
  418. * .tie(console.log) // prints current gas price suggestion
  419. *
  420. */
  421. this.gasPrice = null;
  422. /**
  423. * Estimates gas required to execute given transaction
  424. *
  425. * @param {{ from: ?Address, to: ?Address, data: ?Bytes }} call Transaction request
  426. * @returns {Bond.<BigNumber>} gas estimate
  427. *
  428. * @example
  429. * const { bonds } = require('oo7-parity')
  430. *
  431. * bonds
  432. * .estimateGas({ from: bonds.me, to: '0x00D6Cc1BA9cf89BD2e58009741f4F7325BAdc0ED' })
  433. * .tie(console.log) // prints current gas estimate
  434. *
  435. */
  436. this.estimateGas = null;
  437.  
  438. /**
  439. * Returns block transaction count given block number or hash.
  440. *
  441. * @param {string|number|Bond} block block number or hash
  442. * @returns {Bond.<Number>} number of transactions in block
  443. *
  444. * @example
  445. * const { bonds } = require('oo7-parity')
  446. *
  447. * bonds
  448. * .blockTransactionCount(bonds.blockNumber)
  449. * .tie(console.log) // prints number of transactions in latest block
  450. *
  451. */
  452. this.blockTransactionCount = null;
  453. /**
  454. * Returns uncle count given block number or hash.
  455. *
  456. * @param {string|number|Bond} block block number or hash
  457. * @returns {Bond.<Number>} number of uncles in a block
  458. *
  459. * @example
  460. * const { bonds } = require('oo7-parity')
  461. *
  462. * bonds
  463. * .uncleCount(bonds.blockNumber)
  464. * .tie(console.log) // prints number of uncles in latest block
  465. *
  466. */
  467. this.uncleCount = null;
  468. /**
  469. * Returns uncle given block number or hash and uncle index
  470. *
  471. * @param {string|number|Bond} block block number or hash
  472. * @param {string|number|Bond} index index of an uncle within a block
  473. * @returns {Bond.<Header>} uncle header at that index
  474. *
  475. * @example
  476. * const { bonds } = require('oo7-parity')
  477. *
  478. * bonds
  479. * .uncle(bonds.blockNumber, 0)
  480. * .tie(console.log) // prints the first uncle in latest block
  481. *
  482. */
  483. this.uncle = null;
  484. /**
  485. * Returns transaction given block number or hash and transaction index
  486. *
  487. * @param {string|number|Bond} block block number or hash
  488. * @param {string|number|Bond} index index of a transaction within a block
  489. * @returns {Bond.<Transaction>} transaction at that index
  490. *
  491. * @example
  492. * const { bonds } = require('oo7-parity')
  493. *
  494. * bonds
  495. * .transaction(bonds.blockNumber, 0)
  496. * .tie(console.log) // prints the first uncle in latest block
  497. *
  498. */
  499. this.transaction = null;
  500. /**
  501. * Returns receipt given transaction hash.
  502. *
  503. * @param {string|number|Bond} hash transaction hash
  504. * @returns {Bond.<TransactionReceipt>} transaction at that index
  505. *
  506. * @example
  507. * const { bonds } = require('oo7-parity')
  508. *
  509. * bonds
  510. * .receipt(bonds.transaction(bonds.height, 0).map(x => x ? x.hash : undefined))
  511. * .tie(console.log) // prints receipt of first transaction in latest block
  512. *
  513. */
  514. this.receipt = null;
  515.  
  516. /**
  517. * Returns client version string. (`web3_clientVersion`).
  518. *
  519. * @type {Bond.<String>}
  520. * @example
  521. * const { bonds } = require('oo7-parity')
  522. *
  523. * bonds
  524. * .clientVersion
  525. * .tie(console.log)
  526. *
  527. */
  528. this.clientVersion = null;
  529.  
  530. /**
  531. * Returns current peer count. (`net_peerCount`).
  532. *
  533. * @type {Bond.<Number>}
  534. * @example
  535. * const { bonds } = require('oo7-parity')
  536. *
  537. * bonds
  538. * .peerCount
  539. * .tie(console.log)
  540. *
  541. */
  542. this.peerCount = null;
  543. /**
  544. * Returns true if the node is actively listening for network connections.
  545. *
  546. * @type {Bond.<bool>}
  547. * @example
  548. * const { bonds } = require('oo7-parity')
  549. *
  550. * bonds
  551. * .listening
  552. * .tie(console.log)
  553. *
  554. */
  555. this.listening = null;
  556. /**
  557. * Returns chain id (used for chain replay protection).
  558. * NOTE: It's _not_ network id.
  559. *
  560. * @type {Bond.<Number>}
  561. * @example
  562. * const { bonds } = require('oo7-parity')
  563. *
  564. * bonds
  565. * .chainId
  566. * .tie(console.log)
  567. *
  568. */
  569. this.chainId = null;
  570.  
  571. /**
  572. * Returns a hash of content under given URL.
  573. *
  574. * @param {string|Bond} url URL of the content
  575. * @returns {Bond.<string>} hash of the content
  576. * @example
  577. * const { bonds } = require('oo7-parity')
  578. *
  579. * bonds
  580. * .hashContent('https://google.com')
  581. * .tie(console.log)
  582. *
  583. */
  584. this.hashContent = null;
  585. this.gasPriceHistogram = null;
  586. this.accountsInfo = null;
  587. this.allAccountsInfo = null;
  588. this.hardwareAccountsInfo = null;
  589. this.mode = null;
  590.  
  591. this.defaultExtraData = null;
  592. this.extraData = null;
  593. this.gasCeilTarget = null;
  594. this.gasFloorTarget = null;
  595. this.minGasPrice = null;
  596. this.transactionsLimit = null;
  597. /**
  598. * Returns a string name of currently connected chain.
  599. *
  600. * @type {Bond.<string>}
  601. * @example
  602. * const { bonds } = require('oo7-parity')
  603. *
  604. * bonds
  605. * .chainName
  606. * .tie(console.log)
  607. */
  608. this.chainName = null;
  609. /**
  610. * Returns a status of currently connected chain.
  611. *
  612. * @type {Bond.<object>}
  613. * @example
  614. * const { bonds } = require('oo7-parity')
  615. *
  616. * bonds
  617. * .chainStatus
  618. * .tie(console.log)
  619. */
  620. this.chainStatus = null;
  621.  
  622. this.peers = null;
  623. this.enode = null;
  624. this.nodePort = null;
  625. this.nodeName = null;
  626. this.signerPort = null;
  627. this.dappsPort = null;
  628. this.dappsInterface = null;
  629.  
  630. this.nextNonce = null;
  631. this.pending = null;
  632. this.local = null;
  633. this.future = null;
  634. this.pendingStats = null;
  635. this.unsignedCount = null;
  636.  
  637. this.releaseInfo = null;
  638. this.versionInfo = null;
  639. this.consensusCapability = null;
  640. this.upgradeReady = null;
  641.  
  642. /**
  643. * Replays (re-executes) a transaction. Returns requested traces of execution.
  644. *
  645. * @param {string} hash Transaction hash
  646. * @param {String[]} traces Any subset of `trace`,`vmTrace`,`stateDiff`.
  647. * @returns {Bond.<object>}
  648. * @example
  649. * const { bonds } = require('oo7-parity')
  650. *
  651. * bonds
  652. * .replayTx('0x2ea2e504d09c458dbadc703112125564d53ca03c27a5b28e7b3e2b5804289c45', ['trace'])
  653. * .tie(console.log)
  654. */
  655. this.replayTx = null;
  656. /**
  657. * Executs a transaction and collects traces.
  658. *
  659. * @param {TransactionRequest} transaction Transaction request
  660. * @param {String[]} traces Any subset of `trace`,`vmTrace`,`stateDiff`.
  661. * @param {string|number|Bond} block Block number or hash
  662. * @returns {Bond.<object>}
  663. * @example
  664. * const { bonds } = require('oo7-parity')
  665. *
  666. * bonds
  667. * .callTx({
  668. * from: bonds.me,
  669. * to: bonds.registry.address
  670. * }, ['trace'], 'latest')
  671. * .tie(console.log)
  672. */
  673. this.callTx = null;
  674.  
  675. /**
  676. * Deploys a new contract
  677. *
  678. * @param {string|Bytes} init Initialization bytecode
  679. * @param {ABI} abi Contract ABI
  680. * @param {{from: ?Address, gas: ?BigNumber, gasPrice: ?BigNumber, nonce: ?BigNumber}} options Deployment options
  681. * @returns {ReactivePromise.<DeployStatus>}
  682. * @example
  683. * const { bonds } = require('oo7-parity')
  684. *
  685. * bonds
  686. * .deployContract('0x1234', abi, {})
  687. * .tie(console.log) // Reports deployment progress
  688. */
  689. this.deployContract = null;
  690. /**
  691. * Creates bond-enabled contract object for existing contract.
  692. *
  693. * @param {string|Bond} address Contract address
  694. * @param {ABI} abi Contract ABI
  695. * @param {?ABI} extras Additional methods not defined in the ABI.
  696. * @returns {Contract}
  697. * @example
  698. * const { bonds } = require('oo7-parity')
  699. *
  700. * bonds
  701. * .makeContract(bonds.me, abi)
  702. * .someMethod()
  703. * .tie(console.log) // returns a result of someMethod call
  704. */
  705. this.makeContract = null;
  706.  
  707. /**
  708. * Parity registry contract instance.
  709. * @type {Contract.<Registry>}
  710. */
  711. this.registry = null;
  712.  
  713. /**
  714. * Parity registry contract instance.
  715. * @type {Contract.<GithubHint>}
  716. */
  717. this.githubhint = null;
  718. /**
  719. * Parity registry contract instance.
  720. * @type {Contract.<Operations>}
  721. */
  722. this.operations = null;
  723. /**
  724. * Parity registry contract instance.
  725. * @type {Contract.<BadgeReg>}
  726. */
  727. this.badgereg = null;
  728. /**
  729. * Parity registry contract instance.
  730. * @type {Contract.<TokenReg>}
  731. */
  732. this.tokenreg = null;
  733.  
  734. /**
  735. * A {@link Bond} representing all currently registered badges from BadgeReg.
  736. *
  737. * @type {Bond.<{id:string,name:string,img:string,caption:string,badge:Contract}[]>}
  738. */
  739. this.badges = null;
  740. /**
  741. * Returns a list of badges for given address.
  742. *
  743. * @param {Address} address
  744. * @returns {Bond.<Badge[]>} see {@link Bonds.badges}
  745. */
  746. this.badgesOf = null;
  747.  
  748. /**
  749. * A {@link Bond} representing all currently registered tokens from TokenReg.
  750. *
  751. * @type {Bond.<{id:string,tla:string,base:string,name:string,owner:address,img:string,caption:string}[]>}
  752. */
  753. this.tokens = null;
  754. /**
  755. * Returns a list of tokens with a non-empty balance for given address.
  756. *
  757. * @param {Address} address
  758. * @returns {Bond.<Token[]>} see {@link Bonds.tokens}
  759. */
  760. this.tokensOf = null;
  761.  
  762. return this;
  763. }
  764. }
  765.  
  766. function isNumber (n) {
  767. return typeof (n) === 'number' || (typeof (n) === 'string' && n.match(/^[0-9]+$/));
  768. }
  769.  
  770. function memoized (f) {
  771. var memo;
  772. return function () {
  773. if (memo === undefined) { memo = f(); }
  774. return memo;
  775. };
  776. }
  777.  
  778. function overlay (base, top) {
  779. Object.keys(top).forEach(k => {
  780. base[k] = top[k];
  781. });
  782. return base;
  783. }
  784.  
  785. function transactionPromise (api, tx, progress, f) {
  786. progress({ initialising: null });
  787. let condition = tx.condition || null;
  788. Promise.all([api().eth.accounts(), api().eth.gasPrice()])
  789. .then(([a, p]) => {
  790. progress({ estimating: null });
  791. tx.from = tx.from || a[0];
  792. tx.gasPrice = tx.gasPrice || p;
  793. return tx.gas || api().eth.estimateGas(tx);
  794. })
  795. .then(g => {
  796. progress({ estimated: g });
  797. tx.gas = tx.gas || g;
  798. return api().parity.postTransaction(tx);
  799. })
  800. .then(signerRequestId => {
  801. progress({ requested: signerRequestId });
  802. return api().pollMethod('parity_checkRequest', signerRequestId);
  803. })
  804. .then(transactionHash => {
  805. if (condition) {
  806. progress(f({ signed: transactionHash, scheduled: condition }));
  807. return { signed: transactionHash, scheduled: condition };
  808. } else {
  809. progress({ signed: transactionHash });
  810. return api()
  811. .pollMethod('eth_getTransactionReceipt', transactionHash, (receipt) => receipt && receipt.blockNumber && !receipt.blockNumber.eq(0))
  812. .then(receipt => {
  813. progress(f({ confirmed: receipt }));
  814. return receipt;
  815. });
  816. }
  817. })
  818. .catch(error => {
  819. progress({ failed: error });
  820. });
  821. }
  822.  
  823. class DeployContract extends oo7.ReactivePromise {
  824. constructor (initBond, abiBond, optionsBond, api) {
  825. super([initBond, abiBond, optionsBond, bonds.registry], [], ([init, abi, options, registry]) => {
  826. options.data = init;
  827. delete options.to;
  828. let progress = this.trigger.bind(this);
  829. transactionPromise(api, options, progress, status => {
  830. if (status.confirmed) {
  831. status.deployed = bonds.makeContract(status.confirmed.contractAddress, abi, options.extras || []);
  832. }
  833. return status;
  834. });
  835. // TODO: consider allowing registry of the contract here.
  836. }, false);
  837. this.then(_ => null);
  838. }
  839. isDone (s) {
  840. return !!(s.failed || s.confirmed);
  841. }
  842. }
  843.  
  844. class Transaction extends oo7.ReactivePromise {
  845. constructor (tx, api) {
  846. super([tx], [], ([tx]) => {
  847. let progress = this.trigger.bind(this);
  848. transactionPromise(api, tx, progress, _ => _);
  849. }, false);
  850. this.then(_ => null);
  851. }
  852. isDone (s) {
  853. return !!(s.failed || s.confirmed);
  854. }
  855. }
  856.  
  857. /**
  858. * @param {{api: ParityApi}} Options object
  859. * @returns {Bonds}
  860. */
  861. function createBonds (options) {
  862. const bonds = new Bonds();
  863.  
  864. // We only ever use api() at call-time of this function; this allows the
  865. // options (particularly the transport option) to be changed dynamically
  866. // and the datastructure to be reused.
  867. const api = () => options.api;
  868. const util = ParityApi.util;
  869.  
  870. class TransformBond extends oo7.TransformBond {
  871. constructor (f, a = [], d = [], outResolveDepth = 0, resolveDepth = 1, latched = true, mayBeNull = true) {
  872. super(f, a, d, outResolveDepth, resolveDepth, latched, mayBeNull, api());
  873. }
  874. map (f, outResolveDepth = 0, resolveDepth = 1) {
  875. return new TransformBond(f, [this], [], outResolveDepth, resolveDepth);
  876. }
  877. sub (name, outResolveDepth = 0, resolveDepth = 1) {
  878. return new TransformBond((r, n) => r[n], [this, name], [], outResolveDepth, resolveDepth);
  879. }
  880. static all (list) {
  881. return new TransformBond((...args) => args, list);
  882. }
  883. }
  884.  
  885. class SubscriptionBond extends oo7.Bond {
  886. constructor (module, rpcName, options = []) {
  887. super();
  888. this.module = module;
  889. this.rpcName = rpcName;
  890. this.options = [(_, n) => this.trigger(n), ...options];
  891. }
  892. initialise () {
  893. // promise instead of id because if a dependency triggers finalise() before id's promise is resolved the unsubscribing would call with undefined
  894. this.subscription = api().pubsub[this.module][this.rpcName](...this.options);
  895. }
  896. finalise () {
  897. this.subscription.then(id => api().pubsub.unsubscribe([id]));
  898. }
  899. map (f, outResolveDepth = 0, resolveDepth = 1) {
  900. return new TransformBond(f, [this], [], outResolveDepth, resolveDepth);
  901. }
  902. sub (name, outResolveDepth = 0, resolveDepth = 1) {
  903. return new TransformBond((r, n) => r[n], [this, name], [], outResolveDepth, resolveDepth);
  904. }
  905. static all (list) {
  906. return new TransformBond((...args) => args, list);
  907. }
  908. }
  909.  
  910. class Signature extends oo7.ReactivePromise {
  911. constructor (message, from) {
  912. super([message, from], [], ([message, from]) => {
  913. api().parity.postSign(from, asciiToHex(message))
  914. .then(signerRequestId => {
  915. this.trigger({ requested: signerRequestId });
  916. return api().pollMethod('parity_checkRequest', signerRequestId);
  917. })
  918. .then(signature => {
  919. this.trigger({
  920. signed: splitSignature(signature)
  921. });
  922. })
  923. .catch(error => {
  924. console.error(error);
  925. this.trigger({ failed: error });
  926. });
  927. }, false);
  928. this.then(_ => null);
  929. }
  930. isDone (s) {
  931. return !!s.failed || !!s.signed;
  932. }
  933. }
  934.  
  935. function call (addr, method, args, options) {
  936. let data = util.abiEncode(method.name, method.inputs.map(f => f.type), args);
  937. let decode = d => util.abiDecode(method.outputs.map(f => f.type), d);
  938. return api().eth.call(overlay({ to: addr, data: data }, options)).then(decode);
  939. }
  940.  
  941. function post (addr, method, args, options) {
  942. let toOptions = (addr, method, options, ...args) => {
  943. return overlay({ to: addr, data: util.abiEncode(method.name, method.inputs.map(f => f.type), args) }, options);
  944. };
  945. // inResolveDepth is 2 to allow for Bonded `condition`values which are
  946. // object values in `options`.
  947. return new Transaction(new TransformBond(toOptions, [addr, method, options, ...args], [], 0, 2), api);
  948. }
  949.  
  950. function presub (f) {
  951. return new Proxy(f, {
  952. get (receiver, name) {
  953. if (typeof (name) === 'string' || typeof (name) === 'number') {
  954. return typeof (receiver[name]) !== 'undefined' ? receiver[name] : receiver(name);
  955. } else if (typeof (name) === 'symbol' && oo7.Bond.knowSymbol(name)) {
  956. return receiver(oo7.Bond.fromSymbol(name));
  957. } else {
  958. throw new Error(`Weird value type to be subscripted by: ${typeof (name)}: ${JSON.stringify(name)}`);
  959. }
  960. }
  961. });
  962. }
  963.  
  964. let useSubs = false;
  965.  
  966. bonds.time = new oo7.TimeBond();
  967.  
  968. if (!useSubs) {
  969. bonds.height = new TransformBond(() => api().eth.blockNumber().then(_ => +_), [], [bonds.time]);
  970.  
  971. let onAccountsChanged = bonds.time; // TODO: more accurate notification
  972. let onHardwareAccountsChanged = bonds.time; // TODO: more accurate notification
  973. let onHeadChanged = bonds.height; // TODO: more accurate notification
  974. // let onReorg = undefined; // TODO make more accurate.
  975. let onSyncingChanged = bonds.time;
  976. let onAuthoringDetailsChanged = bonds.time;
  977. let onPeerNetChanged = bonds.time; // TODO: more accurate notification
  978. let onPendingChanged = bonds.time; // TODO: more accurate notification
  979. let onUnsignedChanged = bonds.time; // TODO: more accurate notification
  980. let onAutoUpdateChanged = bonds.height;
  981.  
  982. // eth_
  983. bonds.blockNumber = bonds.height;
  984. bonds.blockByNumber = x => new TransformBond(x => api().eth.getBlockByNumber(x), [x], []).subscriptable();// TODO: chain reorg that includes number x
  985. bonds.blockByHash = x => new TransformBond(x => api().eth.getBlockByHash(x), [x]).subscriptable();
  986. bonds.findBlock = hashOrNumberBond => new TransformBond(hashOrNumber => isNumber(hashOrNumber)
  987. ? api().eth.getBlockByNumber(hashOrNumber)
  988. : api().eth.getBlockByHash(hashOrNumber),
  989. [hashOrNumberBond], [/* onReorg */]).subscriptable();// TODO: chain reorg that includes number x, if x is a number
  990. bonds.blocks = presub(bonds.findBlock);
  991. bonds.block = bonds.blockByNumber(bonds.height); // TODO: DEPRECATE AND REMOVE
  992. bonds.head = new TransformBond(() => api().eth.getBlockByNumber('latest'), [], [onHeadChanged]).subscriptable();// TODO: chain reorgs
  993. bonds.author = new TransformBond(() => api().eth.coinbase(), [], [onAccountsChanged]);
  994. bonds.accounts = new TransformBond(a => a.map(util.toChecksumAddress), [new TransformBond(() => api().eth.accounts(), [], [onAccountsChanged])]).subscriptable();
  995. bonds.defaultAccount = bonds.accounts[0]; // TODO: make this use its subscription
  996. bonds.me = bonds.accounts[0];
  997. // TODO [ToDr] document (Post & Sign)
  998. bonds.post = tx => new Transaction(tx, api);
  999. bonds.sign = (message, from = bonds.me) => new Signature(message, from);
  1000.  
  1001. bonds.balance = x => new TransformBond(x => api().eth.getBalance(x), [x], [onHeadChanged]);
  1002. bonds.code = x => new TransformBond(x => api().eth.getCode(x), [x], [onHeadChanged]);
  1003. bonds.nonce = x => new TransformBond(x => api().eth.getTransactionCount(x).then(_ => +_), [x], [onHeadChanged]);
  1004. bonds.storageAt = (x, y) => new TransformBond((x, y) => api().eth.getStorageAt(x, y), [x, y], [onHeadChanged]);
  1005.  
  1006. bonds.syncing = new TransformBond(() => api().eth.syncing(), [], [onSyncingChanged]);
  1007. bonds.hashrate = new TransformBond(() => api().eth.hashrate(), [], [onAuthoringDetailsChanged]);
  1008. bonds.authoring = new TransformBond(() => api().eth.mining(), [], [onAuthoringDetailsChanged]);
  1009. bonds.ethProtocolVersion = new TransformBond(() => api().eth.protocolVersion(), [], []);
  1010. bonds.gasPrice = new TransformBond(() => api().eth.gasPrice(), [], [onHeadChanged]);
  1011. bonds.estimateGas = x => new TransformBond(x => api().eth.estimateGas(x), [x], [onHeadChanged, onPendingChanged]);
  1012.  
  1013. bonds.blockTransactionCount = hashOrNumberBond => new TransformBond(
  1014. hashOrNumber => isNumber(hashOrNumber)
  1015. ? api().eth.getBlockTransactionCountByNumber(hashOrNumber).then(_ => +_)
  1016. : api().eth.getBlockTransactionCountByHash(hashOrNumber).then(_ => +_),
  1017. [hashOrNumberBond], [/* onReorg */]);
  1018. bonds.uncleCount = hashOrNumberBond => new TransformBond(
  1019. hashOrNumber => isNumber(hashOrNumber)
  1020. ? api().eth.getUncleCountByBlockNumber(hashOrNumber).then(_ => +_)
  1021. : api().eth.getUncleCountByBlockHash(hashOrNumber).then(_ => +_),
  1022. [hashOrNumberBond], [/* onReorg */]).subscriptable();
  1023. bonds.uncle = (hashOrNumberBond, indexBond) => new TransformBond(
  1024. (hashOrNumber, index) => isNumber(hashOrNumber)
  1025. ? api().eth.getUncleByBlockNumber(hashOrNumber, index)
  1026. : api().eth.getUncleByBlockHash(hashOrNumber, index),
  1027. [hashOrNumberBond, indexBond], [/* onReorg */]).subscriptable();
  1028. bonds.transaction = (hashOrNumberBond, indexOrNullBond) => new TransformBond(
  1029. (hashOrNumber, indexOrNull) =>
  1030. indexOrNull === undefined || indexOrNull === null
  1031. ? api().eth.getTransactionByHash(hashOrNumber)
  1032. : isNumber(hashOrNumber)
  1033. ? api().eth.getTransactionByBlockNumberAndIndex(hashOrNumber, indexOrNull)
  1034. : api().eth.getTransactionByBlockHashAndIndex(hashOrNumber, indexOrNull),
  1035. [hashOrNumberBond, indexOrNullBond], [/* onReorg */]).subscriptable();
  1036. bonds.receipt = hashBond => new TransformBond(x => api().eth.getTransactionReceipt(x), [hashBond], []).subscriptable();
  1037.  
  1038. // web3_
  1039. bonds.clientVersion = new TransformBond(() => api().web3.clientVersion(), [], []);
  1040.  
  1041. // net_
  1042. bonds.peerCount = new TransformBond(() => api().net.peerCount().then(_ => +_), [], [onPeerNetChanged]);
  1043. bonds.listening = new TransformBond(() => api().net.listening(), [], [onPeerNetChanged]);
  1044. bonds.chainId = new TransformBond(() => api().net.version(), [], []);
  1045.  
  1046. // parity_
  1047. bonds.hashContent = u => new TransformBond(x => api().parity.hashContent(x), [u], [], false);
  1048. bonds.gasPriceHistogram = new TransformBond(() => api().parity.gasPriceHistogram(), [], [onHeadChanged]).subscriptable();
  1049. bonds.accountsInfo = new TransformBond(() => api().parity.accountsInfo(), [], [onAccountsChanged]).subscriptable(2);
  1050. bonds.allAccountsInfo = new TransformBond(() => api().parity.allAccountsInfo(), [], [onAccountsChanged]).subscriptable(2);
  1051. bonds.hardwareAccountsInfo = new TransformBond(() => api().parity.hardwareAccountsInfo(), [], [onHardwareAccountsChanged]).subscriptable(2);
  1052. bonds.mode = new TransformBond(() => api().parity.mode(), [], [bonds.height]);
  1053.  
  1054. // ...authoring
  1055. bonds.defaultExtraData = new TransformBond(() => api().parity.defaultExtraData(), [], [onAuthoringDetailsChanged]);
  1056. bonds.extraData = new TransformBond(() => api().parity.extraData(), [], [onAuthoringDetailsChanged]);
  1057. bonds.gasCeilTarget = new TransformBond(() => api().parity.gasCeilTarget(), [], [onAuthoringDetailsChanged]);
  1058. bonds.gasFloorTarget = new TransformBond(() => api().parity.gasFloorTarget(), [], [onAuthoringDetailsChanged]);
  1059. bonds.minGasPrice = new TransformBond(() => api().parity.minGasPrice(), [], [onAuthoringDetailsChanged]);
  1060. bonds.transactionsLimit = new TransformBond(() => api().parity.transactionsLimit(), [], [onAuthoringDetailsChanged]);
  1061.  
  1062. // ...chain info
  1063. bonds.chainName = new TransformBond(() => api().parity.netChain(), [], []);
  1064. bonds.chainStatus = new TransformBond(() => api().parity.chainStatus(), [], [onSyncingChanged]).subscriptable();
  1065.  
  1066. // ...networking
  1067. bonds.peers = new TransformBond(() => api().parity.netPeers(), [], [onPeerNetChanged]).subscriptable(2);
  1068. bonds.enode = new TransformBond(() => api().parity.enode(), [], []);
  1069. bonds.nodePort = new TransformBond(() => api().parity.netPort().then(_ => +_), [], []);
  1070. bonds.nodeName = new TransformBond(() => api().parity.nodeName(), [], []);
  1071. bonds.signerPort = new TransformBond(() => api().parity.signerPort().then(_ => +_), [], []);
  1072. bonds.dappsPort = new TransformBond(() => api().parity.dappsPort().then(_ => +_), [], []);
  1073. bonds.dappsInterface = new TransformBond(() => api().parity.dappsInterface(), [], []);
  1074.  
  1075. // ...transaction queue
  1076. bonds.nextNonce = new TransformBond(() => api().parity.nextNonce().then(_ => +_), [], [onPendingChanged]);
  1077. bonds.pending = new TransformBond(() => api().parity.pendingTransactions(), [], [onPendingChanged]);
  1078. bonds.local = new TransformBond(() => api().parity.localTransactions(), [], [onPendingChanged]).subscriptable(3);
  1079. bonds.future = new TransformBond(() => api().parity.futureTransactions(), [], [onPendingChanged]).subscriptable(2);
  1080. bonds.pendingStats = new TransformBond(() => api().parity.pendingTransactionsStats(), [], [onPendingChanged]).subscriptable(2);
  1081. bonds.unsignedCount = new TransformBond(() => api().parity.parity_unsignedTransactionsCount().then(_ => +_), [], [onUnsignedChanged]);
  1082.  
  1083. // ...auto-update
  1084. bonds.releasesInfo = new TransformBond(() => api().parity.releasesInfo(), [], [onAutoUpdateChanged]).subscriptable();
  1085. bonds.versionInfo = new TransformBond(() => api().parity.versionInfo(), [], [onAutoUpdateChanged]).subscriptable();
  1086. bonds.consensusCapability = new TransformBond(() => api().parity.consensusCapability(), [], [onAutoUpdateChanged]);
  1087. bonds.upgradeReady = new TransformBond(() => api().parity.upgradeReady(), [], [onAutoUpdateChanged]).subscriptable();
  1088. } else {
  1089. bonds.height = new TransformBond(_ => +_, [new SubscriptionBond('eth', 'blockNumber')]).subscriptable();
  1090.  
  1091. let onAutoUpdateChanged = bonds.height;
  1092.  
  1093. // eth_
  1094. bonds.blockNumber = bonds.height;
  1095. bonds.blockByNumber = numberBond => new TransformBond(number => new SubscriptionBond('eth', 'getBlockByNumber', [number]), [numberBond]).subscriptable();
  1096. bonds.blockByHash = x => new TransformBond(x => new SubscriptionBond('eth', 'getBlockByHash', [x]), [x]).subscriptable();
  1097. bonds.findBlock = hashOrNumberBond => new TransformBond(hashOrNumber => isNumber(hashOrNumber)
  1098. ? new SubscriptionBond('eth', 'getBlockByNumber', [hashOrNumber])
  1099. : new SubscriptionBond('eth', 'getBlockByHash', [hashOrNumber]),
  1100. [hashOrNumberBond]).subscriptable();
  1101. bonds.blocks = presub(bonds.findBlock);
  1102. bonds.block = bonds.blockByNumber(bonds.height); // TODO: DEPRECATE AND REMOVE
  1103. bonds.head = new SubscriptionBond('eth', 'getBlockByNumber', ['latest']).subscriptable();
  1104. bonds.author = new SubscriptionBond('eth', 'coinbase');
  1105. bonds.me = new SubscriptionBond('parity', 'defaultAccount');
  1106. bonds.defaultAccount = bonds.me; // TODO: DEPRECATE
  1107. bonds.accounts = new SubscriptionBond('eth', 'accounts').subscriptable();
  1108. bonds.post = tx => new Transaction(tx, api);
  1109. bonds.sign = (message, from = bonds.me) => new Signature(message, from);
  1110.  
  1111. bonds.balance = x => new TransformBond(x => new SubscriptionBond('eth', 'getBalance', [x]), [x]);
  1112. bonds.code = x => new TransformBond(x => new SubscriptionBond('eth', 'getCode', [x]), [x]);
  1113. bonds.nonce = x => new TransformBond(x => new SubscriptionBond('eth', 'getTransactionCount', [x]), [x]); // TODO: then(_ => +_) Depth 2 if second TransformBond or apply to result
  1114. bonds.storageAt = (x, y) => new TransformBond((x, y) => new SubscriptionBond('eth', 'getStorageAt', [x, y]), [x, y]);
  1115.  
  1116. bonds.syncing = new SubscriptionBond('eth', 'syncing');
  1117. bonds.hashrate = new SubscriptionBond('eth', 'hashrate');
  1118. bonds.authoring = new SubscriptionBond('eth', 'mining');
  1119. bonds.ethProtocolVersion = new SubscriptionBond('eth', 'protocolVersion');
  1120. bonds.gasPrice = new SubscriptionBond('eth', 'gasPrice');
  1121. bonds.estimateGas = x => new TransformBond(x => new SubscriptionBond('eth', 'estimateGas', [x]), [x]);
  1122.  
  1123. bonds.blockTransactionCount = hashOrNumberBond => new TransformBond(
  1124. hashOrNumber => isNumber(hashOrNumber)
  1125. ? new TransformBond(_ => +_, [new SubscriptionBond('eth', 'getBlockTransactionCountByNumber', [hashOrNumber])])
  1126. : new TransformBond(_ => +_, [new SubscriptionBond('eth', 'getBlockTransactionCountByHash', [hashOrNumber])]),
  1127. [hashOrNumberBond]);
  1128. bonds.uncleCount = hashOrNumberBond => new TransformBond(
  1129. hashOrNumber => isNumber(hashOrNumber)
  1130. ? new TransformBond(_ => +_, [new SubscriptionBond('eth', 'getUncleCountByBlockNumber', [hashOrNumber])])
  1131. : new TransformBond(_ => +_, [new SubscriptionBond('eth', 'getUncleCountByBlockHash', [hashOrNumber])]),
  1132. [hashOrNumberBond]).subscriptable();
  1133. bonds.uncle = (hashOrNumberBond, indexBond) => new TransformBond(
  1134. (hashOrNumber, index) => isNumber(hashOrNumber)
  1135. ? new SubscriptionBond('eth', 'getUncleByBlockNumberAndIndex', [hashOrNumber, index])
  1136. : new SubscriptionBond('eth', 'getUncleByBlockHashAndIndex', [hashOrNumber, index]),
  1137. [hashOrNumberBond, indexBond]).subscriptable();
  1138.  
  1139. bonds.transaction = (hashOrNumberBond, indexOrNullBond) => new TransformBond(
  1140. (hashOrNumber, indexOrNull) =>
  1141. indexOrNull === undefined || indexOrNull === null
  1142. ? new SubscriptionBond('eth', 'getTransactionByHash', [hashOrNumber])
  1143. : isNumber(hashOrNumber)
  1144. ? new SubscriptionBond('eth', 'getTransactionByBlockNumberAndIndex', [hashOrNumber, indexOrNull])
  1145. : new SubscriptionBond('eth', 'getTransactionByBlockHashAndIndex', [hashOrNumber, indexOrNull]),
  1146. [hashOrNumberBond, indexOrNullBond]).subscriptable();
  1147. bonds.receipt = hashBond => new TransformBond(x => new SubscriptionBond('eth', 'getTransactionReceipt', [x]), [hashBond]).subscriptable();
  1148.  
  1149. // web3_
  1150. bonds.clientVersion = new TransformBond(() => api().web3.clientVersion(), [], []);
  1151.  
  1152. // net_
  1153. bonds.peerCount = new TransformBond(_ => +_, [new SubscriptionBond('net', 'peerCount')]);
  1154. bonds.listening = new SubscriptionBond('net', 'listening');
  1155. bonds.chainId = new SubscriptionBond('net', 'version');
  1156.  
  1157. // parity_
  1158. bonds.hashContent = u => new TransformBond(x => api().parity.hashContent(x), [u], [], false);
  1159. bonds.gasPriceHistogram = new SubscriptionBond('parity', 'gasPriceHistogram').subscriptable();
  1160. bonds.mode = new SubscriptionBond('parity', 'mode');
  1161. bonds.accountsInfo = new SubscriptionBond('parity', 'accountsInfo').subscriptable(2);
  1162. bonds.allAccountsInfo = new SubscriptionBond('parity', 'allAccountsInfo').subscriptable(2);
  1163. bonds.hardwareAccountsInfo = new SubscriptionBond('parity', 'hardwareAccountsInfo').subscriptable(2);
  1164.  
  1165. // ...authoring
  1166. bonds.defaultExtraData = new SubscriptionBond('parity', 'defaultExtraData');
  1167. bonds.extraData = new SubscriptionBond('parity', 'extraData');
  1168. bonds.gasCeilTarget = new SubscriptionBond('parity', 'gasCeilTarget');
  1169. bonds.gasFloorTarget = new SubscriptionBond('parity', 'gasFloorTarget');
  1170. bonds.minGasPrice = new SubscriptionBond('parity', 'minGasPrice');
  1171. bonds.transactionsLimit = new SubscriptionBond('parity', 'transactionsLimit');
  1172.  
  1173. // ...chain info
  1174. bonds.chainName = new SubscriptionBond('parity', 'netChain');
  1175. bonds.chainStatus = new SubscriptionBond('parity', 'chainStatus').subscriptable();
  1176.  
  1177. // ...networking
  1178. bonds.peers = new SubscriptionBond('parity', 'netPeers').subscriptable(2);
  1179. bonds.enode = new SubscriptionBond('parity', 'enode');
  1180. bonds.nodePort = new TransformBond(_ => +_, [new SubscriptionBond('parity', 'netPort')]);
  1181. bonds.nodeName = new SubscriptionBond('parity', 'nodeName');
  1182. // Where defined ?
  1183. bonds.signerPort = new TransformBond(() => api().parity.signerPort().then(_ => +_), [], []);
  1184. bonds.dappsPort = new TransformBond(() => api().parity.dappsPort().then(_ => +_), [], []);
  1185. bonds.dappsInterface = new TransformBond(() => api().parity.dappsInterface(), [], []);
  1186.  
  1187. // ...transaction queue
  1188. bonds.nextNonce = new TransformBond(_ => +_, [new SubscriptionBond('parity', 'nextNonce')]);
  1189. bonds.pending = new SubscriptionBond('parity', 'pendingTransactions').subscriptable();
  1190. bonds.local = new SubscriptionBond('parity', 'localTransactions').subscriptable(3);
  1191. bonds.future = new SubscriptionBond('parity', 'futureTransactions').subscriptable(2);
  1192. bonds.pendingStats = new SubscriptionBond('parity', 'pendingTransactionsStats').subscriptable(2);
  1193. bonds.unsignedCount = new TransformBond(_ => +_, [new SubscriptionBond('parity', 'unsignedTransactionsCount')]);
  1194. bonds.requestsToConfirm = new SubscriptionBond('signer', 'requestsToConfirm');
  1195.  
  1196. // ...auto-update
  1197. bonds.releasesInfo = new SubscriptionBond('parity', 'releasesInfo').subscriptable();
  1198. bonds.versionInfo = new SubscriptionBond('parity', 'versionInfo').subscriptable();
  1199. bonds.consensusCapability = new SubscriptionBond('parity', 'consensusCapability').subscriptable();
  1200. bonds.upgradeReady = new TransformBond(() => api().parity.upgradeReady(), [], [onAutoUpdateChanged]).subscriptable();
  1201. }
  1202.  
  1203. // trace TODO: Implement contract object with new trace_many feature
  1204. bonds.replayTx = (x, whatTrace) => new TransformBond((x, whatTrace) => api().trace.replayTransaction(x, whatTrace), [x, whatTrace], []).subscriptable();
  1205. bonds.callTx = (x, whatTrace, blockNumber) => new TransformBond((x, whatTrace, blockNumber) => api().trace.call(x, whatTrace, blockNumber), [x, whatTrace, blockNumber], []).subscriptable();
  1206.  
  1207. function traceCall (addr, method, args, options) {
  1208. let data = util.abiEncode(method.name, method.inputs.map(f => f.type), args);
  1209. let decode = d => util.abiDecode(method.outputs.map(f => f.type), d);
  1210. let traceMode = options.traceMode;
  1211. delete options.traceMode;
  1212. return api().trace.call(overlay({ to: addr, data: data }, options), traceMode, 'latest').then(decode);
  1213. }
  1214.  
  1215. bonds.deployContract = function (init, abi, options = {}) {
  1216. return new DeployContract(init, abi, options, api);
  1217. };
  1218.  
  1219. bonds.makeContract = function (address, abi, extras = [], debug = false) {
  1220. var r = { address: address };
  1221. let unwrapIfOne = a => a.length === 1 ? a[0] : a;
  1222. abi.forEach(i => {
  1223. if (i.type === 'function' && i.constant) {
  1224. let f = function (...args) {
  1225. var options = args.length === i.inputs.length + 1 ? args.pop() : {};
  1226. if (args.length !== i.inputs.length) {
  1227. throw new Error(`Invalid number of arguments to ${i.name}. Expected ${i.inputs.length}, got ${args.length}.`);
  1228. }
  1229. let f = (addr, ...fargs) => debug
  1230. ? traceCall(address, i, args, options)
  1231. : call(addr, i, fargs, options)
  1232. .then(rets => rets.map((r, o) => cleanup(r, i.outputs[o].type, api)))
  1233. .then(unwrapIfOne);
  1234. return new TransformBond(f, [address, ...args], [bonds.height]).subscriptable(); // TODO: should be subscription on contract events
  1235. };
  1236. r[i.name] = (i.inputs.length === 0) ? memoized(f) : (i.inputs.length === 1) ? presub(f) : f;
  1237. r[i.name].args = i.inputs;
  1238. }
  1239. });
  1240. extras.forEach(i => {
  1241. let f = function (...args) {
  1242. let expectedInputs = (i.numInputs || i.args.length);
  1243. var options = args.length === expectedInputs + 1 ? args.pop() : {};
  1244. if (args.length !== expectedInputs) {
  1245. throw new Error(`Invalid number of arguments to ${i.name}. Expected ${expectedInputs}, got ${args.length}. ${args}`);
  1246. }
  1247. let c = abi.find(j => j.name === i.method);
  1248. let f = (addr, ...fargs) => {
  1249. let args = i.args.map((v, index) => v === null ? fargs[index] : typeof (v) === 'function' ? v(fargs[index]) : v);
  1250. return debug
  1251. ? traceCall(address, i, args, options)
  1252. : call(addr, c, args, options).then(unwrapIfOne);
  1253. };
  1254. return new TransformBond(f, [address, ...args], [bonds.height]).subscriptable(); // TODO: should be subscription on contract events
  1255. };
  1256. r[i.name] = (i.args.length === 1) ? presub(f) : f;
  1257. r[i.name].args = i.args;
  1258. });
  1259. abi.forEach(i => {
  1260. if (i.type === 'function' && !i.constant) {
  1261. r[i.name] = function (...args) {
  1262. var options = args.length === i.inputs.length + 1 ? args.pop() : {};
  1263. if (args.length !== i.inputs.length) { throw new Error(`Invalid number of arguments to ${i.name}. Expected ${i.inputs.length}, got ${args.length}. ${args}`); }
  1264. return debug
  1265. ? traceCall(address, i, args, options)
  1266. : post(address, i, args, options).subscriptable();
  1267. };
  1268. r[i.name].args = i.inputs;
  1269. }
  1270. });
  1271. var eventLookup = {};
  1272. abi.filter(i => i.type === 'event').forEach(i => {
  1273. eventLookup[util.abiSignature(i.name, i.inputs.map(f => f.type))] = i.name;
  1274. });
  1275.  
  1276. function prepareIndexEncode (v, t, top = true) {
  1277. if (v instanceof Array) {
  1278. if (top) {
  1279. return v.map(x => prepareIndexEncode(x, t, false));
  1280. } else {
  1281. throw new Error('Invalid type');
  1282. }
  1283. }
  1284. var val;
  1285. if (t === 'string' || t === 'bytes') {
  1286. val = util.sha3(v);
  1287. } else {
  1288. val = util.abiEncode(null, [t], [v]);
  1289. }
  1290. if (val.length !== 66) {
  1291. throw new Error('Invalid length');
  1292. }
  1293. return val;
  1294. }
  1295.  
  1296. abi.forEach(i => {
  1297. if (i.type === 'event') {
  1298. r[i.name] = function (indexed = {}, params = {}) {
  1299. return new TransformBond((addr, indexed) => {
  1300. var topics = [util.abiSignature(i.name, i.inputs.map(f => f.type))];
  1301. i.inputs.filter(f => f.indexed).forEach(f => {
  1302. try {
  1303. topics.push(indexed[f.name] ? prepareIndexEncode(indexed[f.name], f.type) : null);
  1304. } catch (e) {
  1305. throw new Error(`Couldn't encode indexed parameter ${f.name} of type ${f.type} with value ${indexed[f.name]}`);
  1306. }
  1307. });
  1308. return api().eth.getLogs({
  1309. address: addr,
  1310. fromBlock: params.fromBlock || 0,
  1311. toBlock: params.toBlock || 'pending',
  1312. limit: params.limit || 10,
  1313. topics: topics
  1314. }).then(logs => logs.map(l => {
  1315. l.blockNumber = +l.blockNumber;
  1316. l.transactionIndex = +l.transactionIndex;
  1317. l.logIndex = +l.logIndex;
  1318. l.transactionLogIndex = +l.transactionLogIndex;
  1319. var e = {};
  1320. let unins = i.inputs.filter(f => !f.indexed);
  1321. util.abiDecode(unins.map(f => f.type), l.data).forEach((v, j) => {
  1322. let f = unins[j];
  1323. if (v instanceof Array && !f.type.endsWith(']')) {
  1324. v = util.bytesToHex(v);
  1325. }
  1326. if (f.type.substr(0, 4) === 'uint' && +f.type.substr(4) <= 48) {
  1327. v = +v;
  1328. }
  1329. e[f.name] = v;
  1330. });
  1331. i.inputs.filter(f => f.indexed).forEach((f, j) => {
  1332. if (f.type === 'string' || f.type === 'bytes') {
  1333. e[f.name] = l.topics[1 + j];
  1334. } else {
  1335. var v = util.abiDecode([f.type], l.topics[1 + j])[0];
  1336. if (v instanceof Array) {
  1337. v = util.bytesToHex(v);
  1338. }
  1339. if (f.type.substr(0, 4) === 'uint' && +f.type.substr(4) <= 48) {
  1340. v = +v;
  1341. }
  1342. e[f.name] = v;
  1343. }
  1344. });
  1345. e.event = eventLookup[l.topics[0]];
  1346. e.log = l;
  1347. return e;
  1348. }));
  1349. }, [address, indexed], [bonds.height]).subscriptable();
  1350. };
  1351. r[i.name].args = i.inputs;
  1352. }
  1353. });
  1354. return r;
  1355. };
  1356.  
  1357. if (useSubs) {
  1358. bonds.registry = bonds.makeContract(new SubscriptionBond('parity', 'registryAddress'), RegistryABI, RegistryExtras);
  1359. } else {
  1360. bonds.registry = bonds.makeContract(new TransformBond(() => api().parity.registryAddress(), [], [bonds.time]), RegistryABI, RegistryExtras);
  1361. }
  1362.  
  1363. bonds.githubhint = bonds.makeContract(bonds.registry.lookupAddress('githubhint', 'A'), GitHubHintABI);
  1364. bonds.operations = bonds.makeContract(bonds.registry.lookupAddress('operations', 'A'), OperationsABI);
  1365. bonds.badgereg = bonds.makeContract(bonds.registry.lookupAddress('badgereg', 'A'), BadgeRegABI);
  1366. bonds.tokenreg = bonds.makeContract(bonds.registry.lookupAddress('tokenreg', 'A'), TokenRegABI);
  1367.  
  1368. bonds.badges = new TransformBond(n => {
  1369. var ret = [];
  1370. for (var i = 0; i < +n; ++i) {
  1371. let id = i;
  1372. ret.push(oo7.Bond.all([
  1373. bonds.badgereg.badge(id),
  1374. bonds.badgereg.meta(id, 'IMG'),
  1375. bonds.badgereg.meta(id, 'CAPTION')
  1376. ]).map(([[addr, name, owner], img, caption]) => ({
  1377. id,
  1378. name,
  1379. img,
  1380. caption,
  1381. badge: bonds.makeContract(addr, BadgeABI)
  1382. }))
  1383. );
  1384. }
  1385. return ret;
  1386. }, [bonds.badgereg.badgeCount()], [], 1);
  1387.  
  1388. bonds.badgesOf = address => new TransformBond(
  1389. (addr, bads) => bads.map(b => ({
  1390. certified: b.badge.certified(addr),
  1391. badge: b.badge,
  1392. id: b.id,
  1393. img: b.img,
  1394. caption: b.caption,
  1395. name: b.name
  1396. })),
  1397. [address, bonds.badges], [], 2
  1398. ).map(all => all.filter(_ => _.certified));
  1399.  
  1400. bonds.tokens = new TransformBond(n => {
  1401. var ret = [];
  1402. for (var i = 0; i < +n; ++i) {
  1403. let id = i;
  1404. ret.push(oo7.Bond.all([
  1405. bonds.tokenreg.token(id),
  1406. bonds.tokenreg.meta(id, 'IMG'),
  1407. bonds.tokenreg.meta(id, 'CAPTION')
  1408. ]).map(([[addr, tla, base, name, owner], img, caption]) => ({
  1409. id,
  1410. tla,
  1411. base,
  1412. name,
  1413. img,
  1414. caption,
  1415. token: bonds.makeContract(addr, TokenABI)
  1416. }))
  1417. );
  1418. }
  1419. return ret;
  1420. }, [bonds.tokenreg.tokenCount()], [], 1);
  1421.  
  1422. bonds.tokensOf = address => new TransformBond(
  1423. (addr, bads) => bads.map(b => ({
  1424. balance: b.token.balanceOf(addr),
  1425. token: b.token,
  1426. id: b.id,
  1427. name: b.name,
  1428. tla: b.tla,
  1429. base: b.base,
  1430. img: b.img,
  1431. caption: b.caption
  1432. })),
  1433. [address, bonds.tokens], [], 2
  1434. ).map(all => all.filter(_ => _.balance.gt(0)));
  1435.  
  1436. bonds.namesOf = address => new TransformBond((reg, addr, accs) => ({
  1437. owned: accs[addr] ? accs[addr].name : null,
  1438. registry: reg || null
  1439. }), [bonds.registry.reverse(address), address, bonds.accountsInfo]);
  1440.  
  1441. bonds.registry.names = oo7.Bond.mapAll([bonds.registry.ReverseConfirmed({}, { limit: 100 }), bonds.accountsInfo],
  1442. (reg, info) => {
  1443. let r = {};
  1444. Object.keys(info).forEach(k => r[k] = info[k].name);
  1445. reg.forEach(a => r[a.reverse] = bonds.registry.reverse(a.reverse));
  1446. return r;
  1447. }, 1);
  1448.  
  1449. return bonds;
  1450. }
  1451.  
  1452. const t = defaultProvider();
  1453. const options = t ? { api: new ParityApi(t) } : null;
  1454. /** @type {Bonds} */
  1455. const bonds = options ? createBonds(options) : null;
  1456.  
  1457. const isOwned = addr => oo7.Bond.mapAll([addr, bonds.accounts], (a, as) => as.indexOf(a) !== -1);
  1458. const isNotOwned = addr => oo7.Bond.mapAll([addr, bonds.accounts], (a, as) => as.indexOf(a) === -1);
  1459.  
  1460. module.exports = {
  1461. // Bonds stuff
  1462. // abiPolyfill,
  1463. options,
  1464. bonds,
  1465. Bonds,
  1466. createBonds,
  1467.  
  1468. // Util functions
  1469. isOwned,
  1470. isNotOwned,
  1471. asciiToHex,
  1472. bytesToHex,
  1473. hexToAscii,
  1474. isAddressValid,
  1475. toChecksumAddress,
  1476. sha3,
  1477. capitalizeFirstLetter,
  1478. singleton,
  1479. denominations,
  1480. denominationMultiplier,
  1481. interpretRender,
  1482. combineValue,
  1483. defDenom,
  1484. formatValue,
  1485. formatValueNoDenom,
  1486. formatToExponential,
  1487. interpretQuantity,
  1488. splitValue,
  1489. formatBalance,
  1490. formatBlockNumber,
  1491. isNullData,
  1492. splitSignature,
  1493. removeSigningPrefix,
  1494. cleanup,
  1495.  
  1496. // ABIs
  1497. abiPolyfill,
  1498. RegistryABI,
  1499. RegistryExtras,
  1500. GitHubHintABI,
  1501. OperationsABI,
  1502. BadgeRegABI,
  1503. TokenRegABI,
  1504. BadgeABI,
  1505. TokenABI
  1506. };