Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
snowypowers committed Feb 20, 2018
2 parents 1b01fd1 + 43087bd commit 171ff99
Show file tree
Hide file tree
Showing 32 changed files with 716 additions and 96 deletions.
42 changes: 42 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,27 @@ Changelog

This details the changes made from the previous recorded version.

3.3.0
=====

- API

- Add support for manpulating smart contracts. This means that you can send assets from smart contracts. This support is currently enabled only in the core API methods ``sendAsset`` and ``doInvoke``.

- Wallet

- Add ``confirm`` to Balance object.

- SC

- Add ContractParam.hash160

- Fixes

- Add more logging messages throughout.
- ``api.signTx`` now checks and converts the return value from external function to a Transaction object.
- Fix regex string for ``rpc.getVersion``.

3.2.1
=====

Expand Down Expand Up @@ -107,6 +128,27 @@ This details the changes made from the previous recorded version.
2.x.x
=====

2.3.4
-----

- Fix ``TxAttrUsage`` not being imported properly.

2.3.3
-----

- Fixes

- push instead of unshift for ``api.attachInvokedContractForMintToken``.
- getPrices patch.
- update export name for ``TxAttrUsage``.
- Fix transaction attribute deserialization.
- Fix _emitNum emitting trimmed hex numbers.

2.3.2
-----

- Docs moved to ``docs`` folder

2.3.1
-----

Expand Down
10 changes: 5 additions & 5 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
scv_sort = ('semver',)

scv_whitelist_branches = ('master', 'dev')
scv_whitelist_tags = ('1.1.2', '2.3.4', re.compile('3.2.[\d.]+'))
scv_whitelist_tags = ('1.1.2', '2.3.4', re.compile('3.3.[\d.]+'))

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
Expand All @@ -61,17 +61,17 @@

# General information about the project.
project = u'neon-js'
copyright = u'2017, Ethan Fast, Jun Xiang Yak'
copyright = u'2017 - 2018, Ethan Fast, Jun Xiang Yak'
author = u'Ethan Fast, Jun Xiang Yak'

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = u'3.2.1'
version = u'3.3.0'
# The full version, including alpha/beta/rc tags.
release = u'3.2.1'
release = u'3.3.0'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down Expand Up @@ -165,6 +165,6 @@
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'neon-js', u'neon-js Documentation',
author, 'neon-js', 'One line description of project.',
author, 'neon-js', 'JS SDK for interacting with NEO blockchain',
'Miscellaneous'),
]
2 changes: 1 addition & 1 deletion docs/reference/utility.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Format
Hashing
-------

.. autofunction:: hash160
.. autofunction:: utils.hash160

.. autofunction:: hash256

Expand Down
69 changes: 69 additions & 0 deletions docs/tutorial/adv-multitx.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
*******************************
Advanced: Multiple Transactions
*******************************

In this tutorial, I shall go through how can we send multiple transactions within the same block.

If you have been using the current methods ``sendAsset`` and ``doInvoke``, you would have realised that the second transaction coming out from the same address will fail if done quickly enough. This is due to the second transaction being unaware of the first transaction and thus it tries to spend the same inputs as the first transaction has used. Therefore, this is double spending and the node rejects our second transaction.

A look at the Balance object
----------------------------

Within the Balance object, the assetBalance object looks like this::

{
balance: 1,
spent: [],
unspent: [
{ txid: 'abc', index: 0, value: 10 },
{ txid: 'abc', index: 1, value: 5 }
],
unconfirmed: []
}

Other than ``balance``, each of the arrays is a list of ``Coin`` objects that basically represent a spendable transaction output. When we are constructing a transaction involving assets, ``neon-js`` selects coins from the ``unspent`` array, selecting more until there is enough to meet the demand as stated in the ``intents``. The selected coins are transformed and added to the transaction as ``inputs`` while the ``intents`` are transformed and added to the transaction as ``outputs``.

Once the transaction is sent off to a RPC node, we should not reuse the selected coins as inputs for a second transaction as that would be double spending. However, if we were to retrieve a new ``Balance`` object from the 3rd party provider such as neoscan, the ``Balance`` object will not take in account the recently sent transaction.

Applying Transaction
--------------------

