Skip to content

Commit fcf1ac0

Browse files
committed
Encapsulate the config
1 parent 3b747f2 commit fcf1ac0

File tree

2 files changed

+53
-43
lines changed

2 files changed

+53
-43
lines changed

src/main/kotlin/org/komputing/fauceth/Application.kt

Lines changed: 15 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -38,46 +38,18 @@ const val ADDRESS_KEY = "address"
3838
val keystoreFile = File("fauceth_keystore.json")
3939
val ens = ENS(getMin3RPC())
4040

41-
val config = systemProperties() overriding
42-
EnvironmentVariables() overriding
43-
ConfigurationProperties.fromOptionalFile(File("fauceth.properties"))
44-
45-
4641
fun main(args: Array<String>) = io.ktor.server.netty.EngineMain.main(args)
4742

4843
fun Application.module() {
49-
var keyPair: ECKeyPair? = config.getOrNull(Key("app.ethkey", stringType))?.let {
50-
PrivateKey(it.toBigInteger(16)).toECKeyPair()
51-
}
5244

53-
val hcaptchaSecret = config[Key("hcaptcha.secret", stringType)]
54-
val hcaptchaSiteKey = config[Key("hcaptcha.sitekey", stringType)]
45+
val config = FaucethConfig()
5546

56-
val appTitle = config.getOrElse(Key("app.title", stringType), "FaucETH")
57-
val appHeroImage = config.getOrNull(Key("app.imageURL", stringType))
58-
val amount = BigInteger(config.getOrNull(Key("app.amount", stringType)) ?: "$ETH_IN_WEI")
47+
val rpc = HttpEthereumRPC(config.chainRPCURL)
5948

60-
val chainRPCURL = config[Key("chain.rpc", stringType)]
61-
val chainExplorer = config.getOrNull(Key("chain.explorer", stringType))
62-
val chainId = BigInteger(config[Key("chain.id", stringType)])
63-
64-
if (keyPair == null) {
65-
if (!keystoreFile.exists()) {
66-
keyPair = createEthereumKeyPair()
67-
keystoreFile.createNewFile()
68-
keystoreFile.writeText(keyPair.privateKey.key.toString())
69-
} else {
70-
keyPair = PrivateKey(keystoreFile.readText().toBigInteger()).toECKeyPair()
71-
}
72-
}
73-
74-
val rpc = HttpEthereumRPC(chainRPCURL)
75-
76-
val initialNonce = rpc.getTransactionCount(keyPair.toAddress())
49+
val initialNonce = rpc.getTransactionCount(config.keyPair.toAddress())
7750

7851
val atomicNonce = AtomicNonce(initialNonce!!)
7952

80-
8153
routing {
8254
static("/static") {
8355
staticRootFolder
@@ -88,7 +60,7 @@ fun Application.module() {
8860

8961
call.respondHtml {
9062
head {
91-
title { +appTitle }
63+
title { +config.appTitle }
9264

9365
script(src = "https://js.hcaptcha.com/1/api.js") {}
9466

@@ -121,9 +93,9 @@ fun Application.module() {
12193
id = "mainForm"
12294

12395
h1(classes = "center") {
124-
+appTitle
96+
+config.appTitle
12597
}
126-
appHeroImage?.let { url ->
98+
config.appHeroImage?.let { url ->
12799
div(classes = "center") {
128100
img(src = url, classes = "image")
129101
}
@@ -134,7 +106,7 @@ fun Application.module() {
134106
placeholder = "Please enter some address or ENS name"
135107
}
136108
div(classes = "h-captcha center") {
137-
attributes["data-sitekey"] = hcaptchaSiteKey
109+
attributes["data-sitekey"] = config.hcaptchaSiteKey
138110
}
139111
}
140112
div(classes = "center") {
@@ -155,7 +127,7 @@ fun Application.module() {
155127
b {
156128
+"Address: "
157129
}
158-
+keyPair.toAddress().toString()
130+
+config.keyPair.toAddress().toString()
159131
br
160132
b {
161133
+"Nonce: "
@@ -168,7 +140,7 @@ fun Application.module() {
168140
post("/request") {
169141
val receiveParameters = call.receiveParameters()
170142

171-
val captchaResult: Boolean = verifyCaptcha(receiveParameters["h-captcha-response"] ?: "", hcaptchaSecret)
143+
val captchaResult: Boolean = verifyCaptcha(receiveParameters["h-captcha-response"] ?: "", config.hcaptchaSecret)
172144
var address = Address(receiveParameters[ADDRESS_KEY] ?: "")
173145
val ensName = receiveParameters[ADDRESS_KEY]?.let { name -> ENSName(name) }
174146
if (ensName?.isPotentialENSDomain() == true) {
@@ -190,10 +162,10 @@ fun Application.module() {
190162

191163
val tx = createEmptyTransaction().apply {
192164
to = address
193-
value = amount
165+
value = config.amount
194166
nonce = atomicNonce.getAndIncrement()
195167
gasLimit = DEFAULT_GAS_LIMIT
196-
chain = chainId
168+
chain = config.chainId
197169
}
198170

199171
val feeSuggestionResult = retry(decorrelatedJitterBackoff(base = 10L, max = 5000L)) {
@@ -207,17 +179,17 @@ fun Application.module() {
207179
tx.maxPriorityFeePerGas = feeSuggestionResult!!.maxPriorityFeePerGas
208180
tx.maxFeePerGas = feeSuggestionResult.maxFeePerGas
209181

210-
val signature = tx.signViaEIP1559(keyPair)
182+
val signature = tx.signViaEIP1559(config.keyPair)
211183

212184
val txHash: String = retry(decorrelatedJitterBackoff(base = 10L, max = 5000L)) {
213185
val res = rpc.sendRawTransaction(tx.encode(signature).toHexString())
214186
if (res?.startsWith("0x") != true) throw IllegalStateException("Got no hash from RPC for tx")
215187
res
216188
}
217189

218-
val amountString = BigDecimal(amount).divide(BigDecimal(ETH_IN_WEI))
219-
val msg = if (chainExplorer != null) {
220-
"send $amountString ETH (<a href='${chainExplorer}/tx/$txHash'>view here</a>)"
190+
val amountString = BigDecimal(config.amount).divide(BigDecimal(ETH_IN_WEI))
191+
val msg = if (config.chainExplorer != null) {
192+
"send $amountString ETH (<a href='${config.chainExplorer}/tx/$txHash'>view here</a>)"
221193
} else {
222194
"send $amountString ETH (transaction: $txHash)"
223195
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package org.komputing.fauceth
2+
3+
import com.natpryce.konfig.*
4+
import org.kethereum.ETH_IN_WEI
5+
import org.kethereum.crypto.createEthereumKeyPair
6+
import org.kethereum.crypto.toECKeyPair
7+
import org.kethereum.model.ECKeyPair
8+
import org.kethereum.model.PrivateKey
9+
import java.io.File
10+
import java.math.BigInteger
11+
12+
class FaucethConfig {
13+
private val config = ConfigurationProperties.systemProperties() overriding
14+
EnvironmentVariables() overriding
15+
ConfigurationProperties.fromOptionalFile(File("fauceth.properties"))
16+
17+
val keyPair: ECKeyPair = config.getOrNull(Key("app.ethkey", stringType))?.let {
18+
PrivateKey(it.toBigInteger(16)).toECKeyPair()
19+
} ?: if (!keystoreFile.exists()) {
20+
createEthereumKeyPair().also {
21+
keystoreFile.createNewFile()
22+
keystoreFile.writeText(it.privateKey.key.toString())
23+
}
24+
} else {
25+
PrivateKey(keystoreFile.readText().toBigInteger()).toECKeyPair()
26+
}
27+
28+
val hcaptchaSecret = config[Key("hcaptcha.secret", stringType)]
29+
val hcaptchaSiteKey = config[Key("hcaptcha.sitekey", stringType)]
30+
31+
val appTitle = config.getOrElse(Key("app.title", stringType), "FaucETH")
32+
val appHeroImage = config.getOrNull(Key("app.imageURL", stringType))
33+
val amount = BigInteger(config.getOrNull(Key("app.amount", stringType)) ?: "$ETH_IN_WEI")
34+
35+
val chainRPCURL = config[Key("chain.rpc", stringType)]
36+
val chainExplorer = config.getOrNull(Key("chain.explorer", stringType))
37+
val chainId = BigInteger(config[Key("chain.id", stringType)])
38+
}

0 commit comments

Comments
 (0)