diff --git a/docs/building-apps/wallet/component/kt/configClient.mdx b/docs/building-apps/wallet/component/kt/configClient.mdx new file mode 100644 index 000000000..c344030ac --- /dev/null +++ b/docs/building-apps/wallet/component/kt/configClient.mdx @@ -0,0 +1,56 @@ +import { CodeExample } from "@site/src/components/CodeExample"; + +### Configuring the Client + +The Kotlin wallet SDK uses the [ktor client](https://ktor.io/docs/getting-started-ktor-client.html) for all network requests (excluding Horizon, where the Stellar SDK's HTTP client is used). Currently, the okhttp engine is configured to be used with the client. You can read more about how to configure the ktor client [here](https://ktor.io/docs/create-client.html#configure-client). + +For example, the client can be globally configured: + + + +```kotlin +val walletCustomClient = + Wallet( + StellarConfiguration.Testnet, + ApplicationConfiguration( + defaultClientConfig = { + engine { this.config { this.connectTimeout(Duration.ofSeconds(10)) } } + install(HttpRequestRetry) { + retryOnServerErrors(maxRetries = 5) + exponentialDelay() + } + } + ) + ) +``` + + + +This Kotlin code will set the connect timeout to ten seconds via the [okhttp configuration](https://ktor.io/docs/http-client-engines.html#okhttp) and also installs the [retry plugin](https://ktor.io/docs/client-retry.html). You can also specify client configuration for specific wallet SDK classes. + +For example, to change connect timeout when connecting to some anchor server: + + + +```kotlin +val anchorCustomClient = + walletCustomClient.anchor("example.com") { + engine { this.config { this.connectTimeout(Duration.ofSeconds(30)) } } + } +``` + + + +### Closing Resources + +After the wallet class is no longer used, it's necessary to close all clients used by it. While in some applications it may not be required (e.g. the wallet lives for the whole lifetime of the application), in other cases it can be required. If your wallet class is short-lived, it's recommended to close client resources using a close function: + + + +```kotlin +fun closeWallet() { + wallet.close() +} +``` + + diff --git a/docs/building-apps/wallet/component/kt/httpConfig.mdx b/docs/building-apps/wallet/component/kt/httpConfig.mdx new file mode 100644 index 000000000..d49f9028d --- /dev/null +++ b/docs/building-apps/wallet/component/kt/httpConfig.mdx @@ -0,0 +1,14 @@ +import { CodeExample } from "@site/src/components/CodeExample"; + +There is one more available configuration for a wallet that allows it to configure internal logic of the SDK. For example, to test with local servers on an HTTP protocol, HTTP can be manually enabled. + + + +```kotlin +val walletCustom = Wallet( + StellarConfiguration.Testnet, + ApplicationConfiguration { defaultRequest { url { protocol = URLProtocol.HTTP } } } +) +``` + + diff --git a/docs/building-apps/wallet/component/kt/watcher.mdx b/docs/building-apps/wallet/component/kt/watcher.mdx new file mode 100644 index 000000000..29a5bca35 --- /dev/null +++ b/docs/building-apps/wallet/component/kt/watcher.mdx @@ -0,0 +1,31 @@ +import { CodeExample } from "@site/src/components/CodeExample"; + +Next, let's get the channel provided by `WatcherResult` to receive events. + + + +```kt +do { + val event = result.channel.receive() + when (event) { + is StatusChange -> + println("Status changed to ${event.status}. Transaction: ${event.transaction}") + is ExceptionHandlerExit -> println("Exception handler exited the job") + is ChannelClosed -> println("Channel closed. Job is done") + } +} while (event !is ChannelClosed) +``` + + + +This code example will consume all events coming from the channel until it's closed. There are three types of events: + +- `StatusChange`: indicates that transaction status has changed. +- `ExceptionHandlerExit`: indicates that the exception handler exited the processing loop. With default retry handler it happens when retries are exhausted. +- `ChannelClosed`: indicates that the channel is closed and no more events will be emitted. This event will always fire. If `ExceptionHandlerExit` happened, channel will close right after. Otherwise, (under normal circumstances) it will stop when all transactions reach terminal statuses. + +:::info + +Events are stored in the channel until they are received, and calling the `receive()` method will block the channel until a message is received. You can read more about how channels work in the [channel documentation](https://kotlinlang.org/docs/coroutines-and-channels.html#channels). + +::: diff --git a/docs/building-apps/wallet/component/ts/configClient.mdx b/docs/building-apps/wallet/component/ts/configClient.mdx new file mode 100644 index 000000000..d1c980d19 --- /dev/null +++ b/docs/building-apps/wallet/component/ts/configClient.mdx @@ -0,0 +1,24 @@ +import { CodeExample } from "@site/src/components/CodeExample"; + +### Configuring the Client + +The Typescript wallet SDK uses the [axios client](https://axios-http.com/docs/intro) for all network requests. You can read more about how to configure the axios client [here](https://axios-http.com/docs/instance). + +For example, we can configure our axios client to be globally configured with a timeout: + + + +```typescript +const customClient: AxiosInstance = axios.create({ + timeout: 1000, +}); +let appConfig = new ApplicationConfiguration(DefaultSigner, customClient); +let wal = new Wallet({ + stellarConfiguration: StellarConfiguration.TestNet(), + applicationConfiguration: appConfig, +}); +``` + + + +You can find more [configure options here.](https://axios-http.com/docs/req_config) diff --git a/docs/building-apps/wallet/intro.mdx b/docs/building-apps/wallet/intro.mdx index 4c3680973..9c07c7334 100644 --- a/docs/building-apps/wallet/intro.mdx +++ b/docs/building-apps/wallet/intro.mdx @@ -8,8 +8,11 @@ import { WalletCodeExample as CodeExample } from "@site/src/components/WalletCod import Header from "./component/header.mdx"; import KtInstall from "./component/kt/install.mdx"; import TsInstall from "./component/ts/install.mdx"; +import KtHttpConfig from "./component/kt/httpConfig.mdx"; +import KtConfigClient from "./component/kt/configClient.mdx"; +import TsConfigClient from "./component/ts/configClient.mdx"; -
+
## Installation @@ -53,99 +56,9 @@ let wallet = new Wallet({ -There is one more available configuration for a wallet that allows it to configure internal logic of the SDK. For example, to test with local servers on an HTTP protocol, HTTP can be manually enabled. +} /> - - -```kotlin -val walletCustom = Wallet( - StellarConfiguration.Testnet, - ApplicationConfiguration { defaultRequest { url { protocol = URLProtocol.HTTP } } } -) -``` - - - -### Configuring the Client - -The Kotlin wallet SDK uses the [ktor client](https://ktor.io/docs/getting-started-ktor-client.html) for all network requests (excluding Horizon, where the Stellar SDK's HTTP client is used). Currently, the okhttp engine is configured to be used with the client. You can read more about how to configure the ktor client [here](https://ktor.io/docs/create-client.html#configure-client). - -The Typescript wallet SDK uses the [axios client](https://axios-http.com/docs/intro) for all network requests. You can read more about how to configure the axios client [here](https://axios-http.com/docs/instance). - -For example, the client can be globally configured: - - - -```kotlin -val walletCustomClient = - Wallet( - StellarConfiguration.Testnet, - ApplicationConfiguration( - defaultClientConfig = { - engine { this.config { this.connectTimeout(Duration.ofSeconds(10)) } } - install(HttpRequestRetry) { - retryOnServerErrors(maxRetries = 5) - exponentialDelay() - } - } - ) - ) -``` - -```typescript -const customClient: AxiosInstance = axios.create({ - timeout: 1000, -}); -let appConfig = new ApplicationConfiguration(DefaultSigner, customClient); -let wal = new Wallet({ - stellarConfiguration: StellarConfiguration.TestNet(), - applicationConfiguration: appConfig, -}); -``` - - - -This Kotlin code will set the connect timeout to ten seconds via the [okhttp configuration](https://ktor.io/docs/http-client-engines.html#okhttp) and also installs the [retry plugin](https://ktor.io/docs/client-retry.html). You can also specify client configuration for specific wallet SDK classes. - -In Typescript, we can use axios to [configure](https://axios-http.com/docs/req_config) the timeout in milliseconds. - -For example, to change connect timeout when connecting to some anchor server: - - - -```kotlin -val anchorCustomClient = - walletCustomClient.anchor("example.com") { - engine { this.config { this.connectTimeout(Duration.ofSeconds(30)) } } - } -``` - -```typescript -const customClient: AxiosInstance = axios.create({ - timeout: 10000, -}); -let appConfig = new ApplicationConfiguration(DefaultSigner, customClient); -let wal = new Wallet({ - stellarConfiguration: StellarConfiguration.TestNet(), - applicationConfiguration: appConfig, -}); -``` - - - -### Closing Resources - -After the wallet class is no longer used, it's necessary to close all clients used by it. While in some applications it may not be required (e.g. the wallet lives for the whole lifetime of the application), in other cases it can be required. If your wallet class is short-lived, it's recommended to close client resources using a close function: - - - -```kotlin -fun closeWallet() { - wallet.close() -} -``` - - +} ts={} /> ## Stellar Basics @@ -159,6 +72,10 @@ To interact with the Horizon instance configured in the previous steps, simply d val stellar = wallet.stellar() ``` +```typescript +const stellar = wallet.stellar(); +``` + This example will create a Stellar class that manages the connection to Horizon service. @@ -198,7 +115,7 @@ suspend fun anchorToml(): TomlInfo { ``` ```typescript -let resp = await anchor.getInfo(); +let resp = await anchor.sep1(); ``` diff --git a/docs/building-apps/wallet/sep10.mdx b/docs/building-apps/wallet/sep10.mdx index 74bc63b7a..e6685bdda 100644 --- a/docs/building-apps/wallet/sep10.mdx +++ b/docs/building-apps/wallet/sep10.mdx @@ -61,7 +61,7 @@ suspend fun getAuthToken(): AuthToken { let authKey = Keypair.fromSecret("my secret key"); const getAuthToken = async (): Promise => { - return anchor.auth().authenticate({ authKey }); + return anchor.sep10().authenticate({ authKey }); }; ``` @@ -122,7 +122,7 @@ const demoWalletSigner: WalletSigner = { }; const getAuthToken = async () => { - return anchor.auth().authenticate({ + return anchor.sep10().authenticate({ accountKp, walletSigner: demoWalletSigner, clientDomain: "https://demo-wallet-server.stellar.org/sign", diff --git a/docs/building-apps/wallet/sep24.mdx b/docs/building-apps/wallet/sep24.mdx index a0c9c2859..6a0f5626a 100644 --- a/docs/building-apps/wallet/sep24.mdx +++ b/docs/building-apps/wallet/sep24.mdx @@ -3,6 +3,9 @@ title: Hosted Deposit and Withdrawal sidebar_position: 50 --- +import { LanguageSpecific } from "@site/src/components/LanguageSpecific"; +import KtWatcher from "./component/kt/watcher.mdx"; + import { WalletCodeExample as CodeExample } from "@site/src/components/WalletCodeExample"; import Header from "./component/header.mdx"; @@ -23,7 +26,7 @@ val sep24 = anchor.sep24() ``` ```typescript -let sep24 = await anchor.interactive(); +let sep24 = await anchor.sep24(); ``` @@ -40,7 +43,7 @@ suspend fun getAnchorServices(): AnchorServiceInfo { ```typescript const getAnchorServices = async (): Promise => { - anchor.getServicesInfo(); + return await anchor.getServicesInfo(); }; ``` @@ -81,8 +84,7 @@ val deposit = sep24.deposit(asset, token) ``` ```typescript -let deposit = await anchor.interactive().deposit({ - accountAddress: accountKp.publicKey(), +let deposit = await anchor.sep24().deposit({ assetCode, authToken, }); @@ -119,8 +121,7 @@ val id = withdrawal.id ``` ```typescript -let withdrawal = await anchor.interactive().withdraw({ - accountAddress: accountKp.publicKey(), +let withdrawal = await anchor.sep24().withdraw({ assetCode, authToken, }); @@ -155,8 +156,7 @@ val deposit = sep24.deposit(asset, token, sep9) ``` ```typescript -let deposit = await anchor.interactive().deposit({ - accountAddress: accountKp.publicKey(), +let deposit = await anchor.sep24().deposit({ assetCode, authToken, extraFields: { email_address: "mail@example.com" }, @@ -182,14 +182,15 @@ suspend fun depositDifferentAccount(): InteractiveFlowResponse { ``` ```typescript +import { Memo, MemoText } from "stellar-sdk"; + const recipientAccount = "G..."; -// TODO: Add `memo` param when the SDK supports it const depositDifferentAccount = async (): Promise => { - return anchor.interactive().deposit({ - accountAddress: accountKp.publicKey(), + return anchor.sep24().deposit({ + destinationAccount: recipientAccount, + destinationMemo: new Memo(MemoText, "some memo"), assetCode, authToken, - fundsAccountAddress: recipientAccount, }); }; ``` @@ -207,11 +208,10 @@ val withdrawal = sep24.withdraw(asset, token, withdrawalAccount = originAccount) ```typescript const originAccount = "G..."; -const withdrawal = await anchor.interactive().withdraw({ - accountAddress: accountKp.publicKey(), +const withdrawal = await anchor.sep24().withdraw({ + withdrawalAccount: originAccount, assetCode, authToken, - fundsAccountAddress: recipientAccount, }); ``` @@ -235,9 +235,9 @@ val result = watcher.watchOneTransaction(token, "transaction id") ``` ```typescript -let watcher = anchor.watcher(); +let watcher = anchor.sep24().watcher(); -let result = watcher.watchOneTransaction({ +let { stop, refresh } = watcher.watchOneTransaction({ authToken, assetCode, id: successfulTransaction.id, @@ -260,35 +260,7 @@ val result = watcher.watchAsset(getAuthToken(), asset) -Next, let's get the channel provided by `WatcherResult` to receive events. - - - -```kt -do { - val event = result.channel.receive() - when (event) { - is StatusChange -> - println("Status changed to ${event.status}. Transaction: ${event.transaction}") - is ExceptionHandlerExit -> println("Exception handler exited the job") - is ChannelClosed -> println("Channel closed. Job is done") - } -} while (event !is ChannelClosed) -``` - - - -This code example will consume all events coming from the channel until it's closed. There are three types of events: - -- `StatusChange`: indicates that transaction status has changed. -- `ExceptionHandlerExit`: indicates that the exception handler exited the processing loop. With default retry handler it happens when retries are exhausted. -- `ChannelClosed`: indicates that the channel is closed and no more events will be emitted. This event will always fire. If `ExceptionHandlerExit` happened, channel will close right after. Otherwise, (under normal circumstances) it will stop when all transactions reach terminal statuses. - -:::info - -Events are stored in the channel until they are received, and calling the `receive()` method will block the channel until a message is received. You can read more about how channels work in the [channel documentation](https://kotlinlang.org/docs/coroutines-and-channels.html#channels). - -::: +} /> ### Fetching Transaction @@ -301,7 +273,7 @@ val transaction = sep24.getTransactionBy(token, id = "transaction id") ``` ```typescript -const transaction = await anchor.getTransactionBy({ +const transaction = await anchor.sep24().getTransactionBy({ authToken, id: transactionId, }); @@ -318,7 +290,7 @@ val transactions = sep24.getTransactionsForAsset(asset, token) ``` ```typescript -const transactions = await anchor.getTransactionsForAsset({ +const transactions = await anchor.sep24().getTransactionsForAsset({ authToken, assetCode, }); @@ -338,6 +310,13 @@ First, start the withdrawal: val withdrawal = sep24.withdraw(asset, authToken = token) ``` +```typescript +let withdrawal = await anchor.sep24().withdraw({ + assetCode, + authToken, +}); +``` + Next, open an interactive url : @@ -349,6 +328,11 @@ val url = withdrawal.url // open the url ``` +```typescript +let url = withdrawal.url; +// open the url +``` + After that we need to wait until the anchor is ready to receive funds. To do so, we will be waiting until transaction reaches `pending_user_transfer_start` status @@ -368,6 +352,25 @@ do { ) ``` +```typescript +let watcher = anchor.sep24().watcher(); + +let onMessage = (m) => { + if (m.status === "pending_user_transfer_start") { + // begin transfer code + } +}; + +let { refresh, stop } = watcher.watchOneTransaction({ + authToken, + assetCode, + id: successfulTransaction.id, + onMessage, + onSuccess, + onError, +}); +``` + Next, sign and submit the Stellar transfer: diff --git a/docs/building-apps/wallet/stellar.mdx b/docs/building-apps/wallet/stellar.mdx index 06dc74977..2185d4c8d 100644 --- a/docs/building-apps/wallet/stellar.mdx +++ b/docs/building-apps/wallet/stellar.mdx @@ -60,6 +60,16 @@ suspend fun createAccount(): Transaction { } ``` +```typescript +const transaction = await stellar + .transaction({ + sourceAddress: sourceAccountKeyPair, + baseFee: 100, + }) + .createAccount(destinationAccountKeyPair) + .build(); +``` + #### Modify Account @@ -448,6 +458,11 @@ suspend fun signAndSubmit() { } ``` +```typescript +const signedTxn = transaction.sign(sourceAccountKeyPair); +await wallet.stellar().submitTransaction(signedTxn); +``` + However, the method above doesn't handle fee surge pricing in the network gracefully. If the required fee for a transaction to be included in the ledger becomes too high and transaction expires before making it into the ledger, this method will throw an exception. @@ -478,6 +493,10 @@ It's very simple to use the Horizon SDK connecting to the same Horizon instance val server = wallet.stellar().server ``` +```typescript +const server = wallet.stellar().server; +``` + And you can work with Horizon Server instance: @@ -488,4 +507,11 @@ And you can work with Horizon Server instance: val stellarTransaction = server.transactions().transaction("transaction_id") ``` +```typescript +const stellarTransaction = server + .transactions() + .forAccount("account_id") + .call(); +``` + diff --git a/src/components/LanguageButtons.tsx b/src/components/LanguageButtons.tsx index 8be2c5c1b..61ea2609f 100644 --- a/src/components/LanguageButtons.tsx +++ b/src/components/LanguageButtons.tsx @@ -15,9 +15,9 @@ export const LanguageButtons = () => { {() =>
- setCookie("ts")} style={{maxHeight: "1.2rem"}}/> - setCookie("kt")} style={{maxHeight: "1.1rem"}}/> - setCookie("dart")} style={{maxHeight: "1.2rem"}}/> + setCookie("ts")} style={{maxHeight: "1.2rem", cursor: "pointer"}}/> + setCookie("kt")} style={{maxHeight: "1.1rem", cursor: "pointer"}}/> + setCookie("dart")} style={{maxHeight: "1.2rem", cursor: "pointer"}}/>
}