TypeError: ajtokenSaleInstance.tokensSold не является функцией

Я следую этому руководству на YouTube «Закодируйте свою собственную криптовалюту на Ethereum (полное)». Я застрял в одной из частей, где я пытаюсь вернуть значение TokensSold, но я продолжаю получать ошибку как

"TypeError: ajtokenSaleInstance.tokensSold не является функцией"

Так же работает у инструктора ссылка https://youtu.be/XdKv5uwEk5A?t=22108

Ниже мой код, пожалуйста, помогите

App = {
web3Provider: null,
contracts: {},
account: '0x0', 
loading: false,
tokensSold:0,
tokenPrice:1000000000000000,    
tokensAvilable : 750000,
init : function() {
    console.log('app started');
    return App.intiWeb3();
},

intiWeb3 : function() {
    if (typeof web3 !== 'undefined') {
        //console.log('web3  defined');
        // if there is already instance of web3 is present e.g. from metamask
        App.web3Provider = web3.currentProvider;
        //console.dir(web3.currentProvider);
        web3 = new Web3(web3.currentProvider);
    } else {
        // Specify default instance if no web3 instance is provided
        //console.log('web3 not defined')
        App.web3Provider = new Web3.providers.httpProvider('http://localhost:7545');
        web3 = new Web3(App.web3Provider);
    }

    return App.initContracts();

},

initContracts: function() {
    $.getJSON("AjTokenSale.json", function(ajtokensale) {
        App.contracts.AjTokenSale = TruffleContract(ajtokensale);
        App.contracts.AjTokenSale.setProvider(App.web3Provider);
        App.contracts.AjTokenSale.deployed().then(function(ajtokensale){
            //return ajtokensale.tokenPrice()
            //console.dir('dir is' + ajtokensale.tokenPrice());
            console.log('AJTOKEN sale address is ' + ajtokensale.address);
            //console.dir(ajtokensale);
        }); 
    }).done(function() {
      $.getJSON("AjToken.json", function(ajtoken) {
        App.contracts.AjToken = TruffleContract(ajtoken);
        App.contracts.AjToken.setProvider(App.web3Provider);
        App.contracts.AjToken.deployed().then(function(ajtoken){
            console.log('AJ token  address ' + ajtoken.address);
        });
        return App.render();
      });
     });

},

render: function() {
    if(App.loading) {
        return;
    }
    App.loading = true;

    var loader = $('#loader');
    var content = $('#content');

    loader.show();
    content.hide();

    // load account data
    //var accounts = web3.eth.getallAccounts

    web3.eth.getCoinbase(function(err, account) {
        if(account) {
            App.account = account;
            $('#accountAddress').html("Your account: " + account);
        } else {
            console.log('Address is null, err is '+err)
        }
    });


    //$('#accountAddress').html("Your account: " + accounts[0]);

    App.contracts.AjTokenSale.deployed().then(function(instance) {
        ajtokenSaleInstance = instance;
        //console.log(ajtokenSaleInstance);
        return ajtokenSaleInstance.tokenPrice();
    }).then(function(tokenPrice) {
        App.tokenPrice = tokenPrice.toNumber();
        //console.log('tokenPrice ' + tokenPrice.toNumber());
        $('.token-price').html(web3.fromWei(App.tokenPrice, 'ether'));
        return ajtokenSaleInstance.tokensSold();            
    }).then(function(tokensSold) {
        //App.tokensSold = tokensSold.toNumber(); 
        App.tokensSold = parseInt(tokensSold).toNumber(); 
        //App.tokensSold = 680000;
        $('.tokens-sold').html(App.tokensSold);
        $('.token-available').html(App.tokensAvilable);

        var progressPercent = (Math.ceil(App.tokensSold) / App.tokensAvilable)* 100;
        $('#progress').css('width', progressPercent+'%');

        // load token contract 

        App.contracts.AjToken.deployed().then(function(instance) {
            ajTokenInstance = instance;
            return ajTokenInstance.balanceOf(App.account);
        }).then(function(balance) {
            $('.ajtoken-balance').html(balance.toNumber());
            App.loading = false;
            loader.hide();
            content.show();
        })
    });

    //.done(function() {


    //});

},

buyTokens:  function() {
    $('#content').hide();
    $('#loader').show();

    var numberOfToken = $('#numberOfToken').val();
    App.contracts.AjTokenSale.deployed(function(instance) {
        return instance.buyTokens(numberOfToken, {
            from: App.account, 
            value: numberOfToken * App.tokenPrice,
            gas:500000
        });
    }).then(function(result) {
        console.log("Tokens bought..");
        $('form').trigger('reset');
        $('#loader').hide();
        $('#content').show();
    })
}}


