robertoschler
over 1 year ago  Karma: 50
Can a view function from a funded smart contract execute a send() transaction on an external contract?

I'm creating an open source voting app with a Node.JS front end. I'm hoping I can create a smart contract that can use funds allocated to it at creation time, so that participating voters don't have to pay to vote.

Normally transactions with a smart contract that require gas require the transactions to be signed. In the web app context this typically leads to the use of the Metamask plugin when the client app is a browser. I would like to create an app context where each participating voter does not have to sign/fund each vote (i.e. - each transaction).

BAD IDEAS

Originally I assumed the only way to do this is to have a trusted server "proxy" the user's vote and make an Ethernet payable transaction on the user's behalf using the private key of the smart contract creator. But I believe that approach is too awkward to be useful because of the apparent available app implementations:

  • have the contract creator sign each transaction related to each vote as each vote was cast, an awkward idea at best, dead in the water at worst.

  • batch all the votes and have the creator sign a single transaction to execute the votes against he smart contract. This sucks because you wouldn't get to see each vote show up on the blockchain as each vote was cast.

  • store the creators key on the trusted server and proxy-sign on their behalf. This is also a dead approach because it's a security nightmare and no-one is going to accept it.

IDEA: TWO COOPERATING SMART CONTRACTS?

This is the only reasonable approach I can think of but it depends on one technical detail being possible, that of being able to execute a send() transaction from a view function from one contract against another external contract.

Here is how I see it play out. Two smart contracts are created.

1) The administrative/funding contract. This contract is funded at creation time by the vote creator and contains the funds allocated to facilitate the vote. The funds come from the vote creator when the vote is created. When the vote is closed, any funds left over are sent back to the creator.

2) The voting contract. This contract records votes as they come in and has a function to close the vote.

As a vote is made from a web page that is part of the Node.JS app, the web page uses Web3.js to call a view function in the administrative/funding contract that acts as a proxy for the user's vote. It uses the funds it has on hand to call the vote function in the voting contract.

So my questions are:

1) Is it possible for a view function to execute a send() call on an external contract?

2) Will this technique work?

3) Is there a simpler idea with one smart contract that would work?

4) If the above idea isn't workable, is there any way to accomplish the task of having a voting smart contract(s) where you can eliminate the need for participating voters to fund each vote transaction?

As usual, if you know of any smart contract example/tutorial that does this, please leave a link.

#solidity
Ether
Gas
factory
robertoschler
over 1 year ago  Karma: 50
Can a view function from a funded smart contract execute a send() transaction on an external contract?

I'm creating an open source voting app with a Node.JS front end. I'm hoping I can create a smart contract that can use funds allocated to it at creation time, so that participating voters don't have to pay to vote.

Normally transactions with a smart contract that require gas require the transactions to be signed. In the web app context this typically leads to the use of the Metamask plugin when the client app is a browser. I would like to create an app context where each participating voter does not have to sign/fund each vote (i.e. - each transaction).

BAD IDEAS

Originally I assumed the only way to do this is to have a trusted server "proxy" the user's vote and make an Ethernet payable transaction on the user's behalf using the private key of the smart contract creator. But I believe that approach is too awkward to be useful because of the apparent available app implementations:

  • have the contract creator sign each transaction related to each vote as each vote was cast, an awkward idea at best, dead in the water at worst.

  • batch all the votes and have the creator sign a single transaction to execute the votes against he smart contract. This sucks because you wouldn't get to see each vote show up on the blockchain as each vote was cast.

  • store the creators key on the trusted server and proxy-sign on their behalf. This is also a dead approach because it's a security nightmare and no-one is going to accept it.

IDEA: TWO COOPERATING SMART CONTRACTS?

This is the only reasonable approach I can think of but it depends on one technical detail being possible, that of being able to execute a send() transaction from a view function from one contract against another external contract.

Here is how I see it play out. Two smart contracts are created.

1) The administrative/funding contract. This contract is funded at creation time by the vote creator and contains the funds allocated to facilitate the vote. The funds come from the vote creator when the vote is created. When the vote is closed, any funds left over are sent back to the creator.

2) The voting contract. This contract records votes as they come in and has a function to close the vote.

As a vote is made from a web page that is part of the Node.JS app, the web page uses Web3.js to call a view function in the administrative/funding contract that acts as a proxy for the user's vote. It uses the funds it has on hand to call the vote function in the voting contract.

So my questions are:

1) Is it possible for a view function to execute a send() call on an external contract?

2) Will this technique work?

3) Is there a simpler idea with one smart contract that would work?

4) If the above idea isn't workable, is there any way to accomplish the task of having a voting smart contract(s) where you can eliminate the need for participating voters to fund each vote transaction?

As usual, if you know of any smart contract example/tutorial that does this, please leave a link.

#solidity
Ether
Gas
factory

2 ANSWERS
bro
over 1 year ago Karma: 110

No, it's not possible for a view function to do anything permanent to the blockchain; the point of a view function is that all the interactions/computations are done on one node, and the rest of the peer-to-peer network doesn't have to be involved. If your intent is to have something (votes) permanently recorded in the blockchain, then other nodes need to be involved (to reach consensus).

