Skip to content

Instantly share code, notes, and snippets.

@manustays
Created June 6, 2021 08:28
Show Gist options
  • Select an option

  • Save manustays/ec5277e081fa2c7526cbb604cfdcba75 to your computer and use it in GitHub Desktop.

Select an option

Save manustays/ec5277e081fa2c7526cbb604cfdcba75 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.7.5+commit.eb77ed08.js&optimize=false&runs=200&gist=

REMIX EXAMPLE PROJECT

Remix example project is present when Remix loads very first time or there are no files existing in the File Explorer. It contains 3 directories:

  1. 'contracts': Holds three contracts with different complexity level, denoted with number prefix in file name.
  2. 'scripts': Holds two scripts to deploy a contract. It is explained below.
  3. 'tests': Contains one test file for 'Ballot' contract with unit tests in Solidity.

SCRIPTS

The 'scripts' folder contains example async/await scripts for deploying the 'Storage' contract. For the deployment of any other contract, 'contractName' and 'constructorArgs' should be updated (along with other code if required). Scripts have full access to the web3.js and ethers.js libraries.

To run a script, right click on file name in the file explorer and click 'Run'. Remember, Solidity file must already be compiled.

Output from script will appear in remix terminal.

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
/**
* @title Owner
* @dev Set & change owner
*/
contract Owner {
address private owner;
// event for EVM logging
event OwnerSet(address indexed oldOwner, address indexed newOwner);
// modifier to check if caller is owner
modifier isOwner() {
// If the first argument of 'require' evaluates to 'false', execution terminates and all
// changes to the state and to Ether balances are reverted.
// This used to consume all gas in old EVM versions, but not anymore.
// It is often a good idea to use 'require' to check if functions are called correctly.
// As a second argument, you can also provide an explanation about what went wrong.
require(msg.sender == owner, "Caller is not owner");
_;
}
/**
* @dev Set contract deployer as owner
*/
constructor() {
owner = msg.sender; // 'msg.sender' is sender of current call, contract deployer for a constructor
emit OwnerSet(address(0), owner);
}
/**
* @dev Change owner
* @param newOwner address of new owner
*/
function changeOwner(address newOwner) public isOwner {
emit OwnerSet(owner, newOwner);
owner = newOwner;
}
/**
* @dev Return owner address
* @return address of owner
*/
function getOwner() external view returns (address) {
return owner;
}
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
/**
* @title Ballot
* @dev Implements voting process along with vote delegation
*/
contract Ballot {
struct Voter {
uint weight; // weight is accumulated by delegation
bool voted; // if true, that person already voted
address delegate; // person delegated to
uint vote; // index of the voted proposal
}
struct Proposal {
// If you can limit the length to a certain number of bytes,
// always use one of bytes1 to bytes32 because they are much cheaper
bytes32 name; // short name (up to 32 bytes)
uint voteCount; // number of accumulated votes
}
address public chairperson;
mapping(address => Voter) public voters;
Proposal[] public proposals;
/**
* @dev Create a new ballot to choose one of 'proposalNames'.
* @param proposalNames names of proposals
*/
constructor(bytes32[] memory proposalNames) {
chairperson = msg.sender;
voters[chairperson].weight = 1;
for (uint i = 0; i < proposalNames.length; i++) {
// 'Proposal({...})' creates a temporary
// Proposal object and 'proposals.push(...)'
// appends it to the end of 'proposals'.
proposals.push(Proposal({
name: proposalNames[i],
voteCount: 0
}));
}
}
/**
* @dev Give 'voter' the right to vote on this ballot. May only be called by 'chairperson'.
* @param voter address of voter
*/
function giveRightToVote(address voter) public {
require(
msg.sender == chairperson,
"Only chairperson can give right to vote."
);
require(
!voters[voter].voted,
"The voter already voted."
);
require(voters[voter].weight == 0);
voters[voter].weight = 1;
}
/**
* @dev Delegate your vote to the voter 'to'.
* @param to address to which vote is delegated
*/
function delegate(address to) public {
Voter storage sender = voters[msg.sender];
require(!sender.voted, "You already voted.");
require(to != msg.sender, "Self-delegation is disallowed.");
while (voters[to].delegate != address(0)) {
to = voters[to].delegate;
// We found a loop in the delegation, not allowed.
require(to != msg.sender, "Found loop in delegation.");
}
sender.voted = true;
sender.delegate = to;
Voter storage delegate_ = voters[to];
if (delegate_.voted) {
// If the delegate already voted,
// directly add to the number of votes
proposals[delegate_.vote].voteCount += sender.weight;
} else {
// If the delegate did not vote yet,
// add to her weight.
delegate_.weight += sender.weight;
}
}
/**
* @dev Give your vote (including votes delegated to you) to proposal 'proposals[proposal].name'.
* @param proposal index of proposal in the proposals array
*/
function vote(uint proposal) public {
Voter storage sender = voters[msg.sender];
require(sender.weight != 0, "Has no right to vote");
require(!sender.voted, "Already voted.");
sender.voted = true;
sender.vote = proposal;
// If 'proposal' is out of the range of the array,
// this will throw automatically and revert all
// changes.
proposals[proposal].voteCount += sender.weight;
}
/**
* @dev Computes the winning proposal taking all previous votes into account.
* @return winningProposal_ index of winning proposal in the proposals array
*/
function winningProposal() public view
returns (uint winningProposal_)
{
uint winningVoteCount = 0;
for (uint p = 0; p < proposals.length; p++) {
if (proposals[p].voteCount > winningVoteCount) {
winningVoteCount = proposals[p].voteCount;
winningProposal_ = p;
}
}
}
/**
* @dev Calls winningProposal() function to get the index of the winner contained in the proposals array and then
* @return winnerName_ the name of the winner
*/
function winnerName() public view
returns (bytes32 winnerName_)
{
winnerName_ = proposals[winningProposal()].name;
}
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.7.5;
/**
* @title A simle auction smart-contract
* @author Kumar Abhishek
*/
contract SimpleAuction {
/// The contract owner (auctioneer)
address public auctioneer;
/// The beneficiary address for receiving the highest bid amount
address payable public beneficiary;
/// Current highest bidder
address public highestBidder;
/// Current highest bid amount
uint public highestBid;
/// Timestamp after which the bidding period is over
uint public auctionEndTime;
/// Has the auction ended?
bool public hasAuctionEnded;
// Allow previous bidders (who didn't win) to withdraw their bid amount
// after the auction ends
mapping (address => uint) pendingReturns;
/**
* @param _biddingTime The bidding period in seconds
* @param _beneficiary The beneficiary address that will receive the final highest bid amount
*/
constructor (uint _biddingTime, address payable _beneficiary) {
auctioneer = msg.sender;
beneficiary = _beneficiary;
auctionEndTime = block.timestamp + _biddingTime;
}
/**
* Notify whenever a new highest bid is made
* @param bidder Who made the highest bid
* @param amount The highest bid amount
*/
event HighestBidIncreased(address bidder, uint amount);
/**
* Notify when the auction has ended
* @param winner The address of the bidder who won the auction
* @param amount The winning bid amount
*/
event AuctionEnded(address winner, uint amount);
// Allowed only by the owner/auctioneer
modifier onlyAuctioneer {
require(msg.sender == auctioneer, "Only the auctioneer is allowed to do this!");
_;
}
// Allow only if the auction has not ended
modifier ifAuctionNotEnded {
require(!hasAuctionEnded, "Auction has ended!");
_;
}
// Allow only if the bidding period is not over
modifier ifBiddingPeriodNotOver {
require(block.timestamp <= auctionEndTime, "Bidding period is over!");
_;
}
// Allow only if the bidding period is over
modifier ifBiddingPeriodOver {
require(block.timestamp > auctionEndTime, "Bidding period not yet over!");
_;
}
/**
* Get total funds currently collected by the auction contract
* @dev Only the auctioneer (contract owner) is allowed to see the total funds
* @return total funds
*/
function getFunds() view public onlyAuctioneer returns(uint) {
return address(this).balance;
}
/**
* Make a bid for this auction.
* Bid amount must be more than the current highest bid amount.
* @dev Allowed only if the auction has not ended
* @dev Allowed only if the bidding-period is not over
* @dev If the last highest bid is outbid, it is marked for withdrawal
*/
function bid() public payable ifAuctionNotEnded ifBiddingPeriodNotOver {
// Condition: Bid amount should be higher than the current highestBid
require(msg.value > highestBid, "Bid too low!");
// Mark the last highest-bid for withdrawal (if any)
if (highestBid > 0) {
// The highest bidder might already have an older bid amount pending for return.
// Add highestBidder's latest bid amount to any previous pending return
pendingReturns[highestBidder] = pendingReturns[highestBidder] + highestBid;
}
// Store the current highest bidder
highestBidder = msg.sender;
highestBid = msg.value;
// Notify that a new highest bid has been made
emit HighestBidIncreased(msg.sender, msg.value);
}
/**
* Allow bidders to withdraw their earlier bid amount
* if they have been outbidded by others
* @return whether the withdrawal was successful
*/
function withdraw() public returns (bool) {
uint amount = pendingReturns[msg.sender];
if (amount > 0) {
pendingReturns[msg.sender] = 0;
if (!msg.sender.send(amount)) {
pendingReturns[msg.sender] = amount;
return false;
}
}
return true;
}
/**
* End auction
* @dev Only the Auctioneer is allowed to end the auction
* @dev Allowed only if the auction has not already ended
* @dev Allowed only if the bidding period is over
*/
function endAuction() public onlyAuctioneer ifAuctionNotEnded ifBiddingPeriodOver {
// Mark the auction as ended to avoid multiple transfers to the beneficiary
hasAuctionEnded = true;
emit AuctionEnded(highestBidder, highestBid);
// Transfer the highest bid amount to the beneficiary
beneficiary.transfer(highestBid);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @title A common contract for owners that can be inherited by other contracts
// contract OwnerContract {
// address public owner;
// modifier ownerOnly {
// require (msg.sender == owner, "Only contract owner allowed to do this");
// _;
// }
// constructor () {
// owner = msg.sender;
// balances[owner] = 1000000;
// }
// }
/// @title A simple banking example
contract SoliditySimpleBank {
address public owner;
mapping (address => uint) public balances;
mapping (address => bool) public blacklisted;
modifier blockBlacklisted {
require (!blacklisted[msg.sender], "Sender is blacklisted");
_;
}
modifier ownerOnly {
require (msg.sender == owner, "Only contract owner allowed to do this");
_;
}
// Event to listen to fund transfers
event Sent(address from, address to, uint amount);
constructor () {
owner = msg.sender;
balances[owner] = 1e6;
}
function blacklist(address addr) public ownerOnly {
blacklisted[addr] = true;
}
/**
* Owner can deposit newly created funds to any account
*/
function deposit(address payable receiver, uint amount) public ownerOnly {
require(amount < 1e10);
balances[receiver] += amount;
}
/// Not enough funds to transfer. Requested `requested`,
/// but only `available` available.
error InsufficientBalance(uint requested, uint available);
function transfer(address payable receiver, uint amount) public blockBlacklisted {
if (amount > balances[msg.sender]) {
revert InsufficientBalance({ requested: amount, available: balances[msg.sender] });
}
balances[msg.sender] -= amount;
balances[receiver] += amount;
emit Sent(msg.sender, receiver, amount);
}
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
/**
* @title SimpleStorage
* @dev Store & retrieve two values: id & name
*/
contract SimpleStorage {
uint id;
string name;
address public owner;
//msg.sender; // Address that envoked/called the contract
//msg.value; // Transaction value (?)
/**
* @dev Set contract deployer as owner
*/
constructor () {
// Constructor is executed during the creation of the contract (when deploying the contract).
// Only the creator/owner could be the sender during this stage.
owner = msg.sender;
}
/**
* @dev Store values
* @param _id id of value to store
* @param _name name to store
*/
function set(uint _id, string memory _name) public {
id = _id;
name = _name;
}
/**
* @dev Return stored val
* @return stored id & name
*/
function get() public view returns (uint, string memory) {
return (id, name);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.5;
// written for Solidity version 0.7.5 and above that doesn't break functionality
contract Voting {
address owner;
event AddedCandidate(uint candidateId, string msg);
constructor () {
owner = msg.sender;
// Auto-authorizing the owner to vote!
voters[owner].isAuthorized = true;
}
modifier onlyOwner {
require(msg.sender == owner, "Only owner can do this!");
_;
}
struct Voter {
uint candidateIDVote; // this flag will track which candidate the voter voted for
bool isAuthorized; // this flag will help track the authorization of voter
bool hasVoted; // this flag will help to keep track of 1 voter - 1 vote
}
// describes a Candidate
struct Candidate {
string name;
string party;
uint noOFVotes;
bool doesExist;
}
// "bool doesExist" is to check if this Struct exists
// This is so we can keep track of the candidates
// These state variables are used keep track of the number of Candidates/Voters
// and used to as a way to index them
uint numCandidates; // declares a state variable - number Of Candidates
uint numVoters;
uint numOfVotes ;
// Think of these as a hash table, with the key as a uint and value of
// the struct Candidate/Voter. These mappings will be used in the majority
// of our transactions/calls
// These mappings will hold all the candidates and Voters respectively
mapping (uint => Candidate) candidates;
mapping (address => Voter) voters;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* These functions perform transactions, editing the mappings *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
function addCandidate(string memory name, string memory party) onlyOwner public {
// candidateID is the return variable
uint candidateID = numCandidates++;
// Create new Candidate Struct with name and saves it to storage.
candidates[candidateID] = Candidate(name, party, 0, true);
emit AddedCandidate(candidateID, "New candidate added");
}
function vote(uint candidateID) public {
// 1. Conditions...
// this statement is to check this voter is not already voted
require(!voters[msg.sender].hasVoted, "You have already voted!");
// checks whether the voter is authorized to vote
require(voters[msg.sender].isAuthorized, "You are not authorized!");
// check if the struct exists for the candidate
require(candidates[candidateID].doesExist == true, "Candidate does not exist!");
// 2. Effects...
voters[msg.sender] = Voter(candidateID, true, true);
candidates[candidateID].noOFVotes++;
numOfVotes++;
numVoters++;
}
/// Contract owner can authorize a voter to vote.
/// Only the authorized voters are allowed to vote.
function authorize(address voter) onlyOwner public {
voters[voter].isAuthorized = true;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * *
* Getter Functions, marked by the key word "view" *
* * * * * * * * * * * * * * * * * * * * * * * * * */
// finds the total amount of votes for a specific candidate by looping
//through voters
function totalVotes(uint candidateID) view public returns (uint) {
return candidates[candidateID].noOFVotes;
}
function getNumOfCandidates() public view returns (uint) {
return numCandidates;
}
function getNumOfVoters() public view returns (uint) {
return numVoters;
}
// returns candidate information, including its ID, name, and party
function getCandidate(uint candidateID) public view returns (uint, string memory, string memory, uint) {
return (candidateID, candidates[candidateID].name, candidates[candidateID].party, candidates[candidateID].noOFVotes);
}
}
// Right click on the script name and hit "Run" to execute
(async () => {
try {
console.log('Running deployWithEthers script...')
const contractName = 'Storage' // Change this for other contract
const constructorArgs = [] // Put constructor args (if any) here for your contract
// Note that the script needs the ABI which is generated from the compilation artifact.
// Make sure contract is compiled and artifacts are generated
const artifactsPath = `browser/contracts/artifacts/${contractName}.json` // Change this for different path
const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath))
// 'web3Provider' is a remix global variable object
const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner()
let factory = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer);
let contract = await factory.deploy(...constructorArgs);
console.log('Contract Address: ', contract.address);
// The contract is NOT deployed yet; we must wait until it is mined
await contract.deployed()
console.log('Deployment successful.')
} catch (e) {
console.log(e.message)
}
})()
// Right click on the script name and hit "Run" to execute
(async () => {
try {
console.log('Running deployWithWeb3 script...')
const contractName = 'Storage' // Change this for other contract
const constructorArgs = [] // Put constructor args (if any) here for your contract
// Note that the script needs the ABI which is generated from the compilation artifact.
// Make sure contract is compiled and artifacts are generated
const artifactsPath = `browser/contracts/artifacts/${contractName}.json` // Change this for different path
const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath))
const accounts = await web3.eth.getAccounts()
let contract = new web3.eth.Contract(metadata.abi)
contract = contract.deploy({
data: metadata.data.bytecode.object,
arguments: constructorArgs
})
const newContractInstance = await contract.send({
from: accounts[0],
gas: 1500000,
gasPrice: '30000000000'
})
console.log('Contract deployed at address: ', newContractInstance.options.address)
} catch (e) {
console.log(e.message)
}
})()
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
import "remix_tests.sol"; // this import is automatically injected by Remix.
import "../contracts/3_Ballot.sol";
contract BallotTest {
bytes32[] proposalNames;
Ballot ballotToTest;
function beforeAll () public {
proposalNames.push(bytes32("candidate1"));
ballotToTest = new Ballot(proposalNames);
}
function checkWinningProposal () public {
ballotToTest.vote(0);
Assert.equal(ballotToTest.winningProposal(), uint(0), "proposal at index 0 should be the winning proposal");
Assert.equal(ballotToTest.winnerName(), bytes32("candidate1"), "candidate1 should be the winner name");
}
function checkWinninProposalWithReturnValue () public view returns (bool) {
return ballotToTest.winningProposal() == 0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment