iota_lightnode.js
wraps the IOTA Javascript Library iota.lib.js
and overs the following high-level features
- Generate transaction list of bundles
- Discovery of confirmed/rejected/pending bundles
- Reconnect to next node after timeout
- Proxy server with caching for faster syncing
- Sign transactions offline (cold storage)
- Supports ccurl and curl.js to do the proof of work locally
- Detects if the node can perform the proof of work
- Promotes transactions, detects if the sub-tangle is inconsistent and reattaches the bundle automatically if necessary
- Supports pre-bundles for easier construction of complicated bundles
git clone https://github.com/DaMarkov/iota_lightnode.js.git
cd iota_lightnode.js
npm install
<script type="text/javascript" src="dist/iota_lightnode.browser.js"></script>
<script type="text/javascript" src="deb/curl.min.js"></script>
<script>
var lightnode = window.iota_lightnode.initializeIOTA();//initialize iota lightnode
lightnode.setCurlLibrary(window.curl);//Connect lightnode with curl to do the proof of work in the browser
var seed = lightnode.generateSeedInsecurely();//Generate seed (Seeds generated by this function are NOT cryptographically safe!)
lightnode.calculateFirstAddress(seed, function(error, new_address)//Generate the first address of this seed
{
//Attach address to tangle
var transfer = [{//Transfer to be attached to the tangle
'address': new_address,//Recipient address (our own)
'value': parseInt(0),//Number of IOTA to be transacted
}];
lightnode.sendTransfer(seed, transfer, function(error, attached_bundle)//Prepare bundle, do tip selection, perform proof of work and attach to tangle
{
if (error)//Either invalid transfer or node is down
{
console.error(error);
console.log( "Error! Could not submit transaction! The node you are connecting to might be down." );
}
else//Success
{
console.log( "Successfully attached your transaction to the tangle with bundle", attached_bundle);
console.log( "The transaction hash is: ", attached_bundle[0].hash );
}
});
});
</script>
The folder examples/
contains additional examples.
bin/
contains the compiled version ofccurl
for Windows/Mac/Linux 64-bit.deb/
contains dependencies used in examples. Most noticeablecurl.min.js
which is used to perform the proof of work in browser.dist/
iota_lightnode browser andnode.js
version as well asmnemonic.js
to convert seeds in a readable formatexamples/
example filesproxy-server/
proxy server usingnode.js
. This server connects to a node and acts as a cache.src/
additional source code ofiota_lightnode.js
A address represents an address that has been generated by the seed.
The address list can be retrieved by calling getAddresses
.
var addressList = iota_lightnode.getAddresses();
addressList[0].address;//The public address of this address object as a string of 81 trytes (without checksum)
addressList[0].balance;//The balance is the confirmed balance if all currently pending transaction were confirmed.
addressList[0].confirmedBalance;//The balance of this address as returned by an getBalances API call. This is the balance in IOTA that has been deposited on this address.
addressList[0].used;//True if this address has been used as least ones, i.e. there exists a transaction were this address is used either as an input or output. False if not used in any transaction.
addressList[0].usedAsSent;//True if this address has been used to spent IOTA. Otherwise false. Note that after spending from an address a part of the private key of that address is published on the tangle. Is this field is true and the balance is positive the funds of this address are at risk! The funds should be transfered to an address which has the usedAsSent set to false immediately!
addressList[0].updating;//True if bundles of this address are currently being downloaded from the node. Otherwise false. See also isSyncing() to check for any updating addresses.
Represents the smallest object in IOTA. A transfer changes the balance of one address. A transfer can also contain data like signature. For a simple transaction of 1 IOTA from address A to B to transfer objects are required. One transfer object for address A with value -1 to reduce A' balance and one transfer object for address B with value 1 to increase B's balance by 1 IOTA. Both of these transfers will be in one bundle and therefore will be processed by the network in unison.
var bundleList = iota_lightnode.getBundles();
var bundle = bundleList[0];
var transfer = bundle[0];
transfer.address;//Address of this transfer as a string of 81 trytes (no checksum)
transfer.attachmentTimestamp;//UNIX timestamp in ms when the transaction was attached (more precisely when the proof of work was performed)
transfer.attachmentTimestampLowerBound;//Unused so far
transfer.attachmentTimestampUpperBound;//Unused so far
transfer.branchTransaction;//Hash of one of the transfers that this transfer validates
transfer.bundle;//Bundle hash. This determines which bundle this transfer belongs to
transfer.currentIndex;//Index of this transfer in the bundle. This number is between 0 and lastIndex
transfer.hash;//Hash of the essential part of this transfer
transfer.lastIndex;//Last index in the bundle. This can be used to determine how many transfers are in a bundle
transfer.nonce;//Nonce of this transfer. The nonce is determined be the proof of work and chosen such that the hash of this transfer has a specified number of 9's at the end
transfer.obsoleteTag;//Obsolete. Do not use. Will be removed.
transfer.signatureMessageFragment;//2187 tryte long message. This field will hold the signature (or part of the signature) of the private address that spents IOTA. If the signature is longer than 2187 tryte multiple transfer objects will be used (and the therefore there will be more transfer objects in one bundle)
transfer.tag;//Tag, a string of 27 trytes. Transfers can be searched by their tag
transfer.timestamp;//UNIX timestamp in s when the transaction was created (more precisely when the transfer was signed)
transfer.trunkTransaction;//Hash of one of the transfers that this transfer validates
transfer.value;//Value of this transfer as a integer (can be positive and negative). When this transfer is confirmed the balance of transfer.address will be oldBalance(address) +
A bundle is the atomic structure of IOTA. It contains of a number of transfers.
If a bundle is confirmed all transfers in the bundle are confirmed.
If a bundle is pending all transfers in the bundle are pending.
The first transfer in a bundle contains the field confirmationStatus
.
This field has one of the following values:
Unkown
: the confirmation status is not known. iota_lightnode
has not yet asked the node about the confirmation status of this bundle. Use checkConfirmations
to invoke iota_lightnode
to request the confirmation status
2. Pending
: the bundle has not yet been confirmed by the network
3. Confirmed
: the bundle has been confirmed by the network
4. Reattachment Confirmed
: the bundle did not get confirmed. However, a reattachment of the bundle did get confirmed
5. Rejected
: the bundle did get rejected by the network. The bundle might be invalid or an invalid transaction might reference one transfer of this bundle. In any case the bundle belong to an inconsistent subtangle. In order to get this bundle to confirm it has the be reattached by calling reattachBundle
.
var bundleList = iota_lightnode.getBundles();
var bundle = bundleList[0];
bundle[0];//first transfer object
bundle[1];//second transfer object
bundle[0].confirmationStatus;//Only the first transfer object contains this field!
A transaction is higher level object and contains information about multiple bundles with the same bundle hash.
var transactionList = iota_lightnode.getTransactions();
var transaction = transactionList[0];
transaction.attachmentTimestamp;////UNIX timestamp in ms when the transaction was attached to the tangle
transaction.bundle;//array containing all bundles of this transaction
transaction.bundles;//array of bundle hashes
transaction.transaction.confirmationStatus;//Only the first transfer object contains this field!
transaction.hashes;//array of the tail transaction hashes of each bundle
transaction.inbound;//true if one of the receiving addresses of the transaction belongs is in the address list, otherwise false
transaction.outbound;//true if one of the spending addresses of the transaction belongs is in the address list, otherwise false
transaction.tag;//tag of the first transfer with a positive value
transaction.timestamp;//UNIX timestamp in s when the transaction was signed
transaction.totalValueTransfered;//Total amount of IOTA transfered in the transaction
transaction.value;//Amount of IOTA transfered only involving addresses that are in the address list
- calculateAddress
- calculateFirstAddress
- checkConfirmations
- createPreBundle
- enableLocalProofOfWork
- ensureBundleGetsConfirmed
- findBundle
- fromTrytes
- generateSeedInsecurely
- getAccountData
- getAddresses
- getBalance
- getBundles
- getBundlesOfAddress
- getBundlesOfAddressIndex
- getConfirmedBalance
- getIOTA
- getProvider
- getTransactions
- getTransactionsOfAddress
- getTransactionsOfAddressIndex
- initializeIOTA
- isCheckingConfirmations
- isInAddressList
- isInputAddress
- isPerformingTransfers
- isPerformingProofOfWork
- isProofOfWorkLocal
- isRemoteProofOfWorkAvailable
- isSyncing
- isOutputAddress
- reattachBundle
- reattachTransaction
- sendPreBundle
- sendSignedBundle
- sendTransfer
- setCurlLibrary
- setProvider
- signPreBundle
- toTrytes
- updateAddress
- updateAddressesOneByOne
Generates addresses for a given seed.
window.iota_lightnode.calculateAddress(seed, index, total, checksum, security, callback(error, addresses))
seed
:81-trytes
seed used to generate the address.index
:integer
index of the (first) address to be generated. Set to 0 to obtain the first address of the seed, 1 to obtain the second, etc. Default: 0.total
:integer
number of addresses to be generated. Default: 1.checksum
:bool
Set totrue
to generate address with a checksum (90trytes
long). If set tofalse
, addresses generated will lack a checksum. Default:false
.security
:integer
security parameter that is used for the addresses. Default: The default was set wheninitializeIOTA()
was called.callback
:function
This function will be calledtotal
number of times. The first parameter contains any error(s), the second an array of the addresses that have (so far) been generated.
None
var seed = 'OFMEOSBNBTAXQTGBHLVRRPAMPYUXZAFBAIHMJQHCSVPUELJMHNCNMSTX9DWZH9INOU9OJAUTPOYOTRZKY';
var total = 10;
window.iota_lightnode.calculateAddress(seed, 0, total, true, 3, function(error, addresses) {
console.log(addresses.length, "have been generated so far:", addresses);
});
Similar to calculateAddress
. This function calculates the first address (including checksum) of a given seed.
The security parameter of the generated address is the same when initializeIOTA()
was called.
window.iota_lightnode.calculateFirstAddress(seed, callback(error, addresses))
seed
:81-trytes
seed used to generate the address.callback
:function
This function will be called when the address has ben generated. The first parameter contains any error(s), the second a string with the generated address including the checksum (90trytes
).
None
var seed = 'OFMEOSBNBTAXQTGBHLVRRPAMPYUXZAFBAIHMJQHCSVPUELJMHNCNMSTX9DWZH9INOU9OJAUTPOYOTRZKY';
var total = 10;
window.iota_lightnode.calculateFirstAddress(seed, function(error, addresses) {
console.log("First address is:", addresses);
});
This function updates the confirmation status of the bundles iota_lightnode
is aware of.
I.e. checkConfirmations
goes trough the bundle list returned by getBundles
and updates the confirmation status of pending transactions.
After calling checkConfirmations
the function isCheckingConfirmations
will return true as long as the API calls are being made.
When all bundles have been updated isCheckingConfirmations
will return false.
Note that the bundle list can be filled up by calling getAccountData
of sendTransfer
.
window.iota_lightnode.checkConfirmations()
None
window.iota_lightnode.checkConfirmations();
console.log("Checking confirmation status of transactions...");
while (window.iota_lightnode.isCheckingConfirmations())
;//Do something else
console.log("Confirmation status updated!");
TODO
TODO
TODO
TODO
TODO
This function enables or disable the local proof of work.
window.iota_lightnode.enableLocalProofOfWork(enable)
enable
:bool
Set to true to enable local proof of work. Set to false to disable local proof of work
None
window.iota_lightnode.isRemoteProofOfWorkAvailable(function(available) {//Check if the node we are connected to can perform the proof of work
if (available)//The node can to the proof of work
window.iota_lightnode.enableLocalProofOfWork(false);//OK, we don't have to do anything, let the node do the hard stuff
else//Node does not perform the proof of work
window.iota_lightnode.enableLocalProofOfWork(true);//We have to do the proof of work ourself
});
This functions ensures that a bundle get confirmed by promoting it. Here is a brief summary of the algorithm used: The function attaches transactions to the tangle which validate the bundle. After every attachment the functions sleeps for a few seconds in order to use not to many resources. After 1 minute an API call is made to check if the bundle is still consistent. If the bundle is inconsistent, a reattachment is performed and the reattached bundle starts getting promoted. After about 10 minutes a reattachment is performed in any case.
window.iota_lightnode.ensureBundleGetsConfirmed(bundle, callback(success))
bundle
:object
a bundle as for example returned bysendTransfer
. This is the bundle that will get promoted / reattachedcallback
:function
callback function which takes on parametersuccess
.success
will betrue
when the bundle or a reattachment of the bundle got confirmed by the network. Ifsuccess
isfalse
an error occurred. This might be the case when the connection to the node got disconnected. Note that ifsuccess
isfalse
does NOT imply that the bundle did not get confirmed. It merely means thatiota_lightnode
could not determine the confirmation status of the bundle.
None
window.iota_lightnode.sendTransfer(seed, transfer, function(error, attached_bundle) {
if (error)
console.error(error);
else
{
//Make sure the transaction gets confirmed
window.iota_lightnode.ensureBundleGetsConfirmed(attached_bundle, function(success) {
if (success)
console.log( "Your transaction has been confirmed by the network!" );
else
console.log( "Error! Properly lost connection to the node!" );
});
}
});
Searches the bundle list of iota_lightnode
for a bundle with the bundle hash that is specified.
If there are multiple bundles with the same bundle hash in the list (as may be the case when a reattachment occurred), the first item in the list is returned.
window.iota_lightnode.findBundle(bundleHash)
bundleHash
:string
of 81trytes
. The bundle hash that is being searched for.
If a bundle with the specified bundle hash could be found, the bundle is returned as an object
.
If no bundle with the specified bundle hash could be found, undefined
is returned.
window.iota_lightnode.sendTransfer(seed, transfer, function(error, attached_bundle) {//Execute transactions
if (!error)
{
var bundle_hash = attached_bundle[0].bundle;//Get the bundle hash of the transaction which has been attached
//Find the bundle in the list
var bundleFound = window.iota_lightnode.findBundle(bundle_hash);
if (typeof bundleFound === 'undefined')
console.log( "Bundle could not be found!" );
else
console.log( "Found bundle", bundleFound );
}
});
TODO
TODO
TODO
TODO
TODO
Generates a seed (81 trytes
). This functions is NOT cryptographic cryptographically secure! Do NOT use the function to generates seeds to create wallets and store a lot of IOTA on them!
None.
string
- returns a string of length 81 which contains only the characters A-Z and 9.
var seed = window.iota_lightnode.generateSeedInsecurely();
console.log("New seed:", seed);
});
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
Returns the total balance (sum of all addresses). getAccountData
should have been called before calling getBalance
in order to obtain the addresses / bundles / balances / transactions of a given seed.
Balance is defined as the confirmed balance including all pending transactions.
For example if there are no pending transactions balance and confirmed balance are the same.
If there are pending transactions getBalance
returns the balance if all the pending transactions were actually confirmed.
None.
integer
- returns the sum of the balances of all addresses in IOTA
window.iota_lightnode.getAccountData(seed);
//Wait until account data is loaded
//Assume that there are no pending transactions and there are exactly two addresses connected with this seed
//Address 0 has 100i, Address 1 has 50i
window.iota_lightnode.getBalance();//150 is returned
window.iota_lightnode.getconfirmedBalance();//150 is returned
//Spent all 100i of address 0 by sending it to some third-party address
window.iota_lightnode.getBalance();//50 is returned, since this will be the total balance if the pending transaction were to be confirmed
window.iota_lightnode.getconfirmedBalance();//150 is returned, since the transaction has not been confirmed yet
//After confirmation, address 0 has 0i, address 1 has 50i
window.iota_lightnode.getBalance();//50 is returned
window.iota_lightnode.getconfirmedBalance();//50 is returned, since the transaction got confirmed
});
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
Returns the total confirmed balance (sum of the confirmed balance of all addresses). getAccountData
should have been called before calling getBalance
in order to obtain the addresses / bundles / balances / transactions of a given seed.
None.
integer
- returns the sum of the confirmed balances of all addresses in IOTA
window.iota_lightnode.getAccountData(seed);
//Wait until account data is loaded
//Assume that there are no pending transactions and there are exactly two addresses connected with this seed
//Address 0 has 100i, Address 1 has 50i
window.iota_lightnode.getBalance();//150 is returned
window.iota_lightnode.getconfirmedBalance();//150 is returned
//Spent all 100i of address 0 by sending it to some third-party address
window.iota_lightnode.getBalance();//50 is returned, since this will be the total balance if the pending transaction were to be confirmed
window.iota_lightnode.getconfirmedBalance();//150 is returned, since the transaction has not been confirmed yet
//After confirmation, address 0 has 0i, address 1 has 50i
window.iota_lightnode.getBalance();//50 is returned
window.iota_lightnode.getconfirmedBalance();//50 is returned, since the transaction got confirmed
});
Returns the IOTA object of iota.lib.js
.
None.
Object
- returns the IOTA object ofiota.lib.js
.
window.iota_lightnode.getIOTA().getNewAddress(seed, {'index': index, 'checksum': true, 'security': 2}, function(error, new_address) {
console.log(new_address, "generated with iota.lib.js within iota_lightnode");
});
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
Initializes iota_lightnode.js and iota.lib.js. This function has to be called before any other function of iota_lightnode.js can be called.
window.iota_lightnode.initializeIOTA(security, depth, minWeightMagnitude)
security
:integer
security parameter that should be used for address generation if no additional security parameter is supplied. Default: 2.depth
:integer
depth parameter for iota.lib.js. Used in the tip selection algorithm. Default: 3.minWeightMagnitude
:integer
minimum weight parameter used for the proof of work. The difficult of the proof of work increases with this parameter. Currently, only transactions with weight magnitude >= 14 will be accepted by the network (of main net). Default: 14
Object
- returns the iota_lightnode object.
var lightnode = window.iota_lightnode.initializeIOTA();
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO