0

I am new to ethereum world and trying to get some practise through my MSc Project. I am attempting to create an ethereum application for trading electricity. The contracts are the following:

pragma solidity ^0.4.17;

contract HouseholdFactory{
    address[] public deployedHouseholds;
    mapping (address => uint) public balances;
    address public owner;

    constructor() public{
        owner = address(this);
    }

    function createHousehold(uint capacity ) public{
        address newHousehold = new Household(capacity, msg.sender, owner);
        deployedHouseholds.push(newHousehold);
    }

    function getDeployedHouseholds() public view returns (address[]) {
        return deployedHouseholds;
    }
}
contract Household{

uint public demand;
uint public supply;
uint public batteryCapacity;
uint public amountOfCharge;
uint public excessEnergy;



struct Bid{
    address origin;
    uint price;
    uint amount;
    uint date;
}

Bid[] public Bids;
Bid[] public Asks;
address public owner;
address public contractAddress;
address public parent;
address public exchangeAddress;
uint public balanceContract;
Exchange ex;


constructor(uint capacity, address creator, address watch_address) public {
    owner = creator;
    batteryCapacity = capacity;
    parent = watch_address;
    contractAddress = address(this);
}

function deposit() public payable {
}

function () public payable {}

function getBids(uint index) public view returns(address, uint, uint, uint){
    return (Bids[index].origin,
            Bids[index].price,
            Bids[index].amount,
            Bids[index].date
    );
}

function getAsks(uint index) public view returns(address, uint, uint, uint){
    return (Asks[index].origin,
            Asks[index].price,
            Asks[index].amount,
            Asks[index].date
    );
}

function setExchange(address exchange) public {
    exchangeAddress = exchange;
}

function charge(uint amount) public {
    require(msg.sender == owner);
    amountOfCharge += amount;
}

function discharge(uint amount) public {
    require(msg.sender == owner);
    amountOfCharge -= amount;
}

function submitBid(uint price, uint amount) public {
    Bid memory newBid = Bid({
        origin: contractAddress,
        price: price,
        amount: amount,
        date: now
    });

    Bids.push(newBid);
    ex = Exchange(exchangeAddress);
    ex.submitBid(price, amount);
}

function submitAsk(uint price, uint amount) public {
    Bid memory newAsk = Bid({
        origin: contractAddress,
        price: price,
        amount: amount,
        date: now
    });

    Asks.push(newAsk);
    ex = Exchange(exchangeAddress);
    ex.submitAsk(price, amount);
}

function buyEnergy(uint amount, address recipient, uint price ) external payable returns(bool successful){
    require(address(this).balance < price);

    amountOfCharge += amount;

    recipient.transfer(price*amount/1000); //calculate for kWh
    return true;
}

function sellEnergy(uint amount, address recipient, uint price ) public {

    if(amountOfCharge>amount){
        amountOfCharge -= amount;
    }

    recipient.transfer(price*amount/1000);
}

}

Exchange Contract:

