This week was yet again interesting as we got to do the Token Vendor challenge and the Dice Game. It also included research on scaling and infra where I discovered various protocols and projects working on
In the Token Vendor Challenge I got to learn about the approve() in ERC20 and interaction of different contracts, it was more of getting the basics right by understanding the different functions under the ERC20 contract itself and further implementing other functions by using this contract as an instance.
A withdraw() with onlyOwner as its modifier which allows the owner to withdraw the funds from the Vendor. We had to work on the option if the users wanted to sell the tokens that they bought.
In the Dice game we learnt about randomization in soliidty, but also about how it is easily exploitable because instead of working on building the game itself we were asked to come up with ways of exploiting it.
Blockchain is transparent and deterministic, meaning that once a block has been mined and added to the blockchain, its contents, including the hash value used for randomization, are public and cannot be changed. It’s easily exploitable as we only have to work on finding a pattern and using this pattern we could drain the contract.
It’s easily predictable by attackers to find a pattern and exploit the contract. This allows the attacker to manipulate the random number to their advantage and drain the funds from the contract.
In this contract we learnt about reentrancy attacks where we manipulated the original contract in another contract by implementing logic on the existing function which in turn drained the funds of target contract.
To avoid this as developers we use oracles or trusted third party services to generate random numbers which are designed to be unpredictable.Other ways to avoid would be to implement commit-and-reveal schemes or verifiable delay functions.
Commit-and-reveal-schemes is a two phase process where the hash of the number is first submitted to the smart contract by the user in the first phase and the user reveals the original number by submitting the actual value to the smart contract. The smart contract further verifies if the actual value matches to the submitted hash, this avoids the manipulation of the random number as it’s revealed only after the first phase i.e, the commit phase.
contract CommitReveal {
bytes32 public commitHash;
uint public revealNumber;
bool public revealed;
address public player;
// Commit a number by submitting a hash of the number
function commit(bytes32 hash) public {
require(player == address(0), "Commitment already made");
commitHash = hash;
player = msg.sender;
}
// Reveal the original number by submitting the actual value
function reveal(uint number) public {
require(!revealed, "Already revealed");
require(keccak256(abi.encodePacked(number)) == commitHash, "Invalid reveal");
revealNumber = number;
revealed = true;
}
// Check if the reveal phase is complete and return the random number
function getNumber() public view returns (uint) {
require(revealed, "Not revealed yet");
return revealNumber;
}
}
Verifiable delay functions delays the selection of a random number for a specified period of time, and in this period the contract gathers additional inputs from participants or wait for external events.This delay in generating the random number makes it difficult for someone to predict what the random number will be ahead of time.
import "@pooltogether/vdf-solidity/contracts/VDF.sol";
contract RandomNumberGenerator {
VDF private vdf;
constructor() {
vdf = new VDF(1000); // set the VDF difficulty to 1000
}
function generateRandomNumber(uint256 input) public view returns (uint256) {
uint256 output = vdf.evaluate(input);
return output % 100; // return a random number between 0 and 99
}
}
Alright that’s about it stay tuned for more!