大家好:)
我有问题-从Web3调用时,包含在ERC20TokenInterface中的函数称为“ functionOf(address _owner)”返回0(将在下面提供版本)
package.json
{
"name": "kilotzar",
"version": "1.0.0",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"bignumber.js": "^7.2.1",
"erc20-contract-js": "^1.1.1",
"express": "^4.16.3",
"npm-git-install": "^0.3.0",
"requirejs": "^2.3.5",
"web3": "github:ethereum/web3.js"
},
"devDependencies": {},
"description": ""
}
ERC20Implementation.sol
pragma solidity ^0.4.24;
import "./EIP20Interface.sol";
import "./SafeMath.sol";
/**
* @title Standard ERC20 token
*
* @dev Implementation of the basic standard token.
* https://github.com/ethereum/EIPs/issues/20
* Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
*/
contract EIP20Implementation is EIP20Interface {
using SafeMath for uint256;
mapping(address => uint256) balances;
mapping (address => mapping (address => uint256)) internal allowed;
string public name;
uint8 public decimals;
string public symbol;
/**
* added up to a basic contract - create merge request on url: https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC20/StandardToken.sol;
* @dev Constructor with initial parameters
* @param _initialAmount = intial supply of tokens to be created
* @param _tokenName = name of the tokens
* @param _decimalUnits = number of the decimal ( in a direct relation with _tokenSupply)
* @param _tokenSymbol = abbreviation of token name (doens't have to really be related with _tokenName)
*/
constructor(
uint _initialAmount,
string _tokenName,
uint8 _decimalUnits,
string _tokenSymbol
) public {
balances[msg.sender] = _initialAmount;
totalSupply = _initialAmount;
name = _tokenName;
decimals = _decimalUnits;
symbol = _tokenSymbol;
}
/**
* @dev Gets the balance of the specified address.
* @param _owner The address to query the the balance of.
* @return An uint256 representing the amount owned by the passed address.
*/
// We already have automatically generated getter for mapping structure ( balances ) [but it is needed in order to fulfill [ERC20 Interface];
function balanceOf(address _owner) public view returns (uint256) {
return balances[_owner];
}
/**
* @dev Function to check the amount of tokens that an owner allowed to a spender. ( Look more careful next time, it's just a getter function for list of allowed spenders)
* @param _owner address The address which owns the funds.
* @param _spender address The address which will spend the funds.
* @return A uint256 specifying the amount of tokens still available for the spender.
*/
function allowance(
address _owner,
address _spender
)
public
view
returns (uint256)
{
return allowed[_owner][_spender];
}
/**
* @dev Transfer token for a specified address
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(
address _to,
uint256 _value
) public
returns (bool)
{
require(_value <= balances[msg.sender]);
require(_to != address(0));
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
* Beware that changing an allowance with this method brings the risk that someone may use both the old
* and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
* race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
* @param _spender The address which will spend the funds.
* @param _value The amount of tokens to be spent.
*/
function approve(
address _spender,
uint256 _value
) public
returns (bool)
{
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
/**
* @dev Transfer tokens from one address to another
* @param _from address The address which you want to send tokens from
* @param _to address The address which you want to transfer to
* @param _value uint256 the amount of tokens to be transferred
*/
function transferFrom(
address _from,
address _to,
uint256 _value
)
public
returns (bool)
{
require(_value <= balances[_from]);
require(_value <= allowed[_from][msg.sender]);
require(_to != address(0));
balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
emit Transfer(_from, _to, _value);
return true;
}
/**
* @dev Increase the amount of tokens that an owner allowed to a spender.
* approve should be called when allowed[_spender] == 0. To increment
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* @param _spender The address which will spend the funds.
* @param _addedValue The amount of tokens to increase the allowance by.
*/
function increaseApproval(
address _spender,
uint256 _addedValue
)
public
returns (bool)
{
allowed[msg.sender][_spender] = (
allowed[msg.sender][_spender].add(_addedValue));
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
/**
* @dev Decrease the amount of tokens that an owner allowed to a spender.
* approve should be called when allowed[_spender] == 0. To decrement
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* @param _spender The address which will spend the funds.
* @param _subtractedValue The amount of tokens to decrease the allowance by.
*/
function decreaseApproval(
address _spender,
uint256 _subtractedValue
)
public
returns (bool)
{
uint256 oldValue = allowed[msg.sender][_spender];
if (_subtractedValue >= oldValue) {
allowed[msg.sender][_spender] = 0;
} else {
allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
}
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
/**
* @dev (Fallback) function in order to protect ether from intermedium - idea is not to send ether to smart_contract that represents particular token;
*/
// function () public payable{
// revert();
// }
}
container.js
//address of second account -> for testing purposes: 0xcce3556109e5be65be122dc9a145a4ad4d7f1125 ;
// to do: 1. fix indirect insertion of value;
var contractAbi = [
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_owner",
"type": "address"
},
{
"indexed": true,
"name": "_spender",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"constant": false,
"inputs": [
{
"name": "_spender",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_spender",
"type": "address"
},
{
"name": "_subtractedValue",
"type": "uint256"
}
],
"name": "decreaseApproval",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_spender",
"type": "address"
},
{
"name": "_addedValue",
"type": "uint256"
}
],
"name": "increaseApproval",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"name": "_initialAmount",
"type": "uint256"
},
{
"name": "_tokenName",
"type": "string"
},
{
"name": "_decimalUnits",
"type": "uint8"
},
{
"name": "_tokenSymbol",
"type": "string"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_from",
"type": "address"
},
{
"indexed": true,
"name": "_to",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
},
{
"name": "_spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "decimals",
"outputs": [
{
"name": "",
"type": "uint8"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
}
];
var contractAddress = "0xc591420b1575cc712995639c1c1569013a2b5498";
var contract;
var contractInstance;
var address;
var value;
var txStatus = false;
const owner = 0x2bf792e31b6a770ac5d8395e4255c102dd14c2d3;
const initialAmount = 1000000000;
// const transactionObject = {
// from: "0x2bf792e31b6a770ac5d8395e4255c102dd14c2d3",
// to: contractAddress,
// gas: 3000000,
// gasPrice: 20000000000
// };
$(function(){
initiate();
valueListener();
addressListener();
transactListener();
balanceListener();
if(typeof web3!=='undefined'){
web3 = new Web3(web3.currentProvider);
}
else{
console.log("No web3 instance? You should consider trying MetaMask!")
web3 = new Web3(new Web3.providers.HttpProvider(
'https://ropsten.infura.io/efYr0Kza6Io9M1NPWYA7'
));
}
contract = web3.eth.contract(contractAbi);
contractInstance = contract.at(contractAddress);
});
//util function
function hex2string(hexx) {
var hex = hexx.toString();//force conversion
var str = '';
for (let i = 0; (i < hex.length && hex.substr(i, 2) !== '00'); i += 2)
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
return str;
}
//balance of a owner;
function getBalance(owner){
console.log("Getting contranct balance; ");
console.log(web3.currentProvider);
contractInstance.balanceOf.call(owner, function(error, success){
if (error) console.log("error, function getBalance() : " + error);
else {
// let x = BigNumber(success);
// console.log("success, function balanceOf() : " + x);
console.log("success, function balanceOf() : " + hex2string(success));
console.log("success, function balanceOf() : " + success);
}
});
}
//to do: list 1;
//transfer;
function transfer(address, value){
contractInstance.transfer.sendTransaction(address, value, function(error, success){
if(error) console.log("error " + error);
else{
alert("Uspesno pokrenuta transakcija");
let intervalId = window.setInterval(function(){
transactionStatus(success);
if (txStatus) {
changeTxStatus();
window.clearInterval(intervalId);
}
}, 7000);
}
});
}
//listener for transaction status;
function transactionStatus(transactionHash){
web3.eth.getTransactionReceipt(transactionHash, function(error, success){
if(error) console.log("Something wrong happend " + error);
else{
if(success != null){
txStatus = true;
}
}
});
}
// not container (web3 related) functions;
// from dropdown menu to value bar value;
function initiate(){
$('#dd > a').each(function(){
$(this).on('click', function(event){
let temporary = $(this).html();
$('#value').attr("value", temporary);
$('#value').val(temporary);
});
});
// totalSupply();
}
//directly inserted into value bar;
function valueListener(){
$('#value').change(function(event){
let temporary = $('#value').val();
$('#value').attr("value", temporary);
$('#value').val(temporary);
setValue();
});
}
//directly inserted into address bar;
function addressListener(){
$('#address').change(function(event){
let temporary = $('#address').val();
$('#address').attr("value", temporary);
$('#address').val(temporary);
setAddress();
});
}
// only to change status of transaction from "pending/waiting" to "success"
function changeTxStatus(){
$('body > div > div.transactionContainer > form > div.txStatus > p').html('Success');
$('body > div > div.transactionContainer > form > div.txStatus > p').css('color', 'green');
}
//button listeners;
//listener that will start transaction when 'submit' button is triggered;
function transactListener(){
$('#transactionButton').on('click', function(){
$('.txStatus').css('display', 'block');
transfer(getAddress(), getValue());
});
}
// listener that will triger "getBalance()" call when 'submit' button is trigered;
function balanceListener(){
$('#balanceButton').on('click', function(){
getBalance(owner);
});
}
function getValue(){
return value;
}
function getAddress(){
return address;
}
function setValue(){
value = $('#value').attr("value");
}
function setAddress(){
address = $('#address').attr("value");
}
但是当我从RemixIDE界面调用它时,它可以正常工作。 提供者是MetaMask。 提前致谢! :)