contract Exchange {

    struct Bid {
        address owner;
        uint price;
        uint amount;
        uint date;
    }

    struct Ask {
        address owner;
        uint price;
        uint amount;
        uint date;
    }

    Bid[] public Bids;
    Ask[] public Asks;
    Household hh;

    function ExistingHH(address _t) public {
        hh = Household(_t);
    }

    function deposit() public payable {
    }

    function () public payable{}       

    function submitBid(uint _price, uint _amount) external returns (bool) {
        Bid memory b;
        b.owner = msg.sender;
        b.price = _price;
        b.amount = _amount;
        b.date = now;
        for(uint i = 0; i < Bids.length; i++) {
            if(Bids[i].price > _price) {
                Bid[] memory tempBids = new Bid[](Bids.length - i);
                for(uint j = i; j < Bids.length; j++) {
                    tempBids[j-i] = Bids[j];
                }
                Bids[i] = b;
                Bids.length = Bids.length + 1;
                for(uint k = 0; k < tempBids.length; k++) {
                    Bids[i+k+1] = tempBids[k];
                }

                if(Bids[Bids.length-1].price >= Asks[Asks.length-1].price) {
                    matchBid(Asks.length-1, Bids.length-1);
                }
                return true;
            }
        }
        Bids.push(b);
        if(Asks.length > 0) {
            matchBid(Bids.length-1, Asks.length-1);
        }
        return true;
    }

    function submitAsk(uint _price, uint _amount) external returns (bool) {
        Ask memory a;
        a.owner = msg.sender;
        a.price = _price;
        a.amount = _amount;
        a.date = now;
        for (uint i = 0; i < Asks.length; i ++) {
            if(Asks[i].price < _price) {
                Ask[] memory tempAsks = new Ask[](Asks.length - i);
                for (uint j = i; j < Asks.length; j++) {
                    tempAsks[j-i] = Asks[j];
                }
                Asks[i] = a;
                Asks.length = Asks.length + 1;
                for (uint k = 0; k < tempAsks.length; k++) {
                    Asks[i+k+1] = tempAsks[k];
                }

                if(Bids[Bids.length-1].price >= Asks[Asks.length-1].price) {
                    matchBid(Asks.length-1, Bids.length-1);
                }
                return true;
            }
        }
        Asks.push(a);
        if(Bids.length > 0) {
            matchBid(Asks.length-1, Bids.length-1);
        }
        return true;
    }

    function matchBid(uint bid_index, uint ask_index) public payable returns (bool) {
        if (Bids[bid_index].amount <= 0 || Bids[bid_index].price < Asks[ask_index].price) {
            cleanAskLedger();
            return true;
        }

        hh = Household(Bids[bid_index].owner);
        //uint remainder = Bids[bid_index].amount - Asks[ask_index].amount;
        uint price = Asks[ask_index].price + Bids[bid_index].price / 2;
        if(Bids[bid_index].amount - Asks[ask_index].amount >= 0){
            uint remainder = Bids[bid_index].amount - Asks[ask_index].amount;
            uint calcAmount = Bids[bid_index].amount - remainder;

            hh.buyEnergy(calcAmount, Asks[ask_index].owner, price);

            Bids[bid_index].amount = remainder;
            Asks[ask_index].amount = 0;

            cleanAskLedger();
            return true;
        }

        if(Bids[bid_index].amount - Asks[ask_index].amount < 0){
            calcAmount = Asks[ask_index].amount - remainder;

            hh.buyEnergy(calcAmount, Asks[ask_index].owner, price);

            Bids[bid_index].amount = 0;
            Asks[ask_index].amount = remainder;

            cleanBidLedger();
            return true;
        }
    }

    function cleanAskLedger() public returns (bool) {
        for(uint i = Asks.length - 1; i >= 0; i--) {
            if (Asks[i].amount == 0) {
                delete Asks[i];
            }
        }
        return true;
    }

    function cleanBidLedger() public returns (bool) {
        for(uint i = Bids.length -1; i >= 0; i--) {
            if(Bids[i].amount > 0) {
                delete Bids[i];
            }
        }
        return true;
    }

    function getBidsCount() public view returns(uint) {
        return Bids.length;
    }

    function getAsksCount() public view returns(uint) {
        return Asks.length;
    }
}

There is only once instance of HouseholdFactory that creates Household contracts of which there can be various instances. I want to effectively test if two instances of Household can trade between each other, so then I can incorporate the Exchange contract into the equation. Using mocha, web3 (1.0.0-beta.26), and ganache-cli(v6.1.6) to write up some test scripts. In the following script I am setting up an exchange and two households, sending them some ether so they can operate. Then, I try to submit a trade of "electricity" from one household instance to another:

    const assert = require('assert');
    const ganache = require('ganache-cli');
    const Web3 = require('web3');
    const web3 = new Web3(ganache.provider());

    const compiledFactory = require('../ethereum/build/HouseholdFactory.json');
    const compiledCampaign = require('../ethereum/build/Household.json');
    const compiledExchange = require('../ethereum/build/Exchange.json');


    let accounts;
    let factory;
    let householdAddress;
    let household;

