aelf-sdk-lys1988
Version:
aelf-sdk js library
263 lines (228 loc) • 8.33 kB
JavaScript
/*
This file is part of web3.js.
web3.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
web3.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file contract.js
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2014
*/
var utils = require('../../utils/utils');
var ContractMethod = require('./method.js');
/**
* Should be called to add functions to contract object
*
* @method addFunctionsToContract
* @param {Contract} contract
* @param {Array} abi
*/
var addMethodsToContract = function (contract, wallet) {
contract.abi.Methods.map(function (methodAbi) {
return new ContractMethod(contract._chain, methodAbi, contract.address, wallet);
}).forEach(function (f) {
f.attachToContract(contract);
});
};
/**
* Should be called to check if the contract gets properly deployed on the blockchain.
*
* @method checkForContractAddress
* @param {Object} contract
* @param {Function} callback
* @returns {Undefined}
*/
var checkForContractAddress = function(contract, wallet, callback){
var count = 0,
callbackFired = false;
// wait for receipt
var filter = contract._eth.filter('latest', function(e){
if (!e && !callbackFired) {
count++;
// stop watching after 50 blocks (timeout)
if (count > 50) {
filter.stopWatching(function() {});
callbackFired = true;
if (callback)
callback(new Error('Contract transaction couldn\'t be found after 50 blocks'));
else
throw new Error('Contract transaction couldn\'t be found after 50 blocks');
} else {
contract._eth.getTransactionReceipt(contract.transactionHash, function(e, receipt){
if(receipt && receipt.blockHash && !callbackFired) {
contract._eth.getCode(receipt.contractAddress, function(e, code){
/*jshint maxcomplexity: 6 */
if(callbackFired || !code)
return;
filter.stopWatching(function() {});
callbackFired = true;
if(code.length > 3) {
// console.log('Contract code deployed!');
contract.address = receipt.contractAddress;
// attach events and methods again after we have
addMethodsToContract(contract, wallet);
// call callback for the second time
if(callback)
callback(null, contract);
} else {
if(callback)
callback(new Error('The contract code couldn\'t be stored, please check your gas amount.'));
else
throw new Error('The contract code couldn\'t be stored, please check your gas amount.');
}
});
}
});
}
}
});
};
/**
* Should be called to create new ContractFactory instance
*
* @method ContractFactory
* @param {Array} abi
*/
var ContractFactory = function (chain, abi, wallet) {
this.chain = chain;
this.abi = abi;
this.wallet = wallet;
/**
* Should be called to create new contract on a blockchain
*
* @method new
* @param {Any} contract constructor param1 (optional)
* @param {Any} contract constructor param2 (optional)
* @param {Object} contract transaction object (required)
* @param {Function} callback
* @returns {Contract} returns contract instance
*/
// this.new = function () {
// /*jshint maxcomplexity: 7 */
//
// var contract = new Contract(this.chain, this.abi);
//
// // parse arguments
// var options = {}; // required!
// var callback;
//
// var args = Array.prototype.slice.call(arguments);
// if (utils.isFunction(args[args.length - 1])) {
// callback = args.pop();
// }
//
// var last = args[args.length - 1];
// if (utils.isObject(last) && !utils.isArray(last)) {
// options = args.pop();
// }
//
// // if (options.value > 0) {
// // var constructorAbi = abi.filter(function (json) {
// // return json.type === 'constructor' && json.inputs.length === args.length;
// // })[0] || {};
//
// // if (!constructorAbi.payable) {
// // throw new Error('Cannot send value to non-payable constructor');
// // }
// // }
//
// var bytes = encodeConstructorParams(this.abi, args);
// options.data += bytes;
//
// if (callback) {
//
// // wait for the contract address and check if the code was deployed
// this.eth.sendTransaction(options, function (err, hash) {
// if (err) {
// callback(err);
// } else {
// // add the transaction hash
// contract.transactionHash = hash;
//
// // call callback for the first time
// callback(null, contract);
//
// checkForContractAddress(contract, this.wallet, callback);
// }
// });
// } else {
// var hash = this.eth.sendTransaction(options);
// // add the transaction hash
// contract.transactionHash = hash;
// checkForContractAddress(contract, this.wallet);
// }
//
// return contract;
// };
//
// this.new.getData = this.getData.bind(this);
};
/**
* Should be called to create new ContractFactory
*
* @method contract
* @param {Array} abi
* @returns {ContractFactory} new contract factory
*/
//var contract = function (abi) {
//return new ContractFactory(abi);
//};
/**
* Should be called to get access to existing contract on a blockchain
*
* @method at
* @param {Address} contract address (required)
* @param {Function} callback {optional)
* @returns {Contract} returns contract if no callback was passed,
* otherwise calls callback function (err, contract)
*/
ContractFactory.prototype.at = function (address, callback) {
var contract = new Contract(this.chain, this.abi, address);
// this functions are not part of prototype,
// because we dont want to spoil the interface
addMethodsToContract(contract, this.wallet);
//console.log("address: ", address);
//console.log("abi: ", this.abi);
if (callback) {
callback(null, contract);
}
return contract;
};
/**
* Gets the data, which is data to deploy plus constructor params
*
* @method getData
*/
ContractFactory.prototype.getData = function () {
var options = {}; // required!
var args = Array.prototype.slice.call(arguments);
var last = args[args.length - 1];
if (utils.isObject(last) && !utils.isArray(last)) {
options = args.pop();
}
var bytes = encodeConstructorParams(this.abi, args);
options.data += bytes;
return options.data;
};
/**
* Should be called to create new contract instance
*
* @method Contract
* @param {Array} abi
* @param {Address} contract address
*/
var Contract = function (chain, abi, address) {
this._chain = chain;
this.transactionHash = null;
this.address = address;
this.abi = abi;
};
module.exports = ContractFactory;