solidity-by-example / solidity-by-example.github.io Goto Github PK
View Code? Open in Web Editor NEWSolidity By Example
Home Page: https://solidity-by-example.org/
License: MIT License
Solidity By Example
Home Page: https://solidity-by-example.org/
License: MIT License
Interesting but sorting is never used ....
contract Heap {
using SafeMath for uint256;
// The main operations of a priority queue are insert, delMax, & isEmpty.
constructor() public {
// Start at 0
heap = [0];
}
// We will be storing our heap in an array
uint256[] public heap;
// Inserts adds in a value to our heap.
function insert(uint256 _value) public {
// Add the value to the end of our array
heap.push(_value);
// Start at the end of the array
uint256 currentIndex = heap.length.sub(1);
// Bubble up the value until it reaches it's correct place (i.e. it is smaller than it's parent)
while(currentIndex > 1 && heap[currentIndex.div(2)] < heap[currentIndex]) {
// If the parent value is lower than our current value, we swap them
(heap[currentIndex.div(2)], heap[currentIndex]) = (_value, heap[currentIndex.div(2)]);
// change our current Index to go up to the parent
currentIndex = currentIndex.div(2);
}
}
// RemoveMax pops off the root element of the heap (the highest value here) and rebalances the heap
function removeMax() public returns(uint256){
// Ensure the heap exists
require(heap.length > 1);
// take the root value of the heap
uint256 toReturn = heap[1];
// Takes the last element of the array and put it at the root
heap[1] = heap[heap.length.sub(1)];
// Delete the last element from the array
heap.length = heap.length.sub(1);
// Start at the top
uint256 currentIndex = 1;
// Bubble down
while(currentIndex.mul(2) < heap.length.sub(1)) {
// get the current index of the children
uint256 j = currentIndex.mul(2);
// left child value
uint256 leftChild = heap[j];
// right child value
uint256 rightChild = heap[j.add(1)];
// Compare the left and right child. if the rightChild is greater, then point j to it's index
if (leftChild < rightChild) {
j = j.add(1);
}
// compare the current parent value with the highest child, if the parent is greater, we're done
if(heap[currentIndex] > heap[j]) {
break;
}
// else swap the value
(heap[currentIndex], heap[j]) = (heap[j], heap[currentIndex]);
// and let's keep going down the heap
currentIndex = j;
}
// finally, return the top of the heap
return toReturn;
}
function getHeap() public view returns(uint256[]) {
return heap;
}
function getMax() public view returns(uint256) {
return heap[1];
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
contract ArrayRemoveByShifting {
uint[] internal arr;
function remove(uint _index) internal {
require(_index < arr.length, "index out of bound");
for (uint i = _index; i < arr.length - 1; i++) {
arr[i] = arr[i + 1];
}
arr.pop();
}
// function test() external {
// arr = [1, 2, 3, 4, 5];
// remove(2);
// // [1, 2, 4, 5]
// assert(arr[0] == 1);
// assert(arr[1] == 2);
// assert(arr[2] == 4);
// assert(arr[3] == 5);
// assert(arr.length == 4);
// arr = [1];
// remove(0);
// // []
// assert(arr.length == 0);
// }
}
contract EchidnaTestArrayShift is ArrayRemoveByShifting {
uint[] private copy;
event AssertionFailed();
function test_remove(uint[] memory _arr, uint _i) public {
require(_i < _arr.length);
// emit AssertionFailed();
arr = _arr;
// reset copy
delete copy;
// copy elements except _i th element
for (uint i = 0; i < arr.length; i++) {
if (i != _i) {
copy.push(arr[i]);
}
}
remove(_i);
if (arr.length != copy.length) {
emit AssertionFailed();
}
for (uint i = 0; i < arr.length; i++) {
if (arr[i] != copy[i]) {
emit AssertionFailed();
}
}
}
}
/*
docker pull trailofbits/eth-security-toolbox
docker run -it --rm -v $PWD:/code trailofbits/eth-security-toolbox
echidna-test ./EchidnaTestArrayShift.sol --contract EchidnaTestArrayShift --check-asserts --test-limit 5000
*/
Thanks for creating this website, I frequently return to it when in doubt about how a particular syntax works in Solidity.
Some feedback on the call page. You say that:
... it is not the recommend way to call existing functions.
But do not explain why.
It might be helpful to add a few thoughts about why using the low-level calls is not recommended. As far as I know, the reasons are:
dark mode doesn't fix this for me, it's just a CSS issue.
in Foundation.css, here:
.hljs-code,
.hljs-number,
.hljs-literal,
.hljs-keyword,
.hljs-selector-tag {
color: #099;
}
Changing#099
to #0758fc
increases the contrast from 3 (insufficient) to 4.74 (passing) according to devtools.
will dig in and see if I can do a quick pull request.
Hey man,
I am learning solidity and found this bit of a mistake in your explaination of the code
the code I am refering to is in Bitwiser.sol
// Get position of most significant bit
// x = 1100 = 10, most significant bit = 1000, so this function will return 3
function mostSignificantBit(uint256 x) external pure returns (uint256) {
uint256 i = 0;
while ((x >>= 1) > 0) {
++i;
}
return i;
}
in the second comment 1100 should be equals to 12 not 10
1100 => 8 + 4 + 0 + 0 => 12
Not that these contracts are audited or have real money behind them, but there is an interesting exploit in StakingRewards, I think.
Because of the way the reward rate is calculated, and the fact there is no separation between total supply and balanceOf if the rewards and staking tokens are the same, a malicious owner/user could manipulate the contract into setting a too high reward rate.
This is only possible if the stakingToken and rewardsToken are the same, and the owner sets a ridiculously high rewardAmount in notifyRewardAmount,
after depositing a large amount of the tokens. This would mostly be an issue in rugpulls or memetokens, where the owner and minter of the token could create an artificially high rewardRate, then withdraw their tokens, then users couldn't earn rewards. Furthermore, if two users stake where the rewardRate is too high, someone who stakes a tiny amount could steal the staking balance of another user. The full exploit is written as a foundry test case and I published it in a gist here:
https://gist.github.com/Drblessing/a6ebdfcf91a4b7a0e1c02f860ce5160e
I'm new to solidity so I could be totally wrong here. Thanks! I would love to hear any feedback you may have on it.
to load the source in remix
remix.loadurl("https://raw.githubusercontent.com/solidity-by-example/solidity-by-example.github.io/gh-pages/src/pages/Gas/Gas.sol")
github gist
http://remix.ethereum.org/#gist=138fd234be78e9ddc1a0176f57b0dd17
I would like to create several new entries in the Applications and Defi categories.
Do you allow people to contribute?
What format do you expect us to use?
Looking forward to add content,
:)
where is the folder containing the applications contract in this repo? Sorry, I can't find that can somebody help?
In the English auction code, when a bidder calls bid(), it sends the bid amount (msg.value
) to the contract address, but in the bid() function the bids array only adds value of the current highestBid
(before highestBid
gets set to msg.value
in line 69). A bidder won't receive a full refund if it withdraws before it wins or gets outbidded by others.
A hypothetical example may help see the bug better: Assuming the auction contract gets initiated with _startingBid
= 0, when the first bidder bidder1 bids 1 ether for the NFT, bids[bidder1] = 0
at line 65. If bidder1 withdraws its bid now, it will receive 0 refund from the contract address, even though it sends 1 ether to the contract when calling bid().
The fix is easy, by moving the 3 lines starting at Line 64 to currently Line 70. The winner should also have the bid amount subtract from amount withdrawable.
I created a pull request with fixes & re-generated page.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
contract TestContract1 {
address public owner = msg.sender;
function setOwner(address _owner) public {
require(msg.sender == owner, "not owner");
owner = _owner;
}
}
contract TestContract2 {
address public owner = msg.sender;
uint public value = msg.value;
uint public x;
uint public y;
constructor(uint _x, uint _y) payable {
x = _x;
y = _y;
}
}
contract Proxy {
event Deploy(address);
fallback() external payable {}
function deploy(bytes memory _code) external payable returns (address addr) {
assembly {
// create(v, p, n)
// v = amount of ETH to send
// p = pointer in memory to start of code
// n = size of code
addr := create(callvalue(), add(_code, 0x20), mload(_code))
}
// return address 0 on error
require(addr != address(0), "deploy failed");
emit Deploy(addr);
}
function execute(address _target, bytes memory _data)
external
payable
{
(bool success, ) = _target.call{value: msg.value}(_data);
require(success, "failed");
}
}
contract Helper {
function getBytecode1() external pure returns (bytes memory) {
bytes memory bytecode = type(TestContract1).creationCode;
return bytecode;
}
function getBytecode2(uint _x, uint _y) external pure returns (bytes memory) {
bytes memory bytecode = type(TestContract2).creationCode;
return abi.encodePacked(bytecode, abi.encode(_x, _y));
}
function getCalldata(address _owner) external pure returns (bytes memory) {
return abi.encodeWithSignature("setOwner(address)", _owner);
}
}
contract ArrayShift {
// [1, 2, 3] -- remove(1) --> [1, 3, 3] --> [1, 3]
// [1, 2, 3, 4, 5, 6] -- remove(2) --> [1, 2, 4, 5, 6, 6] --> [1, 2, 4, 5, 6]
// [1, 2, 3, 4, 5, 6] -- remove(0) --> [2, 3, 4, 5, 6, 6] --> [2, 3, 4, 5, 6]
// [1] -- remove(0) --> [1] --> []
uint[] public arr;
function remove(uint _index) public {
require(_index < arr.length, "index out of bound");
// Write your code here
for (uint i = _index; i < arr.length - 1; i++) {
arr[i] = arr[i + 1];
}
arr.pop();
}
function test() external {
arr = [1, 2, 3, 4, 5];
remove(2);
// [1, 2, 4, 5]
assert(arr[0] == 1);
assert(arr[1] == 2);
assert(arr[2] == 4);
assert(arr[3] == 5);
assert(arr.length == 4);
arr = [1];
remove(0);
// []
assert(arr.length == 0);
}
}
https://solidity-by-example.org/app/bi-directional-payment-channel/ specifies v0.8.13 but import SafeMath. Was it just left over from the pre 0.8.0 code or is it genuinely needed in this particular example ?
Incorrect Assignment instead of equality check in asset statements
Throws TypeError
during compilation.
solidity-by-example.github.io/src/pages/array/ArrayReplaceFromEnd.sol
Lines 23 to 31 in ece680e
The array tokens
in the StableSwap is never initialized. Is that intended?
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
// Transparent upgradeable proxy pattern
// Topics
// - Intro (wrong way)
// - Return data from fallback
// - Storage for implementation and admin
// - Separate user / admin interfaces
// - Proxy admin
// - Demo
contract CounterV1 {
uint public count;
function inc() external {
count += 1;
}
}
contract CounterV2 {
uint public count;
function inc() external {
count += 1;
}
function dec() external {
count -= 1;
}
}
contract BuggyProxy {
address public implementation;
address public admin;
constructor() {
admin = msg.sender;
}
function _delegate() private {
(bool ok, bytes memory res) = implementation.delegatecall(msg.data);
require(ok, "delegatecall failed");
}
fallback() external payable {
_delegate();
}
receive() external payable {
_delegate();
}
function upgradeTo(address _implementation) external {
require(msg.sender == admin, "not authorized");
implementation = _implementation;
}
}
contract Dev {
function selectors()
external
view
returns (
bytes4,
bytes4,
bytes4
)
{
return (
Proxy.admin.selector,
Proxy.implementation.selector,
Proxy.upgradeTo.selector
);
}
}
contract Proxy {
// All functions / variables should be private, forward all calls to fallback
// -1 for unknown preimage
// 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc
bytes32 private constant IMPLEMENTATION_SLOT =
bytes32(uint(keccak256("eip1967.proxy.implementation")) - 1);
// 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103
bytes32 private constant ADMIN_SLOT =
bytes32(uint(keccak256("eip1967.proxy.admin")) - 1);
constructor() {
_setAdmin(msg.sender);
}
modifier ifAdmin() {
if (msg.sender == _getAdmin()) {
_;
} else {
_fallback();
}
}
function _getAdmin() private view returns (address) {
return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
}
function _setAdmin(address _admin) private {
require(_admin != address(0), "admin = zero address");
StorageSlot.getAddressSlot(ADMIN_SLOT).value = _admin;
}
function _getImplementation() private view returns (address) {
return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
}
function _setImplementation(address _implementation) private {
require(_implementation.code.length > 0, "implementation is not contract");
StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = _implementation;
}
// Admin interface //
function changeAdmin(address _admin) external ifAdmin {
_setAdmin(_admin);
}
// 0x3659cfe6
function upgradeTo(address _implementation) external ifAdmin {
_setImplementation(_implementation);
}
// 0xf851a440
function admin() external ifAdmin returns (address) {
return _getAdmin();
}
// 0x5c60da1b
function implementation() external ifAdmin returns (address) {
return _getImplementation();
}
// User interface //
function _delegate(address _implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
// calldatacopy(t, f, s) - copy s bytes from calldata at position f to mem at position t
// calldatasize() - size of call data in bytes
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
// delegatecall(g, a, in, insize, out, outsize) -
// - call contract at address a
// - with input mem[in…(in+insize))
// - providing g gas
// - and output area mem[out…(out+outsize))
// - returning 0 on error (eg. out of gas) and 1 on success
let result := delegatecall(gas(), _implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
// returndatacopy(t, f, s) - copy s bytes from returndata at position f to mem at position t
// returndatasize() - size of the last returndata
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
// revert(p, s) - end execution, revert state changes, return data mem[p…(p+s))
revert(0, returndatasize())
}
default {
// return(p, s) - end execution, return data mem[p…(p+s))
return(0, returndatasize())
}
}
}
function _fallback() private {
_delegate(_getImplementation());
}
fallback() external payable {
_fallback();
}
receive() external payable {
_fallback();
}
}
contract ProxyAdmin {
address public owner;
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner, "not owner");
_;
}
function getProxyAdmin(address proxy) external view returns (address) {
(bool ok, bytes memory res) = proxy.staticcall(
abi.encodeCall(Proxy.implementation, ())
);
require(ok, "call failed");
return abi.decode(res, (address));
}
function getProxyImplementation(address proxy) external view returns (address) {
(bool ok, bytes memory res) = proxy.staticcall(abi.encodeCall(Proxy.admin, ()));
require(ok, "call failed");
return abi.decode(res, (address));
}
function changeProxyAdmin(address payable proxy, address admin) external onlyOwner {
Proxy(proxy).changeAdmin(admin);
}
function upgrade(address payable proxy, address implementation) external onlyOwner {
Proxy(proxy).upgradeTo(implementation);
}
}
library StorageSlot {
struct AddressSlot {
address value;
}
function getAddressSlot(bytes32 slot)
internal
pure
returns (AddressSlot storage r)
{
assembly {
r.slot := slot
}
}
}
contract TestSlot {
bytes32 public constant slot = keccak256("TEST_SLOT");
function getSlot() external view returns (address) {
return StorageSlot.getAddressSlot(slot).value;
}
function writeSlot(address _addr) external {
StorageSlot.getAddressSlot(slot).value = _addr;
}
}
replace library math example with square root function
There are cases in Primitives.sol
the comment refers to uint
and int
, however, in code uint256
and int256
has been used instead.
We have made a Chinese version for this warehouse and hope to work together.
Since 0.8, new
keyword support for create2
opcode.
In the english auction example nft.transfer
function is called. ERC721 does not specify a transfer function.
See https://eips.ethereum.org/EIPS/eip-721#specification
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
interface IERC20 {
function transfer(address, uint) external;
}
contract Token {
function transfer(address, uint) external {}
}
contract AbiEncode {
function test(address _contract, bytes calldata data) external {
(bool ok,) = _contract.call(data);
require(ok, "call failed");
}
function encodeWithSignature(address to, uint amount)
external
pure
returns (bytes memory)
{
// Typo is not checked - "transfer(address, uint)"
return abi.encodeWithSignature("transfer(address,uint256)", to, amount);
}
function encodeWithSelector(address to, uint amount)
external
pure
returns (bytes memory)
{
// Type is not checked - (IERC20.transfer.selector, true, amount)
return abi.encodeWithSelector(IERC20.transfer.selector, to, amount);
}
function encodeCall(address to, uint amount) external pure returns (bytes memory) {
// Typo and type errors will not compile
return abi.encodeCall(IERC20.transfer, (to, amount));
}
}
Hello,
The echidna examples in the repo seem to be outdated. It says to run echidna-test
instead of just echidna
as in the documentation. I got an error when I tried echidna-test
.
Also there are some minor corrections in the contracts:
--test-mode assertion
instead of --check-asserts
0x30000
instead of 0x00a329C0648769a73afAC7F9381e08fb43DBEA70
I would be more than happy to create a PR with the corrections but I wanted to confirm with you first if you consider these changes valid.
Cheers.
This line in StakingRewards should be return rewardPerTokenStored;
.
Once _totalSupply
becomes non-zero and some accounts has positive userRewardPerTokenPaid
stored, then _totalSupply
gets back to zero(all tokens has been withdraw
), rewardPerToken()
will return zero and those accounts will get negative earned()
1(causes an uint
underflow).
By the way, I think the contract needs further refactoring.
https://solidity-by-example.org/inheritance/
remove "parent contracts are searched from
// right to left, and in depth-first manner"
pragma solidity ^0.8;
contract Target {
function isContract(address account) public view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
assembly { size := extcodesize(account) }
return size > 0;
}
bool public pwned = false;
function protected() external {
require(!isContract(msg.sender), "no contract allowed");
pwned = true;
}
}
contract Attack {
function pwn(address _target) external {
Target(_target).protected();
}
}
contract Hack {
bool public isContract;
address public addr;
constructor(address _target) {
isContract = Target(_target).isContract(address(this));
addr = address(this);
Target(_target).protected();
}
}
In the Precompute Contract Address with Create2 example
function deploy(bytes memory bytecode, uint _salt) public payable {
......
assembly {
addr := create2(
callvalue(), // wei sent with current call
......
)
......
It is said that you can send msg.value
to the newly deployed contract.
So I had a test just now, to deploy this contract by create2, and try to send 1 wei to it.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
contract SimpleContract {
uint public myNumber;
function setNumber(uint number) public {
myNumber = number;
}
fallback() external payable{}
}
The bytecode of this contract is 0x608060405234801561001057600080fd5b5061015c806100206000396000f3fe60806040526004361061002d5760003560e01c806323fd0e40146100305780633fb5c1cb1461005b5761002e565b5b005b34801561003c57600080fd5b50610045610084565b60405161005291906100ad565b60405180910390f35b34801561006757600080fd5b50610082600480360381019061007d91906100f9565b61008a565b005b60005481565b8060008190555050565b6000819050919050565b6100a781610094565b82525050565b60006020820190506100c2600083018461009e565b92915050565b600080fd5b6100d681610094565b81146100e157600080fd5b50565b6000813590506100f3816100cd565b92915050565b60006020828403121561010f5761010e6100c8565b5b600061011d848285016100e4565b9150509291505056fea2646970667358221220a02fa857b764cbf10d2cc497fdc2937c27717eb3033d67276baef7b1c60d183864736f6c63430008120033
Use any salt you like.
It will get reverted if you send eth value to deploy(bytes memory bytecode, uint _salt)
function.
When searching for past year in https://search.brave.com/ pages which were obviously updated since then doesn't pop up. =(
pragma solidity ^0.7;
/*
- minimal proxy contract (deploy)
- Why is constructor not called? deploys a contract that only calls delegatecall
- Why is it cheap to deploy contract?
- Why is the original contract not affected? uses delegatecall
- delegatecall
- minimal proxy contract (interaction)
- Why is it cheap to deploy contract? there is minimal code
- Why is the original contract not affected? uses delegatecall
- Why is constructor not called? deploys a simple contract that fowards all calls using delegatecall
- vyper create_forwarder_to
- pseudo code (notice constructor of master copy is not called)
- actual code
3d602d80600a3d3981f3363d3d373d3d3d363d73bebebebebebebebebebebebebebebebebebebebe5af43d82803e903d91602b57fd5bf3
- bytecode
- 2 parts (
runtime code - delegate call
creation code - return contract to delegate call
)
- creation code vs runtime code
- clone factory
- mstore diagram
*/
contract PseudoMinimalProxy {
address masterCopy;
constructor(address _masterCopy) {
// notice that constructor of master copy is not called
masterCopy = _masterCopy;
}
function forward() external returns (bytes memory) {
(bool success, bytes memory data) = masterCopy.delegatecall(msg.data);
require(success);
return data;
}
}
contract MinimalProxy {
function clone(address target) external returns (address result) {
bytes20 targetBytes = bytes20(target); // convert address to 20 bytes
// runtime code //
// code to delegatecall to address
// 363d3d373d3d3d363d73 address 5af43d82803e903d91602b57fd5bf3
// creation code //
// copy runtime code into memory and return it
// 3d602d80600a3d3981f3
assembly {
/*
reads the 32 bytes of memory starting at position 0x40
In solidity, the 0x40 slot in memory is special: it contains the "free memory pointer"
which points to the end of the currently allocated memory.
*/
let clone := mload(0x40)
// store 32 bytes to memory
mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
// store 32 bytes to memory at starting at clone + 20 bytes
// 0x14 = 20
mstore(add(clone, 0x14), targetBytes)
// store 32 bytes to memory at starting at clone + 40 bytes
// 0x28 = 40
mstore(add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
// create new contract with code at clone + 0x37 (55 bytes), send 0 Ether
result := create(0, clone, 0x37)
}
}
}
In the line no. 23 - https://github.com/solidity-by-example/solidity-by-example.github.io/blob/9d1ad735bf76015c565a6b60d710e79ac11dae83/src/pages/app/uni-directional-payment-channel/UniDirectionalPaymentChannel.sol
Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
return keccak256(abi.encodePacked(address(this), _amount));
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.