To deal with this problem, the program will have to retain the old ``Balance`` object and reuse it to make the second transaction. We register the transaction with the ``Balance`` object by calling the ``applyTx`` method::

const tx // We assume that this is a tx that sends 3 NEO away.
console.log(tx.hash) // ghi
balance.applyTx(tx)

Now, our asset balance should look like::

{
balance: 1,
spent: [{ txid: 'abc', index: 0, value: 10 }],
unspent: [{ txid: 'abc', index: 1, value: 5 }],
unconfirmed: [
// This is the change from spending the 5 neo
{ txid: 'ghi', index: 0, value: 2}
]
}

We can see that in order for us to send that 3 neo, we actually spent 5 neo and got back 2 neo. However, this effectively locks out 5 neo as we are unable to use that 2 neo until the transaction is confirmed. However, now we can create a new transaction without worry of double spending. Our second transaction can spend up to 10 neo.

Confirming Transaction
----------------------

Once the transaction is confirmed, we can always reset by grabbing a fresh ``Balance`` object by asking our 3rd party provider. But for cases where we do not want to do that, the ``confirm`` function is a simple function to move all ``unconfirmed`` coins to ``unspent``::

balance.confirm()

Now, our asset balance will look like::

{
balance: 1,
spent: [{ txid: 'abc', index: 0, value: 10 }],
unspent: [
{ txid: 'abc',index: 0, value: 10 },
{ txid: 'ghi', index: 0, value: 2}
],
unconfirmed: []
}

135 changes: 135 additions & 0 deletions docs/tutorial/basic-createscript.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
*********************************************
Basic - Creating an invocation script (NEP5)
*********************************************

This is a tutorial for constructing invocation scripts for invoking smart contract functions. This tutorial is specifically targeted at NEP5 contracts as it is currently the most common contract type.

The example I will be using for this tutorial can be found here_.

.. _here: https://github.com/neo-project/examples-csharp/blob/master/ICO_Template/ICO_Template.cs

The parts
----------

We first look at the entry method for the NEP5 contract. The entry method for smart contracts are always named ``Main``

