Last active
September 24, 2019 10:54
-
-
Save branciard/3ccbc62b84d0d07e77326f3f9d4fd640 to your computer and use it in GitHub Desktop.
A smart contract on testnet as back-end with a react front-end on IPFS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This tutorial uses truffle box to create a solidity smart contract. https://www.trufflesuite.com/ | |
The objective is to deploy a smart contract on a testnet and also connect a front-end a react app deployed on IPFS. https://ipfs.io/ | |
You can see the video of this gist here : | |
https://www.youtube.com/watch?v=nOLPf_P2N_o | |
This tutorial uses docker, if you have ubuntu OS you can also follow this memo commands : https://gist.github.com/branciard/3ccbc62b84d0d07e77326f3f9d4fd640#file-memo-ubuntu-commands-old | |
1- download dockerfile in this gist and build image : | |
mkdir workspace | |
curl https://gist.githubusercontent.com/branciard/3ccbc62b84d0d07e77326f3f9d4fd640/raw/337638e70cb238f41b669a040728bbc523882ac1/Dockerfile -o Dockerfile | |
docker build . -t tuto-base | |
2- run docker container and share an empty workspace volume : | |
mkdir workspace | |
cd workspace | |
docker run -it -v $(pwd):/dweb -p 8080:8080 -p 4001:4001 -p 5001:5001 tuto-base bash | |
3- install truffle box react template : | |
cd /dweb | |
truffle unbox react | |
must finsih with : | |
Unbox successful. Sweet! | |
Commands: | |
Compile: truffle compile | |
Migrate: truffle migrate | |
Test contracts: truffle test | |
Test dapp: cd client && npm test | |
Run dev server: cd client && npm run start | |
Build for production: cd client && npm run build | |
4- Compile and test | |
truffle compile | |
truffle test | |
5- test deploy on ganache (simu) | |
In another windows launch : | |
ganache-cli --port 7545 | |
in /dweb archive file and download from the gist | |
mv truffle-config.js truffle-config.js.ori | |
add this lib : | |
npm install [email protected] --save-dev | |
wget https://gist.githubusercontent.com/branciard/3ccbc62b84d0d07e77326f3f9d4fd640/raw/21c946d393e99d0e6795019227547361d12cd54e/truffle-config.js | |
truffle migrate --network development | |
6- start goerli testnet | |
nohup parity --chain goerli --base-path /dweb/data --jsonrpc-port 8545 --jsonrpc-interface all --jsonrpc-hosts all --jsonrpc-cors all --ws-interface all --ws-port 8546 --ws-origins all --ws-hosts all > goerli.log & | |
check logs with : | |
tail -f goerli.log | |
wait and check the node is synch. The curl result must return false : | |
https://wiki.parity.io/JSONRPC-eth-module#example-39 | |
curl --data '{"method":"eth_syncing","params":[],"id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST localhost:8545 | |
7- Create a wallet and call faucet | |
ethkey generate random > wallet.txt | |
while waiting goerli synch. go to https://goerli-faucet.slock.it/ and claim som goerli eth. | |
Use the address value find in your wallet.txt. | |
Add 0x before pasting the address in the form. Need to call x4 the faucet | |
Put also the private key aka secret in wallet.txt into the truffle-config.js | |
8- configure the front-end to be deploy on IPFS | |
cd client | |
rm -rf node_modules | |
npm install ipfs-api --save-dev | |
rm -rf node_modules | |
npm install | |
#in package.json add the following line : | |
"homepage": "./", | |
#see https://www.reddit.com/r/ipfs/comments/8k3f8m/react_app_build_not_working_when_published_to_ipfs/dz6uh75?utm_source=share&utm_medium=web2x | |
add the ipfsDwebUploader.js file | |
wget https://gist.githubusercontent.com/branciard/3ccbc62b84d0d07e77326f3f9d4fd640/raw/9892accba87cb1e9944408cfd7028aa3b5a9c927/ipfsDwebUploader.js | |
#after the eject line add a publish command : | |
"publish": "react-scripts build && rm build/static/js/*.map && rm build/static/css/*.map && node ./ipfsDwebUploader build/" | |
8- Deploy contract on goerli testnet and publish and validate source on etherscan and blockscoot. | |
check synching is equal to : false otherwise : wait... | |
curl --data '{"method":"eth_syncing","params":[],"id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST localhost:8545 | |
truffle migrate --network goerli | |
after deploy OK :check contract address on etherscan : https://goerli.etherscan.io and https://blockscout.com/eth/goerli | |
===================== | |
Deploying 'SimpleStorage' | |
------------------------- | |
> transaction hash: 0x65c57bf335b124282b89280c44f20326517e9b81eed95ca662817441dbc54179 | |
> Blocks: 1 Seconds: 28 | |
> contract address: 0x95Ce78088a7cfDa6d6A73688E42176853ae37704 | |
check your deployment address in network 5 in client/src/contracts/SimpleStorage.json | |
you can Verify and publish the source code : ~/dweb-simple-storage/contracts$ cat SimpleStorage.sol | |
in etherscan and blockscout. | |
9- Upload front-end on IPFS | |
ipfs init --profile=server | |
edit ~/.ipfs/config and replace 127.0.0.1 by 0.0.0.0 | |
ipfs daemon | |
Now you can deploy your site on IPFS with in client dir : | |
npm run publish | |
you must see something like this : | |
To point an .eth domain to this website, use this hash as value: | |
QmRcK48iQkZnoySh9dTB9dRqFfYM7kXtBqQRaf5H7Pitkj | |
To preview you website immediately go to: | |
http://127.0.0.1:8080/ipfs/QmRcK48iQkZnoySh9dTB9dRqFfYM7kXtBqQRaf5H7Pitkj | |
Wait for your site to be propagate an accessible on IPFS on the publoic gatway : | |
https://ipfs.io/ipfs/QmRcK48iQkZnoySh9dTB9dRqFfYM7kXtBqQRaf5H7Pitkj/ | |
Bonus : if you deplot it on mainnet and configure an ENS to target IPFS content QmdSpPGWTcbEzbSLhouLcpoBqy2tKNaLTrWWetT5s1yvJo | |
go to : https://manager.ens.domains/ | |
You can then access the site your : yourENSsite.eth | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
FROM ubuntu:18.10 | |
RUN apt-get update | |
RUN apt-get -y install curl vim git sudo wget python build-essential | |
ENV NVM_DIR /root/.nvm | |
ENV NVM_VERSION v0.34.0 | |
ENV NODE_VERSION v10.16.3 | |
ENV NVM_DIR /usr/local/nvm | |
RUN mkdir $NVM_DIR | |
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash | |
ENV NODE_PATH $NVM_DIR/$NODE_VERSION/lib/node_modules | |
ENV PATH $NVM_DIR/versions/node/$NODE_VERSION/bin:$PATH | |
RUN echo "source $NVM_DIR/nvm.sh && \ | |
nvm install $NODE_VERSION && \ | |
nvm alias default $NODE_VERSION && \ | |
nvm use default" | bash | |
RUN ln -sf NVM_DIR/versions/node/$NODE_VERSION/bin/node /usr/bin/nodejs | |
RUN ln -sf NVM_DIR/versions/node/$NODE_VERSION/bin/node /usr/bin/node | |
RUN ln -sf NVM_DIR/versions/node/$NODE_VERSION/bin/npm /usr/bin/npm | |
RUN npm i -g [email protected] | |
RUN npm install -g [email protected] | |
RUN wget https://releases.parity.io/ethereum/v2.6.3/x86_64-unknown-linux-gnu/parity | |
RUN chmod +x parity | |
RUN cp parity /usr/local/bin | |
RUN parity --version | |
RUN ARCH=`uname -m` && ETHKEY_URL=`curl -sS "https://vanity-service.parity.io/parity-binaries?version=stable&format=markdown&os=linux&architecture=$ARCH" | grep ethkey | awk {'print $5'} | cut -d"(" -f2 | cut -d")" -f1` && wget -q $ETHKEY_URL | |
RUN chmod +x ethkey | |
RUN cp ethkey /usr/local/bin | |
RUN wget https://dist.ipfs.io/go-ipfs/v0.4.22/go-ipfs_v0.4.22_linux-amd64.tar.gz | |
RUN tar xvfz go-ipfs_v0.4.22_linux-amd64.tar.gz | |
RUN cd go-ipfs && ./install.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
//CREDIT TO DAPPNODE HERE : https://raw.githubusercontent.com/dappnode/dappnode-dweb-template/master/ipfsDwebUploader.js | |
// DAppNode params | |
////////////////// | |
//const ipfsProvider = "my.ipfs.dnp.dappnode.eth"; | |
//const ipfsGateway = "http://my.ipfs.dnp.dappnode.eth:8080"; | |
const ipfsProvider = "127.0.0.1"; | |
const ipfsGateway = "http://127.0.0.1:8080"; | |
////////////////// | |
const ipfsAPI = require("ipfs-api"); | |
const ipfs = ipfsAPI(ipfsProvider); | |
const args = process.argv.slice(2); | |
const path = args[0]; | |
console.log("Uploading files..."); | |
ipfs.util.addFromFs(path, { recursive: true }).then(response => { | |
console.log("Succesfully uploaded files!"); | |
printTable(response); | |
const dwebHash = response[response.length - 1].hash; | |
console.log("\n\n\n"); | |
console.log( | |
`To point an .eth domain to this website, use this hash as value:` | |
); | |
console.log("\x1b[36m%s\x1b[0m", `\n ${dwebHash}\n`); | |
console.log(`To preview you website immediately go to:`); | |
console.log("\x1b[36m%s\x1b[0m", `\n ${ipfsGateway}/ipfs/${dwebHash}\n`); | |
}); | |
// Util | |
/** | |
* | |
* @param array must be an array of objects where all the object have the same keys | |
* Demo output | |
path hash size | |
----------------------------------- ---------------------------------------------- ------- | |
build/android-chrome-192x192.png QmVDXMWzpcxJH7dVLy7EcJbiuwMbvW7TzpftQ9WhZJtNYo 25613 | |
build/android-chrome-512x512.png QmSPVmLSSBo9RdVTxUUGvDt3Qkb62Pu5ai3NPLrvdkKFxY 82789 | |
*/ | |
function printTable(array) { | |
const maxLen = {}; | |
array.forEach(elem => { | |
Object.keys(elem).forEach(key => { | |
const len = String(elem[key]).length; | |
const _len = maxLen[key] || 0; | |
maxLen[key] = len > _len ? len : _len; | |
}); | |
}); | |
const sp = "\t"; | |
console.log( | |
Object.keys(array[0]) | |
.map(key => key.padStart(maxLen[key])) | |
.join(sp) | |
); | |
console.log( | |
Object.keys(array[0]) | |
.map(key => "".padStart(maxLen[key], "-")) | |
.join(sp) | |
); | |
array.forEach(elem => { | |
console.log( | |
Object.keys(elem) | |
.map(key => String(elem[key]).padStart(maxLen[key])) | |
.join(sp) | |
); | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## prerequis ubuntu | |
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash | |
bash | |
nvm install 10 | |
node --version | |
#v10.16.3 | |
npm --version | |
#6.9.0 | |
sudo apt-get update | |
sudo apt install -y python build-essential | |
npm i -g [email protected] | |
## create a project dir | |
mkdir dweb-simple-storage | |
cd dweb-simple-storage | |
# unbox the box : https://truffleframework.com/boxes/react | |
truffle unbox react | |
// Compile: truffle compile | |
// Migrate: truffle migrate | |
// Test contracts: truffle test | |
// Test dapp: cd client && npm test | |
// Run dev server: cd client && npm run start | |
// Build for production: cd client && npm run build | |
// | |
#test compile | |
truffle compile | |
#Test contracts | |
truffle test | |
Launch a testnet node goerli : | |
got to | |
https://github.com/paritytech/parity-ethereum/releases | |
wget https://releases.parity.io/ethereum/v2.6.3/x86_64-unknown-linux-gnu/parity | |
chmod +x parity | |
npm install -g [email protected] | |
npm install [email protected] --save-dev | |
mv truffle-config.js truffle-config.js.ori | |
wget https://gist.githubusercontent.com/branciard/3ccbc62b84d0d07e77326f3f9d4fd640/raw/21c946d393e99d0e6795019227547361d12cd54e/truffle-config.js | |
replace by the truffle-config-js file by this https://gist.githubusercontent.com/branciard/3ccbc62b84d0d07e77326f3f9d4fd640/raw/21c946d393e99d0e6795019227547361d12cd54e/truffle-config.js | |
#Create wallet | |
ARCH=`uname -m` | |
ETHKEY_URL=`curl -sS "https://vanity-service.parity.io/parity-binaries?version=stable&format=markdown&os=linux&architecture=$ARCH" | grep ethkey | awk {'print $5'} | cut -d"(" -f2 | cut -d")" -f1` | |
wget -q $ETHKEY_URL | |
chmod +x ethkey | |
./ethkey generate random > wallet.txt | |
replace the __PRIVATE_KEY__ in truffle-config-js with the secret find in wallet.txt 'secret' | |
const privateKeys = [__PRIVATE_KEY__]; // private keys | |
must become : | |
const privateKeys = ['secret from wallet.txt here']; // private keys | |
#Tester sur un deployement local launch in a separate window | |
#launch ganache-cli https://truffleframework.com/ganache | |
ganache-cli --port 7545 | |
#deploy with testnet local ganache | |
truffle migrate --network development | |
launch goerli | |
nohup ./parity --chain goerli --jsonrpc-port 8545 --jsonrpc-interface all --jsonrpc-hosts all --jsonrpc-cors all --ws-interface all --ws-port 8546 --ws-origins all --ws-hosts all > goerli.log & | |
wait and check the node is synch. must be false : | |
https://wiki.parity.io/JSONRPC-eth-module#example-39 | |
curl --data '{"method":"eth_syncing","params":[],"id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST localhost:8545 | |
check also log wih : | |
tail -f parity.log | |
while wainting go to https://goerli-faucet.slock.it/ and claim som goerli eth. Use the address value find in your wallet.txt. | |
Add 0x before pasting the address in the form. | |
When you have some goerli eth and the node is synch you can deploy on it : | |
truffle migrate --network goerli | |
after deploy OK :check contract address on etherscan : https://goerli.etherscan.io and https://blockscout.com/eth/goerli | |
===================== | |
Deploying 'SimpleStorage' | |
------------------------- | |
> transaction hash: 0x65c57bf335b124282b89280c44f20326517e9b81eed95ca662817441dbc54179 | |
> Blocks: 1 Seconds: 28 | |
> contract address: 0x95Ce78088a7cfDa6d6A73688E42176853ae37704 | |
check your deployment address in network 5 in client/src/contracts/SimpleStorage.json | |
you can Verify and publish the source code : ~/dweb-simple-storage/contracts$ cat SimpleStorage.sol | |
in etherscan and blockscout. | |
#install IPFS node : | |
https://dist.ipfs.io/#go-ipfs | |
wget https://dist.ipfs.io/go-ipfs/v0.4.22/go-ipfs_v0.4.22_linux-amd64.tar.gz | |
tar xvfz go-ipfs_v0.4.22_linux-amd64.tar.gz | |
cd go-ipfs | |
sudo ./install.sh | |
launch it : | |
ipfs init --profile=lowpower | |
in a new terminal launch ipfs | |
cd client | |
rm -rf node_modules | |
npm install ipfs-api --save | |
rm -rf node_modules | |
npm install | |
#in package.json add the following line : | |
"homepage": "./", | |
#see https://www.reddit.com/r/ipfs/comments/8k3f8m/react_app_build_not_working_when_published_to_ipfs/dz6uh75?utm_source=share&utm_medium=web2x | |
add the ipfsDwebUploader.js file with this content : | |
wget https://gist.githubusercontent.com/branciard/3ccbc62b84d0d07e77326f3f9d4fd640/raw/9892accba87cb1e9944408cfd7028aa3b5a9c927/ipfsDwebUploader.js | |
#after the eject line add a publish command : | |
"publish": "react-scripts build && rm build/static/js/*.map && rm build/static/css/*.map && node ./ipfsDwebUploader build/" | |
Now you can deploy your site on IPFS with in client dir : | |
npm run publish | |
you must see something like this : | |
To point an .eth domain to this website, use this hash as value: | |
QmRcK48iQkZnoySh9dTB9dRqFfYM7kXtBqQRaf5H7Pitkj | |
To preview you website immediately go to: | |
http://127.0.0.1:8080/ipfs/QmRcK48iQkZnoySh9dTB9dRqFfYM7kXtBqQRaf5H7Pitkj | |
Wait for your site to be propagate an accessible on IPFS on the publoic gatway : | |
https://ipfs.io/ipfs/QmRcK48iQkZnoySh9dTB9dRqFfYM7kXtBqQRaf5H7Pitkj/ | |
Bonus : if you deplot it on mainnet and configure an ENS to target IPFS content QmdSpPGWTcbEzbSLhouLcpoBqy2tKNaLTrWWetT5s1yvJo | |
go to : https://manager.ens.domains/ | |
You can then access the site your : yourENSsite.eth |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const path = require("path"); | |
const HDWalletProvider = require("truffle-hdwallet-provider"); | |
const privateKeys = ['TBD']; // private keys | |
module.exports = { | |
contracts_build_directory: path.join(__dirname, "client/src/contracts"), | |
networks: { | |
development: { | |
host: "127.0.0.1", | |
port: 7545, | |
network_id: "*" | |
}, | |
goerli: { | |
provider: () => | |
new HDWalletProvider(privateKeys, "http://127.0.0.1:8545"), | |
port: 8545, | |
network_id: "5" | |
}, | |
mainnet: { | |
provider: () => | |
new HDWalletProvider(privateKeys, "http://my.ethchain.dnp.dappnode.eth:8545"), | |
gas: 4400000, | |
gasPrice: 22000000000, | |
network_id: "1" | |
} | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment