aion-web3-avm-contract
Advanced tools
Comparing version 1.2.6-beta.1 to 1.2.6-beta.2
{ | ||
"name": "aion-web3-avm-contract", | ||
"namespace": "aion", | ||
"version": "1.2.6-beta.1", | ||
"version": "1.2.6-beta.2", | ||
"description": "Web3 module for using the abi to use AVM Contracts", | ||
@@ -11,3 +11,3 @@ "repository": "https://github.com/aionnetwork/aion_web3/tree/avm-support-update/packages/web3-avm-contract", | ||
"aion-lib": "1.1.4", | ||
"aion-web3-avm-abi": "1.2.6-beta.1", | ||
"aion-web3-avm-abi": "1.2.6-beta.2", | ||
"aion-web3-utils": "1.1.4", | ||
@@ -18,3 +18,3 @@ "bn.js": "^4.11.8", | ||
}, | ||
"gitHead": "3036fcf251ea9470887775635243742a0eabe99b" | ||
"gitHead": "26d0739d1a736a34a936744d12da2ec2a668dfd7" | ||
} |
562
src/index.js
@@ -23,3 +23,8 @@ /* | ||
*/ | ||
/** | ||
* | ||
* @namespace AVM-Contract | ||
*/ | ||
"use strict"; | ||
@@ -29,2 +34,17 @@ | ||
var ABI = require('aion-web3-avm-abi'); | ||
var Method = require('aion-web3-core-method'); | ||
var formatters = require('aion-web3-core-helpers').formatters; | ||
var Subscription = require('aion-web3-core-subscriptions').subscription; | ||
var _ = require('underscore'); | ||
var core = require('aion-web3-core'); | ||
var utils = require('aion-web3-utils'); | ||
var errors = require('aion-web3-core-helpers').errors; | ||
var promiEvent = require('aion-web3-core-promievent'); | ||
/** | ||
*@class | ||
*this is the main avm contract class | ||
*/ | ||
class Contract { | ||
@@ -34,4 +54,10 @@ | ||
this._abi = new ABI(); | ||
this._requestManager = null; | ||
this._initializer = null; | ||
this._callback = null; | ||
this._altTxnObj = null;//this.transactionObject = null; | ||
this._altTxnOutput = null; | ||
this._initializer = null; | ||
this._argsData = null; | ||
@@ -43,2 +69,3 @@ this._jarPath = null; | ||
this._types = []; | ||
this._deployTypes = []; | ||
@@ -49,9 +76,19 @@ // | ||
this._address = null | ||
this._contract = null | ||
this._address = null; | ||
/**This stores the address of the deployed contract*/ | ||
this._contract = null; | ||
this._interface = null; | ||
this.readOnly = {}; | ||
this.transaction = {}; | ||
this.readOnly = {};//this.methodTxnConf; | ||
this.transaction = {};//this.methodTxnConf; | ||
this.avmMethod = {}; | ||
this.avmCall = (txn,callback)=>{ | ||
return this.methodTxnConf(txn,callback,'call') | ||
}; | ||
this.avmSend = (txn,callback)=>{ | ||
return this.methodTxnConf(txn,callback,'send') | ||
}; | ||
this.instance = {}; | ||
@@ -63,3 +100,3 @@ | ||
this._gasPrice = 10000000000;//10000000000 | ||
this._gas = 2000000; | ||
this._gas = 2000000;//2000000 | ||
this._value = 0; | ||
@@ -103,3 +140,10 @@ this._nonce = null; | ||
let res = await this.instance.eth.sendSignedTransaction(signedTx.rawTransaction); | ||
return res; | ||
if(this._callback!==null){ | ||
let callback = this._callback; | ||
this._callback = null; | ||
return callback(res); | ||
}else{ | ||
return res; | ||
} | ||
@@ -124,7 +168,21 @@ }catch(err){ | ||
let ethRes = await this.instance.eth.call(txObject); | ||
if(returnType!==null){ | ||
let res = await this.instance.avm.contract.decode(returnType, ethRes); | ||
return res; | ||
if(this._callback!==null){ | ||
let callback = this._callback; | ||
this._callback = null; | ||
if(returnType!==null){ | ||
let res = await this.instance.avm.contract.decode(returnType, ethRes); | ||
return callback(res); | ||
}else{ | ||
return callback(true); | ||
} | ||
}else{ | ||
return true; | ||
if(returnType!==null){ | ||
let res = await this.instance.avm.contract.decode(returnType, ethRes); | ||
return res; | ||
}else{ | ||
return true; | ||
} | ||
} | ||
@@ -138,3 +196,101 @@ }catch(err){ | ||
/** | ||
*@method estimateGas | ||
*@memberof AVM-Contract | ||
*@param {object} txObject - similar to what would be passed to send/call | ||
*@return {int} value | ||
*/ | ||
this.estimateGas = async (txObject) => { | ||
try{ | ||
let gas = await this.instance.eth.estimateGas(txObject); | ||
return gas; | ||
}catch(err){ | ||
console.log("Estimation Failed!", err); | ||
return false; //may need to be improved for booleans | ||
} | ||
}; | ||
/** | ||
*@method getPastLogs | ||
*@memberof AVM-Contract | ||
*@param {options} options - similar to what would be passed to send/call | ||
*@param {function} callback - user provided callback function | ||
*@return {object} value -Returns object or result of callback | ||
*/ | ||
this.getPastLogs = async (options,callback) => { | ||
var args = Array.prototype.slice.call(arguments); | ||
// get the callback | ||
callback = this._getCallback(args); | ||
if(typeof options.address==='undefined'){ | ||
options.address = this._contract; | ||
} | ||
try{ | ||
let logs = await this.instance.eth.getPastLogs(options); | ||
if(typeof options.address!=='undefined'){ | ||
return logs; | ||
}else{ | ||
return callback(logs); | ||
} | ||
}catch(err){ | ||
console.log("Events Failed!", err); | ||
return false; //may need to be improved for booleans | ||
} | ||
}; | ||
} | ||
methodTxnConf(txnObj=null,callback=null,type){ | ||
if(callback!==null){ | ||
this._callback = callback; | ||
} | ||
//set object properties | ||
let txn = this._altTxnObj; | ||
if(txnObj!==null){ | ||
if(typeof txnObj.gas!== 'undefined'){ | ||
txn.gas = txnObj.gas; | ||
}else{ | ||
txn.gas = this._gas; | ||
} | ||
if(typeof txnObj.gasPrice!== 'undefined'){ | ||
txn.gasPrice = txnObj.gasPrice; | ||
}else{ | ||
txn.gasPrice = this._gasPrice; | ||
} | ||
if(typeof txnObj.value!== 'undefined'){ | ||
txn.value = txnObj.value; | ||
}else{ | ||
txn.value = this._value; | ||
} | ||
} | ||
if(type==="call"){ | ||
if(this._altTxnOutput!==null){ | ||
return this.call(txn, this._altTxnOutput); | ||
}else{ | ||
return this.call(txn); | ||
} | ||
}else if(type==="send"){ | ||
return this.sendTransaction(txn); | ||
}else{ | ||
throw new Error('Invalid method call'); | ||
} | ||
}; | ||
/** | ||
@@ -193,3 +349,3 @@ *@desc get the current value set for gas | ||
/** | ||
*@desc get the current value set for gas | ||
*@memberof *@desc get the current value set for gas | ||
*@param none | ||
@@ -265,4 +421,3 @@ *@return returns the value of _gas | ||
}; | ||
//console.log("HERE IS THE DATA >>>>", txObject.gasPrice,"##",txObject.gas,"##",txObject.value); | ||
//nonce is calculated so only set if user provide a figure | ||
@@ -276,2 +431,3 @@ if(nonce!==null){ | ||
//create functions and make them available. | ||
initFunctions(fns,obj){ | ||
@@ -281,2 +437,28 @@ try{ | ||
//define call functions | ||
//console.log("fn: ",fn); | ||
Object.defineProperty(obj.avmMethod, fn.name,{ | ||
value: function(){ | ||
const props = fn; | ||
let params = []; | ||
let inputs = []; | ||
if(arguments.length > 0){ | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
if(props.inputs[_i]){ | ||
params[_i] = arguments[_i]; | ||
inputs[_i] = props.inputs[_i].name; | ||
} | ||
} | ||
} | ||
var data = obj.data(props.name, inputs, params); | ||
obj._altTxnObj = obj.txnObj(obj._address, obj._contract, data); | ||
if(props.output){ | ||
obj._altTxnOutput = props.output; | ||
} | ||
//assign values | ||
return obj;//this; | ||
}, | ||
writable: false | ||
}); | ||
Object.defineProperty(obj.readOnly, fn.name,{ | ||
@@ -309,2 +491,27 @@ value: function(){ | ||
//define call functions | ||
Object.defineProperty(obj.estimateGas, fn.name,{ | ||
value: function(){ | ||
const props = fn; | ||
let params = []; | ||
let inputs = []; | ||
if(arguments.length > 0){ | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
if(props.inputs[_i]){ | ||
params[_i] = arguments[_i]; | ||
inputs[_i] = props.inputs[_i].name; | ||
} | ||
} | ||
} | ||
var data = obj.data(props.name, inputs, params); | ||
var txn = obj.txnObj(obj._address, obj._contract, data); | ||
return obj.estimateGas(txn); | ||
}, | ||
writable: false | ||
}); | ||
//define functions with send transaction | ||
@@ -342,3 +549,3 @@ Object.defineProperty(obj.transaction, fn.name,{ | ||
}catch(err){ | ||
throw new Error('Unable to initialize functions'); | ||
throw new Error('Unable to initialize functions'+err); | ||
} | ||
@@ -348,8 +555,15 @@ } | ||
/** | ||
*@desc assign values and create function based on abi definition | ||
*@param takes the contract address, abi object, private key and web3 instance | ||
*@return none | ||
*@method initBinding | ||
*@memberof AVM-Contract | ||
*@desc assign values and create function based on abi definition | ||
*@param contract_address, | ||
*@param abi_object, | ||
*@param private_key | ||
*@param web3_instance | ||
*@param takes the contract address, abi object, private key and web3 instance | ||
*@param takes the contract address, abi object, private key and web3 instance | ||
*@return none | ||
**/ | ||
initBinding(contractAddress=null, abi=null, key=null, instance=null) { | ||
if((contractAddress === null)||(abi === null)) { | ||
if((contractAddress === null)&&(abi === null)) { | ||
throw new Error('Missing input parameter(s)'); | ||
@@ -362,5 +576,10 @@ } | ||
if(key!==null){ | ||
//TODO:Improve the following | ||
if(key!==null){ | ||
this._key = key; | ||
let ac = this.instance.eth.accounts.privateKeyToAccount(this._key); | ||
this._address = ac.address; | ||
} | ||
if(instance!==null){ | ||
@@ -370,13 +589,17 @@ this.instance = instance;//web3 intance to process transactions | ||
//TODO:Improve the following | ||
let ac = this.instance.eth.accounts.privateKeyToAccount(this._key); | ||
this._address = ac.address; | ||
var methods = abi.functions ? abi.functions : []; | ||
this.initFunctions(methods,this);//create methods | ||
this.initFunctions(methods,this);//create methods | ||
} | ||
// Converts the Jar into a JarPath to be Encoded for Initialization | ||
deploy(jar) { | ||
/** | ||
*@desc Converts the Jar into a JarPath to be Encoded for Initialization | ||
*@method deploy | ||
*@memberof AVM-Contract | ||
*@param {object} jar - path to jar file | ||
*@return {object} value -returns file stream | ||
*/ | ||
deploy(jar) { | ||
@@ -399,3 +622,10 @@ this._jarPath = fs.readFileSync(jar); | ||
if(this._jarPath === null) { throw new Error('requires a jarFile to be set first through the deploy method'); } | ||
this._argsData = this._abi.encode(types, values); | ||
var initTypes = types; | ||
var initValues = values; | ||
//check if 1 parameter is entered and if there is a value in _deployTypes | ||
if(arguments.length === 1 && this._deployTypes.length > 0){ | ||
initTypes = this._deployTypes; | ||
initValues = arguments[0]; | ||
} | ||
this._argsData = this._abi.encode(initTypes, initValues); | ||
return this; | ||
@@ -409,4 +639,26 @@ } | ||
this._initializer = this._abi.readyDeploy(this._jarPath, this._argsData); | ||
console.log("Configuring AVM Contract Deployment..."); | ||
return this._initializer; | ||
} | ||
// Initialize & Send | ||
async initSend() { | ||
if(this._jarPath === null) { throw new Error('requires a jarFile to be set first through the deploy method'); } | ||
if(this._argsData === null) { this._argsData = this._abi.encode([], []); } | ||
this._initializer = this._abi.readyDeploy(this._jarPath, this._argsData); | ||
let acc = this.instance.eth.accounts.privateKeyToAccount(this._key); | ||
const txObject = { | ||
from: acc.address, | ||
data: this._initializer, | ||
gasPrice: 10000000000, | ||
gas: 5000000, | ||
type: '0x2' | ||
}; | ||
console.log("Deploying AVM Contract..."); | ||
return this._initializer; | ||
return await this.sendTransaction(txObject); | ||
//return this._initializer; | ||
} | ||
@@ -447,6 +699,256 @@ | ||
Interface(abi) { | ||
return this._abi.AvmInterface(abi); | ||
var abi = this._abi.AvmInterface(abi); | ||
this._deployTypes = abi.init; | ||
return abi; | ||
} | ||
/** | ||
* @method AVM Events stuff | ||
*/ | ||
/** | ||
* Adds event listeners and creates a subscription, and remove it once its fired. | ||
* | ||
* @method once | ||
* @param {String} event | ||
* @param {Object} options | ||
* @param {Function} callback | ||
* @return {Object} the event subscription | ||
*/ | ||
once(event, options, callback) { | ||
var args = Array.prototype.slice.call(arguments); | ||
// get the callback | ||
callback = this._getCallback(args); | ||
if (!callback) { | ||
throw errors.InvalidCallback('Once', 'second'); | ||
} | ||
// don't allow fromBlock | ||
if (options) | ||
delete options.fromBlock; | ||
// don't return as once shouldn't provide "on" | ||
this._on(event, options, function (err, res, sub) { | ||
sub.unsubscribe(); | ||
if(_.isFunction(callback)){ | ||
callback(err, res, sub); | ||
} | ||
}); | ||
return undefined; | ||
}; | ||
/** | ||
* Adds event listeners and creates a subscription. | ||
* | ||
* @method _on | ||
* @param {String} event | ||
* @param {Object} options | ||
* @param {Function} callback | ||
* @return {Object} the event subscription | ||
*/ | ||
_on(){ | ||
var subOptions = this._generateEventOptions.apply(this, arguments); | ||
// prevent the event "newListener" and "removeListener" from being overwritten | ||
this._checkListener('newListener', subOptions.event.name, subOptions.callback); | ||
this._checkListener('removeListener', subOptions.event.name, subOptions.callback); | ||
// TODO check if listener already exists? and reuse subscription if options are the same. | ||
// create new subscription | ||
var subscription = new Subscription({ | ||
subscription: { | ||
params: 1, | ||
inputFormatter: [formatters.inputLogFormatter], | ||
outputFormatter: this._decodeEventABI.bind(subOptions.event), | ||
// DUBLICATE, also in web3-eth | ||
subscriptionHandler: function (output) { | ||
if(output.removed) { | ||
this.emit('changed', output); | ||
} else { | ||
this.emit('data', output); | ||
} | ||
if (_.isFunction(this.callback)) { | ||
this.callback(null, output, this); | ||
} | ||
} | ||
}, | ||
type: 'eth', | ||
requestManager: this._requestManager | ||
}); | ||
subscription.subscribe('logs', subOptions.params, subOptions.callback || function () {}); | ||
return subscription; | ||
}; | ||
getPastEvents(){ | ||
var subOptions = this._generateEventOptions.apply(this, arguments); | ||
//console.log("subOptions.params: ",subOptions.params); | ||
//console.log("subOptions.event: ",subOptions.event); | ||
var getPastLogs = new Method({ | ||
name: 'getPastLogs', | ||
call: 'eth_getLogs', | ||
params: 1, | ||
inputFormatter: [formatters.inputLogFormatter], | ||
outputFormatter: this._decodeEventABI.bind(subOptions.event) | ||
}); | ||
getPastLogs.setRequestManager(this.instance.avm._requestManager); | ||
var call = getPastLogs.buildCall(); | ||
getPastLogs = null; | ||
return call(subOptions.params, subOptions.callback); | ||
} | ||
/** | ||
* Gets the event signature and outputformatters | ||
* | ||
* @method _generateEventOptions | ||
* @param {Object} event | ||
* @param {Object} options | ||
* @param {Function} callback | ||
* @return {Object} the event options object | ||
*/ | ||
_generateEventOptions() { | ||
var args = Array.prototype.slice.call(arguments); | ||
// get the callback | ||
var callback = this._getCallback(args); | ||
// get the options | ||
var options = (_.isObject(args[args.length - 1])) ? args.pop() : {}; | ||
var event = (_.isString(args[0])) ? args[0] : 'allevents'; | ||
event = (event.toLowerCase() === 'allevents') ? { | ||
name: 'ALLEVENTS' | ||
//jsonInterface: this._interface | ||
} : { | ||
name: event | ||
//jsonInterface: this._interface | ||
}; | ||
if (!event) { | ||
throw error.EventDoesNotExist(event.name); | ||
} | ||
if (!utils.isAddress(this._contract)) { | ||
throw errors.MissingContractAddress(true); | ||
} | ||
return { | ||
params: this._encodeEventABI(event, options), | ||
event: event, | ||
callback: callback | ||
}; | ||
}; | ||
/** | ||
* Should be used to encode indexed params and options to one final object | ||
* | ||
* @method _encodeEventABI | ||
* @param {Object} event | ||
* @param {Object} options | ||
* @return {Object} everything combined together and encoded | ||
*/ | ||
_encodeEventABI(event, options) { | ||
options = options || {}; | ||
var filter = options.filter || {}, | ||
result = {}; | ||
['fromBlock', 'toBlock'].filter(function (f) { | ||
return options[f] !== undefined; | ||
}).forEach(function (f) { | ||
result[f] = formatters.inputBlockNumberFormatter(options[f]); | ||
}); | ||
// use given topics | ||
if(_.isArray(options.topics)) { | ||
result.topics = options.topics; | ||
// create topics based on filter | ||
} else { | ||
result.topics = []; | ||
if(!result.topics.length) | ||
delete result.topics; | ||
} | ||
if(this._contract) { | ||
result.address = this._contract.toLowerCase(); | ||
} | ||
return result; | ||
}; | ||
/** | ||
* Should be used to decode indexed params and options | ||
* | ||
* @method _decodeEventABI | ||
* @param {Object} data | ||
* @return {Object} result object with decoded indexed && not indexed params | ||
*/ | ||
_decodeEventABI(data) { | ||
var event = this; | ||
data.data = data.data || ''; | ||
data.topics = data.topics || []; | ||
var result = formatters.outputLogFormatter(data); | ||
// if allEvents get the right event | ||
if(event.name === 'ALLEVENTS') { | ||
/*event = event.jsonInterface.find(function (intf) { | ||
return (intf.signature === data.topics[0]); | ||
}) || {anonymous: true};*/ | ||
event = {anonymous: true}; | ||
} | ||
// create empty inputs if none are present (e.g. anonymous events on allEvents) | ||
event.inputs = event.inputs || []; | ||
var argTopics = event.anonymous ? data.topics : data.topics.slice(1); | ||
var _abi = new ABI(); | ||
//result.returnValues = return data_abi.getEvents([], data.data, argTopics); | ||
//delete result.returnValues.__length__; | ||
// add name decode string | ||
//var cntr = new Contract() | ||
var name = _abi.coder_utils.toUtf8String(data.topics[0]).replace(/\0.*$/g,'') | ||
result.event = (!data.topics[0]) ? null : name; | ||
// add signature | ||
result.signature = (!data.topics[0]) ? null : data.topics[0]; | ||
// move the data and topics to "raw" | ||
result.raw = { | ||
data: result.data, | ||
topics: result.topics | ||
}; | ||
delete result.data; | ||
delete result.topics; | ||
return result; | ||
}; | ||
/** | ||
* Get the callback and modiufy the array if necessary | ||
* | ||
* @method _getCallback | ||
* @param {Array} args | ||
* @return {Function} the callback | ||
*/ | ||
_getCallback(args) { | ||
if (args && _.isFunction(args[args.length - 1])) { | ||
return args.pop(); // modify the args array! | ||
} | ||
}; | ||
} | ||
module.exports = Contract; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
64724
769
+ Addedaion-web3-avm-abi@1.2.6-beta.2(transitive)
- Removedaion-web3-avm-abi@1.2.6-beta.1(transitive)