Skip to content

Commit 511bbf5

Browse files
authored
add bep2p tokens for faucet (bnb-chain#5)
1 parent 5e4f578 commit 511bbf5

File tree

3 files changed

+108
-28
lines changed

3 files changed

+108
-28
lines changed

cmd/faucet/faucet.go

Lines changed: 95 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ import (
4141
"sync"
4242
"time"
4343

44+
"github.com/ethereum/go-ethereum/accounts/abi"
45+
4446
"github.com/ethereum/go-ethereum/accounts"
4547
"github.com/ethereum/go-ethereum/accounts/keystore"
4648
"github.com/ethereum/go-ethereum/common"
@@ -83,11 +85,15 @@ var (
8385
noauthFlag = flag.Bool("noauth", false, "Enables funding requests without authentication")
8486
logFlag = flag.Int("loglevel", 3, "Log level to use for Ethereum and the faucet")
8587

86-
fixGasPrice = flag.Int64("faucet.fixedprice", 0, "Will use fixed gas price if specified")
88+
bep2eContracts = flag.String("bep2eContracts", "", "the list of bep2p contracts")
89+
bep2eSymbols = flag.String("bep2eSymbols", "", "the symbol of bep2p tokens")
90+
bep2eAmounts = flag.String("bep2eAmounts", "", "the amount of bep2p tokens")
91+
fixGasPrice = flag.Int64("faucet.fixedprice", 0, "Will use fixed gas price if specified")
8792
)
8893

8994
var (
90-
ether = new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)
95+
ether = new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)
96+
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" } ]`
9197
)
9298

9399
var (
@@ -110,18 +116,51 @@ func main() {
110116
amounts[i] = strings.TrimSuffix(amounts[i], "s")
111117
}
112118
}
119+
bep2eNumAmounts := make([]string, 0)
120+
if bep2eAmounts != nil && len(*bep2eAmounts) > 0 {
121+
bep2eNumAmounts = strings.Split(*bep2eAmounts, ",")
122+
}
123+
124+
symbols := make([]string, 0)
125+
if bep2eSymbols != nil && len(*bep2eSymbols) > 0 {
126+
symbols = strings.Split(*bep2eSymbols, ",")
127+
}
113128