beforeEach(async () => {
    accounts = await web3.eth.getAccounts();

    factory = await new web3.eth.Contract(JSON.parse(compiledFactory.interface))
        .deploy({ data: compiledFactory.bytecode })
        .send({ from: accounts[0], gas: '1999999' });

    exchange = await new web3.eth.Contract(JSON.parse(compiledExchange.interface))
        .deploy({ data: compiledExchange.bytecode })
        .send({ from: accounts[0], gas: '1999999' });

    await factory.methods.createHousehold('5000').send({
        from: accounts[0],
        gas: '1000000'
    });
    await factory.methods.createHousehold('4000').send({
        from: accounts[1],
        gas: '1000000'
    });

    households = await factory.methods.getDeployedHouseholds().call(); //the square brackets is a deconstructing array thing, which extract the first element of the array to assign it to campaignAddres
    console.log(households);
    household1 = await new web3.eth.Contract(
        JSON.parse(compiledCampaign.interface),
        households[0]
    );
    household2 = await new web3.eth.Contract(
        JSON.parse(compiledCampaign.interface),
        households[1]
    );
    //Deposit some money so they can operate
    await household1.methods.deposit().send({
        from: accounts[0],
        gas: '1000000',
        value: web3.utils.toWei( '1', 'ether')
        });
    await household2.methods.deposit().send({
        from: accounts[1],
        gas: '1000000',
        value: web3.utils.toWei( '1', 'ether')
    });
    //Charge their capacity
    await household1.methods.charge('5000').send({
        from: accounts[0],
        gas: '1000000'
        });
    await household2.methods.charge('4000').send({
        from: accounts[1],
        gas: '1000000'
    });

});

