-
Notifications
You must be signed in to change notification settings - Fork 8
/
Wallet.kt
166 lines (147 loc) · 5.34 KB
/
Wallet.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package org.stellar.walletsdk
import io.ktor.client.*
import io.ktor.client.engine.okhttp.*
import io.ktor.client.plugins.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.request.*
import io.ktor.http.*
import io.ktor.serialization.kotlinx.json.*
import io.ktor.utils.io.core.*
import java.util.*
import org.stellar.sdk.Network
import org.stellar.sdk.Server
import org.stellar.walletsdk.anchor.Anchor
import org.stellar.walletsdk.auth.WalletSigner
import org.stellar.walletsdk.horizon.Stellar
import org.stellar.walletsdk.json.defaultJson
import org.stellar.walletsdk.recovery.Recovery
import shadow.okhttp3.OkHttpClient
/**
* Wallet SDK main entry point. It provides methods to build wallet applications on the Stellar
* network.
*/
class Wallet(
stellarConfiguration: StellarConfiguration,
applicationConfiguration: ApplicationConfiguration = ApplicationConfiguration()
) : Closeable {
internal val cfg = Config(stellarConfiguration, applicationConfiguration)
private val clients = mutableListOf(cfg.app.defaultClient)
fun anchor(homeDomain: String, httpClientConfig: ClientConfigFn? = null): Anchor {
val url = if (homeDomain.contains("://")) homeDomain else "https://$homeDomain"
return Anchor(cfg, Url(url), getClient(httpClientConfig))
}
fun stellar(): Stellar {
return Stellar(cfg)
}
fun recovery(httpClientConfig: ClientConfigFn? = null): Recovery {
return Recovery(cfg, stellar(), getClient(httpClientConfig))
}
override fun close() {
clients.forEach { it.close() }
}
@Suppress("UNCHECKED_CAST")
private fun getClient(httpClientConfig: ClientConfigFn?): HttpClient {
val httpClient =
httpClientConfig?.run {
cfg.app.defaultClient.config { (this as HttpClientConfig<OkHttpConfig>).httpClientConfig() }
}
httpClient?.also { clients.add(it) }
return httpClient ?: cfg.app.defaultClient
}
companion object {
val Testnet =
Wallet(
StellarConfiguration.Testnet,
)
}
}
/**
* Configuration for all Stellar-related activity.
*
* @constructor Create empty Stellar configuration
* @property network network to be used
* @property horizonUrl URL of the Horizons server.
* @property baseFee default [base fee]
* (https://developers.stellar.org/docs/encyclopedia/fees-surge-pricing-fee-strategies#network-fees-on-stellar)
* to be used
* @property horizonClient optional HTTP client configuration to be used for Horizon calls.
* @property submitClient optional HTTP client configuration to be used for transaction submission.
*/
data class StellarConfiguration(
val network: Network,
val horizonUrl: String,
/**
* [Default base fee]
* (https://developers.stellar.org/docs/encyclopedia/fees-surge-pricing-fee-strategies#network-fees-on-stellar)
*/
val baseFee: UInt = 100u,
val horizonClient: OkHttpClient? = null,
val submitClient: OkHttpClient? = null
) {
var server: Server =
if (horizonClient != null) {
requireNotNull(submitClient) {
"Horizon and submit client must be both initialized or set to null"
}
Server(horizonUrl, horizonClient, submitClient)
} else {
Server(horizonUrl)
}
// Only used for tests
internal set
companion object {
val Testnet = StellarConfiguration(Network.TESTNET, "https://horizon-testnet.stellar.org")
}
}
internal data class Config(val stellar: StellarConfiguration, val app: ApplicationConfiguration)
/**
* Application configuration
*
* @constructor Create empty Application configuration
* @property defaultSigner default signer implementation to be used across application
* @property base64Decoder Base64 decoder. Default [java.util.Base64] decoder works with Android API
* 23+. To support Android API older than API 23, custom base64Decoder needs to be provided. For
* example, `android.util.Base64`.
* @property useHttp when enabled, switch from https to http scheme. Only allowed when network is
* not [Network.PUBLIC] for security reasons
* @property defaultClientConfig configuration for default client used across the app.
*/
data class ApplicationConfiguration(
val defaultSigner: WalletSigner = WalletSigner.DefaultSigner(),
val base64Decoder: Base64Decoder = defaultBase64Decoder,
val defaultClientConfig: ClientConfigFn = {}
) {
@Suppress("MaxLineLength")
@Deprecated(
"Can be configured using defaultClientConfig",
replaceWith =
ReplaceWith(
"ApplicationConfiguration(defaultSigner, base64Decoder) { defaultRequest { url { protocol = URLProtocol.HTTP } } }",
"io.ktor.client.plugins.defaultRequest",
"io.ktor.http.URLProtocol"
)
)
constructor(
defaultSigner: WalletSigner = WalletSigner.DefaultSigner(),
base64Decoder: Base64Decoder = defaultBase64Decoder,
useHttp: Boolean
) : this(
defaultSigner,
base64Decoder,
{
if (useHttp) {
defaultRequest { url { protocol = URLProtocol.HTTP } }
}
}
)
val defaultClient =
HttpClient(OkHttp) {
install(ContentNegotiation) { json(defaultJson) }
defaultRequest { url { protocol = URLProtocol.HTTPS } }
defaultClientConfig()
}
}
typealias Base64Decoder = ((String) -> ByteArray)
internal typealias ClientConfig = HttpClientConfig<OkHttpConfig>
internal typealias ClientConfigFn = (ClientConfig.() -> Unit)
internal val defaultBase64Decoder: Base64Decoder = { Base64.getDecoder().decode(it) }