.. code-block:: C#
public static Object Main(string operation, params object[] args)
{
There are 2 arguments for the entry method: a string ``operation`` and an array ``args``. This means that for every invocation script, the contract expects exactly 2 arguments.
Of course, this style is not enforced and you can have a smart contract that simply accepts an integer as the only argument. However, it is recommended that any complex contract implement this string and array pattern as it is super flexible and tools will most likely be built around serving this pattern.
Simple calls with create.script
-------------------------------
In ``neon-js``, there is a simple way exposed to create an invocation script through the semantic call ``Neon.create.script``. It is an alias for the method ``Neon.sc.createScript``.
::
const props = {
scriptHash: '5b7074e873973a6ed3708862f219a6fbf4d1c411', // Scripthash for the contract
operation: 'balanceOf', // name of operation to perform.
args: [Neon.u.reverseHex('cef0c0fdcfe7838eff6ff104f9cdec2922297537')] // any optional arguments to pass in. If null, use empty array.
}
const script = Neon.create.script(props)
``script`` is now a hexstring that you can use in a ``invokescript`` RPC call or an invocationTransaction.
::
Neon.rpc.Query.invokeScript(script)
.execute('http://seed3.neo.org:20332')
.then(res => {
console.log(res) // You should get a result with state: "HALT, BREAK"
})
Your console result should look something like this::
{
"jsonrpc": "2.0",
"id": 1234,
"result": {
"script": "143775292229eccdf904f16fff8e83e7cffdc0f0ce51c10962616c616e63654f666711c4d1f4fba619f2628870d36e3a9773e874705b",
"state": "HALT, BREAK",
"gas_consumed": "0.338",
"stack": [
{
"type": "ByteArray",
"value": "80778e06" // This value will vary
}
]
}
}
The ``value`` field is our result and we can turn that into a human readable form by parsing it as a Fixed8::
Neon.u.Fixed8.fromReverseHex('80778e06')
.. note:: This is a generic case for NEP5 tokens with 8 decimals. Some tokens might require different parsing solutions. This will be covered in another tutorial or you can check out the source code under src/api/nep5 .
Chaining scripts
----------------
Invocation transactions might be free now so we are fine with sending an transaction for every transfer but in the future, we want to aggregate them so we fully maximise the 10 free gas that we get per transaction. This is achieved by chaining scripts together.
``create.script`` has the functionality in built for us. Let us use it to retrieve all the information about a specific token.
There are many fields that we want to know about in an NEP5 token: name, decimals, total supply, etc. Instead of performing a ``invokescript`` RPC call for each field, we will be combining it in a single call. The example we are using here is the testnet contract for Red Pulse.
::
const scriptHash = '5b7074e873973a6ed3708862f219a6fbf4d1c411' // TestNet RPX
const getName = { scriptHash, operation: 'name', args: [] }
const getDecimals = { scriptHash, operation: 'decimals', args: [] }
const getSymbol = { scriptHash, operation: 'symbol', args: [] }
const getTotalSupply = { scriptHash, operation: 'totalSupply', args: [] }
const script = Neon.create.script([getName, getDecimals, getSymbol, getTotalSupply])
Similar to the previous example, our ``script`` is now ready to be used in a ``invokescript`` RPC call or an invocationTransaction.
Now our result would look like::
{
"jsonrpc": "2.0",
"id": 1234,
"result": {
"script": "00c1046e616d656711c4d1f4fba619f2628870d36e3a9773e874705b00c108646563696d616c736711c4d1f4fba619f2628870d36e3a9773e874705b00c10673796d626f6c6711c4d1f4fba619f2628870d36e3a9773e874705b00c10b746f74616c537570706c796711c4d1f4fba619f2628870d36e3a9773e874705b",
"state": "HALT, BREAK",
"gas_consumed": "0.646",
"stack": [
{
"type": "ByteArray",
"value": "5265642050756c736520546f6b656e20332e312e34"
},
{
"type": "Integer",
"value": "8"
},
{
"type": "ByteArray",
"value": "525058"
},
{
"type": "ByteArray",
"value": "00f871f54c710f"
}
]
}
}
We can see that the result stack returns the results in the order of our scripts. The first result ``5265642050756c736520546f6b656e20332e312e34`` is the hexstring representation of the name of the token. The second result is the decimal places. The third result is the symbol in hexstring and the last result is the total supply in Fixed8 format.
This last bit in parsing is intentionally left for the reader to try parsing the values themselves.
::
const name = 'Red Pulse Token 3.1.4'
const decimals = 8
const symbol = 'RPX'
const totalSupply = 43467000.00000000
1 change: 1 addition & 0 deletions docs/tutorial/basic-sendasset.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,4 @@ Notes

- The ``sendAsset`` method is found under the ``api`` module for named imports.
- This method only accepts one source of assets to send from. This does not support using multiple sources or multi-sig addresses.
- This supports sending assets from a smart contract by setting the ``address`` field to the contract's address, signing with a private key that is allowed to send from the contract and setting ``sendingFromSmartContract`` to true.
2 changes: 2 additions & 0 deletions docs/tutorial/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ Tutorial

basic-sendasset.rst
basic-claimgas.rst
basic-createscript.rst
adv-multitx.rst
6 changes: 6 additions & 0 deletions docs/wallet/methods/nep2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,9 @@ Do note that the encryption/decryption takes a long time and might not work very

.. autofunction:: nep2.decrypt
:short-name:

.. autofunction:: nep2.encryptAsync
:short-name:

.. autofunction:: nep2.decryptAsync
:short-name:
1 change: 1 addition & 0 deletions src/api/coinmarketcap.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const CURRENCY = ['aud', 'brl', 'cad', 'chf', 'clp', 'cny', 'czk', 'dkk', 'eur',
* @return {Promise<number>} price
*/
export const getPrice = (coin = 'NEO', currency = 'usd') => {
log.warn(`This is deprecated in favor of getPrices. There is a known bug for NEP5 tokens with this function.`)
return query(`https://api.coinmarketcap.com/v1/ticker/${coin.toLowerCase()}/`, currency)
.then((mapping) => {
const price = mapping[coin.toUpperCase()]
Expand Down
Loading

0 comments on commit 171ff99

Please sign in to comment.