describe('Househols', () => {
it('can make submit a bid to the exchange from a household',async () =>{
        addressExchange = exchange.options.address;

        //set the exchange address necessary to interact with it
        await household1.methods.setExchange(addressExchange).send({
            from: accounts[0],
            gas: '1000000'
        });
        await household2.methods.setExchange(addressExchange).send({
            from: accounts[1],
            gas: '1000000'
        });
        await exchange.methods.deposit().send({
            from:accounts[2],
            gas: '1000000',
            value:  web3.utils.toWei( '1', 'ether')
        });


        const check1 = await household1.methods.exchangeAddress().call();
        const check2 = await household2.methods.exchangeAddress().call();

        //check for correct address
        assert.equal(addressExchange, check1 );
        assert.equal(addressExchange, check2 );


        pre_balance1 = await web3.eth.getBalance(household1.options.address);
        pre_balance2 = await web3.eth.getBalance(household2.options.address);
        balanceEx = await web3.eth.getBalance(exchange.options.address);

        console.log('balance of exchange contract', balanceEx);        
        console.log('balance1', pre_balance1);
        console.log('balance2', pre_balance2);

        try{
        confirmation=await household1.methods.buyEnergy(1000, household2.options.address, 10).send({
            from: accounts[0],
            gas: '1999999'
        });
        }catch(err){
        console.log(err);
        }

        balance1 = await web3.eth.getBalance(household1.options.address);
        balance2 = await web3.eth.getBalance(household2.options.address);
        amountOfCharge = await household2.methods.amountOfCharge().call();

        //checking for balance post transaction
        console.log(amountOfCharge);
        console.log('balance1', balance1);
        console.log('balance2', balance2);
        console.log('confirmation', confirmation);

        let difference = balance2 - balance1;
        console.log(difference);       
    });

However on the catch block I get the following error:

{ n: VM Exception while processing transaction: revert
    at Function.n.fromResults (C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\ganache-core\lib\utils\runtimeerror.js:74:1)
    at C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\ganache-core\lib\blockchain_double.js:539:1
    at C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\async\internal\once.js:12:1
    at h (C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\async\internal\eachOfLimit.js:61:1)
    at C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\async\internal\eachOfLimit.js:71:1
    at t.default (C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\async\eachLimit.js:43:1)
    at C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\async\internal\doLimit.js:9:1
    at g.r.emit (C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\async-eventemitter\lib\AsyncEventEmitter.js:42:1)
    at C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\ethereumjs-vm\dist\runBlock.js:52:1
    at C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\ethereumjs-vm\dist\runBlock.js:174:1
    at C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\ethereumjs-vm\dist\cache.js:110:1
    at C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\async\dist\async.js:473:1
    at d (C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\async\dist\async.js:1006:1)
    at C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\async\dist\async.js:1016:1
    at Dt (C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\async\dist\async.js:3196:1)
    at Object.<anonymous> (C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\async\dist\async.js:1046:1)
    at C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\ethereumjs-vm\dist\cache.js:106:1
    at C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\async\dist\async.js:969:1
    at n (C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\async\dist\async.js:5225:1)
    at C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\ethereumjs-vm\dist\cache.js:103:1
    at n (C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\async\dist\async.js:5223:1)
    at C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\ethereumjs-vm\dist\cache.js:103:1
    at n (C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\async\dist\async.js:5223:1)
    at C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\ethereumjs-vm\dist\cache.js:98:1
    at C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\merkle-patricia-tree\util.js:51:1
    at C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\merkle-patricia-tree\node_modules\async\lib\async.js:52:1
    at f (C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\merkle-patricia-tree\node_modules\async\lib\async.js:246:1)
    at C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\merkle-patricia-tree\node_modules\async\lib\async.js:44:1
    at Immediate._onImmediate (C:\Users\GUILHERME\Documents\Blockchain\microgrid\node_modules\ganache-cli\build\webpack:\ganache\node_modules\levelup\lib\levelup.js:286:20)
    at runCallback (timers.js:794:20)
    at tryOnImmediate (timers.js:752:5)
    at processImmediate [as _immediateCallback] (timers.js:729:5)
  name: 'n',
  results:
   { '0x9270bf14fc99feb8f3f95c1220f0097b0245e0985bbc03a6e0fa98a9fece04a3': { error: 'revert', program_counter: 1127, return: '0x0' } },
  hashes:
   [ '0x9270bf14fc99feb8f3f95c1220f0097b0245e0985bbc03a6e0fa98a9fece04a3' ],
  message: 'VM Exception while processing transaction: revert' }
  1. From what i've researched, this error is normally due to the existence of requires, which is the case is caused by the require(address(this).balance < price) in the buyEnergy function within the Household Contract. If I remove it, it works, however, I wanted to know why it doesn't work, as I would like to be able to require that the contract as enough funds before it goes ahead with the transaction. I know for a fact that both contracts have 1 ether in them which should be enough to make the transaction. I wanted to know if anyone could be help me figure out I can't use requires if I am performing a transaction within that function.

  2. From my Exchange contract, I am performing quite heavy computations (with the for loops) to keep the Bids and Asks of the double-auction exchange in order - I am worried that this will be very costly in terms of gas. I wanted to know if anyone knows of a better way to guarantee the ordering of these bids in order to facilitate matching between Bids and Asks.

  3. Lastly, I would like to ask if anyone could clarify who pays for gas when submitting a bid to an exchange that causes subsequent internal functions to be triggered. Is all that gas used to that computation something that the Household contract that externally triggered the submitBid would have to pay? or are these operation costs covered by the contract Exchange?

Thank you in advance for any help you might be able to give.

PS: Apologies for the long post.

  • Did you perhaps mean require(address(this).balance >= price);? – user19510 Jul 12 '18 at 15:53
  • Please ask just one question at a time. The goal of the site is to build up questions and answers that will help other developers in the future. A 3-part question is unlikely to help other developers, who almost certainly won't have the same 3 questions as you. (3 separate questions, on the other hand, might each help someone else.) – user19510 Jul 12 '18 at 15:54
  • Thank you, I have no idea how i missed something so obvious, thanks for the help. I understand, should i make extra questions for the other two points? – guibvieira Jul 12 '18 at 16:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.