I understand that smart contracts are converted into bytecode and stored on a block in the blockchain. Smart contracts could be used similarly to Kickstarter. A project team might set a funding goal that would only be paid out if backers donate enough money to meet the goal.
But how does the the smart contract know when to pay the project team? A block's hash changes wildly depending on its data. So, keeping track of the amount of donations and transaction IDs inside a block should not be possible because it would change the block's hash. Therefore, how does the smart contract know how much money has been funded, and how does it remember where to donations the money to if the funding goal is not met?
Is it true that there is a ledger (or blockchain) and also a state database? If so, I'm assuming that we store values associated with a smart contract on the state database.
Bytecode of a smart contract is published in a transaction (that is mined in a block), and then stored in a storage of the network (usually Ethereum or Binance Smart Chain) associated with an address.
So each time when you're interacting with a smart contract, you're interacting with an address that is associated with a storage chunk containing the bytecode. Plus the bytecode points to other storage slots where the values of its variables are stored.
All state changes (including changes of the storage values) are part of the ledger database. The raw blockchain data only contain the state changes (not the current state), but most higher layers return the current state by default (you can still chose to fetch an older state, e.g. the "defaultBlock" param here). And some layers even disallow accessing previous states (e.g. Solidity and Vyper languages for writing smart contracts - you can compile this code to the bytecode).
But how does the the smart contract know when to pay the project team?
A smart contract can access current balance of any address, including its own. It can also have a variable containing the funding goal. Comparing these two values tells you whether the goal has been reached and whether the smart contract should pay the project team.
However, smart contracts currently don't have any native timers (such as cronjobs) or event handlers - and functions are executed after a transaction is sent to the address of the smart contract (data
field of the transaction states what function you want to execute and what arguments you're passing).
So you need to either send the transaction (executing the withdraw()
function) manually or using some offchain tool (that can watch the current balance and then send the transaction executing the function for you).
pragma solidity ^0.8;
contract MyContract {
uint256 constant FUNDING_GOAL = 1 ether;
address constant TEAM_ADDRESS = address(0x123);
/**
* Throws if the current balance is lower than the goal
* Otherwise sends all of the current balance to the predefined address
*
* Need to send transaction with correct value of the `data` field
* to execute this `withdraw()` function.
* Most client apps generate the correct value of `data` field for you
* after selecting the function name and specifying argument values.
*/
function withdraw() external {
require(address(this).balance >= FUNDING_GOAL, 'Haven\'t reached the funding goal');
payable(TEAM_ADDRESS).transfer(address(this).balance);
}
/**
* Allows this contract to receive native currency of the network (usually ETH or BNB)
*/
receive() external payable {}
}