$(function() {
$(window).load(function() {
    App.init();
});
}); 

Ниже мой код AjTokenSale

 pragma solidity ^0.4.2;
 import './AjToken.sol';

contract AjTokenSale {
address admin;
AjToken public tokenContract;
uint256 public tokenPrice;
uint256 public tokenSold;

event Sell(address _buyer, uint256 _amount);

function AjTokenSale(AjToken _tokenContract, uint256 _tokenPrice) public {
    //Assign an Admin
    admin = msg.sender;
    //Token contract
    tokenContract = _tokenContract;
    //Set the Token Price
    tokenPrice = _tokenPrice;
}    

//Multiply

function multiply(uint x, uint y) internal pure returns(uint z) {

    require (y == 0 || (z = x * y)/y == x);

}

//Buy toekns
function buyTokens(uint256 _numberOfTokens) public payable {
    //Value is equal to token Price

    require(msg.value == multiply(_numberOfTokens , tokenPrice));

    //Require that contract has the enough toekns

    require(tokenContract.balanceOf(this) >= _numberOfTokens);

    //Require that a transfer is successful
    require(tokenContract.transfer(msg.sender, _numberOfTokens));
    //Keep track of tokenSold
    tokenSold += _numberOfTokens;
    //Trigger sell event
    Sell(msg.sender, _numberOfTokens); 
}

//End token sale 

function endSale() public {
    //only Admin can end the sale
    require(msg.sender == admin);       
    // Transfer remaining tokens back to admin
    require(tokenContract.transfer(admin, tokenContract.balanceOf(this))); 
    admin.transfer(address(this).balance);

}

}

ниже код AjToken

pragma solidity ^0.4.2;

contract AjToken {
string  public name = "AJ Token";
string  public symbol = "AJ";
string  public standard = "AJ Token V1.0 standard";
uint256 public totalSupply;

event Transfer(
    address indexed _from,
    address indexed _to,
    uint256 _value
);

event Approval(
    address indexed _owner,
    address indexed _spender,
    uint256 _value
);

mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;

function AjToken (uint256 _initialSupply) public {
    balanceOf[msg.sender] = _initialSupply;
    totalSupply = _initialSupply;
}

function transfer(address _to, uint256 _value) public returns (bool success) {
    require(balanceOf[msg.sender] >= _value);

    balanceOf[msg.sender] -= _value;
    balanceOf[_to] += _value;

    Transfer(msg.sender, _to, _value);

    return true;
}

function approve(address _spender, uint256 _value) public returns (bool success) {
    allowance[msg.sender][_spender] = _value;

    Approval(msg.sender, _spender, _value);

    return true;
}

function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
    require(_value <= balanceOf[_from]);
    require(_value <= allowance[_from][msg.sender]);

    balanceOf[_from] -= _value;
    balanceOf[_to] += _value;

    allowance[_from][msg.sender] -= _value;

    //call transfer event 

    //finally, return boolean


    Transfer(_from, _to, _value);

    return true;
}
}
Не могли бы вы также прикрепить код вашего контракта?
я добавил код .. пожалуйста, посмотрите.
Привет @ user1576448 - вы прикрепили тестовый код Javascript. Нам понадобится фактический код Solidity. (то есть .solфайлы.)
@RichardHorrocks моя ошибка, извините за это. я обновил код

Ответы (1)

Похоже на опечатку.

Ошибка (лишние "с"):

«TypeError: ajtokenSaleInstance.token s Sold не является функцией»

Договор:

uint256 публичный токен продан;

.. Большое спасибо, чувак .. это сработало .. :) ... к сожалению, не могу ответить на вопрос из-за ограничения репутации ..
Нет проблем - рад, что это сработало :-)