Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save branciard/3ccbc62b84d0d07e77326f3f9d4fd640 to your computer and use it in GitHub Desktop.
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 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 truffle-hdwallet-provider@1.0.17 --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
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 truffle@5.0.37
RUN npm install -g ganache-cli@6.7.0
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
#!/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)
);
});
}
## 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 truffle@5.0.37
## 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 ganache-cli@6.7.0
npm install truffle-hdwallet-provider@1.0.17 --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
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