It's not clear if the root issue you're trying to solve is that the end users making the vote don't have Ethereum addresses/ETH at all (in which case the web application they're interacting with to make the vote needs to vote on their behalf, so the web application would need some sort of private key of its own to interact with the smart contract on the blockchain), or that they do have Ethereum addresses/identities, but you want to minimize their gas use.

Assuming it's that latter, you dismissed "the participating voter having to sign each vote", but signing a message with one's own Ethereum address is a free action (no gas), as it's not a blockchain transaction.

What I would suggest as an infrastructure is having voters have their own Ethereum addresses, and when they vote, their "ballot" is a signed message (e.g. "I vote 'yes' on April 1, 2018 for proposal 12345"). That signed message is cached by the web application (and could be used to show other users that a vote happened immediately). The signed messages are batched together and submitted to the blockchain by the web application service. The web application therefore has its own private key to do the submission (and its own ETH to pay for gas). The voting contract has a whitelist of known web application service addresses, and will only accept vote submissions from it. If the web application is compromised, the whitelist should be updated to no longer trust that node, and a replacement created.

This could also be a good use-case for a sidechain network, where gas costs would be minimal. There are several sidechain platforms in development currently, which may be good to look into as they get released!

No, it's not possible for a view function to do anything permanent to the blockchain; the point of a view function is that all the interactions/computations are done on one node, and the rest of the peer-to-peer network doesn't have to be involved. If your intent is to have something (votes) permanently recorded in the blockchain, then other nodes need to be involved (to reach consensus).

It's not clear if the root issue you're trying to solve is that the end users making the vote don't have Ethereum addresses/ETH at all (in which case the web application they're interacting with to make the vote needs to vote on their behalf, so the web application would need some sort of private key of its own to interact with the smart contract on the blockchain), or that they do have Ethereum addresses/identities, but you want to minimize their gas use.

Assuming it's that latter, you dismissed "the participating voter having to sign each vote", but signing a message with one's own Ethereum address is a free action (no gas), as it's not a blockchain transaction.

What I would suggest as an infrastructure is having voters have their own Ethereum addresses, and when they vote, their "ballot" is a signed message (e.g. "I vote 'yes' on April 1, 2018 for proposal 12345"). That signed message is cached by the web application (and could be used to show other users that a vote happened immediately). The signed messages are batched together and submitted to the blockchain by the web application service. The web application therefore has its own private key to do the submission (and its own ETH to pay for gas). The voting contract has a whitelist of known web application service addresses, and will only accept vote submissions from it. If the web application is compromised, the whitelist should be updated to no longer trust that node, and a replacement created.

This could also be a good use-case for a sidechain network, where gas costs would be minimal. There are several sidechain platforms in development currently, which may be good to look into as they get released!

alberto.lasa
over 1 year ago Karma: 10

Any write operation on the blockchain has a gas cost, there is no way to avoid this. But you can load the contract with funds and when a person makes a vote return the cost of gas consumed.

```contract Votes {

address owner;
mapping (uint => uint) votes;
Candidate[] candidates;
struct Candidate {
uint ID;
string name;
}

// Need to allow depositing ether to the contract
function Votes() public payable {
owner = msg.sender;
// -> You have to put the candidates
}

function oneVote(uint candidate) public {
uint gasStart = gasleft();
for (uint i = 0; i < candidates.length; i++) {
if (candidates[i].ID == _candidate) {
votes[
candidate] += 1;
}
}
uint gasEnd = gasleft();
uint usedGas = gasStart - gasEnd;
uint gasCost = usedGas * tx.gasprice;
msg.sender.transfer(gasCost);
}

function returnVotes(uint candidate) view public returns (uint) {
for (uint i = 0; i < candidates.length; i++) {
if (candidates[i].ID == _candidate) {
return votes[
candidate];
}
}
}

function endContract() external {
require(msg.sender == owner);
selfdestruct(owner);
}
}

Any write operation on the blockchain has a gas cost, there is no way to avoid this. But you can load the contract with funds and when a person makes a vote return the cost of gas consumed.

```contract Votes {

address owner;
mapping (uint => uint) votes;
Candidate[] candidates;
struct Candidate {
uint ID;
string name;
}

// Need to allow depositing ether to the contract
function Votes() public payable {
owner = msg.sender;
// -> You have to put the candidates
}

function oneVote(uint candidate) public {
uint gasStart = gasleft();
for (uint i = 0; i < candidates.length; i++) {
if (candidates[i].ID == _candidate) {
votes[
candidate] += 1;
}
}
uint gasEnd = gasleft();
uint usedGas = gasStart - gasEnd;
uint gasCost = usedGas * tx.gasprice;
msg.sender.transfer(gasCost);
}

function returnVotes(uint candidate) view public returns (uint) {
for (uint i = 0; i < candidates.length; i++) {
if (candidates[i].ID == _candidate) {
return votes[
candidate];
}
}
}

function endContract() external {
require(msg.sender == owner);
selfdestruct(owner);
}
}

Earn tokens by posting and answering questions about blockchain!
Karma to eth
YOUR ANSWER