129+
contracts := make([]string, 0)
130+
if bep2eContracts != nil && len(*bep2eContracts) > 0 {
131+
contracts = strings.Split(*bep2eContracts, ",")
132+
}
133+
134+
if len(bep2eNumAmounts) != len(symbols) || len(symbols) != len(contracts) {
135+
log.Crit("Length of bep2eContracts, bep2eSymbols, bep2eAmounts mismatch")
136+
}
137+
138+
bep2eInfos := make(map[string]bep2eInfo, 0)
139+
for idx, s := range symbols {
140+
n, ok := big.NewInt(0).SetString(bep2eNumAmounts[idx], 10)
141+
if !ok {
142+
log.Crit("failed to parse bep2eAmounts")
143+
}
144+
amountStr := big.NewFloat(0).Quo(big.NewFloat(0).SetInt(n), big.NewFloat(0).SetInt64(params.Ether)).String()
145+
146+
bep2eInfos[s] = bep2eInfo{
147+
Contract: common.HexToAddress(contracts[idx]),
148+
Amount: *n,
149+
AmountStr: amountStr,
150+
}
151+
}
114152
// Load up and render the faucet website
115153
tmpl, err := Asset("faucet.html")
116154
if err != nil {
117155
log.Crit("Failed to load the faucet template", "err", err)
118156
}
119157
website := new(bytes.Buffer)
120158
err = template.Must(template.New("").Parse(string(tmpl))).Execute(website, map[string]interface{}{
121-
"Network": *netnameFlag,
122-
"Amounts": amounts,
123-
"Recaptcha": *captchaToken,
124-
"NoAuth": *noauthFlag,
159+
"Network": *netnameFlag,
160+
"Amounts": amounts,
161+
"Recaptcha": *captchaToken,
162+
"NoAuth": *noauthFlag,
163+
"Bep2eInfos": bep2eInfos,
125164
})
126165
if err != nil {
127166
log.Crit("Failed to render the faucet template", "err", err)
@@ -162,7 +201,7 @@ func main() {
162201
ks.Unlock(acc, pass)
163202

164203
// Assemble and start the faucet light service
165-
faucet, err := newFaucet(genesis, *ethPortFlag, enodes, *netFlag, *statsFlag, ks, website.Bytes())
204+
faucet, err := newFaucet(genesis, *ethPortFlag, enodes, *netFlag, *statsFlag, ks, website.Bytes(), bep2eInfos)
166205
if err != nil {
167206
log.Crit("Failed to start faucet", "err", err)
168207
}
@@ -181,6 +220,12 @@ type request struct {
181220
Tx *types.Transaction `json:"tx"` // Transaction funding the account
182221
}
183222

223+
type bep2eInfo struct {
224+
Contract common.Address
225+
Amount big.Int
226+
AmountStr string
227+
}
228+
184229
// faucet represents a crypto faucet backed by an Ethereum light client.
185230
type faucet struct {
186231
config *params.ChainConfig // Chain configurations for signing
@@ -201,9 +246,12 @@ type faucet struct {
201246
update chan struct{} // Channel to signal request updates
202247

203248
lock sync.RWMutex // Lock protecting the faucet's internals
249+
250+
bep2eInfos map[string]bep2eInfo
251+
bep2eAbi abi.ABI
204252
}
205253

206-
func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network uint64, stats string, ks *keystore.KeyStore, index []byte) (*faucet, error) {
254+
func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network uint64, stats string, ks *keystore.KeyStore, index []byte, bep2eInfos map[string]bep2eInfo) (*faucet, error) {
207255
// Assemble the raw devp2p protocol stack
208256
stack, err := node.New(&node.Config{
209257
Name: "geth",
@@ -222,6 +270,10 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u
222270
if err != nil {
223271
return nil, err
224272
}
273+
bep2eAbi, err := abi.JSON(strings.NewReader(bep2eAbiJson))
274+
if err != nil {
275+
return nil, err
276+
}
225277
// Assemble the Ethereum light client protocol
226278
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
227279
cfg := eth.DefaultConfig
@@ -261,14 +313,16 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u
261313
client := ethclient.NewClient(api)
262314

263315
return &faucet{
264-
config: genesis.Config,
265-
stack: stack,
266-
client: client,
267-
index: index,
268-
keystore: ks,
269-
account: ks.Accounts()[0],
270-
timeouts: make(map[string]time.Time),
271-
update: make(chan struct{}, 1),
316+
config: genesis.Config,
317+
stack: stack,
318+
client: client,
319+
index: index,
320+
keystore: ks,
321+
account: ks.Accounts()[0],
322+
timeouts: make(map[string]time.Time),
323+
update: make(chan struct{}, 1),
324+
bep2eInfos: bep2eInfos,
325+
bep2eAbi: bep2eAbi,
272326
}, nil
273327
}
274328

@@ -371,6 +425,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
371425
URL string `json:"url"`
372426
Tier uint `json:"tier"`
373427
Captcha string `json:"captcha"`
428+
Symbol string `json:"symbol"`
374429
}
375430
if err = conn.ReadJSON(&msg); err != nil {
376431
return
@@ -475,13 +530,31 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
475530
fund bool
476531
timeout time.Time
477532
)
478-
if timeout = f.timeouts[username]; time.Now().After(timeout) {
479-
// User wasn't funded recently, create the funding transaction
480-
amount := new(big.Int).Mul(big.NewInt(int64(*payoutFlag)), ether)
481-
amount = new(big.Int).Mul(amount, new(big.Int).Exp(big.NewInt(5), big.NewInt(int64(msg.Tier)), nil))
482-
amount = new(big.Int).Div(amount, new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(msg.Tier)), nil))
483533

484-
tx := types.NewTransaction(f.nonce+uint64(len(f.reqs)), address, amount, 21000, f.price, nil)
534+
if timeout = f.timeouts[username]; time.Now().After(timeout) {
535+
var tx *types.Transaction
536+
if msg.Symbol == "BNB" {
537+
// User wasn't funded recently, create the funding transaction
538+
amount := new(big.Int).Mul(big.NewInt(int64(*payoutFlag)), ether)
539+
amount = new(big.Int).Mul(amount, new(big.Int).Exp(big.NewInt(5), big.NewInt(int64(msg.Tier)), nil))
540+
amount = new(big.Int).Div(amount, new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(msg.Tier)), nil))
541+
542+
tx = types.NewTransaction(f.nonce+uint64(len(f.reqs)), address, amount, 21000, f.price, nil)
543+
} else {
544+
tokenInfo, ok := f.bep2eInfos[msg.Symbol]
545+
if !ok {
546+
f.lock.Unlock()
547+
log.Warn("Failed to find symbol", "symbol", msg.Symbol)
548+
continue
549+
}
550+
input, err := f.bep2eAbi.Pack("transfer", address, &tokenInfo.Amount)
551+
if err != nil {
552+
f.lock.Unlock()
553+
log.Warn("Failed to pack transfer transaction", "err", err)
554+
continue
555+
}
556+
tx = types.NewTransaction(f.nonce+uint64(len(f.reqs)), tokenInfo.Contract, nil, 420000, f.price, input)
557+
}
485558
signed, err := f.keystore.SignTx(f.account, tx, f.config.ChainID)
486559
if err != nil {
487560
f.lock.Unlock()

cmd/faucet/faucet.html

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,13 @@ <h1 style="text-align: center;"><i class="fa fa-bath" aria-hidden="true"></i> {{
5353
<span class="input-group-btn">
5454
<button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Give me BNB <i class="fa fa-caret-down" aria-hidden="true"></i></button>
5555
<ul class="dropdown-menu dropdown-menu-right">{{range $idx, $amount := .Amounts}}
56-
<li><a style="text-align: center;" onclick="tier={{$idx}}; {{if $.Recaptcha}}grecaptcha.execute(){{else}}submit({{$idx}}){{end}}">{{$amount}}</a></li>{{end}}
56+
<li><a style="text-align: center;" onclick="tier={{$idx}};symbol='BNB'; {{if $.Recaptcha}}grecaptcha.execute(){{else}}submit({{$idx}}){{end}}">{{$amount}}</a></li>{{end}}
57+
</ul>
58+
</span>
59+
<span class="input-group-btn">
60+
<button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Peggy tokens<i class="fa fa-caret-down" aria-hidden="true"></i></button>
61+
<ul class="dropdown-menu dropdown-menu-right"> {{range $symbol, $bep2eInfo := .Bep2eInfos}}
62+
<li><a style="text-align: center;" onclick="symbol={{$symbol}}; {{if $.Recaptcha}}grecaptcha.execute(){{else}}submitBep2e({{$symbol}}){{end}}">{{$bep2eInfo.AmountStr}} {{$symbol}}</a></li>{{end}}
5763
</ul>
5864
</span>
5965
</div>{{if .Recaptcha}}
@@ -85,6 +91,7 @@ <h1 style="text-align: center;"><i class="fa fa-bath" aria-hidden="true"></i> {{
8591
var attempt = 0;
8692
var server;
8793
var tier = 0;
94+
var symbol="";
8895
var requests = [];
8996

9097
// Define a function that creates closures to drop old requests
@@ -100,7 +107,7 @@ <h1 style="text-align: center;"><i class="fa fa-bath" aria-hidden="true"></i> {{
100107
};
101108
// Define the function that submits a gist url to the server
102109
var submit = function({{if .Recaptcha}}captcha{{end}}) {
103-
server.send(JSON.stringify({url: $("#url")[0].value, tier: tier{{if .Recaptcha}}, captcha: captcha{{end}}}));{{if .Recaptcha}}
110+
server.send(JSON.stringify({url: $("#url")[0].value, symbol: symbol, tier: tier{{if .Recaptcha}}, captcha: captcha{{end}}}));{{if .Recaptcha}}
104111
grecaptcha.reset();{{end}}
105112
};
106113
// Define a method to reconnect upon server loss

0 commit comments

Comments
 (0)