diff --git a/.env.faucet b/.env.faucet new file mode 100644 index 000000000..b91fe97ac --- /dev/null +++ b/.env.faucet @@ -0,0 +1,9 @@ +FAUCET_NAME="Scoville Faucet" +CHAIN_NAME=Scoville +MINT_NFTS_URL=https://scoville-nft.chiliz.com/ +DEV_LANDING_URL=https://www.chiliz.com/en/chain/ + +VOTE_TOKEN_CONTRACTS_ADDRESSES=0x931497160a90cE18c361b49F007d7285951A1A3e,0x4BadFd82f7eF1772E848A2482B570F95FE4cBff9,0xb4b27b9e52dC421FF82b74f9d36bAa39b1181Dc2,0xd9CbFcd6Ed02032a2591C5a7c0dFB34e9d7F7F2D,0x48E32f760fA1dabCd585C20d235fa6Dbef324d80,0x8377C51D89a3F143464AD0280CAcFEd82691d5B1,0x094DeedE5D44C549D9a28AE946761e36513C5f72,0xE8DcBf10217eB753729c2e30A5F641b5f582bBbf,0xEeE279AD3C283BC34A5Be567bb889Ce2617f2288,0x4eAD97E7D8A477fE5df88B4CD5025E255c42Ff26,0x16Ca3C932F497Eb2BED8820249698B9d6006Eb41,0x8c6Ba7dd73436ba35FC645CCb7a80B2d71F48A85 +VOTE_TOKEN_SYMBOLS=testSSU,testGAL,testCITY,testPSG,testBAR,testJUV,testMENGO,testTRA,testACM,testATM,testAFC,testINTER +VOTE_TOKEN_NAMES=Socios United,Galatasaray S.K.,Manchester City FC,Paris Saint-Germai,FC Barcelona,Juventus,Flamengo,Trabzonspor,AC Milan,Atlético de Madrid,Arsenal FC,Inter Milan +VOTE_TOKEN_AMOUNTS=1,1,1,1,1,1,1,1,1,1,1,1 \ No newline at end of file diff --git a/Dockerfile.faucet b/Dockerfile.faucet index 8b7e0dee5..ef45033ec 100644 --- a/Dockerfile.faucet +++ b/Dockerfile.faucet @@ -1,13 +1,7 @@ -FROM golang:1.15-alpine as builder +FROM golang:1.16-alpine as builder RUN apk add --no-cache make gcc musl-dev linux-headers git bash -# Temporarily pull a custom Go bundle -ADD https://golang.org/dl/go1.15.5.src.tar.gz /tmp/go.tar.gz -RUN (cd /tmp && tar -xf go.tar.gz) -RUN (cd /tmp/go/src && ./make.bash) -ENV PATH="/tmp/go/bin:${PATH}" - ADD . /go-ethereum RUN cd /go-ethereum && make faucet @@ -16,6 +10,8 @@ FROM alpine:latest RUN apk add --no-cache ca-certificates curl jq tini COPY --from=builder /go-ethereum/build/bin/faucet /usr/local/bin/ +COPY --from=builder /go-ethereum/.env.faucet /.env WORKDIR / +EXPOSE 8080 ENTRYPOINT ["faucet"] \ No newline at end of file diff --git a/cmd/faucet/CircularStd-Book.otf b/cmd/faucet/CircularStd-Book.otf new file mode 100644 index 000000000..3a1f1ad82 Binary files /dev/null and b/cmd/faucet/CircularStd-Book.otf differ diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index 500a1e920..dee57eaf8 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -17,7 +17,7 @@ // faucet is an Ether faucet backed by a light client. package main -//go:generate go-bindata -nometadata -o website.go faucet.html +//go:generate go-bindata -nometadata -o website.go faucet.html CircularStd-Book.otf //go:generate gofmt -w -s website.go import ( @@ -60,6 +60,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/params" "github.com/gorilla/websocket" + "github.com/joho/godotenv" ) var ( @@ -86,6 +87,7 @@ var ( bep2eContracts = flag.String("bep2eContracts", "", "the list of bep2p contracts") bep2eSymbols = flag.String("bep2eSymbols", "", "the symbol of bep2p tokens") + bep2eNames = flag.String("bep2eNames", "", "the names of bep2p tokens") bep2eAmounts = flag.String("bep2eAmounts", "", "the amount of bep2p tokens") fixGasPrice = flag.Int64("faucet.fixedprice", 0, "Will use fixed gas price if specified") twitterTokenFlag = flag.String("twitter.token", "", "Bearer token to authenticate with the v2 Twitter API") @@ -97,7 +99,7 @@ var ( var ( ether = new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil) - bep2eAbiJson = `[ { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, { "indexed": true, "internalType": "address", "name": "spender", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "Approval", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "from", "type": "address" }, { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "Transfer", "type": "event" }, { "inputs": [], "name": "totalSupply", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "decimals", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "symbol", "outputs": [ { "internalType": "string", "name": "", "type": "string" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "getOwner", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "account", "type": "address" } ], "name": "balanceOf", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "recipient", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "transfer", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "_owner", "type": "address" }, { "internalType": "address", "name": "spender", "type": "address" } ], "name": "allowance", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "approve", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "sender", "type": "address" }, { "internalType": "address", "name": "recipient", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "transferFrom", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" } ]` + bep2eAbiJson = `[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address[]"},{"name":"_values","type":"uint256[]"}],"name":"batchTransfer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"name","type":"string"},{"name":"symbol","type":"string"},{"name":"decimals","type":"uint8"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"sender","type":"address"},{"name":"recipient","type":"address"},{"name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"name","type":"string"},{"name":"symbol","type":"string"},{"name":"decimals","type":"uint8"},{"name":"minters","type":"address[]"},{"name":"pausers","type":"address[]"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_survey","type":"address"}],"name":"unregisterSurvey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"isPauser","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"name","type":"string"},{"name":"symbol","type":"string"},{"name":"decimals","type":"uint8"},{"name":"initialSupply","type":"uint256"},{"name":"initialHolder","type":"address"},{"name":"minters","type":"address[]"},{"name":"pausers","type":"address[]"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"offset","type":"uint256"},{"name":"count","type":"uint256"},{"name":"cap","type":"uint256"}],"name":"getCirculatingSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"version","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renouncePauser","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getOwnersCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_survey","type":"address"}],"name":"registerSurvey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"}],"name":"addPauser","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getOwner","outputs":[{"name":"tokenOwner","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"}],"name":"addMinter","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"renounceMinter","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"},{"name":"value","type":"uint256"}],"name":"burn","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"recipient","type":"address"},{"name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"isMinter","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_survey","type":"address"}],"name":"isSurveyRegistered","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"sender","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"},{"name":"spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"}],"name":"PauserAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"}],"name":"PauserRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"}],"name":"MinterAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"}],"name":"MinterRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"}]` ) var ( @@ -110,33 +112,48 @@ func main() { flag.Parse() log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*logFlag), log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) + // Load .env + err := godotenv.Load() + if err != nil { + log.Crit("Error loading .env file", err) + } + // Construct the payout tiers amounts := make([]string, *tiersFlag) for i := 0; i < *tiersFlag; i++ { // Calculate the amount for the next tier and format it amount := float64(*payoutFlag) * math.Pow(2.5, float64(i)) - amounts[i] = fmt.Sprintf("%s BNBs", strconv.FormatFloat(amount, 'f', -1, 64)) + amounts[i] = fmt.Sprintf("%s CHZs", strconv.FormatFloat(amount, 'f', -1, 64)) if amount == 1 { amounts[i] = strings.TrimSuffix(amounts[i], "s") } } bep2eNumAmounts := make([]string, 0) - if bep2eAmounts != nil && len(*bep2eAmounts) > 0 { - bep2eNumAmounts = strings.Split(*bep2eAmounts, ",") + contractAmounts := os.Getenv("VOTE_TOKEN_AMOUNTS") + if len(contractAmounts) > 0 { + bep2eNumAmounts = strings.Split(contractAmounts, ",") } symbols := make([]string, 0) - if bep2eSymbols != nil && len(*bep2eSymbols) > 0 { - symbols = strings.Split(*bep2eSymbols, ",") + contractSymbols := os.Getenv("VOTE_TOKEN_SYMBOLS") + if len(contractSymbols) > 0 { + symbols = strings.Split(contractSymbols, ",") + } + + names := make([]string, 0) + contractNames := os.Getenv("VOTE_TOKEN_NAMES") + if len(contractNames) > 0 { + names = strings.Split(contractNames, ",") } contracts := make([]string, 0) - if bep2eContracts != nil && len(*bep2eContracts) > 0 { - contracts = strings.Split(*bep2eContracts, ",") + contractAddresses := os.Getenv("VOTE_TOKEN_CONTRACTS_ADDRESSES") + if len(contractAddresses) > 0 { + contracts = strings.Split(contractAddresses, ",") } - if len(bep2eNumAmounts) != len(symbols) || len(symbols) != len(contracts) { - log.Crit("Length of bep2eContracts, bep2eSymbols, bep2eAmounts mismatch") + if len(bep2eNumAmounts) != len(symbols) || len(symbols) != len(contracts) || len(contracts) != len(names) { + log.Crit("Length of bep2eContracts, bep2eSymbols, bep2eAmounts, bep2eNames mismatch") } bep2eInfos := make(map[string]bep2eInfo, len(symbols)) @@ -145,14 +162,21 @@ func main() { if !ok { log.Crit("failed to parse bep2eAmounts") } - amountStr := big.NewFloat(0).Quo(big.NewFloat(0).SetInt(n), big.NewFloat(0).SetInt64(params.Ether)).String() + amountStr := n.String() bep2eInfos[s] = bep2eInfo{ Contract: common.HexToAddress(contracts[idx]), Amount: *n, AmountStr: amountStr, + Name: names[idx], } } + + faucetName := os.Getenv("FAUCET_NAME") + mintNftsUrl := os.Getenv("MINT_NFTS_URL") + devLandingUrl := os.Getenv("DEV_LANDING_URL") + chainName := os.Getenv("CHAIN_NAME") + // Load up and render the faucet website tmpl, err := Asset("faucet.html") if err != nil { @@ -160,11 +184,15 @@ func main() { } website := new(bytes.Buffer) err = template.Must(template.New("").Parse(string(tmpl))).Execute(website, map[string]interface{}{ - "Network": *netnameFlag, - "Amounts": amounts, - "Recaptcha": *captchaToken, - "NoAuth": *noauthFlag, - "Bep2eInfos": bep2eInfos, + "Network": *netnameFlag, + "Amounts": amounts, + "Recaptcha": *captchaToken, + "NoAuth": *noauthFlag, + "Bep2eInfos": bep2eInfos, + "FaucetName": faucetName, + "MintNftsUrl": mintNftsUrl, + "DevLandingUrl": devLandingUrl, + "ChainName": chainName, }) if err != nil { log.Crit("Failed to render the faucet template", "err", err) @@ -201,8 +229,12 @@ func main() { if err := ks.Unlock(acc, pass); err != nil { log.Crit("Failed to unlock faucet signer account", "err", err) } + font, err := Asset("CircularStd-Book.otf") + if err != nil { + log.Crit("Failed to load the font", "err", err) + } // Assemble and start the faucet light service - faucet, err := newFaucet(genesis, *ethPortFlag, enodes, *netFlag, *statsFlag, ks, website.Bytes(), bep2eInfos) + faucet, err := newFaucet(genesis, *ethPortFlag, enodes, *netFlag, *statsFlag, ks, website.Bytes(), font, bep2eInfos) if err != nil { log.Crit("Failed to start faucet", "err", err) } @@ -225,6 +257,7 @@ type bep2eInfo struct { Contract common.Address Amount big.Int AmountStr string + Name string } // faucet represents a crypto faucet backed by an Ethereum light client. @@ -233,6 +266,7 @@ type faucet struct { stack *node.Node // Ethereum protocol stack client *ethclient.Client // Client connection to the Ethereum chain index []byte // Index page to serve up on the web + font []byte // Font to serve up on the web keystore *keystore.KeyStore // Keystore containing the single signer account accounts.Account // Account funding user faucet requests @@ -259,7 +293,7 @@ type wsConn struct { wlock sync.Mutex } -func newFaucet(genesis *core.Genesis, port int, enodes []*enode.Node, network uint64, stats string, ks *keystore.KeyStore, index []byte, bep2eInfos map[string]bep2eInfo) (*faucet, error) { +func newFaucet(genesis *core.Genesis, port int, enodes []*enode.Node, network uint64, stats string, ks *keystore.KeyStore, index []byte, font []byte, bep2eInfos map[string]bep2eInfo) (*faucet, error) { // Assemble the raw devp2p protocol stack stack, err := node.New(&node.Config{ Name: "geth", @@ -323,6 +357,7 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*enode.Node, network ui stack: stack, client: client, index: index, + font: font, keystore: ks, account: ks.Accounts()[0], timeouts: make(map[string]time.Time), @@ -343,6 +378,7 @@ func (f *faucet) listenAndServe(port int) error { go f.loop() http.HandleFunc("/", f.webHandler) + http.HandleFunc("/font", f.fontHandler) http.HandleFunc("/api", f.apiHandler) http.HandleFunc("/faucet-smart/api", f.apiHandler) return http.ListenAndServe(fmt.Sprintf(":%d", port), nil) @@ -354,6 +390,12 @@ func (f *faucet) webHandler(w http.ResponseWriter, r *http.Request) { w.Write(f.index) } +// webHandler handles all non-api requests, simply flattening and returning the +// faucet website. +func (f *faucet) fontHandler(w http.ResponseWriter, r *http.Request) { + w.Write(f.font) +} + // apiHandler handles requests for Ether grants and transaction statuses. func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) { upgrader := websocket.Upgrader{} @@ -528,7 +570,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) { ) if timeout = f.timeouts[id]; time.Now().After(timeout) { var tx *types.Transaction - if msg.Symbol == "BNB" { + if msg.Symbol == "CHZ" { // User wasn't funded recently, create the funding transaction amount := new(big.Int).Mul(big.NewInt(int64(*payoutFlag)), ether) amount = new(big.Int).Mul(amount, new(big.Int).Exp(big.NewInt(5), big.NewInt(int64(msg.Tier)), nil)) diff --git a/cmd/faucet/faucet.html b/cmd/faucet/faucet.html index 849145a60..b1dd42b59 100644 --- a/cmd/faucet/faucet.html +++ b/cmd/faucet/faucet.html @@ -15,6 +15,42 @@ + +