├── .ci └── drone.yml ├── .gitattributes ├── .gitignore ├── README.md ├── package.json ├── serpent-deprecated ├── DieselPricePeg.se ├── KrakenPriceTicker.se └── README.md └── solidity ├── DieselPrice.sol ├── KrakenPriceTicker.sol ├── README.md ├── WolframAlpha.sol ├── YoutubeViews.sol ├── computation-datasource ├── bitcoin │ ├── BitcoinBalanceExample.sol │ └── computation-archive │ │ ├── Dockerfile │ │ ├── archive.zip │ │ └── script.sh ├── delegated-math │ ├── DelegatedMath.sol │ └── computation-archive │ │ ├── Dockerfile │ │ └── archive.zip ├── paypal │ ├── PaypalExample.sol │ └── computation-archive │ │ ├── Dockerfile │ │ ├── archive.zip │ │ └── pay.py ├── streamr │ ├── README.md │ ├── StreamrTweetsCounter.sol │ └── computation-archive │ │ ├── archive.zip │ │ └── src │ │ ├── Dockerfile │ │ ├── index.js │ │ └── package.json └── url-requests │ ├── UrlRequests.sol │ └── computation-archive │ ├── archive.zip │ └── src │ ├── Dockerfile │ └── url-requests.py ├── gas-price-oracle ├── README.md ├── contracts │ ├── GasPriceOracle.sol │ ├── Migrations.sol │ └── imported │ │ ├── strings.sol │ │ └── usingOraclize.sol ├── gas-price-oracle-tests.jpg ├── migrations │ ├── 1_initial_migration.js │ └── 2_deploy_contracts.js ├── package-lock.json ├── package.json ├── test │ ├── 1-gas-price-oracle-basics.test.js │ ├── 2-gas-price-oracle-stale.test.js │ └── utils.js └── truffle.js ├── lib-experimental ├── KrakenPriceTicker.sol ├── OffchainConcat.sol ├── README.md └── computation-archive │ ├── archive.zip │ └── src │ ├── Dockerfile │ └── concat.py ├── proofshield ├── README.md └── proofShieldExample.sol ├── random-datasource ├── README.md ├── randomExample.sol └── relaxed-commit │ ├── README.md │ └── relaxedRandom.sol └── truffle-examples ├── bitcoin-balance ├── README.md ├── computation-archive │ ├── Dockerfile │ ├── archive.zip │ └── script.sh ├── contracts │ ├── BitcoinAddressExample.sol │ ├── Migrations.sol │ └── provableAPI.sol ├── migrations │ ├── 1_initial_migration.js │ └── 2_deploy_contracts.js ├── package-lock.json ├── package.json ├── shrinkwrap.yaml ├── test │ ├── bitcoin-example-test.js │ └── utils.js └── truffle.js ├── caller-pays-for-query ├── .eslintrc.js ├── .solhint.json ├── README.md ├── contracts │ ├── CallerPaysForQuery.sol │ ├── Migrations.sol │ └── provableAPI.sol ├── migrations │ ├── 1_initial_migration.js │ └── 2_deploy_contracts.js ├── package-lock.json ├── package.json ├── test │ ├── caller-pays-for-query-tests.js │ └── utils.js └── truffle.js ├── delegated-math ├── README.md ├── computation-archive │ ├── Dockerfile │ └── archive.zip ├── contracts │ ├── DelegatedMath.sol │ ├── Migrations.sol │ └── provableAPI.sol ├── migrations │ ├── 1_initial_migration.js │ └── 2_deploy_contracts.js ├── package-lock.json ├── package.json ├── shrinkwrap.yaml ├── test │ ├── delegated-math-test.js │ └── utils.js └── truffle.js ├── diesel-price ├── README.md ├── contracts │ ├── DieselPrice.sol │ ├── Migrations.sol │ └── provableAPI.sol ├── migrations │ ├── 1_initial_migration.js │ └── 2_deploy_contracts.js ├── package-lock.json ├── package.json ├── shrinkwrap.yaml ├── test │ ├── diesel-price-test.js │ └── utils.js └── truffle.js ├── encrypted-query ├── README.md ├── contracts │ ├── EncryptedQuery.sol │ ├── Migrations.sol │ └── provableAPI.sol ├── migrations │ ├── 1_initial_migration.js │ └── 2_deploy_contracts.js ├── package-lock.json ├── package.json ├── shrinkwrap.yaml ├── test │ ├── encrypted-query.js │ └── utils.js └── truffle.js ├── kraken-price-ticker ├── README.md ├── contracts │ ├── KrakenPriceTicker.sol │ ├── Migrations.sol │ └── provableAPI.sol ├── migrations │ ├── 1_initial_migration.js │ └── 2_deploy_contracts.js ├── package-lock.json ├── package.json ├── shrinkwrap.yaml ├── test │ ├── kraken-price-ticker-test.js │ └── utils.js └── truffle.js ├── random-datasource ├── README.md ├── contracts │ ├── Migrations.sol │ ├── RandomExample.sol │ └── provableAPI.sol ├── migrations │ ├── 1_initial_migration.js │ └── 2_deploy_contracts.js ├── package-lock.json ├── package.json ├── test │ ├── random-example-test.js │ └── utils.js └── truffle.js ├── streamr ├── README.md ├── computation-archive │ ├── archive.zip │ └── src │ │ ├── Dockerfile │ │ ├── index.js │ │ └── package.json ├── contracts │ ├── Migrations.sol │ ├── StreamrTweetsCounter.sol │ └── provableAPI.sol ├── migrations │ ├── 1_initial_migration.js │ └── 2_deploy_contracts.js ├── package-lock.json ├── package.json ├── shrinkwrap.yaml ├── test │ ├── streamr-tweets-counter-test.js │ └── utils.js └── truffle.js ├── url-requests ├── README.md ├── computation-archive │ ├── archive.zip │ └── src │ │ ├── Dockerfile │ │ └── url-requests.py ├── contracts │ ├── Migrations.sol │ ├── UrlRequests.sol │ └── provableAPI.sol ├── migrations │ ├── 1_initial_migration.js │ └── 2_deploy_contracts.js ├── package-lock.json ├── package.json ├── shrinkwrap.yaml ├── test │ ├── url-requests-tests.js │ └── utils.js └── truffle.js ├── wolfram-alpha ├── README.md ├── contracts │ ├── Migrations.sol │ ├── WolframAlpha.sol │ └── provableAPI.sol ├── migrations │ ├── 1_initial_migration.js │ └── 2_deploy_contracts.js ├── package-lock.json ├── package.json ├── shrinkwrap.yaml ├── test │ ├── utils.js │ └── wolframalpha-test.js └── truffle.js └── youtube-views ├── README.md ├── contracts ├── Migrations.sol ├── YoutubeViews.sol └── provableAPI.sol ├── migrations ├── 1_initial_migration.js └── 2_deploy_contracts.js ├── package-lock.json ├── package.json ├── shrinkwrap.yaml ├── test ├── utils.js └── youtube-views-test.js └── truffle.js /.ci/drone.yml: -------------------------------------------------------------------------------- 1 | kind: pipeline 2 | name: solc-diesel 3 | 4 | clone: 5 | disable: true 6 | 7 | steps: 8 | - name: clone 9 | image: docker:git 10 | commands: 11 | - git clone https://github.com/provable-things/ethereum-examples.git . 12 | - git checkout $DRONE_COMMIT -B $DRONE_BRANCH 13 | - git clone https://github.com/provable-things/ethereum-api.git 14 | 15 | - name: compile 16 | image: ethereum/solc:stable-alpine 17 | commands: 18 | - cd solidity 19 | - solc github.com/provable-things/ethereum-api/=/drone/src/ethereum-api/ DieselPrice.sol 20 | 21 | --- 22 | kind: pipeline 23 | name: solc-kraken 24 | 25 | clone: 26 | disable: true 27 | 28 | steps: 29 | - name: clone 30 | image: docker:git 31 | commands: 32 | - git clone https://github.com/provable-things/ethereum-examples.git . 33 | - git checkout $DRONE_COMMIT -B $DRONE_BRANCH 34 | - git clone https://github.com/provable-things/ethereum-api.git 35 | 36 | - name: compile 37 | image: ethereum/solc:stable-alpine 38 | commands: 39 | - cd solidity 40 | - solc github.com/provable-things/ethereum-api/=/drone/src/ethereum-api/ KrakenPriceTicker.sol 41 | 42 | --- 43 | kind: pipeline 44 | name: solc-wolfram 45 | 46 | clone: 47 | disable: true 48 | 49 | steps: 50 | - name: clone 51 | image: docker:git 52 | commands: 53 | - git clone https://github.com/provable-things/ethereum-examples.git . 54 | - git checkout $DRONE_COMMIT -B $DRONE_BRANCH 55 | - git clone https://github.com/provable-things/ethereum-api.git 56 | 57 | - name: compile 58 | image: ethereum/solc:stable-alpine 59 | commands: 60 | - cd solidity 61 | - solc github.com/provable-things/ethereum-api/=/drone/src/ethereum-api/ WolframAlpha.sol 62 | 63 | --- 64 | kind: pipeline 65 | name: solc-youtube 66 | 67 | clone: 68 | disable: true 69 | 70 | steps: 71 | - name: clone 72 | image: docker:git 73 | commands: 74 | - git clone https://github.com/provable-things/ethereum-examples.git . 75 | - git checkout $DRONE_COMMIT -B $DRONE_BRANCH 76 | - git clone https://github.com/provable-things/ethereum-api.git 77 | 78 | - name: compile 79 | image: ethereum/solc:stable-alpine 80 | commands: 81 | - cd solidity 82 | - solc github.com/provable-things/ethereum-api/=/drone/src/ethereum-api/ YoutubeViews.sol 83 | 84 | --- 85 | #kind: pipeline 86 | #name: provable-bitcoin 87 | # 88 | #steps: 89 | # - name: test-comp-bitcoin 90 | # image: provable/eth-ci 91 | # commands: 92 | # - /var/workspace/sv-wrapper.sh 93 | # - cd solidity/truffle-examples/bitcoin-balance 94 | # - npm link web3 95 | # - truffle test 96 | # 97 | #--- 98 | kind: pipeline 99 | name: provable-caller-pays 100 | 101 | steps: 102 | - name: test-url-caller-pays 103 | image: provable/eth-ci 104 | commands: 105 | - /var/workspace/sv-wrapper.sh & 106 | - apk add --no-cache g++ make python > /dev/null 107 | - cd solidity/truffle-examples/caller-pays-for-query 108 | - npm link web3 109 | - npm i --no-optional > /dev/null 110 | - while ! grep -q "Listening @ 0x" /tmp/bridge.out; do sleep 1; done 111 | - truffle test 112 | 113 | --- 114 | kind: pipeline 115 | name: provable-math 116 | 117 | steps: 118 | - name: test-comp-math 119 | image: provable/eth-ci 120 | commands: 121 | - /var/workspace/sv-wrapper.sh 122 | - cd solidity/truffle-examples/delegated-math 123 | - npm link web3 124 | - truffle test 125 | 126 | --- 127 | kind: pipeline 128 | name: provable-diesel 129 | 130 | steps: 131 | - name: test-url-diesel 132 | image: provable/eth-ci 133 | commands: 134 | - /var/workspace/sv-wrapper.sh 135 | - cd solidity/truffle-examples/diesel-price 136 | - npm link web3 137 | - truffle test 138 | 139 | --- 140 | #kind: pipeline 141 | #name: provable-ap-kraken 142 | # 143 | #steps: 144 | # - name: test-url-ap-kraken 145 | # image: provable/eth-ci 146 | # commands: 147 | # - /var/workspace/sv-wrapper.sh 148 | # - cd solidity/truffle-examples/kraken-price-ticker 149 | # - npm link web3 150 | # - truffle test 151 | # 152 | #--- 153 | kind: pipeline 154 | name: provable-random 155 | 156 | steps: 157 | - name: test-random 158 | image: provable/eth-ci 159 | commands: 160 | - cd solidity/truffle-examples/random-datasource 161 | - npm i --no-optional -g dotenv 162 | - npm link web3 truffle-hdwallet-provider dotenv 163 | - echo "mnemonic = coast mind object you word swarm dinosaur cereal wash corn tape quarter" >> .env 164 | - echo "infuraKey = dff2672a2a7e43f193a374a16c485c33" >> .env 165 | - truffle test --network rinkeby 166 | 167 | --- 168 | kind: pipeline 169 | name: provable-streamr 170 | 171 | steps: 172 | - name: test-comp-streamr 173 | image: provable/eth-ci 174 | commands: 175 | - /var/workspace/sv-wrapper.sh 176 | - cd solidity/truffle-examples/streamr 177 | - npm link web3 178 | - truffle test 179 | 180 | --- 181 | #kind: pipeline 182 | #name: provable-requests 183 | # 184 | #steps: 185 | # - name: test-comp-ap-requests 186 | # image: provable/eth-ci 187 | # commands: 188 | # - /var/workspace/sv-wrapper.sh 189 | # - cd solidity/truffle-examples/url-requests 190 | # - npm link web3 191 | # - truffle test 192 | # 193 | #--- 194 | kind: pipeline 195 | name: provable-wolfram 196 | 197 | steps: 198 | - name: test-wolfram 199 | image: provable/eth-ci 200 | commands: 201 | - /var/workspace/sv-wrapper.sh 202 | - cd solidity/truffle-examples/wolfram-alpha 203 | - npm link web3 204 | - truffle test 205 | 206 | --- 207 | kind: pipeline 208 | name: provable-youtube 209 | 210 | steps: 211 | - name: test-url-youtube 212 | image: provable/eth-ci 213 | commands: 214 | - /var/workspace/sv-wrapper.sh 215 | - cd solidity/truffle-examples/youtube-views 216 | - npm link web3 217 | - truffle test 218 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | *.sw* 3 | *.log 4 | .node* 5 | **/build 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## __Provable Ethereum Examples__ [![Join the chat at https://gitter.im/oraclize/ethereum-api](https://badges.gitter.im/Join%21Chat.svg)](https://gitter.im/oraclize/ethereum-api?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Info@Provable.xyz](https://camo.githubusercontent.com/5e89710c6ae9ce0da822eec138ee1a2f08b34453/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646f63732d536c6174652d627269676874677265656e2e737667)](http://docs.provable.xyz) [![Contributions Welcome!](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/oraclize/ethereum-examples/issues) [![HitCount](http://hits.dwyl.io/oraclize/ethereum-examples.svg)](http://hits.dwyl.io/oraclize/ethereum-examples) 2 | 3 | Here you can find some code examples showing just how __easy__ it is to integrate the __Provable__ Service into your Ethereum smart-contracts! Thanks to our [__Ethereum API__](https://github.com/provable-things/ethereum-api) using __Provable__ in your projects couldn't be more straightforward. In Solidity it is as simple as inheriting the __`usingProvable`__ contract like so: 4 | 5 | ``` 6 | contract YourSmartContract is usingProvable { 7 | // … 8 | } 9 | ``` 10 | 11 | This provisions your contract with the __`provable_query()`__ function (and many others!), which makes it trivial to leverage our technology straight away. Head into the __`Solidity`__ directory for more information. 12 | 13 | :computer: Happy developing! 14 | 15 | *** 16 | 17 | ### __Serpent__ 18 | 19 | :skull: __CAUTION__: It is highly recommended to avoid using Serpent, especially in production. The examples herein have been left for reasons of posterity but support for it is no longer maintained as Serpent is considered outdated and audits have shown it to be flawed. Use them at your own risk! 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "oraclize-eth-examples", 3 | "version": "0.6.0", 4 | "description": "A repository containing examples of how to use the Oraclize service in ethereum smart-contracts.", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/oraclize/ethereum-examples.git" 8 | }, 9 | "bugs": { 10 | "url": "https://github.com/oraclize/ethereum-examples/issues" 11 | }, 12 | "homepage": "http://www.oraclize.it" 13 | } 14 | -------------------------------------------------------------------------------- /serpent-deprecated/DieselPricePeg.se: -------------------------------------------------------------------------------- 1 | inset("dev.oraclize.it/api.se") 2 | 3 | data owner 4 | data DieselPriceUSD 5 | 6 | def init(): 7 | oraclize_setNetwork(networkID_auto) 8 | oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS) 9 | self.owner = msg.sender 10 | update(0) 11 | 12 | def __callback(myid:bytes32, result:string, proof:bytes): 13 | if(msg.sender != oraclize_cbAddress()): 14 | return 15 | else: 16 | save(self.DieselPriceUSD, result, chars=len(result)) 17 | update(60*10) 18 | 19 | macro update($delay): 20 | oraclize_query($delay,text("URL"),text("xml(https://www.fueleconomy.gov/ws/rest/fuelprices).fuelPrices.diesel")) 21 | 22 | def kill(): 23 | if(msg.sender==self.owner): 24 | suicide(msg.sender) 25 | -------------------------------------------------------------------------------- /serpent-deprecated/KrakenPriceTicker.se: -------------------------------------------------------------------------------- 1 | inset("dev.oraclize.it/api.se") 2 | 3 | data owner 4 | data ETHXBT 5 | 6 | def init(): 7 | oraclize_setNetwork(networkID_auto) 8 | self.owner = msg.sender 9 | #oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS) 10 | update() 11 | 12 | def __callback(myid:bytes32, result:string): 13 | if (msg.sender != oraclize_cbAddress()): 14 | return 15 | else: 16 | save(self.ETHXBT, result, chars=len(result)) 17 | update() 18 | 19 | macro update(): 20 | oraclize_query(60, text("URL"), text("json(https://api.kraken.com/0/public/Ticker?pair=ETHXBT).result.XETHXXBT.c.0")) 21 | 22 | def kill(): 23 | if(msg.sender==self.owner): 24 | suicide(msg.sender) 25 | -------------------------------------------------------------------------------- /serpent-deprecated/README.md: -------------------------------------------------------------------------------- 1 | ## :skull: __CAUTION__ 2 | 3 | It is highly recommended to avoid using Serpent, especially in production. The examples herein have been left for historical reasons but support for it is no longer maintained as Serpent is considered outdated and audits have shown it to be flawed. Use them at your own risk! 4 | -------------------------------------------------------------------------------- /solidity/DieselPrice.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >= 0.5.0 < 0.6.0; 2 | 3 | import "github.com/provable-things/ethereum-api/provableAPI.sol"; 4 | 5 | contract DieselPrice is usingProvable { 6 | 7 | uint public dieselPriceUSD; 8 | 9 | event LogNewDieselPrice(string price); 10 | event LogNewProvableQuery(string description); 11 | 12 | constructor() 13 | public 14 | { 15 | update(); // First check at contract creation... 16 | } 17 | 18 | function __callback( 19 | bytes32 _myid, 20 | string memory _result 21 | ) 22 | public 23 | { 24 | require(msg.sender == provable_cbAddress()); 25 | emit LogNewDieselPrice(_result); 26 | dieselPriceUSD = parseInt(_result, 2); // Let's save it as cents... 27 | // Now do something with the USD Diesel price... 28 | } 29 | 30 | function update() 31 | public 32 | payable 33 | { 34 | emit LogNewProvableQuery("Provable query was sent, standing by for the answer..."); 35 | provable_query("URL", "xml(https://www.fueleconomy.gov/ws/rest/fuelprices).fuelPrices.diesel"); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /solidity/KrakenPriceTicker.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >= 0.5.0 < 0.6.0; 2 | 3 | import "github.com/provable-things/ethereum-api/provableAPI.sol"; 4 | 5 | contract KrakenPriceTicker is usingProvable { 6 | 7 | string public priceETHXBT; 8 | 9 | event LogNewProvableQuery(string description); 10 | event LogNewKrakenPriceTicker(string price); 11 | 12 | constructor() 13 | public 14 | { 15 | provable_setProof(proofType_Android | proofStorage_IPFS); 16 | update(); // Update price on contract creation... 17 | } 18 | 19 | function __callback( 20 | bytes32 _myid, 21 | string memory _result, 22 | bytes memory _proof 23 | ) 24 | public 25 | { 26 | require(msg.sender == provable_cbAddress()); 27 | update(); // Recursively update the price stored in the contract... 28 | priceETHXBT = _result; 29 | emit LogNewKrakenPriceTicker(priceETHXBT); 30 | } 31 | 32 | function update() 33 | public 34 | payable 35 | { 36 | if (provable_getPrice("URL") > address(this).balance) { 37 | emit LogNewProvableQuery("Provable query was NOT sent, please add some ETH to cover for the query fee!"); 38 | } else { 39 | emit LogNewProvableQuery("Provable query was sent, standing by for the answer..."); 40 | provable_query(60, "URL", "json(https://api.kraken.com/0/public/Ticker?pair=ETHXBT).result.XETHXXBT.c.0"); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /solidity/README.md: -------------------------------------------------------------------------------- 1 | ## __Solidity Examples__ 2 | 3 | Here you can find various Solidity examples showing how to use the __Oraclize API__ in your smart-contracts. Simply copy one of the __`.sol`__ files into the [__Remix IDE__](remix.ethereum.org) online Solidity compiler to see them in action! Then fire up the [__Oraclize-Plugin__](https://blog.oraclize.it/built-for-developers-21e414ad2841) (which you'll find under the settings tab) and you'll be able to see your __Oraclize__ queries working in real time! 4 | 5 | Alternatively, if you prefer to develop locally, browse into the __`truffle-examples`__ directory to see how __Oraclize__ works in a [__Truffle__](https://www.truffleframework.com/) development environment. Each self-contained example comes with full test coverage so you can see how to create robust, data-rich smart-contracts that leverage the __Oraclize__ service fully. 6 | 7 | :computer: __Happy developing!__ 8 | 9 | *** 10 | 11 | ### :black_nib: __Features!__ 12 | 13 | The following is a list of the features you can find amongst the samples in this repo, along with links to the pertinent example(s): 14 | 15 | * Sending simple __URL Queries!__ [#1](./DieselPrice.sol). 16 | * Scheduling a query for a __future date__! [#1](./KrakenPriceTicker.sol). 17 | * Sending calls __recursively__! [#1](./KrakenPriceTicker.sol). 18 | * Requesting a __TLSNotary__ authenticity __proof!__ [#1](./computation-datasource/delegated-math/DelegatedMath.sol), [#2](./compuation-datasource/paypal/PaypalExample.sol), & [#3](./contracts/GasPriceOracle.sol). 19 | * Requesting an __Android__ authenticity __proof!__ [#1](./KrakenPriceTicker.sol) & [#2](./computation-datasource/url-requests/UrlRequests.sol). 20 | * Leveraging __JSONPATH__ parsing helpers! [#1](./KrakenPriceTicker.sol). 21 | * Using __IPFS__ for proof storage! [#1](./UrlRequests.sol), [#2](./KrakenPriceTicker.sol) & [#3](./compuation-datasource/delegated-math/DelegatedMath.sol). 22 | * Leveraging __XPATH__ parsing helpers! [#1](./DieselPricePeg.sol) & [#2](./YoutubeViews.sol). 23 | * Using the __computation datasouce__! [#1](./computation-datasource/url-requests/urlRequests.sol), [#2](./computation-datasource/streamr/StreamrTweetsCounter.sol) & [#3](./computation-datasource/bitcoin/BitcoinBalanceExample.sol). 24 | * Using the __WolframAlpha__ datasource! [#1](./WolframAlpha.sol). 25 | 26 | __Coming Soon!__ 27 | 28 | * Nested queries! 29 | * Full query encryption! 30 | * Partial query encryption! 31 | * Leveraging BINARY_SLICE parsing helpers! 32 | 33 | *** 34 | 35 | ### :loudspeaker: __Support__ 36 | 37 | If you need any help when working with the examples here, you can always get timely support in the [__Oraclize Gitter channel here__](https://gitter.im/oraclize)! 38 | -------------------------------------------------------------------------------- /solidity/WolframAlpha.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >= 0.5.0 < 0.6.0; 2 | 3 | import "github.com/provable-things/ethereum-api/provableAPI.sol"; 4 | 5 | contract WolframAlpha is usingProvable { 6 | 7 | string public temperature; 8 | 9 | event LogNewProvableQuery(string description); 10 | event LogNewTemperatureMeasure(string temperature); 11 | 12 | constructor() 13 | public 14 | { 15 | update(); // Update on contract creation... 16 | } 17 | 18 | function __callback( 19 | bytes32 _myid, 20 | string memory _result 21 | ) 22 | public 23 | { 24 | require(msg.sender == provable_cbAddress()); 25 | temperature = _result; 26 | emit LogNewTemperatureMeasure(temperature); 27 | // Do something with the temperature measure... 28 | } 29 | 30 | function update() 31 | public 32 | payable 33 | { 34 | emit LogNewProvableQuery("Provable query was sent, standing by for the answer..."); 35 | provable_query("WolframAlpha", "temperature in London"); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /solidity/YoutubeViews.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >= 0.5.0 < 0.6.0; 2 | 3 | import "github.com/provable-things/ethereum-api/provableAPI.sol"; 4 | 5 | contract YoutubeViews is usingProvable { 6 | 7 | string public viewsCount; 8 | 9 | event LogYoutubeViewCount(string views); 10 | event LogNewProvableQuery(string description); 11 | 12 | constructor() 13 | public 14 | { 15 | update(); // Update views on contract creation... 16 | } 17 | 18 | function __callback( 19 | bytes32 _myid, 20 | string memory _result 21 | ) 22 | public 23 | { 24 | require(msg.sender == provable_cbAddress()); 25 | viewsCount = _result; 26 | emit LogYoutubeViewCount(viewsCount); 27 | // Do something with viewsCount, like tipping the author if viewsCount > X? 28 | } 29 | 30 | function update() 31 | public 32 | payable 33 | { 34 | emit LogNewProvableQuery("Provable query was sent, standing by for the answer..."); 35 | provable_query("URL", 'html(https://www.youtube.com/watch?v=9bZkp7q19f0).xpath(//*[contains(@class, "watch-view-count")]/text())'); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /solidity/computation-datasource/bitcoin/BitcoinBalanceExample.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >= 0.5.0 < 0.6.0; 2 | 3 | import "github.com/oraclize/ethereum-api/oraclizeAPI.sol"; 4 | 5 | contract BitcoinBalanceExample is usingOraclize { 6 | 7 | uint256 public balance; 8 | 9 | event LogBitcoinAddressBalance(uint _balance); 10 | 11 | constructor() 12 | public 13 | { 14 | getBalance("3D2oetdNuZUqQHPJmcMDDHYoqkyNVsFk9r"); 15 | } 16 | 17 | function __callback( 18 | bytes32 _myid, 19 | string memory _result 20 | ) 21 | public 22 | { 23 | require(msg.sender == oraclize_cbAddress()); 24 | balance = parseInt(_result, 8); 25 | emit LogBitcoinAddressBalance(balance); 26 | } 27 | 28 | function getBalance( 29 | string memory _bitcoinAddress 30 | ) 31 | public 32 | payable 33 | { 34 | oraclize_query("computation", ["QmNecqR52vCsxshJx6acki6Nhg8zYLiRco4fwt22Yq2Qiz", _bitcoinAddress]); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /solidity/computation-datasource/bitcoin/computation-archive/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | MAINTAINER Provable "info@provable.xyz" 3 | RUN apt-get update && \ 4 | apt-get install -y \ 5 | curl \ 6 | jq 7 | COPY script.sh . 8 | ENTRYPOINT ["./script.sh"] 9 | -------------------------------------------------------------------------------- /solidity/computation-datasource/bitcoin/computation-archive/archive.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/provable-things/ethereum-examples/f3f650836016c43be3b18ba2819a5609078b0447/solidity/computation-datasource/bitcoin/computation-archive/archive.zip -------------------------------------------------------------------------------- /solidity/computation-datasource/bitcoin/computation-archive/script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | curl --silent https://blockstream.info/api/address/$ARG0 \ 4 | | jq '.chain_stats.funded_txo_sum - .chain_stats.spent_txo_sum' 5 | -------------------------------------------------------------------------------- /solidity/computation-datasource/delegated-math/DelegatedMath.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >= 0.5.0 < 0.6.0; 2 | 3 | import "github.com/oraclize/ethereum-api/oraclizeAPI.sol"; 4 | 5 | contract DelegatedMath is usingOraclize { 6 | 7 | event LogOperationResult(uint result); 8 | 9 | constructor() 10 | public 11 | { 12 | oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS); 13 | delegateOperation("32", "125"); 14 | } 15 | 16 | function __callback( 17 | bytes32 _myid, 18 | string memory _result, 19 | bytes memory _proof 20 | ) 21 | public 22 | { 23 | require(msg.sender == oraclize_cbAddress()); 24 | emit LogOperationResult(parseInt(_result)); 25 | } 26 | 27 | function delegateOperation( 28 | string memory _firstOperand, 29 | string memory _secondOperand 30 | ) 31 | public 32 | payable 33 | { 34 | oraclize_query("computation", ["Qmc8jmuT47cPWadF8ZhErGXj7J4VEp5H29knukCGirsN19", _firstOperand, _secondOperand]); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /solidity/computation-datasource/delegated-math/computation-archive/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | MAINTAINER Oraclize "info@oraclize.it" 3 | 4 | RUN apt-get update && apt-get install bc 5 | CMD echo $ARG0 + $ARG1 | /usr/bin/bc \ 6 | && exit 0; 7 | -------------------------------------------------------------------------------- /solidity/computation-datasource/delegated-math/computation-archive/archive.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/provable-things/ethereum-examples/f3f650836016c43be3b18ba2819a5609078b0447/solidity/computation-datasource/delegated-math/computation-archive/archive.zip -------------------------------------------------------------------------------- /solidity/computation-datasource/paypal/PaypalExample.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >= 0.5.0 < 0.6.0; 2 | 3 | import "github.com/oraclize/ethereum-api/oraclizeAPI.sol"; 4 | 5 | contract PaypalExample is usingOraclize { 6 | 7 | event LogPaymentResult(string payment_info); 8 | 9 | constructor() 10 | public 11 | { 12 | oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS); 13 | createPayment("3", "5"); 14 | } 15 | 16 | function __callback( 17 | bytes32 _myid, 18 | string memory _result, 19 | bytes memory _proof 20 | ) 21 | public 22 | { 23 | require(msg.sender == oraclize_cbAddress()); 24 | emit LogPaymentResult(_result); 25 | } 26 | /** 27 | * @dev This example will require a newly generated hookb.in, the following 28 | * is just a placeholder 29 | */ 30 | function createPayment( 31 | string memory _unitPrice, 32 | string memory _numberUnits 33 | ) 34 | public 35 | payable 36 | { 37 | string memory ipFetcher = "https://hookb.in/Zm8d62bn"; 38 | oraclize_query("computation", ["QmdWaRFWsSjsLSSt8TMvbn7pm2MLCVFN5M2eVUE2Ph6KoD", _unitPrice, _numberUnits, "USD", ipFetcher]); 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /solidity/computation-datasource/paypal/computation-archive/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | MAINTAINER Oraclize "info@oraclize.it" 3 | 4 | RUN apt-get update && apt-get -y install python libffi6 libffi-dev python-dev python-pip libssl-dev wget build-essential 5 | RUN pip install paypalrestsdk \ 6 | && pip install flask \ 7 | && pip install pyOpenSSL 8 | COPY pay.py /tmp/ 9 | ENV FLASK_APP="/tmp/pay.py" 10 | CMD /usr/bin/wget --no-check-certificate -O /dev/null -q "$ARG3" > /dev/null 2> /dev/null; /usr/bin/python -m flask run --host=0.0.0.0 --port 8090 > /dev/null 2> /dev/null && cat /tmp/output 11 | -------------------------------------------------------------------------------- /solidity/computation-datasource/paypal/computation-archive/archive.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/provable-things/ethereum-examples/f3f650836016c43be3b18ba2819a5609078b0447/solidity/computation-datasource/paypal/computation-archive/archive.zip -------------------------------------------------------------------------------- /solidity/computation-datasource/paypal/computation-archive/pay.py: -------------------------------------------------------------------------------- 1 | import paypalrestsdk as pp 2 | from flask import Flask 3 | from flask import request 4 | import requests 5 | import os 6 | import sys 7 | import json 8 | 9 | app = Flask(__name__) 10 | 11 | # reduce logs to standard output 12 | import logging 13 | log = logging.getLogger('werkzeug') 14 | log.setLevel(logging.CRITICAL) 15 | 16 | # get instance ip 17 | r = requests.get('https://api.ipify.org?format=json') 18 | data = r.json() 19 | ip = data['ip'] 20 | 21 | if __name__ == "__main__": 22 | app.run() 23 | 24 | # Create payment and configure paypal sdk. ARG0 is the price of the purchased item in the currency specified by ARG1. ARG0 is the first parameter passed to the oraclize_query, ARG1 is the second one. 25 | pp.configure({ 26 | "mode": "sandbox", # sandbox or live 27 | "client_id": "ARhkpXV_LYHKV51sXjvTlslgk4r2KmTwAiDbLCkTh6xlGjOfJ2ycixzD6eJK6w5_Wb3GkKX6GBs-8j85", 28 | "client_secret": "ECLxwuRHQA6ntAYYuDj2W87PAKuOHLYRwzrjuSC2jJdQWFzQA2qulZnJgzjux4BJjBQEamzOT4A5xXBy" }) 29 | 30 | payment = pp.Payment({ 31 | "intent": "sale", 32 | "redirect_urls": { 33 | "return_url":"http://" + ip + ":8090/confirm_payment", 34 | "cancel_url":"http://" + ip + ":8090/cancel_payment" 35 | }, 36 | "payer": { 37 | "payment_method": "paypal" 38 | }, 39 | "transactions": [{ 40 | "item_list": { 41 | "items": [{ 42 | "name": "item", 43 | "sku": "item", 44 | "price": str(os.environ['ARG0']), 45 | "currency": str(os.environ['ARG2']), 46 | "quantity": str(os.environ['ARG1'])}]}, 47 | "amount": { 48 | "total": int(os.environ['ARG0'])*int(os.environ['ARG1']), 49 | "currency": str(os.environ['ARG2'])}, 50 | "description": "This is the payment transaction description." }]}) 51 | 52 | # To be called to shutdown the application 53 | def shutdown(): 54 | func = request.environ.get('werkzeug.server.shutdown') 55 | func() 56 | 57 | # It creates an API endpoint where the payment url can be fetched 58 | @app.route("/create_payment") 59 | def create(): 60 | if payment.create(): 61 | payment_id = payment.id; 62 | return payment.links[1].href 63 | else: 64 | return payment.error 65 | 66 | # Confirm payment endopoint: called by paypal on payment confirmation received. 67 | # It finalizes the payment on the merchant side, returning the status, payer_id, payment_id and payer_email 68 | @app.route("/confirm_payment") 69 | def confirm(): 70 | payment_id = request.args.get('paymentId','') 71 | payer_id = request.args.get('PayerID','') 72 | payment = pp.Payment.find(payment_id) 73 | if payment.execute({"payer_id": payer_id}): 74 | f = open('/tmp/output','w') 75 | payer_email = payment.payer.payer_info.email 76 | data = {'status': 'received', 'payer_id': payer_id, 'payment_id': payment_id, 'payer_email': payer_email} 77 | f.write(json.dumps(data)) 78 | shutdown() 79 | return 'Valid_Payment' 80 | else: 81 | data = {'status': 'failed', 'payer_id': payer_id, 'payment_id': payment_id} 82 | print(payment.error) 83 | return 'Error' 84 | 85 | # Cancel payment API endpoint: called by paypal on payment failure 86 | @app.route("/cancel_payment") 87 | def cancel(): 88 | payment_id = request.args.get('paymentId','') 89 | payer_id = request.args.get('PayerID','') 90 | data = {'status': 'failed', 'payer_id': payer_id, 'payment_id': payment_id, 'payer_email': payer_email} 91 | f.write(json.dumps(data)) 92 | shutdown() 93 | return 'Cancel_Payment' 94 | -------------------------------------------------------------------------------- /solidity/computation-datasource/streamr/README.md: -------------------------------------------------------------------------------- 1 | ### Using streamr with Oraclize 2 | 3 | Streamr allows you to publish continuous datastreams and interact with them. Using Oraclize, you may import these streams to Ethereum. 4 | 5 | #### StreamrTweetsCounter.sol 6 | 7 | > count BTC-specific tweets since query request 8 | 9 | Utilizes Oraclize's computation datasource and subscribes to streamr's public `BTC Tweets` using the `streamr-client` via websockets. The computation archive is available in the `comp-archive` directory for inspection. By leveraging the computation datasource and pairing it with a datastream from streamr, you are able to emulate a streamr canvas backed by authenticity proofs right on the blockchain. 10 | 11 | The computation query, within the contract, takes a duration parameter. Currently hardcoded as 1, which is equivalent to 1 minute. This can be changed, but note that Oraclize computation instances have a time limit on them, so ensure any value used is below the time limit set (for up to date time limit, refer to the general Oraclize documentation). 12 | -------------------------------------------------------------------------------- /solidity/computation-datasource/streamr/StreamrTweetsCounter.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >= 0.5.0 < 0.6.0; 2 | 3 | import "github.com/oraclize/ethereum-api/oraclizeAPI.sol"; 4 | 5 | contract StreamrTweetsCounter is usingOraclize { 6 | 7 | uint public numberOfTweets; 8 | 9 | event LogResult(string result); 10 | event LogNewOraclizeQuery(string description); 11 | 12 | constructor() 13 | public 14 | { 15 | update(); // First check at contract creation... 16 | } 17 | 18 | function __callback( 19 | bytes32 _myid, 20 | string memory _result 21 | ) 22 | public 23 | { 24 | require(msg.sender == oraclize_cbAddress()); 25 | numberOfTweets = parseInt(_result); 26 | emit LogResult(_result); 27 | } 28 | 29 | function update() 30 | public 31 | payable 32 | { 33 | if (oraclize_getPrice("computation") > address(this).balance) { 34 | emit LogNewOraclizeQuery("Oraclize query was NOT sent, please add some ETH to cover for the query fee"); 35 | } else { 36 | emit LogNewOraclizeQuery("Oraclize query was sent, standing by for the answer..."); 37 | oraclize_query( 38 | "computation", 39 | [ 40 | "QmWFV2UrcUFMFk5R4iTZdusTRsvqohFwHjyXNH1Yu9v3Nm", // The ipfs multihash of archive. 41 | "1" // Desired duration to run the stream (in minutes). 42 | ] 43 | ); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /solidity/computation-datasource/streamr/computation-archive/archive.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/provable-things/ethereum-examples/f3f650836016c43be3b18ba2819a5609078b0447/solidity/computation-datasource/streamr/computation-archive/archive.zip -------------------------------------------------------------------------------- /solidity/computation-datasource/streamr/computation-archive/src/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mhart/alpine-node:8 2 | MAINTAINER Oraclize "info@oraclize.it" 3 | 4 | COPY index.js package.json /tmp/ 5 | WORKDIR /tmp/ 6 | RUN yarn install 7 | CMD node index.js $ARG0 8 | -------------------------------------------------------------------------------- /solidity/computation-datasource/streamr/computation-archive/src/index.js: -------------------------------------------------------------------------------- 1 | global.WebSocket = require('ws') 2 | var StreamrClient = require('streamr-client') 3 | 4 | var optMinutes 5 | console.log(process.argv) 6 | 7 | if(!isNaN(parseInt(process.argv[2]))) { 8 | var parsed = parseInt(process.argv[2]); 9 | console.log('User-defined duration argument found... Setting duration to ' + parsed + ' minutes') 10 | optMinutes = parsed 11 | } else { 12 | console.log('No appropriate duration defined by user, falling back to 1 minute...') 13 | optMinutes = 1 14 | } 15 | 16 | var client = new StreamrClient() 17 | var ctr = 0 18 | var start 19 | var duration = optMinutes * 60 * 1000 20 | 21 | var subscription = client.subscribe( 22 | 'ln2g8OKHSdi7BcL-bcnh2g', 23 | function(message) { 24 | 25 | if (Date.now() > start + duration) { 26 | console.log(ctr) 27 | process.exit(0) 28 | } 29 | 30 | ctr++ 31 | } 32 | ) 33 | 34 | // Event binding examples 35 | client.on('connected', function() { 36 | console.log('A connection has been established!') 37 | }) 38 | 39 | subscription.on('subscribed', function() { 40 | console.log('Subscribed to '+subscription.streamId) 41 | start = Date.now() 42 | }) 43 | -------------------------------------------------------------------------------- /solidity/computation-datasource/streamr/computation-archive/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "streamrTweets", 3 | "version": "0.0.1", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "dependencies": { 7 | "socket.io": "^2.0.2", 8 | "streamr-client": "^0.9.3" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /solidity/computation-datasource/url-requests/UrlRequests.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >= 0.5.0 < 0.6.0; 2 | 3 | import "github.com/oraclize/ethereum-api/oraclizeAPI.sol"; 4 | 5 | contract UrlRequests is usingOraclize { 6 | 7 | event LogNewOraclizeQuery(string description); 8 | event LogResult(string result); 9 | 10 | constructor() 11 | public 12 | { 13 | oraclize_setProof(proofType_Android | proofStorage_IPFS); 14 | } 15 | 16 | function __callback( 17 | bytes32 _myid, 18 | string memory _result, 19 | bytes memory _proof 20 | ) 21 | public 22 | { 23 | require(msg.sender == oraclize_cbAddress()); 24 | emit LogResult(_result); 25 | } 26 | 27 | function request( 28 | string memory _query, 29 | string memory _method, 30 | string memory _url, 31 | string memory _kwargs 32 | ) 33 | public 34 | payable 35 | { 36 | if (oraclize_getPrice("computation") > address(this).balance) { 37 | emit LogNewOraclizeQuery("Oraclize query was NOT sent, please add some ETH to cover for the query fee"); 38 | } else { 39 | emit LogNewOraclizeQuery("Oraclize query was sent, standing by for the answer..."); 40 | oraclize_query("computation", 41 | [_query, 42 | _method, 43 | _url, 44 | _kwargs] 45 | ); 46 | } 47 | } 48 | /** 49 | * @dev Sends a custom content-type in header and returns the header used 50 | * as result. Wrap first argument of computation ds with helper needed, 51 | * such as json in this case 52 | */ 53 | function requestCustomHeaders() 54 | public 55 | payable 56 | { 57 | request("json(QmdKK319Veha83h6AYgQqhx9YRsJ9MJE7y33oCXyZ4MqHE).headers", 58 | "GET", 59 | "http://httpbin.org/headers", 60 | "{'headers': {'content-type': 'json'}}" 61 | ); 62 | } 63 | 64 | function requestBasicAuth() 65 | public 66 | payable 67 | { 68 | request("QmdKK319Veha83h6AYgQqhx9YRsJ9MJE7y33oCXyZ4MqHE", 69 | "GET", 70 | "http://httpbin.org/basic-auth/myuser/secretpass", 71 | "{'auth': ('myuser','secretpass'), 'headers': {'content-type': 'json'}}" 72 | ); 73 | } 74 | 75 | function requestPost() 76 | public 77 | payable 78 | { 79 | request("QmdKK319Veha83h6AYgQqhx9YRsJ9MJE7y33oCXyZ4MqHE", 80 | "POST", 81 | "https://api.postcodes.io/postcodes", 82 | '{"json": {"postcodes" : ["OX49 5NU"]}}' 83 | ); 84 | } 85 | 86 | function requestPut() 87 | public 88 | payable 89 | { 90 | request("QmdKK319Veha83h6AYgQqhx9YRsJ9MJE7y33oCXyZ4MqHE", 91 | "PUT", 92 | "http://httpbin.org/anything", 93 | "{'json' : {'testing':'it works'}}" 94 | ); 95 | } 96 | 97 | function requestCookies() 98 | public 99 | payable 100 | { 101 | request("QmdKK319Veha83h6AYgQqhx9YRsJ9MJE7y33oCXyZ4MqHE", 102 | "GET", 103 | "http://httpbin.org/cookies", 104 | "{'cookies' : {'thiscookie':'should be saved and visible :)'}}" 105 | ); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /solidity/computation-datasource/url-requests/computation-archive/archive.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/provable-things/ethereum-examples/f3f650836016c43be3b18ba2819a5609078b0447/solidity/computation-datasource/url-requests/computation-archive/archive.zip -------------------------------------------------------------------------------- /solidity/computation-datasource/url-requests/computation-archive/src/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM frolvlad/alpine-python3 2 | MAINTAINER Oraclize "info@oraclize.it" 3 | 4 | COPY url-requests.py / 5 | 6 | RUN pip3 install requests 7 | CMD python ./url-requests.py 8 | -------------------------------------------------------------------------------- /solidity/computation-datasource/url-requests/computation-archive/src/url-requests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import ast 4 | import requests 5 | import os 6 | 7 | # parse env args 8 | arg = [os.environ['ARG0'], os.environ['ARG1']] 9 | 10 | # parse 3rd arg into kwargs if available 11 | if 'ARG2' in os.environ: kwargs = ast.literal_eval(os.environ['ARG2']) 12 | else: kwargs = {} 13 | 14 | # attempt the request 15 | req = requests.request(arg[0], arg[1], **kwargs) 16 | 17 | # print text result on single line 18 | print(req.text.replace('\n','')) 19 | 20 | # option if always json 21 | # print(json.loads(req.text)) 22 | -------------------------------------------------------------------------------- /solidity/gas-price-oracle/README.md: -------------------------------------------------------------------------------- 1 | # __A Gas Price Oracle leveraging Oraclize__ 2 |   3 | 4 | ## :computer: __What this is:__ 5 | 6 | Designed for the ethereum community, this is an Oraclize-powered and Oraclize-funded ethereum gas-price oracle for providing ate on-chain gas prices. The smart-contract allows anyone to query the EthGasStation.info for up-to-date gas prices at any time - other smart-contracts can make queries too! In addition, an ongoing recursive query funded by Oraclize will ensure the latest gas prices are updated in the contract every six hours - enjoy! 7 | 8 | 9 |   10 | 11 | --- 12 | 13 |   14 | 15 | ### :fuelpump: __Gas Prices__: 16 | 17 | **❍** Requires ~ 3,600,000 gas for deployment. 18 | 19 | **❍** Gas for normal query to gas station is ~ 111,000. 20 | 21 | **❍** Gas for restarting the recursive chain is ~~170,000~~ 111,000 too now. 22 | 23 | **❍** _Recursive_ callbacks cost ~170409 so limit is 171000. 24 | 25 | **❍** _Non recursive_ callbacks cost ~ 85,350 so their limit is set at 87,000. 26 | 27 | **❍** Recursive restarting queries also refund excess ETH, meaning if the recursions stopped due to insufficient ETH balance, it should be topped up first. 28 | 29 |   30 | 31 | *** 32 | 33 |   34 | 35 | 36 | 37 | ### :mortar_board: __Instructions to test:__ 38 | 39 | ![The passing tests!!](gas-price-oracle-tests.jpg) 40 | 41 | **Pre-flight.** Make sure you have Truffle 5 installed globally: 42 | 43 | **`❍ npm install -g truffle@beta`** 44 | 45 | **1.** Clone the ethereum-examples repo: 46 | 47 | **`❍ git clone https://github.com/oraclize/ethereum-examples.git`** 48 | 49 | **2.** Switch into the gas-price-oracle directory: 50 | 51 | **`❍ cd ethereum-examples/solidity/gas-price-oracle`** 52 | 53 | **3.** Install dependencies: 54 | 55 | **`❍ npm install`** 56 | 57 | **4.** Start Truffle via: 58 | 59 | **`❍ truffle develop`** 60 | 61 | **5.** Start the Ethereum bridge in a new console via: 62 | 63 | **`❍ npm run bridge`** 64 | 65 | **6.** Once bridge is spooled up, back to first console to run the tests via: 66 | 67 | **`❍ truffle_develop> test`** -------------------------------------------------------------------------------- /solidity/gas-price-oracle/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.18; 2 | 3 | 4 | contract Migrations { 5 | address public owner; 6 | uint public last_completed_migration; 7 | 8 | function Migrations() public { 9 | owner = msg.sender; 10 | } 11 | 12 | modifier restricted() { 13 | if (msg.sender == owner) _; 14 | } 15 | 16 | function setCompleted(uint completed) public restricted { 17 | last_completed_migration = completed; 18 | } 19 | 20 | function upgrade(address new_address) public restricted { 21 | Migrations upgraded = Migrations(new_address); 22 | upgraded.setCompleted(last_completed_migration); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /solidity/gas-price-oracle/gas-price-oracle-tests.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/provable-things/ethereum-examples/f3f650836016c43be3b18ba2819a5609078b0447/solidity/gas-price-oracle/gas-price-oracle-tests.jpg -------------------------------------------------------------------------------- /solidity/gas-price-oracle/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => 2 | deployer.deploy(artifacts.require('./Migrations.sol')) -------------------------------------------------------------------------------- /solidity/gas-price-oracle/migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | const contracts = [ 2 | artifacts.require("strings.sol"), 3 | artifacts.require("usingOraclize.sol"), 4 | ] 5 | const gasOracle = artifacts.require("GasPriceOracle.sol") 6 | 7 | module.exports = deployer => { 8 | const gasPrice = 2e10 9 | const amountETH = 1e17 10 | contracts.map(contract => deployer.deploy(contract)) 11 | deployer.deploy(gasOracle, gasPrice, {value: amountETH}) 12 | } 13 | -------------------------------------------------------------------------------- /solidity/gas-price-oracle/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "solidity-gasprice-oracle-priv", 3 | "version": "1.0.0", 4 | "description": "A decentralized gas price oracle, created, funded & powered by Oraclize, leveraging the EthGasStation.info api.", 5 | "main": "index.js", 6 | "directories": { 7 | "doc": "docs" 8 | }, 9 | "dependencies": { 10 | "ethereum-bridge": "0.6.1", 11 | "solc": "0.4.20", 12 | "truffle": "5.0.0-beta.0", 13 | "truffle-hdwallet-provider": "0.0.6", 14 | "web3": "1.0.0-beta.35" 15 | }, 16 | "devDependencies": {}, 17 | "scripts": { 18 | "bridge": "./node_modules/.bin/ethereum-bridge -a 9 -H 127.0.0.1 -p 9545 --dev", 19 | "test": "truffle compile && truffle test" 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "git+https://github.com/oraclize/solidity-gasprice-oracle-priv.git" 24 | }, 25 | "author": "Oraclize", 26 | "license": "MIT", 27 | "bugs": { 28 | "url": "https://github.com/oraclize/solidity-gasprice-oracle-priv/issues" 29 | }, 30 | "homepage": "https://github.com/oraclize/solidity-gasprice-oracle-priv#readme", 31 | "keywords": [ 32 | "oraclize", 33 | "gasprice", 34 | "oracle", 35 | "solidity", 36 | "ethereum" 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /solidity/gas-price-oracle/test/2-gas-price-oracle-stale.test.js: -------------------------------------------------------------------------------- 1 | const Web3 = require('web3') 2 | const web3 = new Web3(new Web3.providers.WebsocketProvider('ws://localhost:9545')) 3 | const gasPriceOracle = artifacts.require('GasPriceOracle.sol') 4 | const {waitForEvent, increaseEVMTime, mineXBlocks} = require('./utils') 5 | const {BN} = web3.utils 6 | 7 | contract('Gas Price Oracle Stale Tests', accounts => { 8 | 9 | let blockNum = 0 10 | const gasAmt = 250000 11 | 12 | const mine50Blocks = () => mineXBlocks(web3, 50) 13 | const increase3Mins = () => increaseEVMTime(web3, 60 * 3) 14 | const fastForwardEVM = async () => {await mine50Blocks(), await increase3Mins()} 15 | 16 | beforeEach(async () => ( 17 | {contract} = await gasPriceOracle.deployed(), 18 | {methods, events} = new web3.eth.Contract(contract._jsonInterface, contract._address) 19 | )) 20 | 21 | it(`Should have set off a recursive query upon contract creation`, async () => { 22 | const hashBefore = await methods.nextRecursiveQuery().call() 23 | const hashAfter = await waitForEvent(events.LogGasPricesUpdated) 24 | assert.notEqual(hashBefore, hashAfter, `Initial query should have begun recursion!`) 25 | }) 26 | 27 | it(`Should advance time until the recursive query becomes stale`, async () => { 28 | const week = 1 * 60 * 60 * 24 * 7 29 | await increaseEVMTime(web3, week) 30 | await mineXBlocks(web3, 100) 31 | const stale = await methods.isRecursiveStale().call() 32 | assert.isTrue(stale, 'Recursive queries should now be stale!') 33 | }) 34 | 35 | it(`Queries using delay of 0, sufficient ETH but gas prices < than previous recursive queries should succeed but not restart recursion`, async () => { 36 | const delay = 0 37 | const account = accounts[5] 38 | const recIDBefore = await methods.nextRecursiveQuery().call() 39 | const structBefore = await methods.queryIDs(recIDBefore).call() 40 | const priceToUse = new BN(`${structBefore[4]}`).sub(new BN(`${1e9}`)) 41 | const gasLimit = await methods.gasLimitRec().call() 42 | assert.isTrue(priceToUse.gt(new BN (0)), 'Price to use should be above zero!') 43 | const cost = await methods.getQueryPrice(gasLimit, priceToUse).call() 44 | await methods.updateGasPrices(delay, priceToUse).send({from: account, value: cost, gas: gasAmt}) 45 | await waitForEvent(events.LogGasPricesUpdated, blockNum) 46 | const stale = await methods.isRecursiveStale().call() 47 | const recIDAfter = await methods.nextRecursiveQuery().call() 48 | const structAfter = await methods.queryIDs(recIDAfter).call() 49 | assert.equal(recIDBefore, recIDAfter, 'Recursive ID should not have been updated!') 50 | assert.equal(delay, 0, 'Delay should be 0 for this test!') 51 | assert.isFalse(structAfter[2], 'Query should not be a revival!') 52 | assert.isTrue(stale, 'Recursive queries should still be stale!') 53 | }) 54 | 55 | it(`Queries using delay of 0, sufficient ETH but gas prices = to previous recursive queries should succeed but not restart recursion`, async () => { 56 | await fastForwardEVM() 57 | blockNum = await web3.eth.getBlockNumber() 58 | const delay = 0 59 | const account = accounts[5] 60 | const recIDBefore = await methods.nextRecursiveQuery().call() 61 | const structBefore = await methods.queryIDs(recIDBefore).call() 62 | const priceToUse = new BN(`${structBefore[4]}`) 63 | const gasLimit = await methods.gasLimitRec().call() 64 | const cost = await methods.getQueryPrice(gasLimit, priceToUse).call() 65 | await methods.updateGasPrices(delay, priceToUse).send({from: account, value: cost, gas: gasAmt}) 66 | await waitForEvent(events.LogGasPricesUpdated, blockNum) 67 | const stale = await methods.isRecursiveStale().call() 68 | const recIDAfter = await methods.nextRecursiveQuery().call() 69 | const structAfter = await methods.queryIDs(recIDAfter).call() 70 | assert.equal(recIDBefore, recIDAfter, 'Recursive ID should not have been updated!') 71 | assert.equal(delay, 0, 'Delay should be 0 for this test!') 72 | assert.isFalse(structAfter[2], 'Query should not be a revival!') 73 | assert.isTrue(stale, 'Recursive queries should still be stale!') 74 | }) 75 | 76 | it('Queries of delay > 0 & high gas prices should not successed but not restart recursion', async () => { 77 | await fastForwardEVM() 78 | blockNum = await web3.eth.getBlockNumber() 79 | const delay = 1 80 | const account = accounts[5] 81 | const gasPrice = new BN(`${100e9}`) 82 | const recIDBefore = await methods.nextRecursiveQuery().call() 83 | const gasLimit = await methods.gasLimitRec().call() 84 | const cost = await methods.getQueryPrice(gasLimit, gasPrice).call() 85 | await methods.updateGasPrices(delay).send({from: account, value: cost, gas: gasAmt}) 86 | await waitForEvent(events.LogGasPricesUpdated, blockNum) 87 | const stale = await methods.isRecursiveStale().call() 88 | const recIDAfter = await methods.nextRecursiveQuery().call() 89 | const structAfter = await methods.queryIDs(recIDAfter).call() 90 | assert.isAbove(delay, 0, 'Delay should be > 0 for this test!') 91 | assert.isTrue(stale, 'Recursive queries should still be stale!') 92 | assert.equal(recIDBefore, recIDAfter, 'Recursive ID should not have been updated!') 93 | assert.isFalse(structAfter[2], 'Query should not be a revival!') 94 | }) 95 | 96 | it(`Queries with delay of 0, high gas prices, but insufficient ETH should not succeed nor restart recursion`, async () => { 97 | const delay = 0 98 | const account = accounts[5] 99 | const gasPrice = new BN(`${100e9}`) 100 | const recIDBefore = await methods.nextRecursiveQuery().call() 101 | const gasLimit = await methods.gasLimitRec().call() 102 | const cost = await methods.getQueryPrice(gasLimit, gasPrice).call() 103 | const amount = new BN(`${cost}`).sub(new BN(`${1e9}`)) 104 | try { 105 | await methods.updateGasPrices(delay, gasPrice).send({from: account, value: amount, gas: gasAmt}) 106 | assert.fail(`Transaction should not have succeeded!`) 107 | } catch (e) { 108 | const stale = await methods.isRecursiveStale().call() 109 | assert.equal(delay, 0, 'Delay should be 0 for this test!') 110 | assert.isTrue(stale, 'Recursive queries should still be stale!') 111 | const recIDAfter = await methods.nextRecursiveQuery().call() 112 | const qIDStruct = await methods.queryIDs(recIDAfter).call() 113 | assert.equal(recIDBefore, recIDAfter, 'Recursive ID should not have been updated!') 114 | assert.isFalse(qIDStruct[2], 'Query should not be a revival!') 115 | } 116 | }) 117 | 118 | it(`Query with delay of 0, a gas price 1Gwei higher than prior call, plus sufficient ETH supplied should succceed and restart recursion`, async () => { 119 | await fastForwardEVM() 120 | blockNum = await web3.eth.getBlockNumber() 121 | const staleBefore = await methods.isRecursiveStale().call() 122 | assert.isTrue(staleBefore, 'Recursive queries should be stale!') 123 | const delay = 0 124 | const account = accounts[5] 125 | const recIDBefore = await methods.nextRecursiveQuery().call() 126 | const structBefore = await methods.queryIDs(recIDBefore).call() 127 | const gasLimit = await methods.gasLimitRec().call() 128 | const priceToUse = new BN(`${structBefore[4]}`).add(new BN(`${1e9}`)) 129 | const cost = await methods.getQueryPrice(gasLimit, priceToUse).call() 130 | const amount = new BN(`${cost}`).mul(new BN(`${10}`)) 131 | await methods.updateGasPrices(delay, priceToUse).send({from: account, value: amount, gas: gasAmt}) 132 | const interimID = await methods.nextRecursiveQuery().call() 133 | const interimStruct = await methods.queryIDs(interimID).call() 134 | const staleInterim = await methods.isRecursiveStale().call() 135 | assert.isTrue(interimStruct[2], 'Query should be a revival!') 136 | assert.isFalse(interimStruct[0], 'Despite manual, ∵ its restarting recursion, query should be an "automated" one!') 137 | assert.notEqual(recIDBefore, interimID, 'There should be a new recursive query ID!') 138 | assert.isTrue(staleInterim, ' Recursive queries should still be stale whilst recursive ID is a revival!') 139 | await waitForEvent(events.LogGasPricesUpdated, blockNum) 140 | const recIDAfter = await methods.nextRecursiveQuery().call() 141 | const structAfter = await methods.queryIDs(recIDAfter).call() 142 | const staleAfter = await methods.isRecursiveStale().call() 143 | assert.equal(delay, 0, 'Delay should be 0 for this test!') 144 | assert.notEqual(interimID, recIDAfter, 'There should be a new recursive query ID!') 145 | assert.isFalse(staleAfter, 'Recursive queries should no longer be stale!') 146 | assert.isFalse(structAfter[2], 'Final query should not be a be a revival!') 147 | assert.isFalse(structAfter[0], 'Final detected query should be an automated one!') 148 | }) 149 | }) 150 | -------------------------------------------------------------------------------- /solidity/gas-price-oracle/test/utils.js: -------------------------------------------------------------------------------- 1 | const waitForEvent = (_event, _from = 0, _to = 'latest') => 2 | new Promise ((resolve,reject) => 3 | _event({fromBlock: _from, toBlock: _to}, (e, ev) => 4 | e ? reject(e) : resolve(ev))) 5 | 6 | const PREFIX = "Returned error: VM Exception while processing transaction: " 7 | 8 | const increaseEVMTime = (web3, secsToIncreaseBy) => 9 | new Promise((resolve, reject) => 10 | web3.currentProvider.send({jsonrpc: '2.0', method: 'evm_increaseTime', params:[secsToIncreaseBy], id: Date.now()}, e => 11 | e ? reject(e) : web3.currentProvider.send({jsonrpc: '2.0', method: 'evm_mine', params: [], id: Date.now() + 1}, (e2, res) => 12 | e2 ? reject(e2) : resolve(res)))) 13 | 14 | const mineXBlocks = (web3, numBlocks) => 15 | new Promise((resolve, reject) => 16 | Promise.all(new Array (numBlocks).fill().map((_,i) => 17 | new Promise ((res, rej) => 18 | web3.currentProvider.send({jsonrpc: '2.0', method: 'evm_mine', params: [], id: Date.now() + i}, e => 19 | e ? rej() : res())))).then(resolve).catch(reject)) 20 | 21 | const getTimestamp = blockNum => 22 | new Promise ((resolve, reject) => 23 | web3.eth.getBlock(blockNum, false, (e, b) => 24 | e ? reject(e) : resolve(b.timestamp))) 25 | 26 | module.exports = { 27 | increaseEVMTime, 28 | getTimestamp, 29 | waitForEvent, 30 | mineXBlocks, 31 | PREFIX 32 | } -------------------------------------------------------------------------------- /solidity/gas-price-oracle/truffle.js: -------------------------------------------------------------------------------- 1 | const HDWalletProvider = require("truffle-hdwallet-provider") 2 | 3 | // Note: If deploying to a live network, please provide a mnemonic & infura apikey. 4 | 5 | const apikey = '' 6 | const mnemonic = '' 7 | 8 | module.exports = { 9 | networks: { 10 | development: { 11 | host: "127.0.0.1", 12 | port: 8545, 13 | network_id: "*", 14 | websockets: true 15 | }, 16 | mainnet: { 17 | provider: () => new HDWalletProvider(mnemonic, `https://mainnet.infura.io/${apikey}`), 18 | network_id: '1', 19 | gas: 3e6, 20 | gasPrice: 20e9 21 | }, 22 | ropsten: { 23 | provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/${apikey}`), 24 | network_id: '3', 25 | gas: 47e5, 26 | gasPrice: 20e9 27 | }, 28 | rinkeby: { 29 | provider: () => new HDWalletProvider(mnemonic, `https://rinkeby.infura.io/${apikey}`), 30 | network_id: '4', 31 | gas: 3e6, 32 | gasPrice: 20e9 33 | } 34 | }, 35 | solc: { 36 | settings: { 37 | optimizer: { 38 | enabled: true 39 | } 40 | } 41 | }, 42 | compilers: { 43 | solc: { 44 | version: '0.4.24' 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /solidity/lib-experimental/KrakenPriceTicker.sol: -------------------------------------------------------------------------------- 1 | /* 2 | Kraken-based ETH/XBT price ticker 3 | 4 | This contract keeps in storage an updated ETH/XBT price, 5 | which is updated every ~60 seconds. 6 | */ 7 | 8 | pragma solidity >= 0.4.1 < 0.5; 9 | 10 | // import library manually here, library github linking not working with oraclize browser-solidity 11 | import "oraclizeLib.sol"; 12 | 13 | contract KrakenPriceTicker { 14 | 15 | string public ETHXBT; 16 | 17 | event newOraclizeQuery(string description); 18 | event newKrakenPriceTicker(string price); 19 | 20 | 21 | function KrakenPriceTicker() { 22 | oraclizeLib.oraclize_setProof(oraclizeLib.proofType_TLSNotary() | oraclizeLib.proofStorage_IPFS()); 23 | update(); 24 | } 25 | 26 | function __callback(bytes32 myid, string result, bytes proof) { 27 | if (msg.sender != oraclizeLib.oraclize_cbAddress()) throw; 28 | ETHXBT = result; 29 | newKrakenPriceTicker(ETHXBT); 30 | update(); 31 | } 32 | 33 | function update() payable { 34 | if (oraclizeLib.oraclize_getPrice("URL") > this.balance) { 35 | newOraclizeQuery("Oraclize query was NOT sent, please add some ETH to cover for the query fee"); 36 | } else { 37 | newOraclizeQuery("Oraclize query was sent, standing by for the answer.."); 38 | oraclizeLib.oraclize_query(60, "URL", "json(https://api.kraken.com/0/public/Ticker?pair=ETHXBT).result.XETHXXBT.c.0"); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /solidity/lib-experimental/OffchainConcat.sol: -------------------------------------------------------------------------------- 1 | /* 2 | Computation N args query example 3 | Takes up to 16 string args and concatenates them 4 | off-chain with a python script 5 | 6 | Also makes use of InlineDynamicHelper library 7 | for converting inline fixed string array declarations 8 | to dynamic-sized arrays, which is what the Oraclize library expects 9 | */ 10 | 11 | // NOTE, the computations here may crash remix's JavascriptVM 12 | // Ensure you are loading in an incognito window, and in a single session 13 | // only deploying and then calling the update function 14 | 15 | pragma solidity >= 0.4.1 < 0.5; 16 | 17 | // import both libraries manually 18 | import "oraclizeLib.sol"; 19 | import "InlineDynamicHelper.sol"; 20 | 21 | contract OffchainConcat is usingInlineDynamic { 22 | 23 | string public CONCATENATED; 24 | address public OAR = oraclizeLib.getOAR(); 25 | OraclizeI public localOrclInstance = oraclizeLib.getCON(); 26 | uint constant public base = localOrclInstance.getPrice("URL"); 27 | 28 | event newOraclizeQuery(string description); 29 | event emitConcatMsg(string msg); 30 | 31 | 32 | function OffchainConcat() { 33 | oraclizeLib.oraclize_setProof(oraclizeLib.proofType_NONE()); 34 | } 35 | 36 | function __callback(bytes32 myid, string result) { 37 | if (msg.sender != oraclizeLib.oraclize_cbAddress()) throw; 38 | CONCATENATED = result; 39 | emitConcatMsg(result); 40 | } 41 | 42 | function update() payable { 43 | if (oraclizeLib.oraclize_getPrice("computation") > this.balance) { 44 | newOraclizeQuery("Oraclize query was NOT sent, please add some ETH to cover for the query fee"); 45 | } else { 46 | newOraclizeQuery("Oraclize query was sent, standing by for the answer.."); 47 | 48 | oraclizeLib.oraclize_query("computation", 49 | ["QmQ4kKevJhmPfB3bNHh4xBVo4EE8fd3L7yoTVKPe6DCFus", 50 | "Last", 51 | "entry", 52 | "will", 53 | "be", 54 | "bytes:", 55 | oraclizeLib.b2s(hex'DEADBEEF1001') // bytes to string equivalent conversion 56 | ].toDynamic() 57 | ); 58 | } 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /solidity/lib-experimental/README.md: -------------------------------------------------------------------------------- 1 | ### Experimental Oraclize Library Examples 2 | 3 | Examples specific to the library version of the Oraclize API, under development at https://github.com/oraclize/ethereum-api/tree/master/lib-experimental 4 | 5 | When trying the `OffchainConcat.sol` contract, ensure you have an IPFS daemon running that is serving `archive.zip` from the `comp-archive` directory for it to successfully be executed off-chain. 6 | 7 | Direct browser-solidity link to examples: https://dapps.oraclize.it/browser-solidity/#version=soljson-v0.4.11+commit.68ef5810.js&optimize=false&gist=ad3d1f6007942b727f5909b55e6445d2 8 | -------------------------------------------------------------------------------- /solidity/lib-experimental/computation-archive/archive.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/provable-things/ethereum-examples/f3f650836016c43be3b18ba2819a5609078b0447/solidity/lib-experimental/computation-archive/archive.zip -------------------------------------------------------------------------------- /solidity/lib-experimental/computation-archive/src/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:14.04 2 | MAINTAINER Oraclize "info@oraclize.it" 3 | 4 | RUN apt-get update && apt-get -y install python-minimal 5 | COPY concat.py /tmp/ 6 | CMD /usr/bin/python /tmp/concat.py -------------------------------------------------------------------------------- /solidity/lib-experimental/computation-archive/src/concat.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | s = '' 4 | 5 | for n in list(range(16)): 6 | arg = 'ARG' + str(n) 7 | if arg in os.environ: 8 | s += os.environ[arg] + ' ' 9 | else: 10 | break 11 | 12 | print s -------------------------------------------------------------------------------- /solidity/proofshield/README.md: -------------------------------------------------------------------------------- 1 | ## Oraclize *ProofShield* Solidity example 2 | 3 | > Note: the *ProofShield* is currently available on **all Ethereum public testnets only** (Rinkeby, Kovan, Ropsten-revival) - it is not integrated yet with private blockchains/testrpc/browser-solidity-vmmode. 4 | 5 | This folder contains a Solidity example contract code showing how the *ProofShield* can be used on Ethereum. 6 | 7 | This code is *experimental*, please DO NOT use this in production. A production-ready version will follow in the future. 8 | 9 | This example code shows how the ProofShield makes it possible to verify on-chain the Oraclize authenticity proofs: this ensures that the data Oraclize sends back to the contract is indeed authentic, before using it. 10 | 11 | The additional gas cost to check the proof on-chain is approximately 60k gas. 12 | -------------------------------------------------------------------------------- /solidity/proofshield/proofShieldExample.sol: -------------------------------------------------------------------------------- 1 | /* 2 | Oraclize ProofShield example 3 | 4 | This contract uses the URL-datasource to securely call off-chain a Web API. 5 | It uses the ProofShield technology to send back to the contract an on-chain verifiable authenticity proof. 6 | */ 7 | 8 | pragma solidity >= 0.4.11 < 0.5; 9 | import "github.com/oraclize/ethereum-api/oraclizeAPI_0.4.sol"; 10 | 11 | 12 | // ORACLIZE_API FOLLOWS: FOR THE ACTUAL EXAMPLE CODE, LOOK AT THE BOTTOM! 13 | 14 | contract usingOraclize__future is usingOraclize { 15 | 16 | modifier oraclize_proofShield_proofVerify(bytes32 _queryId, string _query, string _result, bytes _proof) { 17 | 18 | // Step 1: the prefix has to match 'LP\x01' (Ledger Proof version 1) 19 | 20 | require((_proof[0] == "L") && (_proof[1] == "P") && (_proof[2] == 1)); 21 | 22 | bool proofVerified = oraclize_proofShield_proofVerify__main(_proof, _queryId, bytes(_result), oraclize_getNetworkName()); 23 | 24 | require(proofVerified); 25 | 26 | _; 27 | 28 | } 29 | 30 | function oraclize_proofShield_proofVerify__returnCode(bytes32 _queryId, string _result, bytes _proof) internal returns (uint8){ 31 | 32 | // Step 1: the prefix has to match 'LP\x01' (Ledger Proof version 1) 33 | 34 | if ((_proof[0] != "L")||(_proof[1] != "P")||(_proof[2] != 1)) return 1; 35 | 36 | bool proofVerified = oraclize_proofShield_proofVerify__main(_proof, _queryId, bytes(_result), oraclize_getNetworkName()); 37 | 38 | if (proofVerified == false) return 2; 39 | 40 | return 0; 41 | 42 | } 43 | 44 | function oraclize_proofShield_proofVerify__main(bytes proof, bytes32 queryId, bytes result, string context_name) internal returns (bool){ 45 | 46 | uint offset = 3+65+32+ uint(proof[3+65+1])+2; 47 | 48 | // Step 2: verify the APPKEY1 provenance (must be signed by Ledger) 49 | 50 | bytes memory LEDGERKEY = hex"7fb956469c5c9b89840d55b43537e66a98dd4811ea0a27224272c2e5622911e8537a2f8e86a46baec82864e98dd01e9ccc2f8bc5dfc9cbe5a91a290498dd96e4"; 51 | 52 | bytes memory tosign1 = new bytes(1+65); 53 | 54 | tosign1[0] = 0xFE; 55 | 56 | copyBytes(proof, 3, 65, tosign1, 1); 57 | 58 | bytes memory sig1 = new bytes(uint(proof[3+65+1])+2); 59 | 60 | copyBytes(proof, 3+65, sig1.length, sig1, 0); 61 | 62 | if (verifySig(sha256(tosign1), sig1, LEDGERKEY) == false) return false; 63 | 64 | 65 | 66 | // Step 3: verify the attestation signature, APPKEY1 must sign the message from the correct ledger app (CODEHASH) 67 | 68 | bytes memory tosign2 = new bytes(130); 69 | 70 | copyBytes(proof, offset, 98, tosign2, 0); 71 | 72 | bytes memory sig2 = new bytes(uint(proof[offset+98+1])+2); 73 | 74 | copyBytes(proof, offset+98, sig2.length, sig2, 0); 75 | 76 | bytes memory CODEHASH = hex"f9d90c24eafd50fbca9558ca1f93b80cb7ffa4edb775d9dc73c3cec20df21521"; 77 | 78 | copyBytes(CODEHASH, 0, 32, tosign2, 98); 79 | 80 | bytes memory appkey1_pubkey = new bytes(64); 81 | 82 | copyBytes(proof, 3+1, 64, appkey1_pubkey, 0); 83 | 84 | if (verifySig(sha256(tosign2), sig2, appkey1_pubkey) == false) return false; 85 | 86 | 87 | 88 | // Step 4: check proof verification status 89 | 90 | if (proof[offset+33] != 0) return false; 91 | 92 | 93 | 94 | // Step 5: check queryid match 95 | 96 | bytes memory vresulth = new bytes(32); 97 | 98 | copyBytes(proof, offset, 32, vresulth, 0); 99 | 100 | if (keccak256(vresulth) != keccak256(sha256(context_name, queryId))) return false; 101 | 102 | 103 | 104 | // Step 6: check result match 105 | 106 | copyBytes(proof, offset+66, 32, vresulth, 0); 107 | 108 | if (keccak256(vresulth) != keccak256(sha256(result))) return false; 109 | 110 | 111 | 112 | // Step 7: check query match 113 | 114 | copyBytes(proof, offset+34, 32, vresulth, 0); 115 | 116 | if (keccak256(vresulth, proof[offset+32]) != oraclize_proofShield_commitment[queryId]) return false; 117 | 118 | delete oraclize_proofShield_commitment[queryId]; 119 | 120 | return true; 121 | 122 | } 123 | 124 | mapping (bytes32 => bytes32) oraclize_proofShield_commitment; 125 | 126 | byte constant proofType_Android_v2 = 0x40; 127 | byte constant proofShield = 0x0F; 128 | byte constant proofShield_Ledger = 0x0F; 129 | } 130 | 131 | 132 | // THE EXAMPLE CODE FOLLOWS 133 | 134 | contract proofShieldExample is usingOraclize__future { 135 | 136 | event newAuthenticatedResult(string); 137 | 138 | function proofShieldExample() { 139 | oraclize_setProof(proofType_Android_v2 | proofShield_Ledger); 140 | sendQuery(); 141 | } 142 | 143 | function __callback(bytes32 queryId, string result, bytes proof) { 144 | if (msg.sender != oraclize_cbAddress()) throw; 145 | 146 | if (oraclize_proofShield_proofVerify__returnCode(queryId, result, proof) != 0) { 147 | // the proof verification has failed, do we need to take any action here? (depends on the use case) 148 | } else { 149 | // the proof verification has passed 150 | // now that we know that the random number was safely generated, let's use it.. 151 | 152 | newAuthenticatedResult(result); 153 | } 154 | } 155 | 156 | function sendQuery() payable { 157 | string memory query = "json(https://www.bitstamp.net/api/v2/ticker/ethusd/).last"; 158 | bytes32 queryId = oraclize_query("URL", query); 159 | 160 | oraclize_proofShield_commitment[queryId] = keccak256(sha256(query), proofType_Android_v2); 161 | } 162 | 163 | 164 | 165 | } 166 | -------------------------------------------------------------------------------- /solidity/random-datasource/README.md: -------------------------------------------------------------------------------- 1 | ## Oraclize *Random Datasource* Solidity Example 2 | 3 | > **Note:** the *Random Datasource* is currently available on the **Ethereum mainnet and on all Ethereum public testnets only** (Rinkeby, Kovan, Ropsten-revival) - it is not integrated yet with private blockchains/testrpc/browser-solidity-vmmode. 4 | 5 | > **Note:** The Random Datasource currently does not support a delay > 0. 6 | 7 | This folder contains a Solidity example contract code showing how the Oraclize *random datasource* can be used on Ethereum. 8 | 9 | The rationale behind this method of securely feeding off-chain randomness into the blockchain is explained in the [“A Scalable Architecture for On-Demand, Untrusted Delivery of Entropy”](http://www.oraclize.it/papers/random_datasource-rev1.pdf) whitepaper. 10 | 11 | The design described there prevents Oraclize from tampering with the random results coming from the Trusted Execution Environment (TEE) and protects the user from a number of attack vectors. 12 | 13 | The authenticity proof, attached with the result, can be easily verified not just off-chain but even by any Solidity contract receiving them. The example presented here, showing how to integrate the verification process, discards any random result whose authenticity proofs don't pass the verification process. 14 | 15 | The *randon datasource* is leveraging the *Ledger proof*, first introduced [in this blogpost](https://blog.oraclize.it/welcoming-our-brand-new-ledger-proof-649b9f098ccc), to prove that the origin of the generated randomness is really a secure Ledger device. 16 | 17 | The CODEHASH, i.e. SHA256 of the application's binary, which is hardcoded in the smart contract as part of the verification process, can be used by anybody to ensure that the application code (to be released next week, as it is being polished to increase its readability) is really the one being executed to generate the randomness. 18 | 19 | 20 | 21 | 22 | **Returned proof format** 23 | 24 | 25 | | 1 | 2 | 3 | 4 | 5 | 6| 7 | 8 | 9 | 10 | 11 | 26 | | ------------- |-------------| -----| ------------- |-------------| -----| ------------- |-------------| -----| ------------- |-------------| 27 | | 3 bytes | 65 bytes | var length | 32 bytes | 32 bytes | 8 bytes | 1 byte | 32 bytes | var length | 65 bytes | var length | 28 | | 'LP\x01' (prefix) | APPKEY1 PubKey | APPKEY1 cert (CA:Ledger) | CODEHASH | keyhash | timelock | Nbytes | user nonce | SessionKey sig | SessionPubKey | attestation sig | 29 | 30 | 31 | 32 | **Verification Steps** 33 | 34 | 35 | - Step 1: the prefix has to match 'LP\x01' (Ledger Proof version 1) 36 | - Step 2: the unique keyhash has to match with the sha256 of (context name + queryId) 37 | - Step 3: we assume sig1 is valid (it will be verified during step 5) and we verify if 'result' is the prefix of sha256(sig1) 38 | - Step 4: commitment match verification, sha3(delay, nbytes, unonce, sessionKeyHash) == commitment in storage. 39 | - Step 5: validity verification for sig1 (keyhash and args signed with the sessionKey) 40 | - Step 6: verify the attestation signature, APPKEY1 must sign the sessionKey from the correct ledger app (CODEHASH) 41 | - Step 7: verify the APPKEY1 provenance (must be signed by Ledger) 42 | -------------------------------------------------------------------------------- /solidity/random-datasource/randomExample.sol: -------------------------------------------------------------------------------- 1 | /** 2 | * @notice Provable Random Datasource Example 3 | * 4 | * This contract uses the random-datasource to securely generate 5 | * off-chain random bytes. 6 | * 7 | * The random datasource is currently only available on the 8 | * ethereum main-net & public test-nets (Ropsten, Rinkeby & Kovan). 9 | * 10 | */ 11 | pragma solidity >= 0.5.0 < 0.6.0; 12 | 13 | import "github.com/provable-things/ethereum-api/provableAPI.sol"; 14 | 15 | contract RandomExample is usingProvable { 16 | 17 | uint256 constant MAX_INT_FROM_BYTE = 256; 18 | uint256 constant NUM_RANDOM_BYTES_REQUESTED = 7; 19 | 20 | event LogNewProvableQuery(string description); 21 | event generatedRandomNumber(uint256 randomNumber); 22 | 23 | constructor() 24 | public 25 | { 26 | provable_setProof(proofType_Ledger); 27 | update(); 28 | } 29 | 30 | function __callback( 31 | bytes32 _queryId, 32 | string memory _result, 33 | bytes memory _proof 34 | ) 35 | public 36 | { 37 | require(msg.sender == provable_cbAddress()); 38 | if (provable_randomDS_proofVerify__returnCode(_queryId, _result, _proof) != 0) { 39 | /** 40 | * @notice The proof verification has failed! Handle this case 41 | * however you see fit. 42 | */ 43 | } else { 44 | /** 45 | * 46 | * @notice The proof verifiction has passed! 47 | * 48 | * Let's convert the random bytes received from the query 49 | * to a `uint256`. 50 | * 51 | * To do so, We define the variable `ceiling`, where 52 | * `ceiling - 1` is the highest `uint256` we want to get. 53 | * The variable `ceiling` should never be greater than: 54 | * `(MAX_INT_FROM_BYTE ^ NUM_RANDOM_BYTES_REQUESTED) - 1`. 55 | * 56 | * By hashing the random bytes and casting them to a 57 | * `uint256` we can then modulo that number by our ceiling 58 | * in order to get a random number within the desired 59 | * range of [0, ceiling - 1]. 60 | * 61 | */ 62 | uint256 ceiling = (MAX_INT_FROM_BYTE ** NUM_RANDOM_BYTES_REQUESTED) - 1; 63 | uint256 randomNumber = uint256(keccak256(abi.encodePacked(_result))) % ceiling; 64 | emit generatedRandomNumber(randomNumber); 65 | } 66 | } 67 | 68 | function update() 69 | payable 70 | public 71 | { 72 | uint256 QUERY_EXECUTION_DELAY = 0; // NOTE: The datasource currently does not support delays > 0! 73 | uint256 GAS_FOR_CALLBACK = 200000; 74 | provable_newRandomDSQuery( 75 | QUERY_EXECUTION_DELAY, 76 | NUM_RANDOM_BYTES_REQUESTED, 77 | GAS_FOR_CALLBACK 78 | ); 79 | emit LogNewProvableQuery("Provable query was sent, standing by for the answer..."); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /solidity/random-datasource/relaxed-commit/README.md: -------------------------------------------------------------------------------- 1 | ### "Relaxed" commitment hash Random Example 2 | 3 | The goal of this example is to showcase how to override the __`oraclize_newRandomDSQuery`__ function that appears in the Provable API so that the commitment hash requirements are relaxed making the proof more resilient to block re-organizations. 4 | 5 | The default example __`../randomExample.sol`__ has the highest security guarantees, but the proof will fail at any re-org. This relaxed example is expected to work successfully even with a block re-org up to four blocks deep, which re-orgs occur much less frequently. 6 | -------------------------------------------------------------------------------- /solidity/random-datasource/relaxed-commit/relaxedRandom.sol: -------------------------------------------------------------------------------- 1 | /** 2 | * @notice Provable Random Datasource Example - Relaxed Commit Version 3 | * 4 | * This contract uses the random-datasource to securely generate 5 | * off-chain random bytes. The relaxed commit parameters result in a 6 | * greater chance of a passing proof in exchange for lower security 7 | * guarantees. 8 | * 9 | * The random datasource is currently only available on the 10 | * ethereum main-net & public test-nets (Ropsten, Rinkeby & Kovan). 11 | * 12 | */ 13 | pragma solidity >= 0.5 < 0.6; 14 | 15 | import "github.com/oraclize/ethereum-api/oraclizeAPI_0.5.sol"; 16 | 17 | contract RandomRelaxedExample is usingOraclize { 18 | 19 | uint256 constant MAX_INT_FROM_BYTE = 256; 20 | uint256 constant NUM_RANDOM_BYTES_REQUESTED = 7; 21 | 22 | event LogNewOraclizeQuery(string _description); 23 | event generatedRandomNumber(uint256 _randomUint); 24 | 25 | constructor() 26 | public 27 | { 28 | oraclize_setProof(proofType_Ledger); 29 | update(); 30 | } 31 | 32 | function __callback( 33 | bytes32 _queryId, 34 | string memory _result, 35 | bytes memory _proof 36 | ) 37 | public 38 | { 39 | require(msg.sender == oraclize_cbAddress()); 40 | if ( 41 | oraclize_randomDS_proofVerify__returnCode( 42 | _queryId, 43 | _result, 44 | _proof 45 | ) != 0 46 | ) { 47 | /** 48 | * @notice The proof verification has failed! Handle this case 49 | * however you see fit. 50 | */ 51 | } else { 52 | /** 53 | * 54 | * @notice The proof verifiction has passed! 55 | * 56 | * Let's convert the random bytes received from the query 57 | * to a `uint256`. 58 | * 59 | * To do so, We define the variable `ceiling`, where 60 | * `ceiling - 1` is the highest `uint256` we want to get. 61 | * The variable `ceiling` should never be greater than: 62 | * `(MAX_INT_FROM_BYTE ^ NUM_RANDOM_BYTES_REQUESTED) - 1`. 63 | * 64 | * By hashing the random bytes and casting them to a 65 | * `uint256` we can then modulo that number by our ceiling 66 | * in order to get a random number within the desired 67 | * range of [0, ceiling - 1]. 68 | * 69 | */ 70 | uint256 ceiling = (MAX_INT_FROM_BYTE ** NUM_RANDOM_BYTES_REQUESTED) - 1; 71 | uint256 randomNumber = uint256(keccak256(abi.encodePacked(_result))) % ceiling; 72 | emit generatedRandomNumber(randomNumber); 73 | } 74 | } 75 | 76 | function update() 77 | public 78 | payable 79 | { 80 | uint256 QUERY_EXECUTION_DELAY = 0; 81 | uint256 GAS_FOR_CALLBACK = 200000; 82 | oraclize_newRandomDSQuery( 83 | QUERY_EXECUTION_DELAY, 84 | NUM_RANDOM_BYTES_REQUESTED, 85 | GAS_FOR_CALLBACK 86 | ); 87 | emit LogNewOraclizeQuery( 88 | "Oraclize query was sent, standing by for the answer..." 89 | ); 90 | } 91 | /** 92 | * 93 | * @notice This overrides the Random Datasource function from `oraclizeAPI` 94 | * with a more relaxed one that should fail due to re-orgs much 95 | * less frequently. 96 | * 97 | */ 98 | function oraclize_newRandomDSQuery( 99 | uint256 _delay, 100 | uint256 _nbytes, 101 | uint256 _customGasLimit 102 | ) 103 | internal 104 | returns (bytes32 _queryId) 105 | { 106 | require((_nbytes > 0) && (_nbytes <= 32)); 107 | _delay *= 10; 108 | bytes memory nbytes = new bytes(1); 109 | nbytes[0] = byte(uint8(_nbytes)); 110 | bytes memory unonce = new bytes(32); 111 | bytes memory sessionKeyHash = new bytes(32); 112 | bytes32 sessionKeyHash_bytes32 = oraclize_randomDS_getSessionPubKeyHash(); 113 | assembly { 114 | mstore(unonce, 0x20) 115 | /** 116 | * 117 | * @dev Here is the edit: It removes xoring of last blockhash with 118 | * some current block variables, with that of a block committed 119 | * for a modulo range. This will lower chance of false proof 120 | * fails, by an expected factor of `NUM_RANDOM_BYTES_REQUESTED`. 121 | * 122 | * The original function reads: 123 | * 124 | * mstore( 125 | * add(unonce, 0x20), 126 | * xor(blockhash(sub(number, 1)), 127 | * xor(coinbase, timestamp)) 128 | * ) 129 | * 130 | */ 131 | mstore( 132 | add(unonce, 0x20), 133 | blockhash(sub(sub(number, 1), mod(number, 6))) 134 | ) 135 | mstore(sessionKeyHash, 0x20) 136 | mstore(add(sessionKeyHash, 0x20), sessionKeyHash_bytes32) 137 | } 138 | bytes memory delay = new bytes(32); 139 | assembly { 140 | mstore(add(delay, 0x20), _delay) 141 | } 142 | 143 | bytes memory delay_bytes8 = new bytes(8); 144 | copyBytes(delay, 24, 8, delay_bytes8, 0); 145 | 146 | bytes[4] memory args = [unonce, nbytes, sessionKeyHash, delay]; 147 | bytes32 queryId = oraclize_query("random", args, _customGasLimit); 148 | 149 | bytes memory delay_bytes8_left = new bytes(8); 150 | 151 | assembly { 152 | let x := mload(add(delay_bytes8, 0x20)) 153 | mstore8( 154 | add(delay_bytes8_left, 0x27), 155 | div(x, 0x100000000000000000000000000000000000000000000000000000000000000) 156 | ) 157 | mstore8( 158 | add(delay_bytes8_left, 0x26), 159 | div(x, 0x1000000000000000000000000000000000000000000000000000000000000) 160 | ) 161 | mstore8( 162 | add(delay_bytes8_left, 0x25), 163 | div(x, 0x10000000000000000000000000000000000000000000000000000000000) 164 | ) 165 | mstore8( 166 | add(delay_bytes8_left, 0x24), 167 | div(x, 0x100000000000000000000000000000000000000000000000000000000) 168 | ) 169 | mstore8( 170 | add(delay_bytes8_left, 0x23), 171 | div(x, 0x1000000000000000000000000000000000000000000000000000000) 172 | ) 173 | mstore8( 174 | add(delay_bytes8_left, 0x22), 175 | div(x, 0x10000000000000000000000000000000000000000000000000000) 176 | ) 177 | mstore8( 178 | add(delay_bytes8_left, 0x21), 179 | div(x, 0x100000000000000000000000000000000000000000000000000) 180 | ) 181 | mstore8( 182 | add(delay_bytes8_left, 0x20), 183 | div(x, 0x1000000000000000000000000000000000000000000000000) 184 | ) 185 | 186 | } 187 | 188 | oraclize_randomDS_setCommitment( 189 | queryId, 190 | keccak256( 191 | abi.encodePacked( 192 | delay_bytes8_left, 193 | args[1], 194 | sha256(args[0]), 195 | args[2] 196 | ) 197 | ) 198 | ); 199 | return queryId; 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /solidity/truffle-examples/bitcoin-balance/README.md: -------------------------------------------------------------------------------- 1 | # :wrench: :construction: Testing Provable's Bitcoin Balance Example. 2 | 3 |   4 | 5 | This repo is to demonstrate how you would set up a Provable smart-contract development environment using Truffle & the Ethereum-Bridge to do most of the heavy lifting for you. Head on over to the `./test` folder to examine the javascript files that thoroughly test the smart-contract, which latter you will find in `./contracts`. 6 | 7 | ## :page_with_curl: _Instructions_ 8 | 9 | **1)** Fire up your favourite console & clone this repo somewhere: 10 | 11 | __`❍ git clone https://github.com/provable-things/ethereum-examples.git`__ 12 | 13 | **2)** Enter this directory & install dependencies: 14 | 15 | __`❍ cd ethereum-examples/solidity/truffle-examples/bitcoin-balance && npm install`__ 16 | 17 | **3)** Launch Truffle: 18 | 19 | __`❍ npx truffle develop`__ 20 | 21 | **4)** Open a _new_ console in the same directory & spool up the ethereum-bridge: 22 | 23 | __`❍ npx ethereum-bridge -a 9 -H 127.0.0.1 -p 9545 --dev`__ 24 | 25 | **5)** Once the bridge is ready & listening, go back to the first console with Truffle running & set the tests going! 26 | 27 | __`❍ truffle(develop)> test`__ 28 | 29 |   30 | 31 | ## :camera: Passing Tests: 32 | 33 | ```javascript 34 | Contract: Bitcoin Address Example Tests 35 | ✓ Should retrieve a balance from the bitcoin blockchain (190609ms) 36 | ✓ Should store the bitcoin balance in the smart-contract 37 | 38 | 2 passing (3m) 39 | 40 | ``` 41 | 42 |   43 | 44 | ## :black_nib: Notes: 45 | 46 | __❍__ If you have any issues, head on over to our [Gitter](https://gitter.im/provable/ethereum-api?raw=true) channel to get timely support! 47 | 48 | __*Happy developing!*__ 49 | -------------------------------------------------------------------------------- /solidity/truffle-examples/bitcoin-balance/computation-archive/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | MAINTAINER Provable "info@provable.xyz" 3 | RUN apt-get update && \ 4 | apt-get install -y \ 5 | curl \ 6 | jq 7 | COPY script.sh . 8 | ENTRYPOINT ["./script.sh"] 9 | -------------------------------------------------------------------------------- /solidity/truffle-examples/bitcoin-balance/computation-archive/archive.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/provable-things/ethereum-examples/f3f650836016c43be3b18ba2819a5609078b0447/solidity/truffle-examples/bitcoin-balance/computation-archive/archive.zip -------------------------------------------------------------------------------- /solidity/truffle-examples/bitcoin-balance/computation-archive/script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | curl --silent https://blockstream.info/api/address/$ARG0 \ 4 | | jq '.chain_stats.funded_txo_sum - .chain_stats.spent_txo_sum' 5 | -------------------------------------------------------------------------------- /solidity/truffle-examples/bitcoin-balance/contracts/BitcoinAddressExample.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >= 0.5.0 < 0.6.0; 2 | 3 | import "./provableAPI.sol"; 4 | 5 | contract BitcoinBalanceExample is usingProvable { 6 | 7 | uint256 public balance; 8 | 9 | event LogBitcoinAddressBalance(uint _balance); 10 | 11 | constructor() 12 | public 13 | { 14 | getBalance("3D2oetdNuZUqQHPJmcMDDHYoqkyNVsFk9r"); 15 | } 16 | 17 | function __callback( 18 | bytes32 _myid, 19 | string memory _result 20 | ) 21 | public 22 | { 23 | require(msg.sender == provable_cbAddress()); 24 | balance = parseInt(_result, 8); 25 | emit LogBitcoinAddressBalance(balance); 26 | } 27 | 28 | function getBalance( 29 | string memory _bitcoinAddress 30 | ) 31 | public 32 | payable 33 | { 34 | provable_query("computation", ["QmNecqR52vCsxshJx6acki6Nhg8zYLiRco4fwt22Yq2Qiz", _bitcoinAddress]); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /solidity/truffle-examples/bitcoin-balance/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solidity/truffle-examples/bitcoin-balance/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => 2 | deployer.deploy(artifacts.require("./Migrations.sol")) 3 | -------------------------------------------------------------------------------- /solidity/truffle-examples/bitcoin-balance/migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => deployer.deploy(artifacts.require("BitcoinBalanceExample.sol")) 2 | -------------------------------------------------------------------------------- /solidity/truffle-examples/bitcoin-balance/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "provable-examples-using-truffle__computation-datasource-bitcoin-balance", 3 | "version": "0.1.0", 4 | "description": "Testing set up for Provable's Bitcoin-Balance example contract", 5 | "main": "README.md", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/n/a.git" 12 | }, 13 | "author": "Provable - Greg Kapka", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/n/a/issues" 17 | }, 18 | "homepage": "https://github.com/n/a#readme", 19 | "dependencies": { 20 | "ethereum-bridge": "0.6.2", 21 | "truffle": "5.0.6", 22 | "web3": "1.0.0-beta.36" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /solidity/truffle-examples/bitcoin-balance/test/bitcoin-example-test.js: -------------------------------------------------------------------------------- 1 | const Web3 = require('web3') 2 | const { waitForEvent } = require('./utils') 3 | const bitcoinExample = artifacts.require('./BitcoinBalanceExample.sol') 4 | const web3 = new Web3(new Web3.providers.WebsocketProvider('ws://localhost:9545')) 5 | 6 | contract('Bitcoin Address Example Tests', () => { 7 | 8 | let balance 9 | 10 | beforeEach(async () => ( 11 | { contract } = await bitcoinExample.deployed(), 12 | { methods, events } = new web3.eth.Contract( 13 | contract._jsonInterface, 14 | contract._address 15 | ) 16 | )) 17 | 18 | it('Should retrieve a balance from the bitcoin blockchain', async () => { 19 | const { 20 | returnValues: { 21 | _balance 22 | } 23 | } = await waitForEvent(events.LogBitcoinAddressBalance) 24 | balance = _balance 25 | assert.isAbove( 26 | parseInt(balance), 27 | 0, 28 | 'No balance was retrieved from the bitcoin blockchain!' 29 | ) 30 | }) 31 | 32 | it('Should store the bitcoin balance in the smart-contract', async () => { 33 | const amount = await methods 34 | .balance() 35 | .call() 36 | assert.isTrue( 37 | parseInt(amount) === parseInt(balance), 38 | 'Bitcoin balance was not stored in the smart-contract!' 39 | ) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /solidity/truffle-examples/bitcoin-balance/test/utils.js: -------------------------------------------------------------------------------- 1 | const PREFIX = 'Returned error: VM Exception while processing transaction: ' 2 | 3 | const waitForEvent = (_event, _from = 0, _to = 'latest') => 4 | new Promise ((resolve,reject) => 5 | _event({fromBlock: _from, toBlock: _to}, (e, ev) => 6 | e ? reject(e) : resolve(ev))) 7 | 8 | module.exports = { 9 | waitForEvent, 10 | PREFIX 11 | } 12 | -------------------------------------------------------------------------------- /solidity/truffle-examples/bitcoin-balance/truffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | networks: { 3 | development: { 4 | host: "127.0.0.1", 5 | port: 9545, 6 | network_id: "*", 7 | websockets: true 8 | } 9 | }, 10 | compilers: { 11 | solc: { 12 | version: '0.5.0' 13 | } 14 | }, 15 | } 16 | -------------------------------------------------------------------------------- /solidity/truffle-examples/caller-pays-for-query/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parserOptions: { 3 | ecmaVersion: 2018, 4 | ecmaFeatures: { 5 | impliedStrict: true 6 | } 7 | }, 8 | extends: [ 9 | 'eslint:recommended', 10 | 'standard' 11 | ], 12 | env: { 13 | es6: true, 14 | mocha: true, 15 | node: true 16 | }, 17 | globals: { 18 | artifacts: true, 19 | assert: true, 20 | contract: true, 21 | web3: true 22 | }, 23 | rules: { 24 | quotes: [2, 'single', { avoidEscape: true }], 25 | 'no-template-curly-in-string': 2, 26 | 'no-extra-parens': [1, 'all'], 27 | 'no-misleading-character-class': 1, 28 | 'no-prototype-builtins': 1, 29 | 'no-async-promise-executor': 1, 30 | 'no-await-in-loop': 0, // should probably be on for perf dependent application 31 | 'require-atomic-updates': 1, 32 | // best practices 33 | 'accessor-pairs': 1, 34 | 'array-callback-return': 0, // this best practice calls out the use of map over forEach 35 | 'class-methods-use-this': 1, 36 | 'complexity': [1, 5], 37 | 'curly': [1, 'multi-or-nest', 'consistent'], 38 | 'dot-location': [2, 'property'], 39 | 'no-empty-function': 1, 40 | 'no-eval': 2, 41 | 'no-extend-native': 1, 42 | 'no-extra-bind': 1, 43 | 'no-implicit-coercion': 1, 44 | 'no-implicit-globals': 2, 45 | 'no-implied-eval': 2, 46 | 'no-lone-blocks': 1, 47 | 'no-loop-func': 1, 48 | 'no-magic-numbers': 0, // could be useful? 49 | 'no-new': 1, 50 | 'no-new-func': 2, 51 | 'no-new-wrappers': 1, 52 | 'no-param-reassign': 2, 53 | 'no-redeclare': [2, { 'builtinGlobals': true }], 54 | 'no-shadow': [2, { 55 | 'builtinGlobals': true, 56 | 'allow': [ 57 | 'done', 58 | 'resolve', 59 | 'reject', 60 | 'cb' // x could potentially be added 61 | ] 62 | }], 63 | 'no-return-await': 1, 64 | 'no-script-url': 1, 65 | 'no-self-compare': 1, 66 | 'no-sequences': 1, 67 | 'no-throw-literal': 2, 68 | 'no-unmodified-loop-condition': 1, 69 | 'no-useless-call': 1, 70 | 'no-useless-catch': 1, 71 | 'no-useless-concat': 2, 72 | 'no-useless-escape': 2, 73 | 'no-useless-return': 0, 74 | 'no-warning-comments': [1, { 75 | terms: [ 76 | 'fixme', 77 | 'todo', 78 | 'note' 79 | ], 80 | location: 'anywhere' // useful to highlight comments that need addressing 81 | }], 82 | 'require-await': 1, 83 | 'vars-on-top': 2, 84 | 'wrap-iife': [2, 'inside'], 85 | // strict mode 86 | 'strict': [2, 'safe'], 87 | // variables 88 | 'no-use-before-define': [2, { 89 | variables: true, 90 | functions: true, 91 | classes: true 92 | }], 93 | // node 94 | 'handle-callback-err': 1, 95 | 'no-buffer-constructor': 2, 96 | 'no-mixed-requires': 2, 97 | 'no-new-require': 0, 98 | 'no-path-concat': 1, 99 | 'no-sync': 1 100 | // stylistic (leaving up to standard) 101 | 102 | // ECMAScript 6 (tbd) 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /solidity/truffle-examples/caller-pays-for-query/.solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solhint:default", 3 | "rules": { 4 | "indent": ["error", 4], 5 | "bracket-align": false, 6 | "max-line-length": 180, 7 | "compiler-fixed": false, 8 | "no-simple-event-func-name": false, 9 | "two-lines-top-level-separator": false 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /solidity/truffle-examples/caller-pays-for-query/README.md: -------------------------------------------------------------------------------- 1 | # :construction: Provable: Caller Pays For Query Example 2 | 3 | A Provable/Truffle example showing how you can require the contract caller to provide the ETH to cover the Provable query cost! 4 | 5 | This repo is set up to show how a Provable smart-contract development environment using Truffle alongside the __`ethereum-bridge`__ might look. Head on over to the `./test` folder to examine the javascript files that thoroughly test the smart-contract, which latter you will find in `./contracts`. 6 | 7 | ## :wrench: _Run the tests:_ 8 | 9 | **1)** Fire up your favourite console & clone this repo somewhere: 10 | 11 | __`❍ git clone https://github.com/provable-things/ethereum-examples.git`__ 12 | 13 | **2)** Enter this directory & install dependencies: 14 | 15 | __`❍ cd ethereum-examples/solidity/truffle-examples/caller-pays-for-query && npm i`__ 16 | 17 | **3)** Launch the Truffle development console: 18 | 19 | __`❍ npx truffle develop`__ 20 | 21 | **4)** Open a _new_ console in the same directory & spool up the ethereum-bridge: 22 | 23 | __`❍ npx ethereum-bridge -a 9 -H 127.0.0.1 -p 9545 --dev`__ 24 | 25 | **5)** Once the bridge is ready & listening, go back to the first console with Truffle running & set the tests going! 26 | 27 | __`❍ truffle(develop)> test`__ 28 | 29 |   30 | 31 | ## :camera: Passing Tests: 32 | 33 | ```javascript 34 | 35 | Contract: ❍ Provable Truffle Examples: 36 | ❍ Caller-pays-for-query tests 37 | ✓ Should get contract methods & events 38 | ✓ Should be able to call `queryPrice` public getter 39 | ✓ Contract balance should be 0 40 | ✓ Query price should be > 0 41 | ✓ User cannot make query if msg.value === 0 (43ms) 42 | ✓ User cannot make query if msg.value < query cost 43 | ✓ User can make query if msg.value === query cost 44 | ✓ Query should have emitted event with ETH price in USD (11676ms) 45 | ✓ Eth price in USD should be saved in contract 46 | ✓ User should get refund when making query but sending > query cost (121ms) 47 | 48 | 49 | 10 passing (12s) 50 | 51 | 52 | ``` 53 | 54 |   55 | 56 | ## :black_nib: Notes: 57 | 58 | __❍__ If you have any issues, head on over to our [Gitter](https://gitter.im/provable/ethereum-api?raw=true) channel to get timely support! 59 | 60 | __*Happy developing!*__ 61 | -------------------------------------------------------------------------------- /solidity/truffle-examples/caller-pays-for-query/contracts/CallerPaysForQuery.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >= 0.5.0 < 0.6.0; 2 | 3 | import "./provableAPI.sol"; 4 | 5 | contract CallerPaysForQuery is usingProvable { 6 | 7 | string datasource = "URL"; 8 | uint256 public queryPrice; 9 | string public ethPriceInUSD; 10 | 11 | event LogNewEthPrice(string _price); 12 | /** 13 | * @notice Setting a custom gas price that's higher than the 20gwei default 14 | * ensures `provable_getQueryPrice` returns the actual query price, 15 | * rather than the _first_ query price would be free and ∴ zero 16 | * when using default settings. 17 | */ 18 | constructor() 19 | public 20 | { 21 | provable_setCustomGasPrice(21 * 10 ** 9); 22 | queryPrice = provable_getPrice(datasource); 23 | } 24 | 25 | function __callback( 26 | bytes32 _myid, 27 | string memory _result, 28 | bytes memory _proof 29 | ) 30 | public 31 | { 32 | require(msg.sender == provable_cbAddress()); 33 | ethPriceInUSD = _result; 34 | emit LogNewEthPrice(ethPriceInUSD); 35 | } 36 | 37 | function getEthPriceInUSDViaProvable() 38 | public 39 | payable 40 | { 41 | require( 42 | queryPrice > 0 && 43 | msg.value >= queryPrice 44 | ); 45 | provable_query( 46 | datasource, 47 | "json(https://api.kraken.com/0/public/Ticker?pair=ETHUSD).result.XETHZUSD.c.0" 48 | ); 49 | if (msg.value > queryPrice) { 50 | msg.sender.transfer(msg.value - queryPrice); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /solidity/truffle-examples/caller-pays-for-query/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solidity/truffle-examples/caller-pays-for-query/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => 2 | deployer.deploy(artifacts.require("./Migrations.sol")) 3 | -------------------------------------------------------------------------------- /solidity/truffle-examples/caller-pays-for-query/migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => deployer.deploy(artifacts.require("CallerPaysForQuery.sol")) 2 | -------------------------------------------------------------------------------- /solidity/truffle-examples/caller-pays-for-query/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "provable-examples-using-truffle__url-datasource-caller-pays-for-query", 3 | "version": "0.1.0", 4 | "description": "Testing set up for Provable's Caller-Pays-For-Query example contract", 5 | "main": "README.md", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/n/a.git" 12 | }, 13 | "author": "Provable - Greg Kapka", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/n/a/issues" 17 | }, 18 | "homepage": "https://github.com/n/a#readme", 19 | "dependencies": { 20 | "ethereum-bridge": "0.6.2", 21 | "eslint": "^5.11.1", 22 | "eslint-config-standard": "^12.0.0", 23 | "eslint-plugin-import": "^2.14.0", 24 | "eslint-plugin-mocha": "^5.2.0", 25 | "eslint-plugin-node": "^8.0.0", 26 | "eslint-plugin-promise": "^4.0.1", 27 | "eslint-plugin-standard": "^4.0.0", 28 | "openzeppelin-test-helpers": "github:OpenZeppelin/openzeppelin-test-helpers#2e5c78fe1ad9f03be7e702ef3bb42c1573fd4aed", 29 | "web3": "1.0.0-beta.36" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /solidity/truffle-examples/caller-pays-for-query/test/caller-pays-for-query-tests.js: -------------------------------------------------------------------------------- 1 | const { 2 | waitForEvent, 3 | shouldRevert 4 | } = require('./utils') 5 | 6 | const Web3 = require('web3') 7 | const callerPaysForQueryContract = artifacts.require('CallerPaysForQuery.sol') 8 | const web3WithWebSockets = new Web3(new Web3.providers.WebsocketProvider('ws://localhost:9545')) 9 | const { toBN } = web3.utils 10 | 11 | contract('❍ Provable Truffle Examples:', ([ 12 | _deployer, 13 | _user, 14 | ...accounts 15 | ]) => { 16 | describe('❍ Caller-pays-for-query tests', () => { 17 | let contractEvents 18 | let contractMethods 19 | let contractAddress 20 | let contractQueryPrice 21 | let contractEthPriceInUSDString 22 | 23 | const gasPrice = 20e9 24 | const gasLimit = 4e6 25 | 26 | it('Should get contract methods & events', async () => { 27 | const { contract: deployedContract } = await callerPaysForQueryContract.deployed() 28 | const { methods, events } = new web3WithWebSockets.eth.Contract( 29 | deployedContract._jsonInterface, 30 | deployedContract._address 31 | ) 32 | contractEvents = events 33 | contractMethods = methods 34 | contractAddress = deployedContract._address 35 | }) 36 | 37 | it('Should be able to call `queryPrice` public getter', async () => { 38 | const queryPrice = await contractMethods 39 | .queryPrice() 40 | .call() 41 | contractQueryPrice = parseInt(queryPrice) 42 | }) 43 | 44 | it('Contract balance should be 0', async () => { 45 | const contractBalance = await web3.eth.getBalance(contractAddress) 46 | assert.isTrue(parseInt(contractBalance) === 0) 47 | }) 48 | 49 | it('Query price should be > 0', () => { 50 | assert.isTrue(contractQueryPrice > 0) 51 | }) 52 | 53 | it('User cannot make query if msg.value === 0', async () => { 54 | await shouldRevert( 55 | contractMethods 56 | .getEthPriceInUSDViaProvable() 57 | .send({ 58 | value: 0, 59 | from: _user, 60 | gas: gasLimit, 61 | gasPrice: gasPrice 62 | }) 63 | ) 64 | }) 65 | 66 | it('User cannot make query if msg.value < query cost', async () => { 67 | await shouldRevert( 68 | contractMethods 69 | .getEthPriceInUSDViaProvable() 70 | .send({ 71 | value: contractQueryPrice - 1, 72 | from: _user, 73 | gas: gasLimit, 74 | gasPrice: gasPrice 75 | }) 76 | ) 77 | }) 78 | 79 | it('User can make query if msg.value === query cost', () => { 80 | contractMethods 81 | .getEthPriceInUSDViaProvable() 82 | .send({ 83 | value: contractQueryPrice, 84 | from: _user, 85 | gas: gasLimit, 86 | gasPrice: gasPrice 87 | }) 88 | }) 89 | 90 | it('Query should have emitted event with ETH price in USD', async () => { 91 | const event = await waitForEvent(contractEvents.LogNewEthPrice) 92 | contractEthPriceInUSDString = event.returnValues._price 93 | }) 94 | 95 | it('Eth price in USD should be saved in contract', async () => { 96 | const ethPriceInUSDString = await contractMethods 97 | .ethPriceInUSD() 98 | .call() 99 | assert.isTrue(parseInt(ethPriceInUSDString) > 0) 100 | assert.strictEqual( 101 | ethPriceInUSDString, 102 | contractEthPriceInUSDString 103 | ) 104 | }) 105 | 106 | it('User should get refund when making query but sending > query cost', async () => { 107 | const overspendAmount = contractQueryPrice * 2 108 | const balanceBeforeBN = toBN(await web3.eth.getBalance(_user)) 109 | const { gasUsed } = await contractMethods 110 | .getEthPriceInUSDViaProvable() 111 | .send({ 112 | from: _user, 113 | gas: gasLimit, 114 | gasPrice: gasPrice, 115 | value: overspendAmount 116 | }) 117 | const balanceAfterBN = toBN(await web3.eth.getBalance(_user)) 118 | const totalGasCostBN = toBN(gasUsed).mul(toBN(gasPrice)) 119 | const balanceDeltaBN = balanceBeforeBN.sub(balanceAfterBN) 120 | const expectedDeltaBN = toBN(contractQueryPrice).add(totalGasCostBN) 121 | assert.isTrue(expectedDeltaBN.eq(balanceDeltaBN)) 122 | }) 123 | }) 124 | }) 125 | -------------------------------------------------------------------------------- /solidity/truffle-examples/caller-pays-for-query/test/utils.js: -------------------------------------------------------------------------------- 1 | const shouldFail = require('openzeppelin-test-helpers/src/shouldFail') 2 | 3 | module.exports.waitForEvent = (_event, _from = 0, _to = 'latest') => 4 | new Promise((resolve, reject) => 5 | _event({ fromBlock: _from, toBlock: _to }, (e, ev) => 6 | e ? reject(e) : resolve(ev))) 7 | 8 | module.exports.shouldRevert = _method => 9 | shouldFail.reverting(_method) 10 | -------------------------------------------------------------------------------- /solidity/truffle-examples/caller-pays-for-query/truffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | networks: { 3 | development: { 4 | host: "127.0.0.1", 5 | port: 9545, 6 | network_id: "*", 7 | websockets: true 8 | } 9 | }, 10 | compilers: { 11 | solc: { 12 | version: "0.5.0", 13 | settings: { 14 | optimizer: { 15 | enabled: true, 16 | runs: 200 17 | } 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /solidity/truffle-examples/delegated-math/README.md: -------------------------------------------------------------------------------- 1 | # :wrench: :construction: Testing Provable's Delegated Math Example. 2 | 3 |   4 | 5 | This repo is to demonstrate how you would set up a Provable smart-contract development environment using Truffle & the Ethereum-Bridge to do most of the heavy lifting for you. Head on over to the `./test` folder to examine the javascript files that thoroughly test the smart-contract, which latter you will find in `./contracts`. 6 | 7 | ## :page_with_curl: _Instructions_ 8 | 9 | **1)** Fire up your favourite console & clone this repo somewhere: 10 | 11 | __`❍ git clone https://github.com/provable-things/ethereum-examples.git`__ 12 | 13 | **2)** Enter this directory & install dependencies: 14 | 15 | __`❍ cd ethereum-examples/solidity/truffle-examples/delegated-math && npm install`__ 16 | 17 | **3)** Launch Truffle: 18 | 19 | __`❍ npx truffle develop`__ 20 | 21 | **4)** Open a _new_ console in the same directory & spool up the ethereum-bridge: 22 | 23 | __`❍ npx ethereum-bridge -a 9 -H 127.0.0.1 -p 9545 --dev`__ 24 | 25 | **5)** Once the bridge is ready & listening, go back to the first console with Truffle running & set the tests going! 26 | 27 | __`❍ truffle(develop)> test`__ 28 | 29 |   30 | 31 | ## :camera: Passing Tests: 32 | 33 | ```javascript 34 | Contract: Delegated Math Example Tests 35 | ✓ Should retrieve a result from an offchain computation (80350ms) 36 | ✓ Should have calculated the offchain computation correctly 37 | 38 | 39 | 2 passing (1m) 40 | ``` 41 | 42 |   43 | 44 | ## :black_nib: Notes: 45 | 46 | __❍__ If you have any issues, head on over to our [Gitter](https://gitter.im/provable/ethereum-api?raw=true) channel to get timely support! 47 | 48 | __*Happy developing!*__ 49 | -------------------------------------------------------------------------------- /solidity/truffle-examples/delegated-math/computation-archive/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | MAINTAINER Provable "info@provable.xyz" 3 | 4 | RUN apt-get update && apt-get install bc 5 | CMD echo $ARG0 + $ARG1 | /usr/bin/bc \ 6 | && exit 0; 7 | -------------------------------------------------------------------------------- /solidity/truffle-examples/delegated-math/computation-archive/archive.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/provable-things/ethereum-examples/f3f650836016c43be3b18ba2819a5609078b0447/solidity/truffle-examples/delegated-math/computation-archive/archive.zip -------------------------------------------------------------------------------- /solidity/truffle-examples/delegated-math/contracts/DelegatedMath.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >= 0.5.0 < 0.6.0; 2 | 3 | import "./provableAPI.sol"; 4 | 5 | contract DelegatedMath is usingProvable { 6 | 7 | event LogOperationResult(uint result); 8 | 9 | constructor() 10 | public 11 | { 12 | provable_setProof(proofType_TLSNotary | proofStorage_IPFS); 13 | delegateOperation("32", "125"); 14 | } 15 | 16 | function __callback( 17 | bytes32 _myid, 18 | string memory _result, 19 | bytes memory _proof 20 | ) 21 | public 22 | { 23 | require(msg.sender == provable_cbAddress()); 24 | emit LogOperationResult(parseInt(_result)); 25 | } 26 | 27 | function delegateOperation( 28 | string memory _firstOperand, 29 | string memory _secondOperand 30 | ) 31 | public 32 | payable 33 | { 34 | provable_query("computation", ["Qmc8jmuT47cPWadF8ZhErGXj7J4VEp5H29knukCGirsN19", _firstOperand, _secondOperand]); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /solidity/truffle-examples/delegated-math/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solidity/truffle-examples/delegated-math/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => 2 | deployer.deploy(artifacts.require("./Migrations.sol")) 3 | -------------------------------------------------------------------------------- /solidity/truffle-examples/delegated-math/migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => deployer.deploy(artifacts.require("DelegatedMath.sol")) 2 | -------------------------------------------------------------------------------- /solidity/truffle-examples/delegated-math/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "provable-examples-using-truffle__computation-datasource-delegated-math", 3 | "version": "0.1.0", 4 | "description": "Testing set up for Provable's Delegated-Math example contract", 5 | "main": "README.md", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/n/a.git" 12 | }, 13 | "author": "Provable - Greg Kapka", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/n/a/issues" 17 | }, 18 | "homepage": "https://github.com/n/a#readme", 19 | "dependencies": { 20 | "ethereum-bridge": "0.6.2", 21 | "web3": "1.0.0-beta.36" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solidity/truffle-examples/delegated-math/test/delegated-math-test.js: -------------------------------------------------------------------------------- 1 | const Web3 = require('web3') 2 | const { waitForEvent } = require('./utils') 3 | const delegatedMath = artifacts.require('DelegatedMath.sol') 4 | const web3 = new Web3(new Web3.providers.WebsocketProvider('ws://localhost:9545')) 5 | 6 | contract('Delegated Math Example Tests', () => { 7 | 8 | let delegateResult 9 | 10 | beforeEach(async () => ( 11 | { contract } = await delegatedMath.deployed(), 12 | { methods, events } = new web3.eth.Contract( 13 | contract._jsonInterface, 14 | contract._address 15 | ) 16 | )) 17 | 18 | it('Should retrieve a result from an offchain computation', async () => { 19 | const event = await waitForEvent(events.LogOperationResult) 20 | delegateResult = event.returnValues.result 21 | assert.isAbove( 22 | parseInt(delegateResult), 23 | 0, 24 | 'No result was retrieved from the offchain computation!' 25 | ) 26 | }) 27 | 28 | it('Should have calculated the offchain computation correctly', async () => { 29 | const delegateOp = 32 + 125 // Note: Operands are taken from the smart-contract 30 | assert.equal( 31 | delegateOp, 32 | delegateResult, 33 | 'Offchain computation was not performed correctly!' 34 | ) 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /solidity/truffle-examples/delegated-math/test/utils.js: -------------------------------------------------------------------------------- 1 | const PREFIX = 'Returned error: VM Exception while processing transaction: ' 2 | 3 | const waitForEvent = (_event, _from = 0, _to = 'latest') => 4 | new Promise ((resolve,reject) => 5 | _event({fromBlock: _from, toBlock: _to}, (e, ev) => 6 | e ? reject(e) : resolve(ev))) 7 | 8 | module.exports = { 9 | waitForEvent, 10 | PREFIX 11 | } 12 | -------------------------------------------------------------------------------- /solidity/truffle-examples/delegated-math/truffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | networks: { 3 | development: { 4 | host: "127.0.0.1", 5 | port: 9545, 6 | network_id: "*", 7 | websockets: true 8 | } 9 | }, 10 | compilers: { 11 | solc: { 12 | version: "0.5.0", 13 | settings: { 14 | optimizer: { 15 | enabled: true, 16 | runs: 200 17 | } 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /solidity/truffle-examples/diesel-price/README.md: -------------------------------------------------------------------------------- 1 | # :wrench: :construction: Testing Provable's Diesel Prices Example. 2 | 3 |   4 | 5 | This repo is to demonstrate how you would set up a Provable smart-contract development environment using Truffle & the Ethereum-Bridge to do most of the heavy lifting for you. Head on over to the `./test` folder to examine the javascript files that thoroughly test the smart-contract, which latter you will find in `./contracts`. 6 | 7 | ## :page_with_curl: _Instructions_ 8 | 9 | **1)** Fire up your favourite console & clone this repo somewhere: 10 | 11 | __`❍ git clone https://github.com/provable-things/ethereum-examples.git`__ 12 | 13 | **2)** Enter this directory & install dependencies: 14 | 15 | __`❍ cd ethereum-examples/solidity/truffle-examples/diesel-price && npm install`__ 16 | 17 | **3)** Launch Truffle: 18 | 19 | __`❍ npx truffle develop`__ 20 | 21 | **4)** Open a _new_ console in the same directory & spool up the ethereum-bridge: 22 | 23 | __`❍ npx ethereum-bridge -a 9 -H 127.0.0.1 -p 9545 --dev `__ 24 | 25 | **5)** Once the bridge is ready & listening, go back to the first console with Truffle running & set the tests going! 26 | 27 | __`❍ truffle(develop)> test`__ 28 | 29 |   30 | 31 | ## :camera: Passing Tests: 32 | 33 | ```javascript 34 | Contract: Diesel Price Tests 35 | ✓ Should have logged a new Provable query 36 | ✓ Callback should have logged a new diesel price (4994ms) 37 | ✓ Should set diesel price correctly in contract 38 | ✓ Should revert on second query attempt due to lack of funds (44ms) 39 | 40 | 4 passing (6s) 41 | ``` 42 | 43 |   44 | 45 | ## :black_nib: Notes: 46 | 47 | __❍__ If you have any issues, head on over to our [Gitter](https://gitter.im/provable/ethereum-api?raw=true) channel to get timely support! 48 | 49 | __*Happy developing!*__ 50 | -------------------------------------------------------------------------------- /solidity/truffle-examples/diesel-price/contracts/DieselPrice.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >= 0.5.0 < 0.6.0; 2 | 3 | import "./provableAPI.sol"; 4 | 5 | contract DieselPrice is usingProvable { 6 | 7 | uint public dieselPriceUSD; 8 | 9 | event LogNewDieselPrice(string price); 10 | event LogNewProvableQuery(string description); 11 | 12 | constructor() 13 | public 14 | { 15 | update(); // First check at contract creation... 16 | } 17 | 18 | function __callback( 19 | bytes32 myid, 20 | string memory result 21 | ) 22 | public 23 | { 24 | require(msg.sender == provable_cbAddress()); 25 | emit LogNewDieselPrice(result); 26 | dieselPriceUSD = parseInt(result, 2); // Let's save it as cents... 27 | // Now do something with the USD Diesel price... 28 | } 29 | 30 | function update() 31 | public 32 | payable 33 | { 34 | emit LogNewProvableQuery("Provable query was sent, standing by for the answer..."); 35 | provable_query("URL", "xml(https://www.fueleconomy.gov/ws/rest/fuelprices).fuelPrices.diesel"); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /solidity/truffle-examples/diesel-price/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solidity/truffle-examples/diesel-price/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => 2 | deployer.deploy(artifacts.require("./Migrations.sol")) 3 | -------------------------------------------------------------------------------- /solidity/truffle-examples/diesel-price/migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => deployer.deploy(artifacts.require("DieselPrice.sol")) 2 | -------------------------------------------------------------------------------- /solidity/truffle-examples/diesel-price/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "provable-examples-using-truffle__diesel-price", 3 | "version": "0.1.0", 4 | "description": "Testing set up for Provable's Diesel Price example contract", 5 | "main": "README.md", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/n/a.git" 12 | }, 13 | "author": "Provable - Greg Kapka", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/n/a/issues" 17 | }, 18 | "homepage": "https://github.com/n/a#readme", 19 | "dependencies": { 20 | "ethereum-bridge": "0.6.2", 21 | "web3": "1.0.0-beta.36" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solidity/truffle-examples/diesel-price/test/diesel-price-test.js: -------------------------------------------------------------------------------- 1 | const { 2 | PREFIX, 3 | waitForEvent 4 | } = require('./utils') 5 | 6 | const Web3 = require('web3') 7 | const diesel = artifacts.require('./DieselPrice.sol') 8 | const web3 = new Web3(new Web3.providers.WebsocketProvider('ws://localhost:9545')) 9 | 10 | contract('Diesel Price Tests', accounts => { 11 | 12 | let contractPrice 13 | const gasAmt = 3e6 14 | const address = accounts[0] 15 | 16 | beforeEach(async () => ( 17 | { contract } = await diesel.deployed(), 18 | { methods, events } = new web3.eth.Contract( 19 | contract._jsonInterface, 20 | contract._address 21 | ) 22 | )) 23 | 24 | it('Should have logged a new Provable query', async () => { 25 | const { 26 | returnValues: { 27 | description 28 | } 29 | } = await waitForEvent(events.LogNewProvableQuery) 30 | assert.strictEqual( 31 | description, 32 | 'Provable query was sent, standing by for the answer...', 33 | 'Provable query incorrectly logged!' 34 | ) 35 | }) 36 | 37 | it('Callback should have logged a new diesel price', async () => { 38 | const { 39 | returnValues: { 40 | price 41 | } 42 | } = await waitForEvent(events.LogNewDieselPrice) 43 | contractPrice = price * 100 44 | assert.isAbove( 45 | parseInt(price), 46 | 0, 47 | 'A price should have been retrieved from Provable call!' 48 | ) 49 | }) 50 | 51 | it('Should set diesel price correctly in contract', async () => { 52 | const queriedPrice = await methods 53 | .dieselPriceUSD() 54 | .call() 55 | assert.strictEqual( 56 | parseInt(contractPrice), 57 | parseInt(queriedPrice), 58 | 'Contract\'s diesel price not set correctly!' 59 | ) 60 | }) 61 | 62 | it('Should revert on second query attempt due to lack of funds', async () => { 63 | const expErr = 'revert' 64 | try { 65 | await methods 66 | .update() 67 | .send({ 68 | from: address, 69 | gas: gasAmt 70 | }) 71 | assert.fail('Update transaction should not have succeeded!') 72 | } catch (e) { 73 | assert.isTrue( 74 | e.message.startsWith(`${PREFIX}${expErr}`), 75 | `Expected ${expErr} but got ${e.message} instead!` 76 | ) 77 | } 78 | }) 79 | }) 80 | -------------------------------------------------------------------------------- /solidity/truffle-examples/diesel-price/test/utils.js: -------------------------------------------------------------------------------- 1 | const PREFIX = 'Returned error: VM Exception while processing transaction: ' 2 | 3 | const waitForEvent = (_event, _from = 0, _to = 'latest') => 4 | new Promise ((resolve,reject) => 5 | _event({fromBlock: _from, toBlock: _to}, (e, ev) => 6 | e ? reject(e) : resolve(ev))) 7 | 8 | module.exports = { 9 | waitForEvent, 10 | PREFIX 11 | } 12 | -------------------------------------------------------------------------------- /solidity/truffle-examples/diesel-price/truffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | networks: { 3 | development: { 4 | host: "127.0.0.1", 5 | port: 9545, 6 | network_id: "*", 7 | websockets: true 8 | } 9 | }, 10 | compilers: { 11 | solc: { 12 | version: "0.5.0", 13 | settings: { 14 | optimizer: { 15 | enabled: true, 16 | runs: 200 17 | } 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /solidity/truffle-examples/encrypted-query/README.md: -------------------------------------------------------------------------------- 1 | # :wrench: :construction: Testing Provable's Encrypted Query Example. 2 | 3 |   4 | 5 | This repo is to demonstrate how you would set up a Provable smart-contract development environment using Truffle & the Ethereum-Bridge to do most of the heavy lifting for you. Head on over to the `./test` folder to examine the javascript files that thoroughly test the smart-contract, which later you will find in `./contracts`. 6 | 7 | ## :squirrel: _Query Encryption_ 8 | 9 | **1)** Decide on the Provable query you want to encrypt, the one in this example is: 10 | 11 | ``` 12 | provable_query( 13 | "URL", 14 | "json(https://api.postcodes.io/postcodes).status", 15 | '{"postcodes" : ["OX49 5NU", "M32 0JG", "NE30 1DP"]}' 16 | ) 17 | ``` 18 | 19 | **2)** Fire up your favourite console & clone the Provable encyption tool repo somewhere: 20 | 21 | __`❍ git clone https://github.com/provable-things/encrypted-queries.git`__ 22 | 23 | **3)** Enter the directory and brace yourself to encrypt your query with the Provable public key: 24 | 25 | __`❍ cd encrypted-queries`__ 26 | 27 | Provable public key: 28 | 29 | ``` 30 | 044992e9473b7d90ca54d2886c7addd14a61109af202f1c95e218b0c99eb060c7134c4ae46345d0383ac996185762f04997d6fd6c393c86e4325c469741e64eca9 31 | ``` 32 | 33 | **4)** Encrypt the first query argument: 34 | 35 | __`❍ python encrypted_queries_tools.py -e -p 044992e9473b7d90ca54d2886c7addd14a61109af202f1c95e218b0c99eb060c7134c4ae46345d0383ac996185762f04997d6fd6c393c86e4325c469741e64eca9 "json(https://api.postcodes.io/postcodes).status"`__ 36 | 37 | it will generate a unique encrypted string (each re-run will generate a new unique string, as each encrypted string is meant to be used only by a single contract at a time): 38 | 39 | ``` 40 | BMqMhIFTTzsDbUSfPT233dVWB6wp0ksci7R/c6Jezcy3nEsnX7EQTaqRbej3shF7NlOwGRJAs1IBtYS32f6HrexffY+z1XMCHp+W6vFaIpDSVP0sVxiokuO0fr+ePxHOkvUh9x49BSmageBbHM1RB6QY/xhhvwJtssZOspEHvic= 41 | ``` 42 | 43 | **5)** Encrypt the second query argument: 44 | 45 | __`❍ python encrypted_queries_tools.py -e -p 044992e9473b7d90ca54d2886c7addd14a61109af202f1c95e218b0c99eb060c7134c4ae46345d0383ac996185762f04997d6fd6c393c86e4325c469741e64eca9 '{"postcodes" : ["OX49 5NU", "M32 0JG", "NE30 1DP"]}'`__ 46 | 47 | returning yet another unique encrypted string you will put in place of the plain text query: 48 | 49 | ``` 50 | BDfT0gaCqtru/YRL/qEDEPTopcKe04wXtkRlDw0PNa8hazsDgKXv1G0pBVaHK5um6eTzAggrLKlXVLSUqI6rVzd9oaDST4Zo1NtLf2iMwWI0yx7sWwuhFY0Ot+OltgHLf8SclyRuHZHiOq+Ubx1pBtFGImYH4yMon1PgR+V9iWqN2gzv 51 | ``` 52 | 53 | **6)** Use the previous two non-deterministic outputs and plug them into the query function: 54 | 55 | ``` 56 | provable_query( 57 | "URL", 58 | "BMqMhIFTTzsDbUSfPT233dVWB6wp0ksci7R/c6Jezcy3nEsnX7EQTaqRbej3shF7NlOwGRJAs1IBtYS32f6HrexffY+z1XMCHp+W6vFaIpDSVP0sVxiokuO0fr+ePxHOkvUh9x49BSmageBbHM1RB6QY/xhhvwJtssZOspEHvic=", 59 | "BDfT0gaCqtru/YRL/qEDEPTopcKe04wXtkRlDw0PNa8hazsDgKXv1G0pBVaHK5um6eTzAggrLKlXVLSUqI6rVzd9oaDST4Zo1NtLf2iMwWI0yx7sWwuhFY0Ot+OltgHLf8SclyRuHZHiOq+Ubx1pBtFGImYH4yMon1PgR+V9iWqN2gzv" 60 | ); 61 | ``` 62 | 63 |   64 | 65 | ## :page_with_curl: _Instructions_ 66 | 67 | **1)** Fire up your favourite console & clone this repo somewhere: 68 | 69 | __`❍ git clone https://github.com/provable-things/ethereum-examples.git`__ 70 | 71 | **2)** Enter this directory & install dependencies: 72 | 73 | __`❍ cd ethereum-examples/solidity/truffle-examples/encrypted-query && npm install`__ 74 | 75 | **3)** Launch Truffle: 76 | 77 | __`❍ npx truffle develop`__ 78 | 79 | **4)** Open a _new_ console in the same directory & spool up the ethereum-bridge: 80 | 81 | __`❍ npx ethereum-bridge -a 9 -H 127.0.0.1 -p 9545 --dev`__ 82 | 83 | **5)** Once the bridge is ready & listening, go back to the first console with Truffle running & set the tests going! 84 | 85 | __`❍ truffle(develop)> test`__ 86 | 87 |   88 | 89 | ## :camera: Passing Tests: 90 | 91 | ``` 92 | Contract: Encrypted Query Tests 93 | ✓ Should log a new Provable query 94 | ✓ Callback should log a new request status (40576ms) 95 | ✓ Should set request status correctly in contract 96 | ✓ Should log a failed query due to lack of funds (64ms) 97 | 98 | 4 passing (41s) 99 | ``` 100 | 101 |   102 | 103 | ## :black_nib: Notes: 104 | 105 | __❍__ If you have any issues, head on over to our [Gitter](https://gitter.im/provable/ethereum-api?raw=true) channel to get timely support! 106 | 107 | __*Happy developing!*__ 108 | -------------------------------------------------------------------------------- /solidity/truffle-examples/encrypted-query/contracts/EncryptedQuery.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >= 0.5.0 < 0.6.0; 2 | 3 | import "./provableAPI.sol"; 4 | 5 | contract EncryptedQuery is usingProvable { 6 | 7 | string public requestStatus; 8 | 9 | event LogNewProvableQuery(string description); 10 | event LogNewRequestStatus(string status); 11 | 12 | constructor() 13 | public 14 | { 15 | update(); // Update status on contract creation... 16 | } 17 | 18 | function __callback( 19 | bytes32 _myid, 20 | string memory _result, 21 | bytes memory _proof 22 | ) 23 | public 24 | { 25 | require(msg.sender == provable_cbAddress()); 26 | update(); // Recursively update the status stored in the contract... 27 | requestStatus = _result; 28 | emit LogNewRequestStatus(requestStatus); 29 | } 30 | 31 | function update() 32 | public 33 | payable 34 | { 35 | if (provable_getPrice("URL") > address(this).balance) { 36 | emit LogNewProvableQuery("Provable query was NOT sent, please add some ETH to cover for the query fee!"); 37 | } else { 38 | emit LogNewProvableQuery("Provable query was sent, standing by for the answer..."); 39 | // Query not encrypted: provable_query("URL","json(https://api.postcodes.io/postcodes).status",'{"postcodes" : ["OX49 5NU", "M32 0JG", "NE30 1DP"]}'); 40 | provable_query( 41 | "URL", 42 | "BMqMhIFTTzsDbUSfPT233dVWB6wp0ksci7R/c6Jezcy3nEsnX7EQTaqRbej3shF7NlOwGRJAs1IBtYS32f6HrexffY+z1XMCHp+W6vFaIpDSVP0sVxiokuO0fr+ePxHOkvUh9x49BSmageBbHM1RB6QY/xhhvwJtssZOspEHvic=", 43 | "BDfT0gaCqtru/YRL/qEDEPTopcKe04wXtkRlDw0PNa8hazsDgKXv1G0pBVaHK5um6eTzAggrLKlXVLSUqI6rVzd9oaDST4Zo1NtLf2iMwWI0yx7sWwuhFY0Ot+OltgHLf8SclyRuHZHiOq+Ubx1pBtFGImYH4yMon1PgR+V9iWqN2gzv" 44 | ); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /solidity/truffle-examples/encrypted-query/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | contract Migrations { 4 | 5 | address public owner; 6 | uint public last_completed_migration; 7 | 8 | constructor() public { 9 | owner = msg.sender; 10 | } 11 | 12 | modifier restricted() { 13 | if (msg.sender == owner) _; 14 | } 15 | 16 | function setCompleted(uint completed) public restricted { 17 | last_completed_migration = completed; 18 | } 19 | 20 | function upgrade(address new_address) public restricted { 21 | Migrations upgraded = Migrations(new_address); 22 | upgraded.setCompleted(last_completed_migration); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /solidity/truffle-examples/encrypted-query/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => 2 | deployer.deploy(artifacts.require("./Migrations.sol")) 3 | -------------------------------------------------------------------------------- /solidity/truffle-examples/encrypted-query/migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => deployer.deploy(artifacts.require("EncryptedQuery.sol")) 2 | -------------------------------------------------------------------------------- /solidity/truffle-examples/encrypted-query/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "provable-examples-using-truffle__url-datasource-encrypted-query", 3 | "version": "0.1.0", 4 | "description": "Testing set up for Provable's Encrypted Query example contract", 5 | "main": "README.md", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/n/a.git" 12 | }, 13 | "author": "Provable - Riccardo Persiani", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/n/a/issues" 17 | }, 18 | "homepage": "https://github.com/n/a#readme", 19 | "dependencies": { 20 | "ethereum-bridge": "0.6.2", 21 | "web3": "1.0.0-beta.36" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solidity/truffle-examples/encrypted-query/test/encrypted-query.js: -------------------------------------------------------------------------------- 1 | const Web3 = require('web3') 2 | const { waitForEvent } = require('./utils') 3 | const encrypted = artifacts.require('./EncryptedQuery.sol') 4 | const web3 = new Web3(new Web3.providers.WebsocketProvider('ws://localhost:9545')) 5 | 6 | contract('Encrypted Query Tests', accounts => { 7 | 8 | let requestStatus 9 | const gasAmt = 3e6 10 | const address = accounts[0] 11 | 12 | beforeEach(async () => ( 13 | { contract } = await encrypted.deployed(), 14 | { methods, events } = new web3.eth.Contract( 15 | contract._jsonInterface, 16 | contract._address 17 | ) 18 | )) 19 | 20 | it('Should log a new Provable query', async () => { 21 | const { 22 | returnValues: { 23 | description 24 | } 25 | } = await waitForEvent(events.LogNewProvableQuery) 26 | assert.strictEqual( 27 | description, 28 | 'Provable query was sent, standing by for the answer...', 29 | 'Provable query incorrectly logged!' 30 | ) 31 | }) 32 | 33 | it('Callback should log a new request status', async () => { 34 | const { 35 | returnValues: { 36 | status 37 | } 38 | } = await waitForEvent(events.LogNewRequestStatus) 39 | requestStatus = status 40 | assert.isAbove( 41 | parseFloat(status), 42 | 0, 43 | 'A price should have been retrieved from Provable call!' 44 | ) 45 | }) 46 | 47 | it('Should set request status correctly in contract', async () => { 48 | const queriedStatus = await methods 49 | .requestStatus() 50 | .call() 51 | assert.strictEqual( 52 | requestStatus, 53 | queriedStatus, 54 | 'Contract\'s status not set correctly!' 55 | ) 56 | }) 57 | 58 | it('Should log a failed query due to lack of funds', async () => { 59 | const { events } = await methods 60 | .update() 61 | .send({ 62 | from: address, 63 | gas: gasAmt 64 | }) 65 | const description = events.LogNewProvableQuery.returnValues.description 66 | assert.strictEqual( 67 | description, 68 | 'Provable query was NOT sent, please add some ETH to cover for the query fee!', 69 | 'Provable query incorrectly logged!' 70 | ) 71 | }) 72 | }) 73 | -------------------------------------------------------------------------------- /solidity/truffle-examples/encrypted-query/test/utils.js: -------------------------------------------------------------------------------- 1 | const PREFIX = 'Returned error: VM Exception while processing transaction: ' 2 | 3 | const waitForEvent = (_event, _from = 0, _to = 'latest') => 4 | new Promise ((resolve,reject) => 5 | _event({fromBlock: _from, toBlock: _to}, (e, ev) => 6 | e ? reject(e) : resolve(ev))) 7 | 8 | module.exports = { 9 | waitForEvent, 10 | PREFIX 11 | } 12 | -------------------------------------------------------------------------------- /solidity/truffle-examples/encrypted-query/truffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | networks: { 3 | development: { 4 | host: "127.0.0.1", 5 | port: 9545, 6 | network_id: "*", 7 | websockets: true 8 | } 9 | }, 10 | compilers: { 11 | solc: { 12 | version: "0.5.0", 13 | settings: { 14 | optimizer: { 15 | enabled: true, 16 | runs: 200 17 | } 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /solidity/truffle-examples/kraken-price-ticker/README.md: -------------------------------------------------------------------------------- 1 | # :wrench: :construction: Testing Provable's Kraken Price Ticker Example. 2 | 3 |   4 | 5 | This repo is to demonstrate how you would set up a Provable smart-contract development environment using Truffle & the Ethereum-Bridge to do most of the heavy lifting for you. Head on over to the `./test` folder to examine the javascript files that thoroughly test the smart-contract, which latter you will find in `./contracts`. 6 | 7 | ## :page_with_curl: _Instructions_ 8 | 9 | **1)** Fire up your favourite console & clone this repo somewhere: 10 | 11 | __`❍ git clone https://github.com/provable-things/ethereum-examples.git`__ 12 | 13 | **2)** Enter this directory & install dependencies: 14 | 15 | __`❍ cd ethereum-examples/solidity/truffle-examples/kraken-price-ticker && npm install`__ 16 | 17 | **3)** Launch Truffle: 18 | 19 | __`❍ npx truffle develop`__ 20 | 21 | **4)** Open a _new_ console in the same directory & spool up the ethereum-bridge: 22 | 23 | __`❍ npx ethereum-bridge -a 9 -H 127.0.0.1 -p 9545 --dev`__ 24 | 25 | **5)** Once the bridge is ready & listening, go back to the first console with Truffle running & set the tests going! 26 | 27 | __`❍ truffle(develop)> test`__ 28 | 29 |   30 | 31 | ## :camera: Passing Tests: 32 | 33 | ```javascript 34 | 35 | Contract: Kraken Price Ticker Tests 36 | ✓ Should log a new Provable query 37 | ✓ Callback should log a new ETHXBT price (79193ms) 38 | ✓ Should set ETHXBT price correctly in contract 39 | ✓ Should log a failed query due to lack of funds (79ms) 40 | 41 | 4 passing (1m) 42 | 43 | ``` 44 | 45 |   46 | 47 | ## :black_nib: Notes: 48 | 49 | __❍__ If you have any issues, head on over to our [Gitter](https://gitter.im/provable/ethereum-api?raw=true) channel to get timely support! 50 | 51 | __*Happy developing!*__ 52 | -------------------------------------------------------------------------------- /solidity/truffle-examples/kraken-price-ticker/contracts/KrakenPriceTicker.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >= 0.5.0 < 0.6.0; 2 | 3 | import "./provableAPI.sol"; 4 | 5 | contract KrakenPriceTicker is usingProvable { 6 | 7 | string public priceETHXBT; 8 | 9 | event LogNewProvableQuery(string description); 10 | event LogNewKrakenPriceTicker(string price); 11 | 12 | constructor() 13 | public 14 | { 15 | provable_setProof(proofType_Android | proofStorage_IPFS); 16 | update(); // Update price on contract creation... 17 | } 18 | 19 | function __callback( 20 | bytes32 _myid, 21 | string memory _result, 22 | bytes memory _proof 23 | ) 24 | public 25 | { 26 | require(msg.sender == provable_cbAddress()); 27 | update(); // Recursively update the price stored in the contract... 28 | priceETHXBT = _result; 29 | emit LogNewKrakenPriceTicker(priceETHXBT); 30 | } 31 | 32 | function update() 33 | public 34 | payable 35 | { 36 | if (provable_getPrice("URL") > address(this).balance) { 37 | emit LogNewProvableQuery("Provable query was NOT sent, please add some ETH to cover for the query fee!"); 38 | } else { 39 | emit LogNewProvableQuery("Provable query was sent, standing by for the answer..."); 40 | provable_query(60, "URL", "json(https://api.kraken.com/0/public/Ticker?pair=ETHXBT).result.XETHXXBT.c.0"); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /solidity/truffle-examples/kraken-price-ticker/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solidity/truffle-examples/kraken-price-ticker/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => 2 | deployer.deploy(artifacts.require("./Migrations.sol")) 3 | -------------------------------------------------------------------------------- /solidity/truffle-examples/kraken-price-ticker/migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => deployer.deploy(artifacts.require("KrakenPriceTicker.sol")) 2 | -------------------------------------------------------------------------------- /solidity/truffle-examples/kraken-price-ticker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "provable-examples-using-truffle__url-datasource-kraken-price-ticker", 3 | "version": "0.1.0", 4 | "description": "Testing set up for Provable's Kraken-Price-Ticker example contract", 5 | "main": "README.md", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/n/a.git" 12 | }, 13 | "author": "Provable - Greg Kapka", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/n/a/issues" 17 | }, 18 | "homepage": "https://github.com/n/a#readme", 19 | "dependencies": { 20 | "ethereum-bridge": "0.6.2", 21 | "web3": "1.0.0-beta.36" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solidity/truffle-examples/kraken-price-ticker/test/kraken-price-ticker-test.js: -------------------------------------------------------------------------------- 1 | const Web3 = require('web3') 2 | const { waitForEvent } = require('./utils') 3 | const kraken = artifacts.require('./KrakenPriceTicker.sol') 4 | const web3 = new Web3(new Web3.providers.WebsocketProvider('ws://localhost:9545')) 5 | 6 | contract('Kraken Price Ticker Tests', accounts => { 7 | 8 | let priceETHXBT 9 | const gasAmt = 3e6 10 | const address = accounts[0] 11 | 12 | beforeEach(async () => ( 13 | { contract } = await kraken.deployed(), 14 | { methods, events } = new web3.eth.Contract( 15 | contract._jsonInterface, 16 | contract._address 17 | ) 18 | )) 19 | 20 | it('Should log a new Provable query', async () => { 21 | const { 22 | returnValues: { 23 | description 24 | } 25 | } = await waitForEvent(events.LogNewProvableQuery) 26 | assert.strictEqual( 27 | description, 28 | 'Provable query was sent, standing by for the answer...', 29 | 'Provable query incorrectly logged!' 30 | ) 31 | }) 32 | 33 | it('Callback should log a new ETHXBT price', async () => { 34 | const { 35 | returnValues: { 36 | price 37 | } 38 | } = await waitForEvent(events.LogNewKrakenPriceTicker) 39 | priceETHXBT = price 40 | assert.isAbove( 41 | parseFloat(price), 42 | 0, 43 | 'A price should have been retrieved from Provable call!' 44 | ) 45 | }) 46 | 47 | it('Should set ETHXBT price correctly in contract', async () => { 48 | const queriedPrice = await methods 49 | .priceETHXBT() 50 | .call() 51 | assert.strictEqual( 52 | priceETHXBT, 53 | queriedPrice, 54 | 'Contract\'s ETHXBT price not set correctly!' 55 | ) 56 | }) 57 | 58 | it('Should log a failed query due to lack of funds', async () => { 59 | const { events } = await methods 60 | .update() 61 | .send({ 62 | from: address, 63 | gas: gasAmt 64 | }) 65 | const description = events.LogNewProvableQuery.returnValues.description 66 | assert.strictEqual( 67 | description, 68 | 'Provable query was NOT sent, please add some ETH to cover for the query fee!', 69 | 'Provable query incorrectly logged!' 70 | ) 71 | }) 72 | }) 73 | -------------------------------------------------------------------------------- /solidity/truffle-examples/kraken-price-ticker/test/utils.js: -------------------------------------------------------------------------------- 1 | const PREFIX = 'Returned error: VM Exception while processing transaction: ' 2 | 3 | const waitForEvent = (_event, _from = 0, _to = 'latest') => 4 | new Promise ((resolve,reject) => 5 | _event({fromBlock: _from, toBlock: _to}, (e, ev) => 6 | e ? reject(e) : resolve(ev))) 7 | 8 | module.exports = { 9 | waitForEvent, 10 | PREFIX 11 | } 12 | -------------------------------------------------------------------------------- /solidity/truffle-examples/kraken-price-ticker/truffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | networks: { 3 | development: { 4 | host: "127.0.0.1", 5 | port: 9545, 6 | network_id: "*", 7 | websockets: true 8 | } 9 | }, 10 | compilers: { 11 | solc: { 12 | version: "0.5.0", 13 | settings: { 14 | optimizer: { 15 | enabled: true, 16 | runs: 200 17 | } 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /solidity/truffle-examples/random-datasource/README.md: -------------------------------------------------------------------------------- 1 | # :wrench: :construction: Testing Provable's Random Example. 2 | 3 |   4 | 5 | This repo is to demonstrate how you would set up a Provable smart-contract development environment using Truffle to do most of the heavy lifting for you. Head on over to the `./test` folder to examine the javascript files that thoroughly test the smart-contract, which latter you will find in `./contracts`. 6 | 7 | > **Note:** The Random Datasource currently does not support a delay > 0. 8 | > 9 | ## :page_with_curl: _Instructions_ 10 | 11 | The random datasource is currently available on the Ethereum mainnet and on some Ethereum public testnets only (Rinkeby, Kovan, and Ropsten Revival); and it is not integrated yet with private blockchains/testrpc/browser-solidity-vmmode, so you will need to get a mnemonic passphrase and an infura key to make the example work. 12 | 13 | **1)** Go on the Infura website to get an Infura key: [infura.io](https://infura.io). The key is a 32 HEX characters string 14 | 15 | **2)** Get a mnemonic passphrase, an easy way is to get a Metamask one: [metamask.io](https://metamask.io/) 16 | 17 | **3)** Fire up your favourite console & clone this repo somewhere: 18 | 19 | __`❍ git clone https://github.com/provable-things/ethereum-examples.git`__ 20 | 21 | **4)** Enter this directory & install dependencies: 22 | 23 | __`❍ cd ethereum-examples/solidity/truffle-examples/random-datasource && npm install`__ 24 | 25 | **5)** In `ethereum-examples/solidity/truffle-examples/random-datasource`, create a new file `apikeys.js` or `.env` and add the mnemonic passphrase and the Infura key to it, such as: 26 | 27 | ```javascript 28 | // apikeys.js example 29 | 30 | module.exports = { 31 | mnemonic: 'word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12', 32 | infuraKey: '0123456789abcdef0123456789abcdef' 33 | } 34 | ``` 35 | 36 | or 37 | 38 | ``` 39 | // .env example 40 | 41 | mnemonic = 'word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12' 42 | infuraKey = '0123456789abcdef0123456789abcdef' 43 | ``` 44 | 45 | **6)** Compile with Truffle: 46 | 47 | __`❍ npx truffle compile`__ 48 | 49 | **7)** Test the contract with Truffle leveraging a testnet, such as Rinkeby: 50 | 51 | __`❍ npx truffle test --network rinkeby`__ 52 | 53 |   54 | 55 | ## :camera: Passing Tests: 56 | 57 | ```javascript 58 | Contract: Random Example Tests 59 | ✓ Should log a new Provable query (2421ms) 60 | ✓ Callback should have logged a new uint random number result event (54739) 61 | ✓ Should revert on second query attempt due to lack of funds (15290ms) 62 | 63 | 3 passing (1m) 64 | ``` 65 | 66 |   67 | 68 | ## :black_nib: Notes: 69 | 70 | __❍__ Note that your own Infura key and the Metamask passphrase must be kept secure. The ones provided here are simply placeholders. 71 | 72 | __❍__ If you have any issues, head on over to our [Gitter](https://gitter.im/provable/ethereum-api?raw=true) channel to get timely support! 73 | 74 | __*Happy developing!*__ 75 | 76 | -------------------------------------------------------------------------------- /solidity/truffle-examples/random-datasource/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solidity/truffle-examples/random-datasource/contracts/RandomExample.sol: -------------------------------------------------------------------------------- 1 | /** 2 | * @notice Provable Random Datasource Example 3 | * 4 | * This contract uses the random-datasource to securely generate 5 | * off-chain random bytes. 6 | * 7 | * The random datasource is currently only available on the 8 | * ethereum main-net & public test-nets (Ropsten, Rinkeby & Kovan). 9 | * 10 | */ 11 | pragma solidity >= 0.5.0 < 0.6.0; 12 | 13 | import "./provableAPI.sol"; 14 | 15 | contract RandomExample is usingProvable { 16 | 17 | uint256 constant MAX_INT_FROM_BYTE = 256; 18 | uint256 constant NUM_RANDOM_BYTES_REQUESTED = 7; 19 | 20 | event LogNewProvableQuery(string description); 21 | event generatedRandomNumber(uint256 randomNumber); 22 | 23 | constructor() 24 | public 25 | { 26 | provable_setProof(proofType_Ledger); 27 | update(); 28 | } 29 | 30 | function __callback( 31 | bytes32 _queryId, 32 | string memory _result, 33 | bytes memory _proof 34 | ) 35 | public 36 | { 37 | require(msg.sender == provable_cbAddress()); 38 | if (provable_randomDS_proofVerify__returnCode(_queryId, _result, _proof) != 0) { 39 | /** 40 | * @notice The proof verification has failed! Handle this case 41 | * however you see fit. 42 | */ 43 | } else { 44 | /** 45 | * 46 | * @notice The proof verifiction has passed! 47 | * 48 | * Let's convert the random bytes received from the query 49 | * to a `uint256`. 50 | * 51 | * To do so, We define the variable `ceiling`, where 52 | * `ceiling - 1` is the highest `uint256` we want to get. 53 | * The variable `ceiling` should never be greater than: 54 | * `(MAX_INT_FROM_BYTE ^ NUM_RANDOM_BYTES_REQUESTED) - 1`. 55 | * 56 | * By hashing the random bytes and casting them to a 57 | * `uint256` we can then modulo that number by our ceiling 58 | * in order to get a random number within the desired 59 | * range of [0, ceiling - 1]. 60 | * 61 | */ 62 | uint256 ceiling = (MAX_INT_FROM_BYTE ** NUM_RANDOM_BYTES_REQUESTED) - 1; 63 | uint256 randomNumber = uint256(keccak256(abi.encodePacked(_result))) % ceiling; 64 | emit generatedRandomNumber(randomNumber); 65 | } 66 | } 67 | 68 | function update() 69 | payable 70 | public 71 | { 72 | uint256 QUERY_EXECUTION_DELAY = 0; // NOTE: The datasource currently does not support delays > 0! 73 | uint256 GAS_FOR_CALLBACK = 200000; 74 | provable_newRandomDSQuery( 75 | QUERY_EXECUTION_DELAY, 76 | NUM_RANDOM_BYTES_REQUESTED, 77 | GAS_FOR_CALLBACK 78 | ); 79 | emit LogNewProvableQuery("Provable query was sent, standing by for the answer..."); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /solidity/truffle-examples/random-datasource/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | const Migrations = artifacts.require("./Migrations.sol"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /solidity/truffle-examples/random-datasource/migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => deployer.deploy(artifacts.require("RandomExample.sol")) 2 | -------------------------------------------------------------------------------- /solidity/truffle-examples/random-datasource/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "provable-examples-using-truffle__random-datasource-example", 3 | "version": "0.2.0", 4 | "description": "Testing set up for Provable's Random example contract", 5 | "main": "README.md", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/n/a.git" 12 | }, 13 | "author": "Provable - Riccardo Persiani", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/n/a/issues" 17 | }, 18 | "homepage": "https://github.com/n/a#readme", 19 | "dependencies": { 20 | "dotenv": "^7.0.0", 21 | "truffle": "^5.0.9", 22 | "truffle-hdwallet-provider": "^1.0.0-web3one.5", 23 | "web3": "1.0.0-beta.36" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /solidity/truffle-examples/random-datasource/test/random-example-test.js: -------------------------------------------------------------------------------- 1 | const { 2 | waitForEvent, 3 | getExternalVariable 4 | } = require('./utils') 5 | 6 | const RINKEBY_WSS = `wss://rinkeby.infura.io/ws/v3/${ 7 | getExternalVariable('infuraKey') 8 | }` 9 | 10 | const Web3 = require('web3') 11 | const randomExample = artifacts.require('./RandomExample.sol') 12 | const web3Socket = new Web3(new Web3.providers.WebsocketProvider(RINKEBY_WSS)) 13 | 14 | contract('Random Example Tests', async accounts => { 15 | 16 | const gasAmt = 3e6 17 | const address = accounts[0] 18 | 19 | before(async () => ( 20 | { contract } = await randomExample.deployed(), 21 | { methods } = contract, 22 | { events } = new web3Socket.eth.Contract( 23 | contract._jsonInterface, 24 | contract._address 25 | ) 26 | )) 27 | 28 | it('Should have logged a new Provable query', async () => { 29 | const { 30 | returnValues: { 31 | description 32 | } 33 | } = await waitForEvent(events.LogNewProvableQuery) 34 | assert.strictEqual( 35 | description, 36 | 'Provable query was sent, standing by for the answer...', 37 | 'Provable query incorrectly logged!' 38 | ) 39 | }) 40 | 41 | it('Callback should have logged a new uint random number result event', async () => { 42 | const { 43 | returnValues : { 44 | randomNumber 45 | } 46 | } = await waitForEvent(events.generatedRandomNumber) 47 | assert.isAbove( 48 | parseInt(randomNumber), 49 | 0, 50 | 'A random number should have been retrieved from Provable call!' 51 | ) 52 | }).timeout(600000) 53 | 54 | it('Should revert on second query attempt due to lack of funds', async () => { 55 | const expErr = 'Transaction has been reverted' 56 | try { 57 | await methods 58 | .update() 59 | .send({ 60 | from: address, 61 | gas: gasAmt 62 | }) 63 | assert.fail('Update transaction should not have succeeded!') 64 | } catch (e) { 65 | assert.isTrue( 66 | e.message.startsWith(`${expErr}`), 67 | `Expected ${expErr} but got ${e.message} instead!` 68 | ) 69 | } 70 | }) 71 | }) 72 | -------------------------------------------------------------------------------- /solidity/truffle-examples/random-datasource/test/utils.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const API_PATH = path.resolve(__dirname, '../apikeys.js') 4 | 5 | const PREFIX = 'Returned error: VM Exception while processing transaction: ' 6 | 7 | const waitForEvent = (_event, _from = 0, _to = 'latest') => 8 | new Promise ((resolve, reject) => 9 | _event({ fromBlock: _from, toBlock: _to }, (e, ev) => 10 | e ? reject(e) : resolve(ev))) 11 | 12 | const fileExists = _path => fs.existsSync(_path) 13 | 14 | const getExternalVariable = _variable => 15 | fileExists(API_PATH) 16 | ? require(API_PATH)[_variable] 17 | : process.env[_variable] 18 | ? process.env[_variable] 19 | : (console.log(`Cannot test! Please provide '${_variable}' as an environment variable, or export it from '${API_PATH}'!`), process.exit(1)) 20 | 21 | module.exports = { 22 | waitForEvent, 23 | PREFIX, 24 | getExternalVariable, 25 | fileExists 26 | } 27 | -------------------------------------------------------------------------------- /solidity/truffle-examples/random-datasource/truffle.js: -------------------------------------------------------------------------------- 1 | const { 2 | fileExists, 3 | getExternalVariable, 4 | } = require('./test/utils.js') 5 | 6 | const path = require('path') 7 | const API_PATH = path.resolve(__dirname, 'apikeys.js') 8 | const HDWalletProvider = require("truffle-hdwallet-provider") 9 | 10 | require('dotenv').config() 11 | 12 | module.exports = { 13 | networks: { 14 | development: { 15 | host: "127.0.0.1", 16 | port: 9545, 17 | network_id: "*", 18 | websockets: true 19 | }, 20 | ropsten: { 21 | provider: () => new HDWalletProvider(getExternalVariable('mnemonic'), `https://ropsten.infura.io/v3/${getExternalVariable('infuraKey')}`), 22 | network_id: 3, 23 | gas: 47e5, 24 | gasPrice: 20e9, 25 | websockets: true 26 | }, 27 | rinkeby: { 28 | provider: () => new HDWalletProvider(getExternalVariable('mnemonic'), `https://rinkeby.infura.io/v3/${getExternalVariable('infuraKey')}`), 29 | network_id: 4, 30 | gas: 6e6, 31 | gasPrice: 5e9, 32 | websockets: true 33 | }, 34 | kovan: { 35 | provider: () => new HDWalletProvider(getExternalVariable('mnemonic'), `https://kovan.infura.io/v3/${getExternalVariable('infuraKey')}`), 36 | network_id: 42, 37 | gas: 8e6, 38 | gasPrice: 20e9, 39 | websockets: true 40 | } 41 | }, 42 | compilers: { 43 | solc: { 44 | version: '0.5.0', 45 | settings: { 46 | optimizer: { 47 | enabled: true, // Default: false 48 | runs: 0 // Default: 200 49 | } 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /solidity/truffle-examples/streamr/README.md: -------------------------------------------------------------------------------- 1 | # :wrench: :construction: Testing Provable's Streamr Tweets Example. 2 | 3 |   4 | 5 | This repo is to demonstrate how you would set up a Provable smart-contract development environment using Truffle & the Ethereum-Bridge to do most of the heavy lifting for you. Head on over to the `./test` folder to examine the javascript files that thoroughly test the smart-contract, which latter you will find in `./contracts`. 6 | 7 | ## :page_with_curl: _Instructions_ 8 | 9 | **1)** Fire up your favourite console & clone this repo somewhere: 10 | 11 | __`❍ git clone https://github.com/provable-things/ethereum-examples.git`__ 12 | 13 | **2)** Enter this directory & install dependencies: 14 | 15 | __`❍ cd ethereum-examples/solidity/truffle-examples/streamr && npm install`__ 16 | 17 | **3)** Launch Truffle: 18 | 19 | __`❍ npx truffle develop`__ 20 | 21 | **4)** Open a _new_ console in the same directory & spool up the ethereum-bridge: 22 | 23 | __`❍ npx ethereum-bridge -a 9 -H 127.0.0.1 -p 9545 --dev`__ 24 | 25 | **5)** Once the bridge is ready & listening, go back to the first console with Truffle running & set the tests going! 26 | 27 | __`❍ truffle(develop)> test`__ 28 | 29 |   30 | 31 | ## :camera: Passing Tests: 32 | 33 | ```javascript 34 | 35 | Contract: Streamr Tweets Counter Example Tests 36 | ✓ Should have logged a new Provable query 37 | ✓ Should retrieve number of tweets over the last minute (135221ms) 38 | ✓ Should have saved the number of tweets in the smart-contract 39 | ✓ Should log a failed second query due to lack of funds (91ms) 40 | 41 | 4 passing (2m) 42 | 43 | ``` 44 | 45 |   46 | 47 | ## :black_nib: Notes: 48 | 49 | __❍__ If you have any issues, head on over to our [Gitter](https://gitter.im/provable/ethereum-api?raw=true) channel to get timely support! 50 | 51 | __*Happy developing!*__ 52 | -------------------------------------------------------------------------------- /solidity/truffle-examples/streamr/computation-archive/archive.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/provable-things/ethereum-examples/f3f650836016c43be3b18ba2819a5609078b0447/solidity/truffle-examples/streamr/computation-archive/archive.zip -------------------------------------------------------------------------------- /solidity/truffle-examples/streamr/computation-archive/src/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mhart/alpine-node:8 2 | MAINTAINER Provable "info@provable.xyz" 3 | 4 | COPY index.js package.json /tmp/ 5 | WORKDIR /tmp/ 6 | RUN yarn install 7 | CMD node index.js $ARG0 8 | -------------------------------------------------------------------------------- /solidity/truffle-examples/streamr/computation-archive/src/index.js: -------------------------------------------------------------------------------- 1 | global.WebSocket = require('ws') 2 | var StreamrClient = require('streamr-client') 3 | 4 | var optMinutes 5 | console.log(process.argv) 6 | 7 | if(!isNaN(parseInt(process.argv[2]))) { 8 | var parsed = parseInt(process.argv[2]); 9 | console.log('User-defined duration argument found... Setting duration to ' + parsed + ' minutes') 10 | optMinutes = parsed 11 | } else { 12 | console.log('No appropriate duration defined by user, falling back to 1 minute...') 13 | optMinutes = 1 14 | } 15 | 16 | var client = new StreamrClient() 17 | var ctr = 0 18 | var start 19 | var duration = optMinutes * 60 * 1000 20 | 21 | var subscription = client.subscribe( 22 | 'ln2g8OKHSdi7BcL-bcnh2g', 23 | function(message) { 24 | 25 | if (Date.now() > start + duration) { 26 | console.log(ctr) 27 | process.exit(0) 28 | } 29 | 30 | ctr++ 31 | } 32 | ) 33 | 34 | // Event binding examples 35 | client.on('connected', function() { 36 | console.log('A connection has been established!') 37 | }) 38 | 39 | subscription.on('subscribed', function() { 40 | console.log('Subscribed to '+subscription.streamId) 41 | start = Date.now() 42 | }) 43 | -------------------------------------------------------------------------------- /solidity/truffle-examples/streamr/computation-archive/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "streamrTweets", 3 | "version": "0.0.1", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "dependencies": { 7 | "socket.io": "^2.0.2", 8 | "streamr-client": "^0.9.3" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /solidity/truffle-examples/streamr/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solidity/truffle-examples/streamr/contracts/StreamrTweetsCounter.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >= 0.5.0 < 0.6.0; 2 | 3 | import "./provableAPI.sol"; 4 | 5 | contract StreamrTweetsCounter is usingProvable { 6 | 7 | uint public numberOfTweets; 8 | 9 | event LogResult(string result); 10 | event LogNewProvableQuery(string description); 11 | 12 | constructor() 13 | public 14 | { 15 | update(); // First check at contract creation... 16 | } 17 | 18 | function __callback( 19 | bytes32 _myid, 20 | string memory _result 21 | ) 22 | public 23 | { 24 | require(msg.sender == provable_cbAddress()); 25 | numberOfTweets = parseInt(_result); 26 | emit LogResult(_result); 27 | } 28 | 29 | function update() 30 | public 31 | payable 32 | { 33 | if (provable_getPrice("computation") > address(this).balance) { 34 | emit LogNewProvableQuery("Provable query was NOT sent, please add some ETH to cover for the query fee"); 35 | } else { 36 | emit LogNewProvableQuery("Provable query was sent, standing by for the answer..."); 37 | provable_query( 38 | "computation", 39 | [ 40 | "QmWFV2UrcUFMFk5R4iTZdusTRsvqohFwHjyXNH1Yu9v3Nm", // The ipfs multihash of archive. 41 | "1" // Desired duration to run the stream (in minutes). 42 | ] 43 | ); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /solidity/truffle-examples/streamr/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => 2 | deployer.deploy(artifacts.require("./Migrations.sol")) 3 | -------------------------------------------------------------------------------- /solidity/truffle-examples/streamr/migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => deployer.deploy(artifacts.require("StreamrTweetsCounter.sol")) 2 | -------------------------------------------------------------------------------- /solidity/truffle-examples/streamr/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "provable-examples-using-truffle__computation-datasource-streamr-example", 3 | "version": "0.1.0", 4 | "description": "Testing set up for Provable's Streamr example contract", 5 | "main": "README.md", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/n/a.git" 12 | }, 13 | "author": "Provable - Greg Kapka", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/n/a/issues" 17 | }, 18 | "homepage": "https://github.com/n/a#readme", 19 | "dependencies": { 20 | "ethereum-bridge": "0.6.2", 21 | "web3": "1.0.0-beta.36" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solidity/truffle-examples/streamr/test/streamr-tweets-counter-test.js: -------------------------------------------------------------------------------- 1 | const Web3 = require('web3') 2 | const { waitForEvent } = require('./utils') 3 | const streamrTweetsCounter = artifacts.require('./StreamrTweetsCounter.sol') 4 | const web3 = new Web3(new Web3.providers.WebsocketProvider('ws://localhost:9545')) 5 | 6 | contract('Streamr Tweets Counter Example Tests', accounts => { 7 | 8 | let numTweets 9 | const gasAmt = 3e6 10 | const address = accounts[0] 11 | 12 | beforeEach(async () => ( 13 | { contract } = await streamrTweetsCounter.deployed(), 14 | { methods, events } = new web3.eth.Contract( 15 | contract._jsonInterface, 16 | contract._address 17 | ) 18 | )) 19 | 20 | it('Should have logged a new Provable query', async () => { 21 | const event = await waitForEvent(events.LogNewProvableQuery) 22 | const description = event.returnValues.description 23 | assert.equal( 24 | description, 25 | 'Provable query was sent, standing by for the answer...', 26 | 'Provable query incorrectly logged!' 27 | ) 28 | }) 29 | 30 | it('Should retrieve number of tweets over the last minute', async () => { 31 | const event = await waitForEvent(events.LogResult) 32 | const contractNumTweets = event.returnValues.result 33 | numTweets = contractNumTweets 34 | assert.isAbove( 35 | parseInt(contractNumTweets), 36 | 0, 37 | 'No result was retrieved from the offchain twitter stream!' 38 | ) 39 | }) 40 | 41 | it('Should have saved the number of tweets in the smart-contract', async () => { 42 | const tweetCount = await methods 43 | .numberOfTweets() 44 | .call() 45 | assert.equal( 46 | parseInt(tweetCount), 47 | parseInt(numTweets), 48 | 'Number of tweets should have been saved after Provable callback' 49 | ) 50 | }) 51 | 52 | it('Should log a failed second query due to lack of funds', async () => { 53 | const { events } = await methods 54 | .update() 55 | .send({ 56 | from: address, 57 | gas: gasAmt 58 | }) 59 | const description = events.LogNewProvableQuery.returnValues.description 60 | assert.equal( 61 | description, 62 | 'Provable query was NOT sent, please add some ETH to cover for the query fee', 63 | 'Provable query incorrectly logged!' 64 | ) 65 | }) 66 | }) 67 | -------------------------------------------------------------------------------- /solidity/truffle-examples/streamr/test/utils.js: -------------------------------------------------------------------------------- 1 | const waitForEvent = (_event, _from = 0, _to = 'latest') => 2 | new Promise ((resolve,reject) => 3 | _event({fromBlock: _from, toBlock: _to}, (e, ev) => 4 | e ? reject(e) : resolve(ev))) 5 | 6 | module.exports = { 7 | waitForEvent 8 | } 9 | -------------------------------------------------------------------------------- /solidity/truffle-examples/streamr/truffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | networks: { 3 | development: { 4 | host: "127.0.0.1", 5 | port: 9545, 6 | network_id: "*", 7 | websockets: true 8 | } 9 | }, 10 | compilers: { 11 | solc: { 12 | version: "0.5.0", 13 | settings: { 14 | optimizer: { 15 | enabled: true, 16 | runs: 200 17 | } 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /solidity/truffle-examples/url-requests/README.md: -------------------------------------------------------------------------------- 1 | # :wrench: :construction: Testing Provable's Url-Requests Example. 2 | 3 |   4 | 5 | This repo is to demonstrate how you would set up a Provable smart-contract development environment using Truffle & the Ethereum-Bridge to do most of the heavy lifting for you. Head on over to the `./test` folder to examine the javascript files that thoroughly test the smart-contract, which latter you will find in `./contracts`. 6 | 7 | ## :page_with_curl: _Instructions_ 8 | 9 | **1)** Fire up your favourite console & clone this repo somewhere: 10 | 11 | __`❍ git clone https://github.com/provable-things/ethereum-examples.git`__ 12 | 13 | **2)** Enter this directory & install dependencies: 14 | 15 | __`❍ cd ethereum-examples/solidity/truffle-examples/url-requests && npm install`__ 16 | 17 | **3)** Launch Truffle: 18 | 19 | __`❍ npx truffle develop`__ 20 | 21 | **4)** Open a _new_ console in the same directory & spool up the ethereum-bridge: 22 | 23 | __`❍ npx ethereum-bridge -a 9 -H 127.0.0.1 -p 9545 --dev`__ 24 | 25 | **5)** Once the bridge is ready & listening, go back to the first console with Truffle running & set the tests going! 26 | 27 | __`❍ truffle(develop)> test`__ 28 | 29 |   30 | 31 | ## :camera: Passing Tests: 32 | 33 | ```javascript 34 | 35 | Contract: Provable Example using Truffle 36 | URL Requests Tests 37 | ✓ Should log a new query upon a request for custom headers (246ms) 38 | ✓ Should log a new query upon a basic auth request (189ms) 39 | ✓ Should log a new query upon a POST request (271ms) 40 | ✓ Should log a new query upon a PUT request (150ms) 41 | ✓ Should log a new query upon a for request cookies (216ms) 42 | ✓ Should log a failed second request for custom headers due to lack of funds (97ms) 43 | ✓ Should log a failed second basic auth request due to lack of funds (75ms) 44 | ✓ Should log a failed second POST request due to lack of funds (75ms) 45 | ✓ Should log a failed second PUT request due to lack of funds (73ms) 46 | ✓ Should log a failed second request for cookies due to lack of funds (51ms) 47 | 48 | 10 passing 49 | ``` 50 | 51 |   52 | 53 | ## :black_nib: Notes: 54 | 55 | __❍__ The computation data-source combined with the ethereum-bridge in a development environment can make for a slightly slower than usual response time for the Provable `__callback` - please be patient whilst this occurs! 56 | 57 | __❍__ Note also that the `UrlRequests.sol` smart-contract in `./contracts` has the proof-type commented out in the constructor. This is because the TLS-Notary proof has been disabled on test-nets due to abuse. Using Oraclize on the ethereum main-net _without_ proofs however is _not_ recommended, so don't forget to re-enable them for live deployments! 58 | 59 | __❍__ If you have any further issues, head on over to our [Gitter](https://gitter.im/provable/ethereum-api?raw=true) channel to get timely support! 60 | 61 | __*Happy developing!*__ 62 | -------------------------------------------------------------------------------- /solidity/truffle-examples/url-requests/computation-archive/archive.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/provable-things/ethereum-examples/f3f650836016c43be3b18ba2819a5609078b0447/solidity/truffle-examples/url-requests/computation-archive/archive.zip -------------------------------------------------------------------------------- /solidity/truffle-examples/url-requests/computation-archive/src/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM frolvlad/alpine-python3 2 | MAINTAINER Provable "info@provable.xyz" 3 | 4 | COPY url-requests.py / 5 | 6 | RUN pip3 install requests 7 | CMD python ./url-requests.py 8 | -------------------------------------------------------------------------------- /solidity/truffle-examples/url-requests/computation-archive/src/url-requests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import ast 4 | import requests 5 | import os 6 | 7 | # parse env args 8 | arg = [os.environ['ARG0'], os.environ['ARG1']] 9 | 10 | # parse 3rd arg into kwargs if available 11 | if 'ARG2' in os.environ: kwargs = ast.literal_eval(os.environ['ARG2']) 12 | else: kwargs = {} 13 | 14 | # attempt the request 15 | req = requests.request(arg[0], arg[1], **kwargs) 16 | 17 | # print text result on single line 18 | print(req.text.replace('\n','')) 19 | 20 | # option if always json 21 | # print(json.loads(req.text)) 22 | -------------------------------------------------------------------------------- /solidity/truffle-examples/url-requests/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solidity/truffle-examples/url-requests/contracts/UrlRequests.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >= 0.5.0 < 0.6.0; 2 | 3 | import "./provableAPI.sol"; 4 | 5 | contract UrlRequests is usingProvable { 6 | 7 | event LogNewProvableQuery(string description); 8 | event LogResult(string result); 9 | 10 | constructor() 11 | public 12 | { 13 | provable_setProof(proofType_Android | proofStorage_IPFS); 14 | } 15 | 16 | function __callback( 17 | bytes32 _myid, 18 | string memory _result, 19 | bytes memory _proof 20 | ) 21 | public 22 | { 23 | require(msg.sender == provable_cbAddress()); 24 | emit LogResult(_result); 25 | } 26 | 27 | function request( 28 | string memory _query, 29 | string memory _method, 30 | string memory _url, 31 | string memory _kwargs 32 | ) 33 | public 34 | payable 35 | { 36 | if (provable_getPrice("computation") > address(this).balance) { 37 | emit LogNewProvableQuery("Provable query was NOT sent, please add some ETH to cover for the query fee"); 38 | } else { 39 | emit LogNewProvableQuery("Provable query was sent, standing by for the answer..."); 40 | provable_query("computation", 41 | [_query, 42 | _method, 43 | _url, 44 | _kwargs] 45 | ); 46 | } 47 | } 48 | /** 49 | * @dev Sends a custom content-type in header and returns the header used 50 | * as result. Wrap first argument of computation ds with helper needed, 51 | * such as json in this case 52 | */ 53 | function requestCustomHeaders() 54 | public 55 | payable 56 | { 57 | request("json(QmdKK319Veha83h6AYgQqhx9YRsJ9MJE7y33oCXyZ4MqHE).headers", 58 | "GET", 59 | "http://httpbin.org/headers", 60 | "{'headers': {'content-type': 'json'}}" 61 | ); 62 | } 63 | 64 | function requestBasicAuth() 65 | public 66 | payable 67 | { 68 | request("QmdKK319Veha83h6AYgQqhx9YRsJ9MJE7y33oCXyZ4MqHE", 69 | "GET", 70 | "http://httpbin.org/basic-auth/myuser/secretpass", 71 | "{'auth': ('myuser','secretpass'), 'headers': {'content-type': 'json'}}" 72 | ); 73 | } 74 | 75 | function requestPost() 76 | public 77 | payable 78 | { 79 | request("QmdKK319Veha83h6AYgQqhx9YRsJ9MJE7y33oCXyZ4MqHE", 80 | "POST", 81 | "https://api.postcodes.io/postcodes", 82 | '{"json": {"postcodes" : ["OX49 5NU"]}}' 83 | ); 84 | } 85 | 86 | function requestPut() 87 | public 88 | payable 89 | { 90 | request("QmdKK319Veha83h6AYgQqhx9YRsJ9MJE7y33oCXyZ4MqHE", 91 | "PUT", 92 | "http://httpbin.org/anything", 93 | "{'json' : {'testing':'it works'}}" 94 | ); 95 | } 96 | 97 | function requestCookies() 98 | public 99 | payable 100 | { 101 | request("QmdKK319Veha83h6AYgQqhx9YRsJ9MJE7y33oCXyZ4MqHE", 102 | "GET", 103 | "http://httpbin.org/cookies", 104 | "{'cookies' : {'thiscookie':'should be saved and visible :)'}}" 105 | ); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /solidity/truffle-examples/url-requests/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => 2 | deployer.deploy(artifacts.require("./Migrations.sol")) 3 | -------------------------------------------------------------------------------- /solidity/truffle-examples/url-requests/migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => 2 | deployer.deploy(artifacts.require("UrlRequests.sol")) 3 | -------------------------------------------------------------------------------- /solidity/truffle-examples/url-requests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "provable-examples-using-truffle__computation-datasource-url-requests", 3 | "version": "0.1.0", 4 | "description": "Testing set up for Provable's Url-Requests example contract", 5 | "main": "README.md", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/n/a.git" 12 | }, 13 | "author": "Provable - Greg Kapka", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/n/a/issues" 17 | }, 18 | "homepage": "https://github.com/n/a#readme", 19 | "dependencies": { 20 | "ethereum-bridge": "0.6.2", 21 | "web3": "1.0.0-beta.36" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solidity/truffle-examples/url-requests/test/url-requests-tests.js: -------------------------------------------------------------------------------- 1 | const Web3 = require('web3') 2 | const {waitForEvent} = require('./utils') 3 | const urlRequests = artifacts.require('./UrlRequests.sol') 4 | const web3 = new Web3(new Web3.providers.WebsocketProvider('ws://localhost:9545')) 5 | 6 | contract('Provable Example using Truffle', async ([ ACCOUNT_ZERO, ...accounts ]) => { 7 | 8 | describe("URL Requests Tests", async () => { 9 | 10 | const GAS_AMOUNT = 3e6 11 | const URL_REQUEST_CONTRACTS = new Array(5).fill() 12 | const QUERY_SENT_STRING = 'Provable query was sent, standing by for the answer...' 13 | const QUERY_NOT_SENT_STRING = 'Provable query was NOT sent, please add some ETH to cover for the query fee' 14 | 15 | it('Should log a new query upon a request for custom headers', async () => { 16 | const { contract } = await urlRequests.new() 17 | const { methods, events } = new web3.eth.Contract( 18 | contract._jsonInterface, 19 | contract._address 20 | ) 21 | URL_REQUEST_CONTRACTS[0] = { methods, events } 22 | const { events: txEvents } = await methods 23 | .requestCustomHeaders() 24 | .send({ 25 | from: ACCOUNT_ZERO, 26 | gas: GAS_AMOUNT 27 | }) 28 | const description = txEvents.LogNewProvableQuery.returnValues.description 29 | assert.strictEqual( 30 | description, 31 | QUERY_SENT_STRING, 32 | ) 33 | }) 34 | 35 | it('Should log a new query upon a basic auth request', async () => { 36 | const { contract } = await urlRequests.new() 37 | const { methods, events } = new web3.eth.Contract( 38 | contract._jsonInterface, 39 | contract._address 40 | ) 41 | URL_REQUEST_CONTRACTS[1] = { methods, events } 42 | const { events: txEvents } = await methods 43 | .requestBasicAuth() 44 | .send({ 45 | from: ACCOUNT_ZERO, 46 | gas: GAS_AMOUNT 47 | }) 48 | const description = txEvents.LogNewProvableQuery.returnValues.description 49 | assert.strictEqual( 50 | description, 51 | QUERY_SENT_STRING, 52 | ) 53 | }) 54 | 55 | it('Should log a new query upon a POST request', async () => { 56 | const { contract } = await urlRequests.new() 57 | const { methods, events } = new web3.eth.Contract( 58 | contract._jsonInterface, 59 | contract._address 60 | ) 61 | URL_REQUEST_CONTRACTS[2] = { methods, events } 62 | const { events: txEvents } = await methods 63 | .requestPost() 64 | .send({ 65 | from: ACCOUNT_ZERO, 66 | gas: GAS_AMOUNT 67 | }) 68 | const description = txEvents.LogNewProvableQuery.returnValues.description 69 | assert.strictEqual( 70 | description, 71 | QUERY_SENT_STRING, 72 | ) 73 | }) 74 | 75 | it('Should log a new query upon a PUT request', async () => { 76 | const { contract } = await urlRequests.new() 77 | const { methods, events } = new web3.eth.Contract( 78 | contract._jsonInterface, 79 | contract._address 80 | ) 81 | URL_REQUEST_CONTRACTS[3] = { methods, events } 82 | const { events: txEvents } = await methods 83 | .requestPut() 84 | .send({ 85 | from: ACCOUNT_ZERO, 86 | gas: GAS_AMOUNT 87 | }) 88 | const description = txEvents.LogNewProvableQuery.returnValues.description 89 | assert.strictEqual( 90 | description, 91 | QUERY_SENT_STRING, 92 | ) 93 | }) 94 | 95 | it('Should log a new query upon a for request cookies', async () => { 96 | const { contract } = await urlRequests.new() 97 | const { methods, events } = new web3.eth.Contract( 98 | contract._jsonInterface, 99 | contract._address 100 | ) 101 | URL_REQUEST_CONTRACTS[4] = { methods, events } 102 | const { events: txEvents } = await methods 103 | .requestCookies() 104 | .send({ 105 | from: ACCOUNT_ZERO, 106 | gas: GAS_AMOUNT 107 | }) 108 | const description = txEvents.LogNewProvableQuery.returnValues.description 109 | assert.strictEqual( 110 | description, 111 | QUERY_SENT_STRING, 112 | ) 113 | }) 114 | 115 | it('Should log a failed second request for custom headers due to lack of funds', async () => { 116 | const { events } = await URL_REQUEST_CONTRACTS[0] 117 | .methods 118 | .requestCustomHeaders() 119 | .send({ 120 | from: ACCOUNT_ZERO, 121 | gas: GAS_AMOUNT 122 | }) 123 | const description = events.LogNewProvableQuery.returnValues.description 124 | assert.strictEqual( 125 | description, 126 | QUERY_NOT_SENT_STRING 127 | ) 128 | }) 129 | 130 | it('Should log a failed second basic auth request due to lack of funds', async () => { 131 | const { events } = await URL_REQUEST_CONTRACTS[1] 132 | .methods 133 | .requestBasicAuth() 134 | .send({ 135 | from: ACCOUNT_ZERO, 136 | gas: GAS_AMOUNT 137 | }) 138 | const description = events.LogNewProvableQuery.returnValues.description 139 | assert.strictEqual( 140 | description, 141 | QUERY_NOT_SENT_STRING 142 | ) 143 | }) 144 | 145 | it('Should log a failed second POST request due to lack of funds', async () => { 146 | const { events } = await URL_REQUEST_CONTRACTS[2] 147 | .methods 148 | .requestPost() 149 | .send({ 150 | from: ACCOUNT_ZERO, 151 | gas: GAS_AMOUNT 152 | }) 153 | const description = events.LogNewProvableQuery.returnValues.description 154 | assert.strictEqual( 155 | description, 156 | QUERY_NOT_SENT_STRING 157 | ) 158 | }) 159 | 160 | it('Should log a failed second PUT request due to lack of funds', async () => { 161 | const { events } = await URL_REQUEST_CONTRACTS[3] 162 | .methods 163 | .requestPut() 164 | .send({ 165 | from: ACCOUNT_ZERO, 166 | gas: GAS_AMOUNT 167 | }) 168 | const description = events.LogNewProvableQuery.returnValues.description 169 | assert.strictEqual( 170 | description, 171 | QUERY_NOT_SENT_STRING 172 | ) 173 | }) 174 | 175 | it('Should log a failed second request for cookies due to lack of funds', async () => { 176 | const { events } = await URL_REQUEST_CONTRACTS[4] 177 | .methods 178 | .requestCookies() 179 | .send({ 180 | from: ACCOUNT_ZERO, 181 | gas: GAS_AMOUNT 182 | }) 183 | const description = events.LogNewProvableQuery.returnValues.description 184 | assert.strictEqual( 185 | description, 186 | QUERY_NOT_SENT_STRING 187 | ) 188 | }) 189 | 190 | it('Should emit result from request for custom headers', async () => { 191 | const { 192 | returnValues: { result } 193 | } = await waitForEvent(URL_REQUEST_CONTRACTS[0].events.LogResult) 194 | assert.isTrue( 195 | result.includes('"Accept-Encoding": "gzip, deflate"') && 196 | result.includes('"Content-Type": "json"') 197 | ) 198 | }) 199 | 200 | it('Should emit result from basic auth request', async () => { 201 | const { 202 | returnValues: { result } 203 | } = await waitForEvent(URL_REQUEST_CONTRACTS[1].events.LogResult) 204 | const expRes = '{ \"authenticated\": true, \"user\": \"myuser\"}' 205 | assert.strictEqual( 206 | expRes, 207 | result 208 | ) 209 | }) 210 | 211 | it('Should emit result from POST request', async () => { 212 | const SUCCESS_STATUS_CODE = 200 213 | const QUERIED_COUNTRY = "England" 214 | const QUERIED_POSTCODE = "OX49 5NU" 215 | const { 216 | returnValues: { result } 217 | } = await waitForEvent(URL_REQUEST_CONTRACTS[2].events.LogResult) 218 | const jsonParsedResult = JSON.parse(result) 219 | assert.strictEqual( 220 | jsonParsedResult.status, 221 | SUCCESS_STATUS_CODE 222 | ) 223 | assert.strictEqual( 224 | jsonParsedResult.result[0].result.country, 225 | QUERIED_COUNTRY 226 | ) 227 | assert.strictEqual( 228 | jsonParsedResult.result[0].result.postcode, 229 | QUERIED_POSTCODE 230 | ) 231 | }) 232 | 233 | it('Should emit result from PUT request', async () => { 234 | const EXPECTED_METHOD = "PUT" 235 | const EXPECTED_KEY = "testing" 236 | const EXPECTED_VALUE = "it works" 237 | const EXPECTED_HEADERS = "gzip, deflate" 238 | const EXPECTED_DATA_STRING = `{"${EXPECTED_KEY}": "${EXPECTED_VALUE}"}` 239 | const { 240 | returnValues: { result } 241 | } = await waitForEvent(URL_REQUEST_CONTRACTS[3].events.LogResult) 242 | const jsonParsedResult = JSON.parse(result) 243 | assert.strictEqual( 244 | jsonParsedResult.method, 245 | EXPECTED_METHOD 246 | ) 247 | assert.strictEqual( 248 | jsonParsedResult.data, 249 | EXPECTED_DATA_STRING 250 | ) 251 | assert.strictEqual( 252 | jsonParsedResult.headers["Accept-Encoding"], 253 | EXPECTED_HEADERS 254 | ) 255 | assert.strictEqual( 256 | jsonParsedResult.json[EXPECTED_KEY], 257 | EXPECTED_VALUE 258 | ) 259 | }) 260 | 261 | it('Should emit result from cookie request', async () => { 262 | const EXPECTED_COOKIE_KEY = "thiscookie" 263 | const EXPECTED_COOKIE_VALUE = "should be saved and visible :)" 264 | const { 265 | returnValues: { result } 266 | } = await waitForEvent(URL_REQUEST_CONTRACTS[4].events.LogResult) 267 | const jsonParsedResult = JSON.parse(result) 268 | assert.strictEqual( 269 | jsonParsedResult.cookies[EXPECTED_COOKIE_KEY], 270 | EXPECTED_COOKIE_VALUE 271 | ) 272 | }) 273 | }) 274 | }) 275 | -------------------------------------------------------------------------------- /solidity/truffle-examples/url-requests/test/utils.js: -------------------------------------------------------------------------------- 1 | const waitForEvent = (_event, _from = 0, _to = 'latest') => 2 | new Promise ((resolve,reject) => 3 | _event({fromBlock: _from, toBlock: _to}, (e, ev) => 4 | e ? reject(e) : resolve(ev))) 5 | 6 | module.exports = { 7 | waitForEvent 8 | } 9 | -------------------------------------------------------------------------------- /solidity/truffle-examples/url-requests/truffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | networks: { 3 | development: { 4 | host: "127.0.0.1", 5 | port: 9545, 6 | network_id: "*", 7 | websockets: true 8 | } 9 | }, 10 | compilers: { 11 | solc: { 12 | version: "0.5.0", 13 | settings: { 14 | optimizer: { 15 | enabled: true, 16 | runs: 200 17 | } 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /solidity/truffle-examples/wolfram-alpha/README.md: -------------------------------------------------------------------------------- 1 | # :wrench: :construction: Testing Provable's Wolfram Alpha Example. 2 | 3 |   4 | 5 | This repo is to demonstrate how you would set up a Provable smart-contract development environment using Truffle & the Ethereum-Bridge to do most of the heavy lifting for you. Head on over to the `./test` folder to examine the javascript files that thoroughly test the smart-contract, which latter you will find in `./contracts`. 6 | 7 | ## :page_with_curl: _Instructions_ 8 | 9 | **1)** Fire up your favourite console & clone this repo somewhere: 10 | 11 | __`❍ git clone https://github.com/provable-things/ethereum-examples.git`__ 12 | 13 | **2)** Enter this directory & install dependencies: 14 | 15 | __`❍ cd ethereum-examples/solidity/truffle-examples/wolfram-alpha && npm install`__ 16 | 17 | **3)** Launch Truffle: 18 | 19 | __`❍ npx truffle develop`__ 20 | 21 | **4)** Open a _new_ console in the same directory & spool up the ethereum-bridge: 22 | 23 | __`❍ npx ethereum-bridge -a 9 -H 127.0.0.1 -p 9545 --dev`__ 24 | 25 | **5)** Once the bridge is ready & listening, go back to the first console with Truffle running & set the tests going! 26 | 27 | __`❍ truffle(develop)> test`__ 28 | 29 |   30 | 31 | ## :camera: Passing Tests: 32 | 33 | ```javascript 34 | 35 | Contract: WolframAlpha Example Tests 36 | ✓ Should have logged a new Provable query 37 | ✓ Callback should have logged a new temperature measure event (10317ms) 38 | ✓ Should have saved the new temperature 39 | ✓ Should revert on second query attempt due to lack of funds (54ms) 40 | 41 | 4 passing (11ms) 42 | 43 | ``` 44 | 45 |   46 | 47 | ## :black_nib: Notes: 48 | 49 | __❍__ If you have any issues, head on over to our [Gitter](https://gitter.im/provable/ethereum-api?raw=true) channel to get timely support! 50 | 51 | __*Happy developing!*__ 52 | -------------------------------------------------------------------------------- /solidity/truffle-examples/wolfram-alpha/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solidity/truffle-examples/wolfram-alpha/contracts/WolframAlpha.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >= 0.5.0 < 0.6.0; 2 | 3 | import "./provableAPI.sol"; 4 | 5 | contract WolframAlpha is usingProvable { 6 | 7 | string public temperature; 8 | 9 | event LogNewProvableQuery(string description); 10 | event LogNewTemperatureMeasure(string temperature); 11 | 12 | constructor() 13 | public 14 | { 15 | update(); // Update on contract creation... 16 | } 17 | 18 | function __callback( 19 | bytes32 _myid, 20 | string memory _result 21 | ) 22 | public 23 | { 24 | require(msg.sender == provable_cbAddress()); 25 | temperature = _result; 26 | emit LogNewTemperatureMeasure(temperature); 27 | // Do something with the temperature measure... 28 | } 29 | 30 | function update() 31 | public 32 | payable 33 | { 34 | emit LogNewProvableQuery("Provable query was sent, standing by for the answer..."); 35 | provable_query("WolframAlpha", "temperature in London"); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /solidity/truffle-examples/wolfram-alpha/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => 2 | deployer.deploy(artifacts.require("./Migrations.sol")) 3 | -------------------------------------------------------------------------------- /solidity/truffle-examples/wolfram-alpha/migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => deployer.deploy(artifacts.require("WolframAlpha.sol")) 2 | -------------------------------------------------------------------------------- /solidity/truffle-examples/wolfram-alpha/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "provable-examples-using-truffle__computation-datasource-wolfram-alpha", 3 | "version": "0.1.0", 4 | "description": "Testing set up for Provable's Wolfram-Alpha example contract", 5 | "main": "README.md", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/n/a.git" 12 | }, 13 | "author": "Provable - Greg Kapka", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/n/a/issues" 17 | }, 18 | "homepage": "https://github.com/n/a#readme", 19 | "dependencies": { 20 | "ethereum-bridge": "0.6.2", 21 | "web3": "1.0.0-beta.36" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solidity/truffle-examples/wolfram-alpha/test/utils.js: -------------------------------------------------------------------------------- 1 | const PREFIX = 'Returned error: VM Exception while processing transaction: ' 2 | 3 | const waitForEvent = (_event, _from = 0, _to = 'latest') => 4 | new Promise ((resolve,reject) => 5 | _event({fromBlock: _from, toBlock: _to}, (e, ev) => 6 | e ? reject(e) : resolve(ev))) 7 | 8 | module.exports = { 9 | waitForEvent, 10 | PREFIX 11 | } 12 | -------------------------------------------------------------------------------- /solidity/truffle-examples/wolfram-alpha/test/wolframalpha-test.js: -------------------------------------------------------------------------------- 1 | const { 2 | PREFIX, 3 | waitForEvent 4 | } = require('./utils') 5 | 6 | const Web3 = require('web3') 7 | const wolframAlpha = artifacts.require('./WolframAlpha.sol') 8 | const web3 = new Web3(new Web3.providers.WebsocketProvider('ws://localhost:9545')) 9 | 10 | contract('WolframAlpha Example Tests', accounts => { 11 | 12 | const gasAmt = 3e6 13 | let loggedTemperature 14 | const address = accounts[0] 15 | 16 | beforeEach(async () => ( 17 | { contract } = await wolframAlpha.deployed(), 18 | { methods, events } = new web3.eth.Contract( 19 | contract._jsonInterface, 20 | contract._address 21 | ) 22 | )) 23 | 24 | it('Should have logged a new Provable query', async () => { 25 | const { 26 | returnValues: { 27 | description 28 | } 29 | } = await waitForEvent(events.LogNewProvableQuery) 30 | assert.strictEqual( 31 | description, 32 | 'Provable query was sent, standing by for the answer...', 33 | 'Provable query incorrectly logged!') 34 | }) 35 | 36 | it('Callback should have logged a new temperature measure event', async () => { 37 | const { 38 | returnValues: { 39 | temperature 40 | } 41 | } = await waitForEvent(events.LogNewTemperatureMeasure) 42 | loggedTemperature = temperature 43 | assert.isAbove( 44 | parseInt(temperature), 45 | 0, 46 | 'A temperature should have been retrieved from Provable call!' 47 | ) 48 | }) 49 | 50 | it('Should have saved the new temperature', async () => { 51 | const temprCont = await methods 52 | .temperature() 53 | .call() 54 | assert.strictEqual( 55 | loggedTemperature, 56 | temprCont, 57 | 'Contract\'s temperature price not set correctly!' 58 | ) 59 | }) 60 | 61 | it('Should revert on second query attempt due to lack of funds', async () => { 62 | const expErr = 'revert' 63 | try { 64 | await methods 65 | .update() 66 | .send({ 67 | from: address, 68 | gas: gasAmt 69 | }) 70 | assert.fail('Update transaction should not have succeeded!') 71 | } catch(e) { 72 | assert.isTrue( 73 | e.message.startsWith(`${PREFIX}${expErr}`), 74 | `Expected ${expErr} but got ${e.message} instead!` 75 | ) 76 | } 77 | }) 78 | }) 79 | -------------------------------------------------------------------------------- /solidity/truffle-examples/wolfram-alpha/truffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | networks: { 3 | development: { 4 | host: "127.0.0.1", 5 | port: 9545, 6 | network_id: "*", 7 | websockets: true 8 | } 9 | }, 10 | compilers: { 11 | solc: { 12 | version: "0.5.0", 13 | settings: { 14 | optimizer: { 15 | enabled: true, 16 | runs: 200 17 | } 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /solidity/truffle-examples/youtube-views/README.md: -------------------------------------------------------------------------------- 1 | # :wrench: :construction: Testing Provable's Youtube Views Example. 2 | 3 |   4 | 5 | This repo is to demonstrate how you would set up a Provable smart-contract development environment using Truffle & the Ethereum-Bridge to do most of the heavy lifting for you. Head on over to the `./test` folder to examine the javascript files that thoroughly test the smart-contract, which latter you will find in `./contracts`. 6 | 7 | ## :page_with_curl: _Instructions_ 8 | 9 | **1)** Fire up your favourite console & clone this repo somewhere: 10 | 11 | __`❍ git clone https://github.com/provable-things/ethereum-examples.git`__ 12 | 13 | **2)** Enter this directory & install dependencies: 14 | 15 | __`❍ cd ethereum-examples/solidity/truffle-examples/youtube-views && npm install`__ 16 | 17 | **3)** Launch Truffle: 18 | 19 | __`❍ npx truffle develop`__ 20 | 21 | **4)** Open a _new_ console in the same directory & spool up the ethereum-bridge: 22 | 23 | __`❍ npx ethereum-bridge -a 9 -H 127.0.0.1 -p 9545 --dev`__ 24 | 25 | **5)** Once the bridge is ready & listening, go back to the first console with Truffle running & set the tests going! 26 | 27 | __`❍ truffle(develop)> test`__ 28 | 29 |   30 | 31 | ## :camera: Passing Tests: 32 | 33 | ```javascript 34 | 35 | Contract: Youtube Views Tests 36 | ✓ Should have logged a new Provable query 37 | ✓ Callback should have logged a new YouTube views event (10390ms) 38 | ✓ Should store YouTube views correctly in contract 39 | ✓ Should revert on second query attempt due to lack of funds (58ms) 40 | 41 | 4 passing (11s) 42 | 43 | ``` 44 | 45 |   46 | 47 | ## :black_nib: Notes: 48 | 49 | __❍__ If you have any issues, head on over to our [Gitter](https://gitter.im/provable-things/ethereum-api?raw=true) channel to get timely support! 50 | 51 | __*Happy developing!*__ 52 | -------------------------------------------------------------------------------- /solidity/truffle-examples/youtube-views/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solidity/truffle-examples/youtube-views/contracts/YoutubeViews.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >= 0.5.0 < 0.6.0; 2 | 3 | import "./provableAPI.sol"; 4 | 5 | contract YoutubeViews is usingProvable { 6 | 7 | string public viewsCount; 8 | 9 | event LogYoutubeViewCount(string views); 10 | event LogNewProvableQuery(string description); 11 | 12 | constructor() 13 | public 14 | { 15 | update(); // Update views on contract creation... 16 | } 17 | 18 | function __callback( 19 | bytes32 _myid, 20 | string memory _result 21 | ) 22 | public 23 | { 24 | require(msg.sender == provable_cbAddress()); 25 | viewsCount = _result; 26 | emit LogYoutubeViewCount(viewsCount); 27 | // Do something with viewsCount, like tipping the author if viewsCount > X? 28 | } 29 | 30 | function update() 31 | public 32 | payable 33 | { 34 | emit LogNewProvableQuery("Provable query was sent, standing by for the answer..."); 35 | provable_query("URL", 'html(https://www.youtube.com/watch?v=9bZkp7q19f0).xpath(//*[contains(@class, "watch-view-count")]/text())'); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /solidity/truffle-examples/youtube-views/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => 2 | deployer.deploy(artifacts.require("./Migrations.sol")) 3 | -------------------------------------------------------------------------------- /solidity/truffle-examples/youtube-views/migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | module.exports = deployer => deployer.deploy(artifacts.require("YoutubeViews.sol")) 2 | -------------------------------------------------------------------------------- /solidity/truffle-examples/youtube-views/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "provable-examples-using-truffle__computation-datasource-youtube-views", 3 | "version": "0.1.0", 4 | "description": "Testing set up for Provable's Youtube-Views example contract", 5 | "main": "README.md", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/n/a.git" 12 | }, 13 | "author": "Provable - Greg Kapka", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/n/a/issues" 17 | }, 18 | "homepage": "https://github.com/n/a#readme", 19 | "dependencies": { 20 | "ethereum-bridge": "0.6.2", 21 | "web3": "1.0.0-beta.36" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solidity/truffle-examples/youtube-views/test/utils.js: -------------------------------------------------------------------------------- 1 | const PREFIX = 'Returned error: VM Exception while processing transaction: ' 2 | 3 | const waitForEvent = (_event, _from = 0, _to = 'latest') => 4 | new Promise ((resolve,reject) => 5 | _event({fromBlock: _from, toBlock: _to}, (e, ev) => 6 | e ? reject(e) : resolve(ev))) 7 | 8 | module.exports = { 9 | waitForEvent, 10 | PREFIX 11 | } 12 | -------------------------------------------------------------------------------- /solidity/truffle-examples/youtube-views/test/youtube-views-test.js: -------------------------------------------------------------------------------- 1 | const { 2 | PREFIX, 3 | waitForEvent 4 | } = require('./utils') 5 | 6 | const Web3 = require('web3') 7 | const youtubeViews = artifacts.require('./YoutubeViews.sol') 8 | const web3 = new Web3(new Web3.providers.WebsocketProvider('ws://localhost:9545')) 9 | 10 | contract('Youtube Views Tests', accounts => { 11 | 12 | let loggedViews 13 | const gasAmt = 3e6 14 | const address = accounts[0] 15 | 16 | beforeEach(async () => ( 17 | { contract } = await youtubeViews.deployed(), 18 | { methods, events } = new web3.eth.Contract( 19 | contract._jsonInterface, 20 | contract._address 21 | ) 22 | )) 23 | 24 | it('Should have logged a new Provable query', async () => { 25 | const { 26 | returnValues: { 27 | description 28 | } 29 | } = await waitForEvent(events.LogNewProvableQuery) 30 | assert.strictEqual( 31 | description, 32 | 'Provable query was sent, standing by for the answer...', 33 | 'Provable query incorrectly logged!' 34 | ) 35 | }) 36 | 37 | it('Callback should have logged a new YouTube views event', async () => { 38 | const { 39 | returnValues: { 40 | views 41 | } 42 | } = await waitForEvent(events.LogYoutubeViewCount) 43 | loggedViews = views 44 | assert.isAbove( 45 | parseInt(views), 46 | 0, 47 | 'A view count should have been retrieved from Provable call!' 48 | ) 49 | }) 50 | 51 | it('Should store YouTube views correctly in contract', async () => { 52 | const queriedViews = await methods 53 | .viewsCount() 54 | .call() 55 | assert.strictEqual( 56 | queriedViews, 57 | loggedViews, 58 | 'Contract\'s views are not set correctly!' 59 | ) 60 | }) 61 | 62 | it('Should revert on second query attempt due to lack of funds', async () => { 63 | const expErr = 'revert' 64 | try { 65 | await methods 66 | .update() 67 | .send({ 68 | from: address, 69 | gas: gasAmt 70 | }) 71 | assert.fail('Update transaction should not have succeeded!') 72 | } catch (e) { 73 | assert.isTrue( 74 | e.message.startsWith(`${PREFIX}${expErr}`), 75 | `Expected ${expErr} but got ${e.message} instead!` 76 | ) 77 | } 78 | }) 79 | }) 80 | -------------------------------------------------------------------------------- /solidity/truffle-examples/youtube-views/truffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | networks: { 3 | development: { 4 | host: "127.0.0.1", 5 | port: 9545, 6 | network_id: "*", 7 | websockets: true 8 | } 9 | }, 10 | compilers: { 11 | solc: { 12 | version: "0.5.0", 13 | settings: { 14 | optimizer: { 15 | enabled: true, 16 | runs: 200 17 | } 18 | } 19 | } 20 | } 21 | } 22 | --------------------------------------------------------------------------------