The HashRun contract is a Solidity-based smart contract designed for Ethereum networks, leveraging Chainlink oracles to interact with off-chain data. It is particularly aimed at managing charitable challenges, where donations are collected until a certain challenge is met. The status of the challenge (e.g., "ongoing", "accomplished", "failed") is determined through data fetched from external APIs via Chainlink oracles. This contract allows for donations to be made directly to the contract and provides mechanisms for funds withdrawal by the beneficiary or donors, depending on the outcome of the challenge.
- Donation Management: Collects and tracks donations towards a challenge.
- Oracle Integration: Utilizes Chainlink oracles for secure and reliable off-chain data retrieval to update the challenge status.
- Dynamic Challenge Status: The challenge can be in one of several states, such as "ongoing", "accomplished", or "failed", determined by external data sources.
- Secure Withdrawals: Implements withdrawal patterns for both donors (in case of challenge failure) and beneficiaries (upon challenge completion).
- Pausable: The contract can be paused and unpaused by the owner, providing a mechanism to stop interactions in case of emergencies or maintenance.
Initializes the contract with the necessary parameters for Chainlink oracle requests and sets the beneficiary address.
Accepts Ether donations sent to the contract.
Triggers a Chainlink oracle request to update the challenge status based on data from an external API.
A callback function used by Chainlink oracles to return the challenge status.
Allows the contract owner to pause the contract.
Allows the contract owner to unpause the contract.
Enables donors to withdraw their donations if the challenge fails.
Transfers the total donations to the beneficiary upon successful challenge completion.
onlyOwner
: Restricts function access to the contract owner.whenNotPaused
: Ensures that interactions are only allowed when the contract is not paused.
LogChallengeStarted
: Emitted when the contract is deployed.LogNewDonation
: Emitted upon receiving a new donation.LogChallengeStatusRefreshed
: Indicates the challenge status has been updated.LogPaused
andLogUnpaused
: Signal the pausing and unpausing of the contract.LogDonationWithdrawn
: Emitted when a donor withdraws their donation.LogFundsTransferred
: Emitted when funds are transferred to the beneficiary.
- Solidity ^0.8.0
- Chainlink contracts
- Configure Environment: Set up a development environment with Truffle or Hardhat to compile and deploy the contract.
- Deploy Contract: Deploy the
HashRun
contract to an Ethereum network. Provide the constructor parameters, including the beneficiary address, Chainlink oracle address, job ID, and fee. - Verify Contract: After deployment, verify the contract on Etherscan for transparency and interaction.
- Reentrancy Guard: Uses the Checks-Effects-Interactions pattern to prevent reentrancy attacks.
- Chainlink Oracles: Relies on Chainlink for secure and reliable off-chain data fetching.
- Ownership and Pausability: Implement ownership and pausable features to manage and mitigate potential issues or attacks.
This contract represents a foundational structure for blockchain-based charitable initiatives, emphasizing transparency, security, and reliability through the integration of Chainlink oracles for off-chain data interaction.
The HashRun smart contract is designed to manage a donation-driven challenge, leveraging the Chainlink network to interact with external data sources. This contract facilitates the collection of donations, tracking the progress of a challenge based on data from Strava, and distributing the funds to a beneficiary upon successful completion of the challenge. It employs Chainlink Oracles for secure and reliable data retrieval from Strava, ensuring the integrity and automation of challenge status updates.
- Donation Management: Users can send ETH as donations to the contract. These donations contribute towards the challenge's funding goal.
- Challenge Status: Utilizes Chainlink Oracles to fetch the latest status of a specific activity from Strava (e.g., a running or cycling event). The status determines whether the challenge is ongoing, accomplished, or failed.
- Funds Distribution: Upon successful completion of the challenge (as verified through Strava data), the contract automatically transfers the accumulated donations to the designated beneficiary.
- Withdrawal Functionality: Donors have the ability to withdraw their donations if the challenge fails or is canceled.
- Pausable Contract: The contract owner can pause and unpause the contract to temporarily halt donations and withdrawals for maintenance or emergency purposes.
Upon deployment, the contract is initialized with the following parameters:
flowstakeAddress
: The beneficiary's address that will receive the funds upon successful completion of the challenge.oracle
: The address of the Chainlink Oracle that will fetch the activity status from Strava.jobId
: A unique identifier for the Chainlink job that specifies the task to be performed by the Oracle.fee
: The LINK token fee to be paid to the Oracle for data retrieval services.
ETH donations are accepted through the contract's fallback function. Each donation is logged, and the total donation amount is updated accordingly.
The contract owner can initiate a status update request to Chainlink Oracles, specifying the URL and path to the desired Strava activity. The Oracle fetches the activity status from Strava and returns the data to the contract through the fulfill
callback function. Based on the response, the contract updates the challenge's status accordingly.
Donors can withdraw their donations if the challenge fails. Upon successful completion of the challenge, the contract owner triggers the transfer of the total collected donations to the beneficiary's address.
The contract can be paused or unpaused by the owner to temporarily disable donation and withdrawal functionalities. This feature provides an additional layer of control and security.
For demonstration purposes, the contract is configured to reference a specific Strava activity:
- Strava Activity URL: https://www.strava.com/activities/10037054514
The contract utilizes this URL to verify the completion status of the activity through Chainlink Oracles, determining the outcome of the associated challenge.
The contract implements checks-effects-interactions patterns to mitigate reentrancy attacks, especially in withdrawal functions. Additionally, the use of Chainlink Oracles ensures the reliability and tamper-proof nature of the external data fetched from Strava.
To deploy and use the HashRun contract, ensure you have a funded Ethereum wallet with ETH for deployment and LINK tokens for paying Oracle fees. Compile and deploy the contract using Remix, Hardhat, or Truffle, providing the necessary constructor parameters. Interact with the contract through Ethereum wallet interfaces or programmatically using Web3 libraries.
For further details on Chainlink Oracles and job specifications, refer to the Chainlink documentation.
[UPDATE: the challenge is over! 65KM have been run, and 1.85 ETH have been collected :) Thanks to all!]
This is the back-end engine of the Cryptorun challenge. The goal of this challenge is for Thomas Vanderstraeten to run 60km around Brussels to raise funds and awareness for BeCode.
The catch: funds will be collected in crypto-currency using ETH, and the GPS of Thomas will be connected to the Blockchain!
You can find detailed explanation of the code behind this challenge on this general blog article. Please also consult this blog article dedicated to testing of the contract.
Special thanks to Hannes for his kind review and suggestions!
The smart contract lives at address 0x7ad38438b15338f6d1846961903055ada6fff054, it can be consulted here on Etherscan. NOTE THAT IT IS NOW CLOSED TO ANY DONATIONS!
The Oracle in charge of connecting with Strava runs on AWS Lambda with a Python 2.7 runtime.
A exceedingly simple dummy Oracle for the Truffle test suite. This Lambda has the same interface as the real Oracle, but the status that it returns can easily be switched as it is read from an environment variable. We use the aws-cli to directly update this environment variable during the tests, to fake the evolution of the challenge status.
We use Truffle to perform all tests. Once you're done with the below setup, just run truffle test test/cryptoRun.js
and enjoy the show.
Note that since Truffle cannot read the Oraclize.sol file directly from GitHub, we have to import this contract locally and source it accordingly in the CryptoRun contract import statement (we use the version available here). It is important that the Oraclize contract is named usingOraclize.sol
so that Truffle knows it's this one that must be imported.
Make sure you have ganache-cli
installed. Then run in a daemon window
ganache-cli --defaultBalanceEther 1000000 --mnemonic "test blockchain"
Note that the mnemonic option will ensure that it's always the same addresses that will be generated, which is require so we don't have to constantly update the OAR in the Ethereum Bridge setup (see further).
After ganache has been started, make sure you have Ethereum Bridge installed. For this, clone locally the repo available here, then run npm install
. You can then run the following command in a daemon window
node bridge -H localhost:8545 -a 9
Wait for the bridge to load (long and verbose). After it's done, it should instruct you to put the following line in the Oraclized smart contract constructor:
OAR = OraclizeAddrResolverI(0x6f485C8BF6fc43eA212E93BBF8ce046C7f1cb475);
Note that the actual address might vary. Sometimes there might be issue with the Bridge warning that it has already see specific Tx IDs - this is due to incompatibilites with latest solc versions. In that case just delete everything within the ethereum-bridge/database/tingodb folder.
Make sure you have the correct access rights to modify the test Lambda for the Oracle - this will be needed for the forced refreshed during the tests.
Before deploying, do make sure to have removed the following lines from the contract used for testing:
The below line
import "./usingOraclize.sol";
must be replaced by
import "github.com/oraclize/ethereum-api/oraclizeAPI.sol";
The below line should be completely removed from the contract constructor function
OAR = OraclizeAddrResolverI(0x6f485C8BF6fc43eA212E93BBF8ce046C7f1cb475);
The below line
oraclize_query("URL", "json(https://pgy2ax76f9.execute-api.eu-central-1.amazonaws.com/test/CryptoRunTest).challenge_status");
must be replaced by
oraclize_query("URL", "json(https://pgy2ax76f9.execute-api.eu-central-1.amazonaws.com/prod/CryptoRun).challenge_status");
The address of Flowstake must be specified as a constructor parameter when the contract is first deployed.