diff --git a/settings.gradle.kts b/settings.gradle.kts index 928282f..b87e2d9 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -53,5 +53,6 @@ dependencyResolutionManagement { rootProject.name = "kotlin-sdk" include(":app") +include(":trails-actions") include(":oms-client-kotlin-sdk") include(":oms-client-kotlin-sdk-waas-generated") diff --git a/trails-actions/build.gradle.kts b/trails-actions/build.gradle.kts new file mode 100644 index 0000000..881d136 --- /dev/null +++ b/trails-actions/build.gradle.kts @@ -0,0 +1,58 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.ktlint) + id("org.jetbrains.kotlin.plugin.serialization") version "2.4.0" +} + +ktlint { + version.set(libs.versions.ktlint.get()) + android.set(true) + outputToConsole.set(true) + filter { + exclude("**/build/**") + exclude("**/generated/**") + } +} + +android { + namespace = "com.omsclient.kotlin_sdk_trails_actions" + compileSdk = 35 + + defaultConfig { + applicationId = "com.omsclient.kotlin_sdk_trails_actions" + minSdk = 26 + targetSdk = 35 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro", + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } +} + +dependencies { + implementation(project(":oms-client-kotlin-sdk")) + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.appcompat) + implementation(libs.androidx.browser) + implementation(libs.material) + implementation(libs.okhttp) + implementation(libs.kotlinx.coroutines.android) + implementation(libs.kotlinx.serialization.json) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) +} diff --git a/trails-actions/proguard-rules.pro b/trails-actions/proguard-rules.pro new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/trails-actions/proguard-rules.pro @@ -0,0 +1 @@ + diff --git a/trails-actions/src/main/AndroidManifest.xml b/trails-actions/src/main/AndroidManifest.xml new file mode 100644 index 0000000..795f252 --- /dev/null +++ b/trails-actions/src/main/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/trails-actions/src/main/java/com/omsclient/kotlin_sdk_trails_actions/TrailsActionsActivity.kt b/trails-actions/src/main/java/com/omsclient/kotlin_sdk_trails_actions/TrailsActionsActivity.kt new file mode 100644 index 0000000..e333b3d --- /dev/null +++ b/trails-actions/src/main/java/com/omsclient/kotlin_sdk_trails_actions/TrailsActionsActivity.kt @@ -0,0 +1,2165 @@ +package com.omsclient.kotlin_sdk_trails_actions + +import android.content.ClipData +import android.content.ClipboardManager +import android.content.Context +import android.content.Intent +import android.content.res.ColorStateList +import android.net.Uri +import android.os.Bundle +import android.text.InputType +import android.util.Log +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import android.widget.ScrollView +import android.widget.Space +import android.widget.TextView +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.browser.customtabs.CustomTabColorSchemeParams +import androidx.browser.customtabs.CustomTabsIntent +import androidx.core.content.ContextCompat +import com.google.android.material.button.MaterialButton +import com.google.android.material.card.MaterialCardView +import com.google.android.material.checkbox.MaterialCheckBox +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.android.material.textfield.TextInputEditText +import com.google.android.material.textfield.TextInputLayout +import com.omsclient.kotlin_sdk.Network +import com.omsclient.kotlin_sdk.OMSClient +import com.omsclient.kotlin_sdk.OMSClientSessionExpiredEvent +import com.omsclient.kotlin_sdk.models.FeeOptionSelection +import com.omsclient.kotlin_sdk.models.FeeOptionWithBalance +import com.omsclient.kotlin_sdk.models.SendTransactionRequest +import com.omsclient.kotlin_sdk.models.SendTransactionResponse +import com.omsclient.kotlin_sdk.models.TransactionStatus +import com.omsclient.kotlin_sdk.models.Wallet +import com.omsclient.kotlin_sdk.network.OMSClientEnvironment +import com.omsclient.kotlin_sdk.utils.formatUnits +import com.omsclient.kotlin_sdk.utils.parseUnits +import com.omsclient.kotlin_sdk.wallet.CompleteAuthResult +import com.omsclient.kotlin_sdk.wallet.OidcProviders +import com.omsclient.kotlin_sdk.wallet.OidcRedirectAuthResult +import com.omsclient.kotlin_sdk.wallet.PendingWalletSelection +import com.omsclient.kotlin_sdk.wallet.WalletClient +import com.omsclient.kotlin_sdk.wallet.WalletSelectionBehavior +import com.omsclient.kotlin_sdk_trails_actions.generated.CommitIntentRequest +import com.omsclient.kotlin_sdk_trails_actions.generated.CreateYieldActionRequest +import com.omsclient.kotlin_sdk_trails_actions.generated.ExecuteIntentRequest +import com.omsclient.kotlin_sdk_trails_actions.generated.FundMethod +import com.omsclient.kotlin_sdk_trails_actions.generated.GetYieldAggregateBalancesRequest +import com.omsclient.kotlin_sdk_trails_actions.generated.GetYieldMarketsRequest +import com.omsclient.kotlin_sdk_trails_actions.generated.IntentMode +import com.omsclient.kotlin_sdk_trails_actions.generated.IntentStatus +import com.omsclient.kotlin_sdk_trails_actions.generated.OkHttpWebRpcTransport +import com.omsclient.kotlin_sdk_trails_actions.generated.QuoteIntentRequest +import com.omsclient.kotlin_sdk_trails_actions.generated.QuoteIntentRequestOptions +import com.omsclient.kotlin_sdk_trails_actions.generated.RouteProvider +import com.omsclient.kotlin_sdk_trails_actions.generated.TradeType +import com.omsclient.kotlin_sdk_trails_actions.generated.TrailsApiTrailsClient +import com.omsclient.kotlin_sdk_trails_actions.generated.WaitIntentReceiptRequest +import com.omsclient.kotlin_sdk_trails_actions.generated.WebRpcError +import com.omsclient.kotlin_sdk_trails_actions.generated.WebRpcTransportException +import com.omsclient.kotlin_sdk_trails_actions.generated.YieldActionArguments +import com.omsclient.kotlin_sdk_trails_actions.generated.YieldBalance +import com.omsclient.kotlin_sdk_trails_actions.generated.YieldBalanceQuery +import com.omsclient.kotlin_sdk_trails_actions.generated.YieldBalances +import com.omsclient.kotlin_sdk_trails_actions.generated.YieldMarket +import com.omsclient.kotlin_sdk_trails_actions.generated.YieldRewardRate +import com.omsclient.kotlin_sdk_trails_actions.generated.YieldTransaction +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.cancel +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.contentOrNull +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive +import java.math.BigInteger +import java.text.NumberFormat +import java.util.Locale +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException + +class TrailsActionsActivity : AppCompatActivity() { + private val uiScope = MainScope() + private val authPreferences by lazy { + getSharedPreferences(TRAILS_ACTIONS_PREFERENCES_NAME, Context.MODE_PRIVATE) + } + private val sdk by lazy { + OMSClient( + context = this, + publishableKey = DemoConfig.demoPublishableKey, + projectId = DemoConfig.demoProjectId, + environment = OMSClientEnvironment.demoDefaults(), + ) + } + private val trailsClient = + TrailsApiTrailsClient( + baseUrl = TRAILS_API_URL, + transport = OkHttpWebRpcTransport(), + headers = { + mapOf(TRAILS_ACCESS_KEY_HEADER to TRAILS_ACCESS_KEY) + }, + ) + + private lateinit var root: LinearLayout + private lateinit var authStatusView: TextView + private lateinit var sessionStateCard: View + private lateinit var sessionStateView: TextView + private lateinit var walletView: TextView + private lateinit var balancesView: TextView + private lateinit var balancesStatusView: TextView + private lateinit var positionsView: TextView + private lateinit var positionsStatusView: TextView + private lateinit var positionsContainer: LinearLayout + private lateinit var swapStatusView: TextView + private lateinit var depositStatusView: TextView + private lateinit var earnStatusView: TextView + private lateinit var lastTransactionView: TextView + private lateinit var logView: TextView + private lateinit var emailInput: TextInputEditText + private lateinit var codeInput: TextInputEditText + private lateinit var sessionLifetimeInput: TextInputEditText + private lateinit var swapAmountInput: TextInputEditText + private lateinit var depositAmountInput: TextInputEditText + private lateinit var earnAmountInput: TextInputEditText + private lateinit var manualWalletSelectionCheckbox: MaterialCheckBox + private lateinit var authCard: View + private lateinit var emailStepContainer: View + private lateinit var codeStepContainer: View + private lateinit var walletCard: View + private lateinit var balancesCard: View + private lateinit var actionsCard: View + private lateinit var positionsCard: View + private lateinit var signOutButton: MaterialButton + private lateinit var startGoogleRedirectSignInButton: MaterialButton + private lateinit var startEmailSignInButton: MaterialButton + private lateinit var confirmCodeButton: MaterialButton + private lateinit var cancelCodeStepButton: MaterialButton + private lateinit var prepareSwapButton: MaterialButton + private lateinit var sendSwapButton: MaterialButton + private lateinit var prepareDepositButton: MaterialButton + private lateinit var sendDepositButton: MaterialButton + private lateinit var prepareEarnButton: MaterialButton + private lateinit var sendEarnButton: MaterialButton + private lateinit var openExplorerButton: MaterialButton + + private var balances = BalanceState.signedOut + private var earnPositions: List = emptyList() + private val withdrawStatusesByPosition = mutableMapOf() + private val lastWithdrawTransactionHashes = mutableMapOf() + private var preparedSwap: PreparedSwapTransaction? = null + private var preparedDeposit: PreparedYieldTransactions? = null + private var preparedEarn: PreparedSwapAndDepositPlan? = null + private var selectedFeeOption: FeeOptionWithBalance? = null + private var lastTransactionHash: String? = null + private var expiredSessionEvent: OMSClientSessionExpiredEvent? = null + private var unsubscribeSessionExpired: (() -> Unit)? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + buildUi() + bindActions() + restoreAuthPreferences() + subscribeSessionExpiry() + renderSessionState() + if (sdk.session.walletAddress != null) { + refreshSignedInData() + } + handleOidcRedirectCallback(intent) + } + + override fun onNewIntent(intent: Intent) { + super.onNewIntent(intent) + setIntent(intent) + handleOidcRedirectCallback(intent) + } + + override fun onDestroy() { + unsubscribeSessionExpired?.invoke() + unsubscribeSessionExpired = null + uiScope.cancel() + super.onDestroy() + } + + private fun buildUi() { + val scrollView = + ScrollView(this).apply { + setBackgroundColor(color(R.color.surface_900)) + isFillViewport = true + } + root = + LinearLayout(this).apply { + orientation = LinearLayout.VERTICAL + setPadding(dp(20), dp(20), dp(20), dp(28)) + } + scrollView.addView(root, matchWrap()) + setContentView(scrollView) + + val header = + horizontal { + addView( + text("Trails Actions Demo", 30f, R.color.slate_900, true), + LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f), + ) + signOutButton = button("Logout", outline = true) + addView(signOutButton, LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)) + } + root.addView(header, matchWrap()) + + sessionStateCard = + card { + addView(authDemoSectionTitle("OMSClientSessionState")) + sessionStateView = monospaceBody("") + addView(sessionStateView, matchWrap(topMargin = 10)) + } + root.addView(sessionStateCard, matchWrap(topMargin = 18)) + + authCard = + card { + addView(sectionTitle("Sign-In")) + authStatusView = body("Enter an email to start.") + addView(authStatusView, matchWrap(topMargin = 8)) + manualWalletSelectionCheckbox = + MaterialCheckBox(this@TrailsActionsActivity).apply { + text = "Use manual wallet selection" + setTextColor(color(R.color.slate_900)) + textSize = 14f + } + addView(manualWalletSelectionCheckbox, matchWrap(topMargin = 12)) + addView(fieldLabel("Session lifetime"), matchWrap(topMargin = 14)) + addView(smallBody("Shorten this to test session expiry easier."), matchWrap(topMargin = 2)) + sessionLifetimeInput = input("", InputType.TYPE_CLASS_NUMBER) + addView(wrapInput(sessionLifetimeInput, suffixText = "seconds"), matchWrap(topMargin = 8)) + emailStepContainer = + vertical { + startGoogleRedirectSignInButton = button("Continue with Google") + addView(startGoogleRedirectSignInButton, matchWrap(topMargin = 16)) + addView(centerBody("or continue with email"), matchWrap(topMargin = 14)) + emailInput = input("Email", InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS) + addView(wrapInput(emailInput), matchWrap(topMargin = 16)) + startEmailSignInButton = button("Send Login Code") + addView(startEmailSignInButton, matchWrap(topMargin = 14)) + } + addView(emailStepContainer) + codeStepContainer = + vertical { + addView(codeStepTitle("Verification Code")) + codeInput = input("Enter code", InputType.TYPE_CLASS_NUMBER) + addView(wrapInput(codeInput), matchWrap(topMargin = 10)) + addView( + horizontal { + cancelCodeStepButton = button("Cancel", outline = true) + addView(cancelCodeStepButton, weightedButton()) + addView(space(width = 12)) + confirmCodeButton = button("Verify Code") + addView(confirmCodeButton, weightedButton()) + }, + matchWrap(topMargin = 12), + ) + } + addView(codeStepContainer, matchWrap(topMargin = 18)) + } + root.addView(authCard, matchWrap(topMargin = 18)) + + walletCard = + card { + addView(sectionTitle("Wallet")) + walletView = body("No wallet selected.") + addView(walletView) + addView( + horizontal { + addView( + button("Copy").also { button -> + button.setOnClickListener { copyWalletAddress() } + }, + weightedButton(), + ) + addView(space(width = 10)) + addView( + button("Refresh", outline = true).also { button -> + button.setOnClickListener { refreshSignedInData() } + }, + weightedButton(), + ) + }, + matchWrap(topMargin = 12), + ) + } + root.addView(walletCard, matchWrap(topMargin = 18)) + + balancesCard = + card { + addView(sectionTitle("Polygon balances")) + balancesView = body(BalanceState.signedOut.display) + addView(balancesView, matchWrap(topMargin = 12)) + balancesStatusView = body(BalanceState.signedOut.status) + addView(balancesStatusView, matchWrap(topMargin = 8)) + } + root.addView(balancesCard, matchWrap(topMargin = 18)) + + actionsCard = + card { + addView(sectionTitle("Polygon Trails Actions")) + addView(actionDivider("Swap POL to USDC"), matchWrap(topMargin = 14)) + swapAmountInput = input("POL amount", InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL) + swapAmountInput.setText(DEFAULT_SWAP_POL_AMOUNT) + addView(wrapInput(swapAmountInput), matchWrap(topMargin = 12)) + addView( + horizontal { + prepareSwapButton = button("Prepare Swap") + addView(prepareSwapButton, weightedButton()) + addView(space(width = 10)) + sendSwapButton = button("Send Swap", outline = true) + addView(sendSwapButton, weightedButton()) + }, + matchWrap(topMargin = 12), + ) + swapStatusView = body("Swap status: waiting to prepare.") + addView(swapStatusView, matchWrap(topMargin = 8)) + + addView(actionDivider("Deposit USDC using Earn"), matchWrap(topMargin = 18)) + depositAmountInput = input("USDC amount", InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL) + depositAmountInput.setText(DEFAULT_DEPOSIT_USDC_AMOUNT) + addView(wrapInput(depositAmountInput), matchWrap(topMargin = 12)) + addView( + horizontal { + prepareDepositButton = button("Prepare Deposit") + addView(prepareDepositButton, weightedButton()) + addView(space(width = 10)) + sendDepositButton = button("Send Deposit", outline = true) + addView(sendDepositButton, weightedButton()) + }, + matchWrap(topMargin = 12), + ) + depositStatusView = body("Deposit status: waiting to prepare.") + addView(depositStatusView, matchWrap(topMargin = 8)) + + addView(actionDivider("Swap POL to USDC, then deposit"), matchWrap(topMargin = 18)) + earnAmountInput = input("POL amount", InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL) + earnAmountInput.setText(DEFAULT_EARN_POL_AMOUNT) + addView(wrapInput(earnAmountInput), matchWrap(topMargin = 12)) + addView( + horizontal { + prepareEarnButton = button("Prepare Swap + Deposit") + addView(prepareEarnButton, weightedButton()) + addView(space(width = 10)) + sendEarnButton = button("Send Swap + Deposit", outline = true) + addView(sendEarnButton, weightedButton()) + }, + matchWrap(topMargin = 12), + ) + earnStatusView = body("Swap and Deposit status: waiting to prepare.") + addView(earnStatusView, matchWrap(topMargin = 8)) + + lastTransactionView = body("Last transaction: none") + addView(lastTransactionView, matchWrap(topMargin = 18)) + openExplorerButton = button("Open Last Transaction", outline = true) + addView(openExplorerButton, matchWrap(topMargin = 10)) + } + root.addView(actionsCard, matchWrap(topMargin = 18)) + + positionsCard = + card { + addView(sectionTitle("Earn positions")) + positionsView = body("Sign in to load earn positions.") + addView(positionsView, matchWrap(topMargin = 8)) + positionsContainer = vertical {} + addView(positionsContainer, matchWrap(topMargin = 12)) + positionsStatusView = body("") + addView(positionsStatusView, matchWrap(topMargin = 8)) + } + root.addView(positionsCard, matchWrap(topMargin = 18)) + + root.addView( + card { + addView(sectionTitle("Log")) + logView = + body("Ready.").apply { + typeface = android.graphics.Typeface.MONOSPACE + textSize = 12f + } + addView(logView) + }, + matchWrap(topMargin = 18), + ) + } + + private fun bindActions() { + startGoogleRedirectSignInButton.setOnClickListener { startGoogleRedirectSignIn() } + startEmailSignInButton.setOnClickListener { startEmailSignIn() } + confirmCodeButton.setOnClickListener { completeEmailSignIn() } + cancelCodeStepButton.setOnClickListener { + sdk.wallet.signOut() + clearExpiredSessionState() + codeInput.text?.clear() + showEmailStep() + } + signOutButton.setOnClickListener { + sdk.wallet.signOut() + clearExpiredSessionState() + clearPreparedState() + resetLoadedData() + appendLog("Logged out.") + renderSessionState() + } + prepareSwapButton.setOnClickListener { prepareSwap() } + sendSwapButton.setOnClickListener { sendSwap() } + prepareDepositButton.setOnClickListener { prepareDeposit() } + sendDepositButton.setOnClickListener { sendDeposit() } + prepareEarnButton.setOnClickListener { prepareEarn() } + sendEarnButton.setOnClickListener { sendEarn() } + openExplorerButton.setOnClickListener { + lastTransactionHash?.let(::openExplorer) + } + } + + private fun startGoogleRedirectSignIn() { + launchAction( + label = "Start Google redirect sign-in", + onStart = { showGoogleRedirectPendingStep("Opening Google redirect sign-in...") }, + onFailure = { + showEmailStep() + authStatusView.text = "Google redirect sign-in failed: ${describe(it)}" + }, + ) { + persistAuthPreferences() + clearExpiredSessionState() + val started = + sdk.wallet.startOidcRedirectAuth( + provider = + OidcProviders.google( + clientId = DemoConfig.demoGoogleWebClientId, + ), + redirectUri = DemoConfig.oidcRedirectUri, + loginHint = expiredSessionEmail(), + ) + appendLog("Google redirect auth started: state=${started.state}") + showGoogleRedirectPendingStep("Waiting for Google redirect callback...") + openInAppBrowser(started.authorizationUrl) + } + } + + private fun startEmailSignIn() { + launchAction( + label = "Start email sign-in", + onStart = { authStatusView.text = "Requesting email code..." }, + onFailure = { authStatusView.text = "Email sign-in failed: ${describe(it)}" }, + ) { + val email = requireEmailForSignIn() + persistAuthPreferences() + clearExpiredSessionState() + sdk.wallet.startEmailAuth(email) + authStatusView.text = "Code requested for $email." + showPendingCodeStep() + emailInput.text?.clear() + appendLog("Email verifier committed for $email") + } + } + + private fun completeEmailSignIn() { + launchAction( + label = "Verify email code", + onStart = { authStatusView.text = "Confirming code..." }, + onFailure = { authStatusView.text = "Code confirmation failed: ${describe(it)}" }, + ) { + val code = requireInput(codeInput, "Verification code") + codeInput.text?.clear() + val result = completeEmailAuthWithConfiguredLifetime(code) + when (result) { + is CompleteAuthResult.WalletSelected -> { + renderSignedInWallet(result.wallet, "Email login complete") + } + + is CompleteAuthResult.WalletSelection -> { + completePendingWalletSelection(result.pendingSelection, "Email login complete") + } + } + } + } + + private fun refreshSignedInData() { + launchAction( + label = "Refresh Polygon data", + onStart = { + balancesStatusView.text = "Loading Polygon balances..." + positionsContainer.removeAllViews() + positionsView.visibility = View.VISIBLE + positionsView.text = "Loading Polygon earn positions..." + positionsStatusView.text = "Loading Polygon earn positions..." + positionsStatusView.visibility = View.GONE + }, + onFailure = { + balancesStatusView.text = "Refresh failed: ${describe(it)}" + positionsContainer.removeAllViews() + positionsView.visibility = View.VISIBLE + positionsView.text = "Unable to load earn positions." + positionsStatusView.text = "Earn positions status: ${describe(it)}" + positionsStatusView.visibility = View.VISIBLE + }, + ) { + val walletAddress = requireWalletAddress() + balances = getPolygonBalances(walletAddress) + val positionsResult = getPolygonEarnPositions(walletAddress) + earnPositions = positionsResult.positions + balancesView.text = balances.display + balancesStatusView.text = balances.status + renderEarnPositions(positionsResult) + positionsResult.errors.forEach { error -> + appendLog("! Earn balance error: $error") + } + } + } + + private fun prepareSwap() { + launchAction( + label = "Prepare swap", + onStart = { swapStatusView.text = "Swap status: preparing Trails intent..." }, + onFailure = { swapStatusView.text = "Swap status: ${describe(it)}" }, + ) { + val prepared = prepareSwapPolToUsdc(requireWalletAddress(), requireInput(swapAmountInput, "POL amount")) + preparedSwap = prepared + swapStatusView.text = "Swap status: prepared for about ${prepared.outputDisplay}." + appendLog("Prepared ${prepared.title}: ${prepared.request.to}") + } + } + + private fun sendSwap() { + launchAction( + label = "Send swap", + onStart = { swapStatusView.text = "Swap status: sending..." }, + onFailure = { swapStatusView.text = "Swap status: ${describe(it)}" }, + ) { + val prepared = preparedSwap ?: throw IllegalStateException("Prepare the swap first.") + val initialBalances = balances + val latest = sendPreparedSwap(prepared) + val hash = latest.txnHash ?: latest.txnId + lastTransactionHash = hash + renderLastTransaction() + swapStatusView.text = "Swap status: sent ${shortHash(hash)}. Refreshing balances..." + waitForUsdcBalanceIncrease( + initialBalances = initialBalances, + minIncreaseRaw = prepared.outputRaw, + selectedFeeOption = prepared.executionState.selectedFeeOption, + setStatus = { swapStatusView.text = it }, + pendingStatus = "Swap status: sent ${shortHash(hash)}. Waiting for expected USDC balance", + successStatus = "Swap status: sent ${shortHash(hash)}. USDC balance updated.", + staleStatus = "Swap status: sent ${shortHash(hash)}. USDC balance has not reached the expected swap output yet.", + ) + } + } + + private fun prepareDeposit() { + launchAction( + label = "Prepare deposit", + onStart = { depositStatusView.text = "Deposit status: preparing Earn action..." }, + onFailure = { depositStatusView.text = "Deposit status: ${describe(it)}" }, + ) { + val prepared = prepareDepositUsdc(requireWalletAddress(), requireInput(depositAmountInput, "USDC amount")) + preparedDeposit = prepared + depositStatusView.text = + "Deposit status: prepared ${prepared.transactions.size} transaction${plural( + prepared.transactions.size, + )} for ${prepared.marketName}." + } + } + + private fun sendDeposit() { + launchAction( + label = "Send deposit", + onStart = { depositStatusView.text = "Deposit status: sending..." }, + onFailure = { depositStatusView.text = "Deposit status: ${describe(it)}" }, + ) { + val prepared = preparedDeposit ?: throw IllegalStateException("Prepare the deposit first.") + val response = sendYieldTransactions(prepared.transactions, "Deposit") { depositStatusView.text = it } + lastTransactionHash = response.txnHash + renderLastTransaction() + depositStatusView.text = "Deposit status: sent ${shortHash(response.txnHash ?: response.txnId)}. Refreshing..." + refreshAfterSend() + } + } + + private fun prepareEarn() { + launchAction( + label = "Prepare swap and deposit", + onStart = { earnStatusView.text = "Swap and Deposit status: preparing Trails actions..." }, + onFailure = { earnStatusView.text = "Swap and Deposit status: ${describe(it)}" }, + ) { + val walletAddress = requireWalletAddress() + val market = findPolygonUsdcEarnMarket() + val swap = prepareSwapPolToUsdc(walletAddress, requireInput(earnAmountInput, "POL amount")) + val depositAmount = formatUnits(swap.outputRaw.toBigInteger(), 6) + preparedEarn = + PreparedSwapAndDepositPlan( + swap = swap, + market = market, + depositAmount = depositAmount, + ) + earnStatusView.text = + "Swap and Deposit status: prepared swap output for ${market.metadata.name}." + appendLog("Prepared swap and deposit: ${swap.outputDisplay} into ${market.metadata.name}") + } + } + + private fun sendEarn() { + launchAction( + label = "Send swap and deposit", + onStart = { earnStatusView.text = "Swap and Deposit status: sending swap..." }, + onFailure = { earnStatusView.text = "Swap and Deposit status: ${describe(it)}" }, + ) { + val plan = preparedEarn ?: throw IllegalStateException("Prepare the swap and deposit first.") + val initialBalances = balances + val swapResponse = sendPreparedSwap(plan.swap) + val swapHash = swapResponse.txnHash ?: swapResponse.txnId + lastTransactionHash = swapHash + renderLastTransaction() + val didReceiveSwapOutput = + waitForUsdcBalanceIncrease( + initialBalances = initialBalances, + minIncreaseRaw = plan.swap.outputRaw, + selectedFeeOption = plan.swap.executionState.selectedFeeOption, + setStatus = { earnStatusView.text = it }, + pendingStatus = "Swap and Deposit status: sent ${shortHash(swapHash)}. Waiting for USDC output", + successStatus = "Swap and Deposit status: USDC output detected. Preparing deposit step...", + staleStatus = "Swap and Deposit status: USDC output has not appeared yet.", + ) + if (!didReceiveSwapOutput) { + appendLog("Skipping deposit because the swap output was not detected.") + return@launchAction + } + val deposit = + prepareDepositUsdc( + walletAddress = requireWalletAddress(), + usdcAmount = plan.depositAmount, + preferredMarket = plan.market, + ) + val depositResponse = sendYieldTransactions(deposit.transactions, "Swap and Deposit") { earnStatusView.text = it } + lastTransactionHash = depositResponse.txnHash + renderLastTransaction() + earnStatusView.text = + "Swap and Deposit status: sent ${shortHash(depositResponse.txnHash ?: depositResponse.txnId)}. Refreshing..." + refreshAfterSend() + } + } + + private fun withdrawEarnPosition(position: EarnPosition) { + launchAction( + label = "Withdraw ${position.marketName}", + onStart = { + withdrawStatusesByPosition[position.id] = "Withdraw status: preparing ${position.marketName}..." + lastWithdrawTransactionHashes.remove(position.id) + renderEarnPositions(EarnPositionsResult(earnPositions, emptyList())) + }, + onFailure = { + withdrawStatusesByPosition[position.id] = "Withdraw status: ${describe(it)}" + renderEarnPositions(EarnPositionsResult(earnPositions, emptyList())) + }, + ) { + require(position.canWithdraw) { "This earn position cannot be withdrawn." } + val prepared = prepareWithdrawEarnPosition(requireWalletAddress(), position) + val response = + sendYieldTransactions(prepared.transactions, "Withdraw") { status -> + withdrawStatusesByPosition[position.id] = status + renderEarnPositions(EarnPositionsResult(earnPositions, emptyList())) + } + val hash = response.txnHash ?: response.txnId + lastTransactionHash = hash + lastWithdrawTransactionHashes[position.id] = hash + renderLastTransaction() + withdrawStatusesByPosition[position.id] = "Withdraw status: sent ${shortHash(hash)}. Refreshing..." + renderEarnPositions(EarnPositionsResult(earnPositions, emptyList())) + refreshAfterSend() + } + } + + private suspend fun sendPreparedSwap(prepared: PreparedSwapTransaction): SendTransactionResponse { + selectedFeeOption = null + val intentId = + prepared.executionState.committedIntentId + ?: trailsClient + .commitIntent(CommitIntentRequest(prepared.intent)) + .intentId + .also { committedIntentId -> + prepared.executionState.committedIntentId = committedIntentId + } + val response = + prepared.executionState.submittedResponse + ?: sdk + .wallet + .sendTransaction( + network = Network.POLYGON, + request = prepared.request, + selectFeeOption = ::selectFeeOption, + ).also { submittedResponse -> + prepared.executionState.submittedResponse = submittedResponse + prepared.executionState.selectedFeeOption = selectedFeeOption + } + val latest = waitForTransactionHash(response) + prepared.executionState.submittedResponse = latest + val hash = latest.txnHash ?: throw IllegalStateException("Wallet transaction hash was not available.") + if (!prepared.executionState.didExecuteIntent) { + trailsClient.executeIntent(ExecuteIntentRequest(intentId = intentId, depositTransactionHash = hash)) + prepared.executionState.didExecuteIntent = true + } + waitForIntentSuccess(intentId) + return latest + } + + private suspend fun getPolygonBalances(walletAddress: String): BalanceState { + val polBalance = + sdk.indexer.getNativeTokenBalance( + network = Network.POLYGON, + walletAddress = walletAddress, + ) + val usdcBalances = + sdk.indexer.getTokenBalances( + network = Network.POLYGON, + contractAddress = POLYGON_USDC, + walletAddress = walletAddress, + includeMetadata = false, + ) + val polRaw = polBalance?.balance ?: "0" + val usdcRaw = usdcBalances.balances.firstOrNull()?.balance ?: "0" + return BalanceState( + pol = formatTokenAmount(polRaw, 18, "POL"), + usdc = formatTokenAmount(usdcRaw, 6, "USDC"), + polRaw = polRaw, + usdcRaw = usdcRaw, + status = "Balances updated.", + ) + } + + private suspend fun getPolygonEarnPositions(walletAddress: String): EarnPositionsResult { + val markets = + trailsClient + .yieldGetMarkets( + GetYieldMarketsRequest( + chainId = POLYGON_CHAIN_ID.toString(), + limit = 100u, + ), + ).items + val marketById = markets.associateBy { it.id } + val balancesResult = + trailsClient + .yieldGetAggregateBalances( + GetYieldAggregateBalancesRequest( + queries = + listOf( + YieldBalanceQuery( + address = walletAddress, + network = "polygon", + ), + ), + ), + ) + return EarnPositionsResult( + positions = + balancesResult + .items + .mapNotNull { balances -> balances.toEarnPosition(marketById[balances.yieldId]) } + .sortedByDescending { it.sortValue }, + errors = balancesResult.errors.map { error -> "${error.yieldId}: ${error.error}" }, + ) + } + + private suspend fun prepareSwapPolToUsdc( + walletAddress: String, + polAmount: String, + ): PreparedSwapTransaction { + val amountRaw = parsePositiveAmount(polAmount, decimals = 18, label = "POL") + val response = + trailsClient.quoteIntent( + QuoteIntentRequest( + ownerAddress = walletAddress, + originChainId = POLYGON_CHAIN_ID.toULong(), + originTokenAddress = POLYGON_NATIVE_TOKEN, + destinationChainId = POLYGON_CHAIN_ID.toULong(), + destinationTokenAddress = POLYGON_USDC, + destinationToAddress = walletAddress, + originTokenAmount = amountRaw, + tradeType = TradeType.EXACT_INPUT, + fundMethod = FundMethod.WALLET, + mode = IntentMode.SWAP, + options = QuoteIntentRequestOptions(swapProvider = RouteProvider.AUTO), + ), + ) + val deposit = response.intent.depositTransaction + require(deposit.chainId == POLYGON_CHAIN_ID.toULong()) { + "Trails returned chain ${deposit.chainId}, but this demo only sends Polygon transactions." + } + val outputRaw = response.intent.quote.toAmountMin ?: response.intent.quote.toAmount + return PreparedSwapTransaction( + title = "Swap POL to USDC", + request = + SendTransactionRequest( + to = deposit.to, + value = deposit.value.toBigInteger(), + data = deposit.data, + ), + intent = response.intent, + outputRaw = outputRaw, + outputDisplay = formatTokenAmount(outputRaw, 6, "USDC"), + ) + } + + private suspend fun prepareDepositUsdc( + walletAddress: String, + usdcAmount: String, + preferredMarket: YieldMarket? = null, + ): PreparedYieldTransactions { + val amount = parsePositiveDisplayAmount(usdcAmount, decimals = 6, label = "USDC") + val market = preferredMarket ?: findPolygonUsdcEarnMarket() + val inputToken = market.inputTokens.firstOrNull() ?: market.token + val response = + trailsClient.yieldCreateEnterAction( + CreateYieldActionRequest( + earnMarketId = market.id, + userWalletAddress = walletAddress, + args = + YieldActionArguments( + amount = amount, + inputToken = inputToken.address ?: inputToken.symbol, + inputTokenNetwork = inputToken.network, + receiverAddress = walletAddress, + ), + ), + ) + return PreparedYieldTransactions( + title = "Deposit USDC using Earn", + transactions = parseYieldTransactions(response.action.transactions, "Deposit"), + marketName = market.metadata.name, + ) + } + + private suspend fun prepareWithdrawEarnPosition( + walletAddress: String, + position: EarnPosition, + ): PreparedYieldTransactions { + val response = + trailsClient.yieldCreateExitAction( + CreateYieldActionRequest( + earnMarketId = position.marketId, + userWalletAddress = walletAddress, + args = + YieldActionArguments( + amount = position.amount, + outputToken = position.outputToken, + outputTokenNetwork = position.outputTokenNetwork, + ), + ), + ) + return PreparedYieldTransactions( + title = "Withdraw ${position.marketName}", + transactions = parseYieldTransactions(response.action.transactions, "Withdraw"), + marketName = position.marketName, + ) + } + + private suspend fun findPolygonUsdcEarnMarket(): YieldMarket { + val markets = + trailsClient + .yieldGetMarkets( + GetYieldMarketsRequest( + chainId = POLYGON_CHAIN_ID.toString(), + search = "USDC", + limit = 50u, + ), + ).items + return markets + .filter { it.status.enter } + .filter { market -> market.inputToken().address.equals(POLYGON_USDC, ignoreCase = true) } + .filter { reasonableApyRate(it.rewardRate) != null } + .maxByOrNull { reasonableApyRate(it.rewardRate) ?: 0.0 } + ?: throw IllegalStateException("No enterable Polygon USDC earn market was returned.") + } + + private suspend fun sendYieldTransactions( + transactions: List, + label: String, + setStatus: (String) -> Unit, + ): SendTransactionResponse { + var latest: SendTransactionResponse? = null + transactions.forEachIndexed { index, transaction -> + val stepLabel = + if (transactions.size == 1) { + "transaction" + } else { + "transaction ${index + 1}/${transactions.size}" + } + setStatus("$label status: sending $stepLabel...") + latest = + sdk.wallet.sendTransaction( + network = Network.POLYGON, + request = transaction.request, + selectFeeOption = ::selectFeeOption, + ) + setStatus("$label status: sent $stepLabel ${shortHash(latest?.txnHash ?: latest?.txnId.orEmpty())}.") + } + return latest ?: throw IllegalStateException("$label action did not send a transaction.") + } + + private suspend fun refreshAfterSend() { + delay(POST_SEND_REFRESH_DELAY_MS) + refreshSignedInDataSnapshot() + } + + private suspend fun waitForUsdcBalanceIncrease( + initialBalances: BalanceState, + minIncreaseRaw: String, + selectedFeeOption: FeeOptionWithBalance?, + setStatus: (String) -> Unit, + pendingStatus: String, + successStatus: String, + staleStatus: String, + ): Boolean { + repeat(POST_SEND_REFRESH_ATTEMPTS) { index -> + val attempt = index + 1 + val suffix = + if (attempt == 1) { + "..." + } else { + " ($attempt/$POST_SEND_REFRESH_ATTEMPTS)..." + } + setStatus("$pendingStatus$suffix") + refreshSignedInDataSnapshot() + if (hasUsdcBalanceIncrease(initialBalances, balances, minIncreaseRaw, selectedFeeOption)) { + setStatus(successStatus) + return true + } + if (attempt < POST_SEND_REFRESH_ATTEMPTS) { + delay(POST_SEND_REFRESH_DELAY_MS) + } + } + setStatus("$staleStatus Use Refresh to check again.") + return false + } + + private suspend fun refreshSignedInDataSnapshot(): EarnPositionsResult { + val walletAddress = requireWalletAddress() + balances = getPolygonBalances(walletAddress) + val positionsResult = getPolygonEarnPositions(walletAddress) + earnPositions = positionsResult.positions + balancesView.text = balances.display + balancesStatusView.text = balances.status + renderEarnPositions(positionsResult) + positionsResult.errors.forEach { error -> + appendLog("! Earn balance error: $error") + } + return positionsResult + } + + private suspend fun waitForIntentSuccess(intentId: String) { + repeat(POST_SEND_REFRESH_ATTEMPTS) { index -> + val attempt = index + 1 + val receiptResult = + runCatching { + trailsClient.waitIntentReceipt(WaitIntentReceiptRequest(intentId = intentId)).intentReceipt + } + receiptResult + .onSuccess { receipt -> + when (receipt.status) { + IntentStatus.SUCCEEDED -> { + return + } + + IntentStatus.FAILED, + IntentStatus.ABORTED, + IntentStatus.REFUNDED, + IntentStatus.INVALID, + -> { + throw IllegalStateException( + "Trails intent $intentId finished with ${receipt.status.wireValue}.", + ) + } + + IntentStatus.UNKNOWN_DEFAULT -> { + throw IllegalStateException("Trails intent $intentId returned an unsupported status.") + } + + IntentStatus.QUOTED, + IntentStatus.COMMITTED, + IntentStatus.EXECUTING, + -> { + appendLog("Waiting for Trails intent $intentId ($attempt/$POST_SEND_REFRESH_ATTEMPTS).") + } + } + }.onFailure { throwable -> + if (attempt == POST_SEND_REFRESH_ATTEMPTS) { + throw throwable + } + appendLog("Waiting for Trails intent receipt ($attempt/$POST_SEND_REFRESH_ATTEMPTS): ${describe(throwable)}") + } + if (attempt < POST_SEND_REFRESH_ATTEMPTS) { + delay(POST_SEND_REFRESH_DELAY_MS) + } + } + throw IllegalStateException("Trails intent did not finish yet. Use Refresh to check again.") + } + + private suspend fun waitForTransactionHash(response: SendTransactionResponse): SendTransactionResponse { + if (!response.txnHash.isNullOrBlank()) return response + var latest = response + repeat(POST_SEND_REFRESH_ATTEMPTS) { attempt -> + delay(POST_SEND_REFRESH_DELAY_MS) + val status = sdk.wallet.getTransactionStatus(response.txnId) + latest = + SendTransactionResponse( + txnId = response.txnId, + status = status.status, + txnHash = status.txnHash, + ) + if (!latest.txnHash.isNullOrBlank()) return latest + if (latest.status == TransactionStatus.UNKNOWN_DEFAULT) { + throw IllegalStateException("Wallet transaction returned an unsupported status.") + } + appendLog("Waiting for chain hash (${attempt + 1}/$POST_SEND_REFRESH_ATTEMPTS).") + } + throw IllegalStateException("Wallet transaction hash was not available yet. Try again in a few seconds.") + } + + private suspend fun selectFeeOption(feeOptions: List): FeeOptionSelection? { + if (feeOptions.isEmpty()) return null + appendLog("Fee options: ${feeOptions.joinToString { feeOptionLabel(it) }}") + return suspendCancellableCoroutine { continuation -> + val labels = feeOptions.map(::feeOptionLabel).toTypedArray() + val firstAvailable = feeOptions.firstOrNull(::hasEnoughBalance) + var resumed = false + + fun resumeOnce(selection: FeeOptionSelection?) { + if (!resumed) { + resumed = true + continuation.resume(selection) + } + } + + fun cancelOnce() { + if (!resumed) { + resumed = true + continuation.resumeWithException(IllegalStateException("Fee selection cancelled")) + } + } + val builder = + MaterialAlertDialogBuilder(this) + .setTitle("Select fee") + .setItems(labels) { _, index -> + selectedFeeOption = feeOptions[index] + resumeOnce(feeOptions[index].selection) + }.setOnCancelListener { + cancelOnce() + } + firstAvailable?.let { option -> + builder.setPositiveButton("Select first available") { _, _ -> + selectedFeeOption = option + resumeOnce(option.selection) + } + } + val dialog = builder.show() + continuation.invokeOnCancellation { dialog.dismiss() } + } + } + + private suspend fun completePendingWalletSelection( + pendingSelection: PendingWalletSelection, + status: String, + ) { + authStatusView.text = "Select a wallet to finish sign-in." + appendLog("Wallet selection required: type=${pendingSelection.walletType} count=${pendingSelection.wallets.size}") + val selected = + try { + requestWalletSelectionChoice(pendingSelection) + } catch (throwable: Throwable) { + sdk.wallet.signOut() + showEmailStep() + throw throwable + } + renderSignedInWallet(selected.wallet, status) + } + + private suspend fun requestWalletSelectionChoice(pendingSelection: PendingWalletSelection) = + suspendCancellableCoroutine { continuation -> + var resumed = false + + fun resumeOnce(action: suspend () -> com.omsclient.kotlin_sdk.wallet.WalletSelectionResult) { + if (resumed) return + resumed = true + uiScope.launch { + runCatching { action() } + .onSuccess { continuation.resume(it) } + .onFailure { continuation.resumeWithException(it) } + } + } + + val labels = + buildList { + pendingSelection.wallets.forEach { wallet -> + add("${shortAddress(wallet.address)}\n${wallet.reference ?: wallet.id}") + } + add("Create new wallet") + }.toTypedArray() + val dialog = + MaterialAlertDialogBuilder(this) + .setTitle("Select wallet") + .setItems(labels) { _, index -> + val wallet = pendingSelection.wallets.getOrNull(index) + if (wallet != null) { + resumeOnce { pendingSelection.selectWallet(wallet.id) } + } else { + resumeOnce { pendingSelection.createAndSelectWallet() } + } + }.setOnCancelListener { + if (!resumed) { + resumed = true + continuation.resumeWithException(IllegalStateException("Wallet selection cancelled")) + } + }.show() + continuation.invokeOnCancellation { dialog.dismiss() } + } + + private fun parseYieldTransactions( + transactions: List, + label: String, + ): List { + val parsed = + transactions + .filter { it.isMessage != true } + .map { parseUnsignedYieldTransaction(it.unsignedTransaction) } + require(parsed.isNotEmpty()) { "$label action did not return a transaction." } + val unsupported = parsed.firstOrNull { it.chainId != POLYGON_CHAIN_ID } + require(unsupported == null) { + "$label returned chain ${unsupported?.chainId}, but this demo only sends Polygon transactions." + } + return parsed + } + + private fun parseUnsignedYieldTransaction(tx: JsonElement?): ParsedYieldTransaction { + val txObject = tx?.asObject() ?: throw IllegalStateException("Yield action returned an incomplete transaction.") + val to = txObject.string("to") ?: throw IllegalStateException("Yield action returned no transaction recipient.") + val chainId = txObject.string("chainId")?.toIntOrNull() ?: txObject.numberString("chainId")?.toDoubleOrNull()?.toInt() + return ParsedYieldTransaction( + to = to, + data = txObject.string("data") ?: "0x", + value = txObject.string("value")?.takeUnless { it == "null" }?.toBigIntegerOrNull() ?: BigInteger.ZERO, + chainId = chainId ?: throw IllegalStateException("Yield action returned no chain id."), + ) + } + + private fun YieldBalances.toEarnPosition(market: YieldMarket?): EarnPosition? { + val balance = primaryBalance() ?: return null + return EarnPosition( + id = yieldId, + marketId = yieldId, + marketName = market?.metadata?.name ?: balance.shareToken?.name ?: "${balance.token.symbol} position", + provider = market?.providerId ?: balance.shareToken?.symbol ?: yieldId, + amount = balance.amount, + amountDisplay = formatDisplayAmount(balance.amount), + amountRaw = balance.amountRaw, + amountUsd = formatUsdAmount(balance.amountUsd), + apy = formatApy(rewardRate ?: market?.rewardRate), + tokenSymbol = balance.token.symbol, + outputToken = balance.token.address ?: balance.token.symbol, + outputTokenNetwork = balance.token.network, + canWithdraw = market?.status?.exit != false, + sortValue = balance.amountUsd?.toDoubleOrNull() ?: balance.amount.toDoubleOrNull() ?: 0.0, + ) + } + + private fun YieldBalances.primaryBalance(): YieldBalance? = + outputTokenBalance?.takeIf { it.hasPositiveAmount() } ?: balances.firstOrNull { it.hasPositiveAmount() } + + private fun YieldBalance.hasPositiveAmount(): Boolean = + amountRaw.toBigIntegerOrNull()?.let { it > BigInteger.ZERO } + ?: amount.toDoubleOrNull()?.let { it > 0.0 } + ?: false + + private fun YieldMarket.inputToken() = inputTokens.firstOrNull() ?: token + + private fun handleOidcRedirectCallback(intent: Intent?) { + val callbackUrl = intent?.data?.toString() ?: return + launchAction( + label = "Handle Google redirect sign-in callback", + onStart = { showGoogleRedirectPendingStep("Completing Google redirect sign-in...") }, + ) { + when (val result = handleOidcRedirectCallbackWithConfiguredLifetime(callbackUrl)) { + is OidcRedirectAuthResult.Completed -> { + consumeIntentData() + renderSignedInWallet(result.wallet, "Google redirect login complete") + } + + is OidcRedirectAuthResult.WalletSelection -> { + consumeIntentData() + completePendingWalletSelection( + pendingSelection = result.pendingSelection, + status = "Google redirect login complete", + ) + } + + is OidcRedirectAuthResult.Failed -> { + consumeIntentData() + showEmailStep() + authStatusView.text = "Google redirect completion failed: ${describe(result.error)}" + } + + OidcRedirectAuthResult.NoPendingAuth -> { + consumeIntentData() + renderSessionState() + } + + OidcRedirectAuthResult.NotOidcRedirectCallback -> { + renderSessionState() + } + } + } + } + + private fun consumeIntentData() { + setIntent(Intent(intent).apply { data = null }) + } + + private fun openInAppBrowser(url: String) { + val colorSchemeParams = + CustomTabColorSchemeParams + .Builder() + .setToolbarColor(ContextCompat.getColor(this, R.color.surface_800)) + .build() + CustomTabsIntent + .Builder() + .setShowTitle(true) + .setDefaultColorSchemeParams(colorSchemeParams) + .build() + .launchUrl(this, Uri.parse(url)) + } + + private fun subscribeSessionExpiry() { + unsubscribeSessionExpired = + sdk.wallet.onSessionExpired { event -> + renderExpiredSession(event) + } + } + + private fun renderSessionState() { + val walletAddress = sdk.session.walletAddress + if (walletAddress == null) { + renderSessionStateBox() + expiredSessionEvent?.let(::renderExpiredSession) ?: resetUiForNoSession() + return + } + + clearExpiredSessionState() + renderSessionStateBox() + authStatusView.text = "Restored persisted wallet session" + walletView.text = "Wallet:\n$walletAddress" + authCard.visibility = View.GONE + emailStepContainer.visibility = View.GONE + codeStepContainer.visibility = View.GONE + walletCard.visibility = View.VISIBLE + balancesCard.visibility = View.VISIBLE + actionsCard.visibility = View.VISIBLE + positionsCard.visibility = View.VISIBLE + signOutButton.visibility = View.VISIBLE + renderLastTransaction() + balancesView.text = balances.display + balancesStatusView.text = balances.status + if (earnPositions.isEmpty()) { + positionsContainer.removeAllViews() + positionsView.visibility = View.VISIBLE + positionsView.text = "Loading Polygon earn positions..." + positionsStatusView.visibility = View.GONE + } else { + renderEarnPositions(EarnPositionsResult(earnPositions, emptyList())) + } + } + + private fun renderSignedInWallet( + wallet: Wallet, + status: String, + ) { + clearExpiredSessionState() + renderSessionStateBox() + authStatusView.text = status + walletView.text = "Wallet:\n${wallet.address}" + authCard.visibility = View.GONE + emailStepContainer.visibility = View.GONE + codeStepContainer.visibility = View.GONE + walletCard.visibility = View.VISIBLE + balancesCard.visibility = View.VISIBLE + actionsCard.visibility = View.VISIBLE + positionsCard.visibility = View.VISIBLE + signOutButton.visibility = View.VISIBLE + positionsContainer.removeAllViews() + positionsView.visibility = View.VISIBLE + positionsView.text = "Loading Polygon earn positions..." + positionsStatusView.visibility = View.GONE + appendLog("Wallet ready: ${wallet.address}") + refreshSignedInData() + } + + private fun renderExpiredSession(event: OMSClientSessionExpiredEvent) { + val isNewEvent = expiredSessionEvent != event + expiredSessionEvent = event + renderSessionStateBox() + prefillExpiredSessionEmail() + authStatusView.text = + buildString { + append("Wallet session expired. Sign in again") + event.session.sessionEmail?.takeIf { it.isNotBlank() }?.let { email -> + append(" as ") + append(email) + } + append(".") + } + walletView.text = "No wallet selected." + clearPreparedState() + resetLoadedData() + signOutButton.visibility = View.VISIBLE + authCard.visibility = View.VISIBLE + emailStepContainer.visibility = View.VISIBLE + codeStepContainer.visibility = View.GONE + walletCard.visibility = View.GONE + balancesCard.visibility = View.GONE + actionsCard.visibility = View.GONE + positionsCard.visibility = View.GONE + if (isNewEvent) { + appendLog( + "Wallet session expired at ${event.expiredAt}: " + + "wallet=${event.session.walletAddress ?: "none"} email=${event.session.sessionEmail ?: "none"}", + ) + } + } + + private fun resetUiForNoSession() { + renderSessionStateBox() + authStatusView.text = "Waiting for sign-in." + walletView.text = "No wallet selected." + authCard.visibility = View.VISIBLE + emailStepContainer.visibility = View.VISIBLE + codeStepContainer.visibility = View.GONE + walletCard.visibility = View.GONE + balancesCard.visibility = View.GONE + actionsCard.visibility = View.GONE + positionsCard.visibility = View.GONE + signOutButton.visibility = View.GONE + renderLastTransaction() + } + + private fun showEmailStep() { + renderSessionStateBox() + authStatusView.text = "Waiting for sign-in." + authCard.visibility = View.VISIBLE + emailStepContainer.visibility = View.VISIBLE + codeStepContainer.visibility = View.GONE + walletCard.visibility = View.GONE + balancesCard.visibility = View.GONE + actionsCard.visibility = View.GONE + positionsCard.visibility = View.GONE + signOutButton.visibility = View.GONE + codeInput.text?.clear() + emailInput.post { + emailInput.requestFocus() + emailInput.setSelection(emailInput.text?.length ?: 0) + } + } + + private fun showGoogleRedirectPendingStep(status: String) { + renderSessionStateBox() + authStatusView.text = status + authCard.visibility = View.VISIBLE + emailStepContainer.visibility = View.GONE + codeStepContainer.visibility = View.GONE + walletCard.visibility = View.GONE + balancesCard.visibility = View.GONE + actionsCard.visibility = View.GONE + positionsCard.visibility = View.GONE + signOutButton.visibility = View.VISIBLE + renderLastTransaction() + } + + private fun showPendingCodeStep() { + renderSessionStateBox() + authCard.visibility = View.VISIBLE + emailStepContainer.visibility = View.GONE + codeStepContainer.visibility = View.VISIBLE + walletCard.visibility = View.GONE + balancesCard.visibility = View.GONE + actionsCard.visibility = View.GONE + positionsCard.visibility = View.GONE + signOutButton.visibility = View.VISIBLE + codeInput.post { + codeInput.requestFocus() + codeInput.setSelection(codeInput.text?.length ?: 0) + } + } + + private fun renderSessionStateBox() { + val session = sdk.session + val expiredEvent = expiredSessionEvent + sessionStateCard.visibility = + if (session.walletAddress == null && expiredEvent == null) { + View.GONE + } else { + View.VISIBLE + } + sessionStateView.text = + if (expiredEvent != null && session.walletAddress == null) { + buildString { + appendLine("expiredAt: ${expiredEvent.expiredAt}") + appendLine("walletAddress: ${expiredEvent.session.walletAddress ?: "null"}") + appendLine("expiresAt: ${expiredEvent.session.expiresAt ?: "null"}") + appendLine("loginType: ${expiredEvent.session.loginType ?: "null"}") + append("sessionEmail: ${expiredEvent.session.sessionEmail ?: "null"}") + } + } else { + buildString { + appendLine("walletAddress: ${session.walletAddress ?: "null"}") + appendLine("expiresAt: ${session.expiresAt ?: "null"}") + appendLine("loginType: ${session.loginType ?: "null"}") + append("sessionEmail: ${session.sessionEmail ?: "null"}") + } + } + } + + private fun requireWalletAddress(): String = + sdk.session.walletAddress?.takeIf { it.isNotBlank() } + ?: throw IllegalStateException("Sign in before preparing a Trails action.") + + private fun requireEmailForSignIn(): String { + val typedEmail = + emailInput.text + ?.toString() + ?.trim() + .orEmpty() + if (typedEmail.isNotEmpty()) { + return typedEmail + } + val expiredEmail = expiredSessionEmail() + if (expiredEmail != null) { + emailInput.setText(expiredEmail) + emailInput.setSelection(expiredEmail.length) + return expiredEmail + } + error("Email is required.") + } + + private fun expiredSessionEmail(): String? = + expiredSessionEvent + ?.session + ?.sessionEmail + ?.takeIf { it.isNotBlank() } + + private fun clearExpiredSessionState() { + expiredSessionEvent = null + } + + private suspend fun completeEmailAuthWithConfiguredLifetime(code: String): CompleteAuthResult { + val sessionLifetimeSeconds = requestedSessionLifetimeSeconds() + persistAuthPreferences() + return if (sessionLifetimeSeconds == null) { + sdk.wallet.completeEmailAuth( + code = code, + walletSelection = currentWalletSelectionBehavior(), + ) + } else { + sdk.wallet.completeEmailAuth( + code = code, + walletSelection = currentWalletSelectionBehavior(), + sessionLifetimeSeconds = sessionLifetimeSeconds, + ) + } + } + + private suspend fun handleOidcRedirectCallbackWithConfiguredLifetime(callbackUrl: String): OidcRedirectAuthResult { + val sessionLifetimeSeconds = requestedSessionLifetimeSeconds() + persistAuthPreferences() + return if (sessionLifetimeSeconds == null) { + sdk.wallet.handleOidcRedirectCallback( + callbackUrl = callbackUrl, + walletSelection = currentWalletSelectionBehavior(), + ) + } else { + sdk.wallet.handleOidcRedirectCallback( + callbackUrl = callbackUrl, + walletSelection = currentWalletSelectionBehavior(), + sessionLifetimeSeconds = sessionLifetimeSeconds, + ) + } + } + + private fun currentWalletSelectionBehavior(): WalletSelectionBehavior = + if (manualWalletSelectionCheckbox.isChecked) { + WalletSelectionBehavior.Manual + } else { + WalletSelectionBehavior.Automatic + } + + private fun restoreAuthPreferences() { + manualWalletSelectionCheckbox.isChecked = + authPreferences.getBoolean(TRAILS_ACTIONS_MANUAL_WALLET_SELECTION_KEY, false) + sessionLifetimeInput.setText( + authPreferences.getString( + TRAILS_ACTIONS_SESSION_LIFETIME_SECONDS_KEY, + TRAILS_ACTIONS_DEFAULT_SESSION_LIFETIME_SECONDS, + ), + ) + } + + private fun persistAuthPreferences() { + val rawValue = currentSessionLifetimeSecondsText() + parseSessionLifetimeSeconds(rawValue) + authPreferences + .edit() + .putBoolean(TRAILS_ACTIONS_MANUAL_WALLET_SELECTION_KEY, manualWalletSelectionCheckbox.isChecked) + .apply { + if (rawValue.isBlank()) { + remove(TRAILS_ACTIONS_SESSION_LIFETIME_SECONDS_KEY) + } else { + putString(TRAILS_ACTIONS_SESSION_LIFETIME_SECONDS_KEY, rawValue) + } + }.apply() + } + + private fun requestedSessionLifetimeSeconds(): Long? = parseSessionLifetimeSeconds(currentSessionLifetimeSecondsText()) + + private fun currentSessionLifetimeSecondsText(): String = + sessionLifetimeInput.text + ?.toString() + ?.trim() + .orEmpty() + + private fun parseSessionLifetimeSeconds(rawValue: String): Long? { + if (rawValue.isBlank()) return null + val parsed = rawValue.toLongOrNull() + require(parsed != null && parsed > 0L) { + "Session lifetime seconds must be a positive whole number." + } + return parsed + } + + private fun prefillExpiredSessionEmail() { + val email = expiredSessionEmail() ?: return + if (emailInput.text?.isNotBlank() == true) return + emailInput.setText(email) + emailInput.setSelection(email.length) + } + + private fun resetLoadedData() { + balances = BalanceState.signedOut + earnPositions = emptyList() + withdrawStatusesByPosition.clear() + lastWithdrawTransactionHashes.clear() + balancesView.text = balances.display + balancesStatusView.text = balances.status + positionsContainer.removeAllViews() + positionsView.visibility = View.VISIBLE + positionsView.text = "Sign in to load earn positions." + positionsStatusView.text = "" + positionsStatusView.visibility = View.GONE + } + + private fun clearPreparedState() { + preparedSwap = null + preparedDeposit = null + preparedEarn = null + selectedFeeOption = null + lastTransactionHash = null + withdrawStatusesByPosition.clear() + lastWithdrawTransactionHashes.clear() + swapStatusView.text = "Swap status: waiting to prepare." + depositStatusView.text = "Deposit status: waiting to prepare." + earnStatusView.text = "Swap and Deposit status: waiting to prepare." + renderLastTransaction() + if (::positionsContainer.isInitialized && earnPositions.isNotEmpty()) { + renderEarnPositions(EarnPositionsResult(earnPositions, emptyList())) + } + } + + private fun renderLastTransaction() { + val hash = lastTransactionHash + lastTransactionView.text = + if (hash.isNullOrBlank()) { + "Last transaction: none" + } else { + "Last transaction: ${shortHash(hash)}" + } + openExplorerButton.visibility = if (hash.isNullOrBlank()) View.GONE else View.VISIBLE + } + + private fun requireInput( + input: TextInputEditText, + label: String, + ): String { + val value = + input.text + ?.toString() + ?.trim() + .orEmpty() + require(value.isNotBlank()) { "$label is required." } + return normalizeAmountInput(value) + } + + private fun launchAction( + label: String, + onStart: (() -> Unit)? = null, + onFailure: ((Throwable) -> Unit)? = null, + action: suspend () -> Unit, + ) { + uiScope.launch { + appendLog("> $label") + onStart?.invoke() + runCatching { action() } + .onFailure { throwable -> + onFailure?.invoke(throwable) + appendLog("! ${describe(throwable)}") + } + } + } + + private fun copyWalletAddress() { + val address = sdk.session.walletAddress + if (address.isNullOrBlank()) { + Toast.makeText(this, "No wallet address", Toast.LENGTH_SHORT).show() + return + } + val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + clipboard.setPrimaryClip(ClipData.newPlainText("Wallet address", address)) + Toast.makeText(this, "Wallet address copied", Toast.LENGTH_SHORT).show() + } + + private fun appendLog(message: String) { + if (message.startsWith("!")) { + Log.e(TAG, message) + } else { + Log.d(TAG, message) + } + logView.text = + buildString { + append(logView.text) + append('\n') + append(message) + }.lineSequence() + .toList() + .takeLast(80) + .joinToString("\n") + } + + private fun describe(error: Throwable): String = + when (error) { + is WebRpcError -> error.message.ifBlank { error.error } + is WebRpcTransportException -> error.message ?: error::class.java.simpleName + else -> error.message ?: error::class.java.simpleName + } + + private fun openExplorer(hash: String) { + startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("${Network.POLYGON.explorerUrl}/tx/$hash"))) + } + + private fun positionsStatus(result: EarnPositionsResult): String = + when { + result.errors.isNotEmpty() -> "Earn positions loaded with ${result.errors.size} API error${plural(result.errors.size)}." + result.positions.isNotEmpty() -> "Earn positions updated." + else -> NO_EARN_POSITIONS_STATUS + } + + private fun renderEarnPositions(result: EarnPositionsResult) { + positionsContainer.removeAllViews() + val hasVisibleWithdrawStatus = + result.positions.any { position -> + withdrawStatusesByPosition[position.id]?.isNotBlank() == true + } + + if (result.positions.isEmpty()) { + positionsView.visibility = View.VISIBLE + positionsView.text = NO_EARN_POSITIONS_STATUS + } else { + positionsView.visibility = View.GONE + result.positions.forEachIndexed { index, position -> + if (index > 0) { + positionsContainer.addView( + dividerLine(), + LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp(1)).apply { + topMargin = dp(14) + }, + ) + } + positionsContainer.addView(positionRow(position), matchWrap(topMargin = if (index == 0) 0 else 14)) + } + } + + val status = positionsStatus(result) + if (!hasVisibleWithdrawStatus && (result.positions.isNotEmpty() || status != NO_EARN_POSITIONS_STATUS)) { + positionsStatusView.text = status + positionsStatusView.visibility = View.VISIBLE + } else { + positionsStatusView.text = "" + positionsStatusView.visibility = View.GONE + } + } + + private fun positionRow(position: EarnPosition): LinearLayout = + vertical { + addView(fieldLabel(position.marketName)) + addView(smallBody(position.provider), matchWrap(topMargin = 2)) + addView(body(positionAmountText(position)), matchWrap(topMargin = 8)) + addView(smallBody("APY ${position.apy}"), matchWrap(topMargin = 2)) + addView( + button("Withdraw", outline = true).apply { + isEnabled = position.canWithdraw + setOnClickListener { withdrawEarnPosition(position) } + }, + matchWrap(topMargin = 10), + ) + addView(smallBody(if (position.canWithdraw) "All" else "Unavailable"), matchWrap(topMargin = 4)) + withdrawStatusesByPosition[position.id] + ?.takeIf { it.isNotBlank() } + ?.let { status -> + addView(body(status), matchWrap(topMargin = 8)) + } + lastWithdrawTransactionHashes[position.id] + ?.takeIf { it.isNotBlank() } + ?.let { hash -> + addView(body("Last withdraw: ${shortHash(hash)}"), matchWrap(topMargin = 6)) + } + } + + private fun positionAmountText(position: EarnPosition): String = + buildString { + append(position.amountDisplay) + append(' ') + append(position.tokenSymbol) + append(" / ") + append(position.amountUsd ?: "USD unavailable") + } + + private fun normalizeAmountInput(value: String): String = + buildString { + var hasDecimal = false + value.replace(',', '.').forEach { char -> + when { + char in '0'..'9' -> { + append(char) + } + + char == '.' && !hasDecimal -> { + append(char) + hasDecimal = true + } + } + } + }.let { if (it.startsWith('.')) "0$it" else it } + + private fun parsePositiveAmount( + amount: String, + decimals: Int, + label: String, + ): String = parsePositiveDisplayAmount(amount, decimals, label).let { parseUnits(it, decimals).toString() } + + private fun parsePositiveDisplayAmount( + amount: String, + decimals: Int, + label: String, + ): String { + val normalized = normalizeAmountInput(amount) + require(normalized.isNotBlank()) { "Enter a $label amount." } + require(parseUnits(normalized, decimals) > BigInteger.ZERO) { "Enter a $label amount greater than zero." } + return normalized + } + + private fun formatTokenAmount( + raw: String, + decimals: Int, + symbol: String, + ): String = + raw + .toBigIntegerOrNull() + ?.let { formatUnits(it, decimals) } + ?.let { formatDisplayAmount(it, maxFractionDigits = 6) } + ?.let { "$it $symbol" } + ?: "- $symbol" + + private fun formatDisplayAmount( + amount: String, + maxFractionDigits: Int = 4, + ): String { + val parts = amount.split('.', limit = 2) + val whole = parts.firstOrNull().orEmpty().ifBlank { "0" } + val fraction = + parts + .getOrNull(1) + .orEmpty() + .take(maxFractionDigits) + .trimEnd('0') + return if (fraction.isEmpty()) whole else "$whole.$fraction" + } + + private fun formatUsdAmount(value: String?): String? = + value + ?.toDoubleOrNull() + ?.let { + NumberFormat + .getCurrencyInstance(Locale.US) + .format(it) + } + + private fun formatApy(rewardRate: YieldRewardRate?): String { + val rate = reasonableApyRate(rewardRate) ?: return "-" + val percent = rate * 100.0 + return if (percent >= 10.0) { + "%.1f%%".format(Locale.US, percent) + } else { + "%.2f%%".format(Locale.US, percent) + } + } + + private fun reasonableApyRate(rewardRate: YieldRewardRate?): Double? = + rewardRate?.total?.takeIf { it.isFinite() && it in 0.0..MAX_REASONABLE_USDC_APY_RATE } + + private fun shortHash(value: String): String = + if (value.length > 18) { + "${value.take(10)}...${value.takeLast(8)}" + } else { + value + } + + private fun shortAddress(value: String): String = + if (value.length > 18) { + "${value.take(10)}...${value.takeLast(6)}" + } else { + value + } + + private fun plural(count: Int): String = if (count == 1) "" else "s" + + private fun feeOptionLabel(option: FeeOptionWithBalance): String = + buildString { + append(option.feeOption.token.symbol) + append(" fee ") + append(option.feeOption.displayValue) + option.available?.let { + append(" / available ") + append(it) + } + } + + private fun hasEnoughBalance(option: FeeOptionWithBalance): Boolean { + val balance = option.availableRaw?.toBigIntegerOrNull() ?: return false + val fee = option.feeOption.value.toBigIntegerOrNull() ?: return false + return balance >= fee + } + + private fun hasUsdcBalanceIncrease( + initialBalances: BalanceState, + refreshedBalances: BalanceState, + minIncreaseRaw: String, + selectedFeeOption: FeeOptionWithBalance?, + ): Boolean { + val initialRaw = rawUnsignedAmount(initialBalances.usdcRaw) + val refreshedRaw = rawUnsignedAmount(refreshedBalances.usdcRaw) + val minIncrease = rawUnsignedAmount(minIncreaseRaw) + val expectedIncrease = (minIncrease - usdcFeeRaw(selectedFeeOption)).coerceAtLeast(BigInteger.ZERO) + return if (expectedIncrease == BigInteger.ZERO) { + refreshedRaw > initialRaw + } else { + refreshedRaw >= initialRaw + expectedIncrease + } + } + + private fun usdcFeeRaw(option: FeeOptionWithBalance?): BigInteger { + val token = option?.feeOption?.token ?: return BigInteger.ZERO + val isUsdc = + token.contractAddress.equals(POLYGON_USDC, ignoreCase = true) || + token.symbol.equals("USDC", ignoreCase = true) + return if (isUsdc) { + rawUnsignedAmount(option.feeOption.value) + } else { + BigInteger.ZERO + } + } + + private fun rawUnsignedAmount(value: String): BigInteger = + value + .toBigIntegerOrNull() + ?.takeIf { it >= BigInteger.ZERO } + ?: BigInteger.ZERO + + private fun JsonElement.asObject(): JsonObject? = + when (this) { + is JsonObject -> this + is JsonPrimitive -> contentOrNull?.let { TrailsJson.parseToJsonElement(it).jsonObject } + else -> null + } + + private fun JsonObject.string(name: String): String? = (this[name] as? JsonPrimitive)?.contentOrNull + + private fun JsonObject.numberString(name: String): String? = this[name]?.jsonPrimitive?.toString()?.trim('"') + + private fun card(content: LinearLayout.() -> Unit): MaterialCardView = + MaterialCardView(this).apply { + radius = dp(8).toFloat() + strokeWidth = dp(1) + strokeColor = color(R.color.border_300) + setCardBackgroundColor(color(R.color.surface_800)) + cardElevation = 0f + addView( + vertical { + setPadding(dp(20), dp(20), dp(20), dp(20)) + content() + }, + matchWrap(), + ) + } + + private fun vertical(content: LinearLayout.() -> Unit): LinearLayout = + LinearLayout(this).apply { + orientation = LinearLayout.VERTICAL + content() + } + + private fun horizontal(content: LinearLayout.() -> Unit): LinearLayout = + LinearLayout(this).apply { + orientation = LinearLayout.HORIZONTAL + isBaselineAligned = false + content() + } + + private fun sectionTitle(value: String): TextView = text(value, 20f, R.color.slate_900, bold = true) + + private fun authDemoSectionTitle(value: String): TextView = text(value, 18f, R.color.slate_900, bold = true) + + private fun fieldLabel(value: String): TextView = text(value, 14f, R.color.slate_900, bold = true) + + private fun codeStepTitle(value: String): TextView = text(value, 16f, R.color.slate_900, bold = true) + + private fun body(value: String): TextView = text(value, 13f, R.color.slate_700, bold = false) + + private fun smallBody(value: String): TextView = text(value, 12f, R.color.slate_700, bold = false) + + private fun centerBody(value: String): TextView = + body(value).apply { + textAlignment = View.TEXT_ALIGNMENT_CENTER + } + + private fun actionDivider(value: String): LinearLayout = + horizontal { + gravity = android.view.Gravity.CENTER_VERTICAL + addView(dividerLine(), LinearLayout.LayoutParams(0, dp(1), 1f)) + addView( + text(value, 13f, R.color.slate_500, bold = true).apply { + textAlignment = View.TEXT_ALIGNMENT_CENTER + }, + LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply { + marginStart = dp(10) + marginEnd = dp(10) + }, + ) + addView(dividerLine(), LinearLayout.LayoutParams(0, dp(1), 1f)) + } + + private fun dividerLine(): View = + View(this).apply { + setBackgroundColor(color(R.color.border_300)) + } + + private fun monospaceBody(value: String): TextView = + smallBody(value).apply { + typeface = android.graphics.Typeface.MONOSPACE + setTextIsSelectable(true) + } + + private fun text( + value: String, + size: Float, + colorRes: Int, + bold: Boolean, + ): TextView = + TextView(this).apply { + text = value + textSize = size + setTextColor(color(colorRes)) + if (bold) typeface = android.graphics.Typeface.DEFAULT_BOLD + } + + private fun button( + value: String, + outline: Boolean = false, + ): MaterialButton = + MaterialButton(this).apply { + text = value + isAllCaps = false + cornerRadius = dp(10) + minHeight = dp(52) + if (outline) { + strokeWidth = dp(1) + strokeColor = ColorStateList.valueOf(color(R.color.border_300)) + backgroundTintList = ColorStateList.valueOf(color(R.color.surface_700)) + setTextColor(color(R.color.slate_900)) + } else { + strokeWidth = 0 + backgroundTintList = ColorStateList.valueOf(color(R.color.brand_500)) + setTextColor(color(R.color.black)) + } + } + + private fun input( + hint: String, + inputType: Int, + ): TextInputEditText = + TextInputEditText(this).apply { + this.hint = hint + this.inputType = inputType + maxLines = 1 + setPadding(dp(16), dp(12), dp(16), dp(12)) + setTextColor(color(R.color.slate_900)) + setHintTextColor(color(R.color.slate_500)) + } + + private fun wrapInput( + input: TextInputEditText, + suffixText: String? = null, + ): TextInputLayout = + TextInputLayout(this).apply { + val fieldHint = input.hint + if (!fieldHint.isNullOrBlank()) { + hint = fieldHint + input.hint = null + } + boxBackgroundMode = TextInputLayout.BOX_BACKGROUND_OUTLINE + boxBackgroundColor = color(R.color.surface_900) + boxStrokeColor = color(R.color.border_300) + boxStrokeWidth = dp(1) + boxStrokeWidthFocused = dp(1) + setBoxCornerRadii( + dp(10).toFloat(), + dp(10).toFloat(), + dp(10).toFloat(), + dp(10).toFloat(), + ) + setDefaultHintTextColor(ColorStateList.valueOf(color(R.color.slate_500))) + hintTextColor = ColorStateList.valueOf(color(R.color.slate_500)) + this.suffixText = suffixText + setSuffixTextColor(ColorStateList.valueOf(color(R.color.slate_500))) + input.background = null + addView(input, matchWrap()) + } + + private fun space(width: Int = 0): Space = Space(this).apply { minimumWidth = dp(width) } + + private fun matchWrap(topMargin: Int = 0): LinearLayout.LayoutParams = + LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply { + this.topMargin = topMargin + } + + private fun weightedButton(): LinearLayout.LayoutParams = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f) + + private fun color(id: Int): Int = getColor(id) + + private fun dp(value: Int): Int = (value * resources.displayMetrics.density).toInt() + + private data class BalanceState( + val pol: String, + val usdc: String, + val polRaw: String, + val usdcRaw: String, + val status: String, + ) { + val display: String + get() = "POL: $pol\nUSDC: $usdc" + + companion object { + val signedOut = BalanceState("-", "-", "0", "0", "Sign in to load balances.") + } + } + + private data class EarnPositionsResult( + val positions: List, + val errors: List, + ) + + private data class EarnPosition( + val id: String, + val marketId: String, + val marketName: String, + val provider: String, + val amount: String, + val amountDisplay: String, + val amountRaw: String, + val amountUsd: String?, + val apy: String, + val tokenSymbol: String, + val outputToken: String, + val outputTokenNetwork: String, + val canWithdraw: Boolean, + val sortValue: Double, + ) + + private data class ParsedYieldTransaction( + val to: String, + val data: String, + val value: BigInteger, + val chainId: Int, + ) { + val request: SendTransactionRequest + get() = SendTransactionRequest(to = to, value = value, data = data) + } + + private data class PreparedSwapTransaction( + val title: String, + val request: SendTransactionRequest, + val intent: com.omsclient.kotlin_sdk_trails_actions.generated.Intent, + val outputRaw: String, + val outputDisplay: String, + val executionState: PreparedSwapExecutionState = PreparedSwapExecutionState(), + ) + + private data class PreparedSwapExecutionState( + var committedIntentId: String? = null, + var submittedResponse: SendTransactionResponse? = null, + var selectedFeeOption: FeeOptionWithBalance? = null, + var didExecuteIntent: Boolean = false, + ) + + private data class PreparedYieldTransactions( + val title: String, + val transactions: List, + val marketName: String, + ) + + private data class PreparedSwapAndDepositPlan( + val swap: PreparedSwapTransaction, + val market: YieldMarket, + val depositAmount: String, + ) + + private companion object { + const val TAG = "TrailsActions" + const val TRAILS_API_URL = "https://trails-api.sequence.app" + + // Demo-only Trails access key used by the public Trails sample apps; do not reuse for production apps. + const val TRAILS_ACCESS_KEY = "AQAAAAAAAMCYJYqQIBlKgsdYZIC44JP84lo" + const val TRAILS_ACCESS_KEY_HEADER = "X-Access-Key" + const val POLYGON_CHAIN_ID = 137 + const val POLYGON_USDC = "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359" + const val POLYGON_NATIVE_TOKEN = "0x0000000000000000000000000000000000000000" + const val DEFAULT_SWAP_POL_AMOUNT = "0.5" + const val DEFAULT_DEPOSIT_USDC_AMOUNT = "0.1" + const val DEFAULT_EARN_POL_AMOUNT = "1" + const val NO_EARN_POSITIONS_STATUS = "No deposited earn positions." + const val MAX_REASONABLE_USDC_APY_RATE = 0.5 + const val POST_SEND_REFRESH_ATTEMPTS = 24 + const val POST_SEND_REFRESH_DELAY_MS = 2_500L + const val TRAILS_ACTIONS_PREFERENCES_NAME = "oms_client_trails_actions_preferences" + const val TRAILS_ACTIONS_MANUAL_WALLET_SELECTION_KEY = "manual_wallet_selection" + const val TRAILS_ACTIONS_SESSION_LIFETIME_SECONDS_KEY = "session_lifetime_seconds" + val TRAILS_ACTIONS_DEFAULT_SESSION_LIFETIME_SECONDS = WalletClient.DEFAULT_SESSION_LIFETIME_SECONDS.toString() + val TrailsJson = kotlinx.serialization.json.Json { ignoreUnknownKeys = true } + } +} + +private object DemoConfig { + const val demoPublishableKey: String = "AQAAAAAAAAK2JvvZhWqZ51riasWBftkrVXE" + const val demoProjectId: String = "proj_014kg56dc0a75" + const val demoGoogleWebClientId: String = "970987756660-0dh5gubqfiugm452raf7mm39qaq639hn.apps.googleusercontent.com" + const val oidcRedirectUri: String = "omsclientkotlindemo://auth/callback" +} diff --git a/trails-actions/src/main/java/com/omsclient/kotlin_sdk_trails_actions/generated/TrailsApiClient.kt b/trails-actions/src/main/java/com/omsclient/kotlin_sdk_trails_actions/generated/TrailsApiClient.kt new file mode 100644 index 0000000..8c2fa53 --- /dev/null +++ b/trails-actions/src/main/java/com/omsclient/kotlin_sdk_trails_actions/generated/TrailsApiClient.kt @@ -0,0 +1,7061 @@ +package com.omsclient.kotlin_sdk_trails_actions.generated + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encodeToString +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement + +import kotlinx.coroutines.CancellationException +import java.io.IOException +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody + +// trails-api v1 95ad285f8962228eca9a635c79f8cad7804669be +// -- +// Code generated by webrpc-gen@v0.36.1 with gen-kotlin generator. DO NOT EDIT. +// +// webrpc-gen -schema=proto/trails-api.ridl -target=gen-kotlin -client -okhttpTransport=true -packageName=com.omsclient.kotlin_sdk_trails_actions.generated -out=trails-actions/src/main/java/com/omsclient/kotlin_sdk_trails_actions/generated/TrailsApiClient.kt + +// WebRPC description and code-gen version +const val WEBRPC_VERSION = "v1" + +// Schema version of your RIDL schema +const val WEBRPC_SCHEMA_VERSION = "v1" + +// Schema hash generated from your RIDL schema +const val WEBRPC_SCHEMA_HASH = "95ad285f8962228eca9a635c79f8cad7804669be" + +// region Types + +@Serializable(with = IntentModeSerializer::class) +enum class IntentMode(val wireValue: String) { + SWAP("SWAP"), + FUND("FUND"), + EARN("EARN"), + PAY("PAY"), + WITHDRAW("WITHDRAW"), + UNKNOWN_DEFAULT("UNKNOWN_DEFAULT"); + + companion object { + fun fromWireValue(value: String): IntentMode { + return values().find { it.wireValue == value } ?: UNKNOWN_DEFAULT + } + } +} + +object IntentModeSerializer : KSerializer { + override val descriptor: SerialDescriptor = + String.serializer().descriptor + + override fun serialize(encoder: Encoder, value: IntentMode) { + encoder.encodeSerializableValue( + String.serializer(), + value.wireValue, + ) + } + + override fun deserialize(decoder: Decoder): IntentMode { + return IntentMode.fromWireValue( + decoder.decodeSerializableValue( + String.serializer(), + ), + ) + } +} + + +@Serializable(with = TradeTypeSerializer::class) +enum class TradeType(val wireValue: String) { + EXACT_INPUT("EXACT_INPUT"), + EXACT_OUTPUT("EXACT_OUTPUT"), + UNKNOWN_DEFAULT("UNKNOWN_DEFAULT"); + + companion object { + fun fromWireValue(value: String): TradeType { + return values().find { it.wireValue == value } ?: UNKNOWN_DEFAULT + } + } +} + +object TradeTypeSerializer : KSerializer { + override val descriptor: SerialDescriptor = + String.serializer().descriptor + + override fun serialize(encoder: Encoder, value: TradeType) { + encoder.encodeSerializableValue( + String.serializer(), + value.wireValue, + ) + } + + override fun deserialize(decoder: Decoder): TradeType { + return TradeType.fromWireValue( + decoder.decodeSerializableValue( + String.serializer(), + ), + ) + } +} + + +@Serializable(with = RouteProviderSerializer::class) +enum class RouteProvider(val wireValue: String) { + AUTO("AUTO"), + CCTP("CCTP"), + GASZIP("GASZIP"), + HYPERLANE("HYPERLANE"), + LIFI("LIFI"), + LZ_OFT("LZ_OFT"), + LZ_TRANSFER("LZ_TRANSFER"), + OIF("OIF"), + RELAY("RELAY"), + SOMNIA_EXCHANGE("SOMNIA_EXCHANGE"), + SOMNIA_SWAP("SOMNIA_SWAP"), + SUSHI("SUSHI"), + WETH("WETH"), + ZEROX("ZEROX"), + UNKNOWN_DEFAULT("UNKNOWN_DEFAULT"); + + companion object { + fun fromWireValue(value: String): RouteProvider { + return values().find { it.wireValue == value } ?: UNKNOWN_DEFAULT + } + } +} + +object RouteProviderSerializer : KSerializer { + override val descriptor: SerialDescriptor = + String.serializer().descriptor + + override fun serialize(encoder: Encoder, value: RouteProvider) { + encoder.encodeSerializableValue( + String.serializer(), + value.wireValue, + ) + } + + override fun deserialize(decoder: Decoder): RouteProvider { + return RouteProvider.fromWireValue( + decoder.decodeSerializableValue( + String.serializer(), + ), + ) + } +} + + +@Serializable(with = RoutePreferenceSerializer::class) +enum class RoutePreference(val wireValue: String) { + RECOMMENDED("RECOMMENDED"), + FASTEST("FASTEST"), + CHEAPEST("CHEAPEST"), + TRUSTLESS("TRUSTLESS"), + UNKNOWN_DEFAULT("UNKNOWN_DEFAULT"); + + companion object { + fun fromWireValue(value: String): RoutePreference { + return values().find { it.wireValue == value } ?: UNKNOWN_DEFAULT + } + } +} + +object RoutePreferenceSerializer : KSerializer { + override val descriptor: SerialDescriptor = + String.serializer().descriptor + + override fun serialize(encoder: Encoder, value: RoutePreference) { + encoder.encodeSerializableValue( + String.serializer(), + value.wireValue, + ) + } + + override fun deserialize(decoder: Decoder): RoutePreference { + return RoutePreference.fromWireValue( + decoder.decodeSerializableValue( + String.serializer(), + ), + ) + } +} + + +@Serializable(with = FundMethodSerializer::class) +enum class FundMethod(val wireValue: String) { + WALLET("WALLET"), + DIRECT_TRANSFER("DIRECT_TRANSFER"), + ONRAMP_MESH("ONRAMP_MESH"), + ONRAMP_MELD("ONRAMP_MELD"), + ONRAMP_BLUVO("ONRAMP_BLUVO"), + UNKNOWN_DEFAULT("UNKNOWN_DEFAULT"); + + companion object { + fun fromWireValue(value: String): FundMethod { + return values().find { it.wireValue == value } ?: UNKNOWN_DEFAULT + } + } +} + +object FundMethodSerializer : KSerializer { + override val descriptor: SerialDescriptor = + String.serializer().descriptor + + override fun serialize(encoder: Encoder, value: FundMethod) { + encoder.encodeSerializableValue( + String.serializer(), + value.wireValue, + ) + } + + override fun deserialize(decoder: Decoder): FundMethod { + return FundMethod.fromWireValue( + decoder.decodeSerializableValue( + String.serializer(), + ), + ) + } +} + + +@Serializable(with = EdgeRailSerializer::class) +enum class EdgeRail(val wireValue: String) { + SOLANA("SOLANA"), + UNKNOWN_DEFAULT("UNKNOWN_DEFAULT"); + + companion object { + fun fromWireValue(value: String): EdgeRail { + return values().find { it.wireValue == value } ?: UNKNOWN_DEFAULT + } + } +} + +object EdgeRailSerializer : KSerializer { + override val descriptor: SerialDescriptor = + String.serializer().descriptor + + override fun serialize(encoder: Encoder, value: EdgeRail) { + encoder.encodeSerializableValue( + String.serializer(), + value.wireValue, + ) + } + + override fun deserialize(decoder: Decoder): EdgeRail { + return EdgeRail.fromWireValue( + decoder.decodeSerializableValue( + String.serializer(), + ), + ) + } +} + + +@Serializable(with = EdgeModeSerializer::class) +enum class EdgeMode(val wireValue: String) { + ORIGIN("ORIGIN"), + DESTINATION("DESTINATION"), + UNKNOWN_DEFAULT("UNKNOWN_DEFAULT"); + + companion object { + fun fromWireValue(value: String): EdgeMode { + return values().find { it.wireValue == value } ?: UNKNOWN_DEFAULT + } + } +} + +object EdgeModeSerializer : KSerializer { + override val descriptor: SerialDescriptor = + String.serializer().descriptor + + override fun serialize(encoder: Encoder, value: EdgeMode) { + encoder.encodeSerializableValue( + String.serializer(), + value.wireValue, + ) + } + + override fun deserialize(decoder: Decoder): EdgeMode { + return EdgeMode.fromWireValue( + decoder.decodeSerializableValue( + String.serializer(), + ), + ) + } +} + + +@Serializable(with = EdgeStatusSerializer::class) +enum class EdgeStatus(val wireValue: String) { + PENDING("PENDING"), + DEPOSITED("DEPOSITED"), + FILLED("FILLED"), + REFUNDED("REFUNDED"), + FAILED("FAILED"), + UNKNOWN_DEFAULT("UNKNOWN_DEFAULT"); + + companion object { + fun fromWireValue(value: String): EdgeStatus { + return values().find { it.wireValue == value } ?: UNKNOWN_DEFAULT + } + } +} + +object EdgeStatusSerializer : KSerializer { + override val descriptor: SerialDescriptor = + String.serializer().descriptor + + override fun serialize(encoder: Encoder, value: EdgeStatus) { + encoder.encodeSerializableValue( + String.serializer(), + value.wireValue, + ) + } + + override fun deserialize(decoder: Decoder): EdgeStatus { + return EdgeStatus.fromWireValue( + decoder.decodeSerializableValue( + String.serializer(), + ), + ) + } +} + + +@Serializable(with = IntentProtocolVersionSerializer::class) +enum class IntentProtocolVersion(val wireValue: String) { + v1("v1"), + v1_5("v1.5"), + UNKNOWN_DEFAULT("UNKNOWN_DEFAULT"); + + companion object { + fun fromWireValue(value: String): IntentProtocolVersion { + return values().find { it.wireValue == value } ?: UNKNOWN_DEFAULT + } + } +} + +object IntentProtocolVersionSerializer : KSerializer { + override val descriptor: SerialDescriptor = + String.serializer().descriptor + + override fun serialize(encoder: Encoder, value: IntentProtocolVersion) { + encoder.encodeSerializableValue( + String.serializer(), + value.wireValue, + ) + } + + override fun deserialize(decoder: Decoder): IntentProtocolVersion { + return IntentProtocolVersion.fromWireValue( + decoder.decodeSerializableValue( + String.serializer(), + ), + ) + } +} + + +@Serializable(with = IntentStatusSerializer::class) +enum class IntentStatus(val wireValue: String) { + QUOTED("QUOTED"), + COMMITTED("COMMITTED"), + EXECUTING("EXECUTING"), + FAILED("FAILED"), + SUCCEEDED("SUCCEEDED"), + ABORTED("ABORTED"), + REFUNDED("REFUNDED"), + INVALID("INVALID"), + UNKNOWN_DEFAULT("UNKNOWN_DEFAULT"); + + companion object { + fun fromWireValue(value: String): IntentStatus { + return values().find { it.wireValue == value } ?: UNKNOWN_DEFAULT + } + } +} + +object IntentStatusSerializer : KSerializer { + override val descriptor: SerialDescriptor = + String.serializer().descriptor + + override fun serialize(encoder: Encoder, value: IntentStatus) { + encoder.encodeSerializableValue( + String.serializer(), + value.wireValue, + ) + } + + override fun deserialize(decoder: Decoder): IntentStatus { + return IntentStatus.fromWireValue( + decoder.decodeSerializableValue( + String.serializer(), + ), + ) + } +} + + +@Serializable(with = TransactionTypeSerializer::class) +enum class TransactionType(val wireValue: String) { + UNKNOWN("UNKNOWN"), + DEPOSIT("DEPOSIT"), + ORIGIN("ORIGIN"), + DESTINATION("DESTINATION"), + ROUTE("ROUTE"), + REFUND("REFUND"), + UNKNOWN_DEFAULT("UNKNOWN_DEFAULT"); + + companion object { + fun fromWireValue(value: String): TransactionType { + return values().find { it.wireValue == value } ?: UNKNOWN_DEFAULT + } + } +} + +object TransactionTypeSerializer : KSerializer { + override val descriptor: SerialDescriptor = + String.serializer().descriptor + + override fun serialize(encoder: Encoder, value: TransactionType) { + encoder.encodeSerializableValue( + String.serializer(), + value.wireValue, + ) + } + + override fun deserialize(decoder: Decoder): TransactionType { + return TransactionType.fromWireValue( + decoder.decodeSerializableValue( + String.serializer(), + ), + ) + } +} + + +@Serializable(with = TransactionContextSerializer::class) +enum class TransactionContext(val wireValue: String) { + NONE("NONE"), + CCTPV2_MESSAGE("CCTPV2_MESSAGE"), + LZ_COMPOSE("LZ_COMPOSE"), + LZ_RECEIVE("LZ_RECEIVE"), + HYPERLANE_PAY_FOR_GAS("HYPERLANE_PAY_FOR_GAS"), + UNKNOWN_DEFAULT("UNKNOWN_DEFAULT"); + + companion object { + fun fromWireValue(value: String): TransactionContext { + return values().find { it.wireValue == value } ?: UNKNOWN_DEFAULT + } + } +} + +object TransactionContextSerializer : KSerializer { + override val descriptor: SerialDescriptor = + String.serializer().descriptor + + override fun serialize(encoder: Encoder, value: TransactionContext) { + encoder.encodeSerializableValue( + String.serializer(), + value.wireValue, + ) + } + + override fun deserialize(decoder: Decoder): TransactionContext { + return TransactionContext.fromWireValue( + decoder.decodeSerializableValue( + String.serializer(), + ), + ) + } +} + + +@Serializable(with = TransactionStatusSerializer::class) +enum class TransactionStatus(val wireValue: String) { + UNKNOWN("UNKNOWN"), + ON_HOLD("ON_HOLD"), + PENDING("PENDING"), + RELAYING("RELAYING"), + SENT("SENT"), + ERRORED("ERRORED"), + MINING("MINING"), + SUCCEEDED("SUCCEEDED"), + FAILED("FAILED"), + ABORTED("ABORTED"), + REVERTED("REVERTED"), + UNKNOWN_DEFAULT("UNKNOWN_DEFAULT"); + + companion object { + fun fromWireValue(value: String): TransactionStatus { + return values().find { it.wireValue == value } ?: UNKNOWN_DEFAULT + } + } +} + +object TransactionStatusSerializer : KSerializer { + override val descriptor: SerialDescriptor = + String.serializer().descriptor + + override fun serialize(encoder: Encoder, value: TransactionStatus) { + encoder.encodeSerializableValue( + String.serializer(), + value.wireValue, + ) + } + + override fun deserialize(decoder: Decoder): TransactionStatus { + return TransactionStatus.fromWireValue( + decoder.decodeSerializableValue( + String.serializer(), + ), + ) + } +} + + +@Serializable(with = ChainGasUsageStatusSerializer::class) +enum class ChainGasUsageStatus(val wireValue: String) { + NORMAL("NORMAL"), + BUSY("BUSY"), + VERY_BUSY("VERY_BUSY"), + UNKNOWN_DEFAULT("UNKNOWN_DEFAULT"); + + companion object { + fun fromWireValue(value: String): ChainGasUsageStatus { + return values().find { it.wireValue == value } ?: UNKNOWN_DEFAULT + } + } +} + +object ChainGasUsageStatusSerializer : KSerializer { + override val descriptor: SerialDescriptor = + String.serializer().descriptor + + override fun serialize(encoder: Encoder, value: ChainGasUsageStatus) { + encoder.encodeSerializableValue( + String.serializer(), + value.wireValue, + ) + } + + override fun deserialize(decoder: Decoder): ChainGasUsageStatus { + return ChainGasUsageStatus.fromWireValue( + decoder.decodeSerializableValue( + String.serializer(), + ), + ) + } +} + + +@Serializable(with = CCTPTransferStatusSerializer::class) +enum class CCTPTransferStatus(val wireValue: String) { + UNKNOWN("UNKNOWN"), + ON_HOLD("ON_HOLD"), + PENDING("PENDING"), + FETCHING("FETCHING"), + COMPLETE("COMPLETE"), + FAILED("FAILED"), + UNKNOWN_DEFAULT("UNKNOWN_DEFAULT"); + + companion object { + fun fromWireValue(value: String): CCTPTransferStatus { + return values().find { it.wireValue == value } ?: UNKNOWN_DEFAULT + } + } +} + +object CCTPTransferStatusSerializer : KSerializer { + override val descriptor: SerialDescriptor = + String.serializer().descriptor + + override fun serialize(encoder: Encoder, value: CCTPTransferStatus) { + encoder.encodeSerializableValue( + String.serializer(), + value.wireValue, + ) + } + + override fun deserialize(decoder: Decoder): CCTPTransferStatus { + return CCTPTransferStatus.fromWireValue( + decoder.decodeSerializableValue( + String.serializer(), + ), + ) + } +} + + +@Serializable(with = RelayTransferStatusSerializer::class) +enum class RelayTransferStatus(val wireValue: String) { + UNKNOWN("UNKNOWN"), + ON_HOLD("ON_HOLD"), + PENDING("PENDING"), + FETCHING("FETCHING"), + COMPLETE("COMPLETE"), + REFUNDED("REFUNDED"), + FAILED("FAILED"), + UNKNOWN_DEFAULT("UNKNOWN_DEFAULT"); + + companion object { + fun fromWireValue(value: String): RelayTransferStatus { + return values().find { it.wireValue == value } ?: UNKNOWN_DEFAULT + } + } +} + +object RelayTransferStatusSerializer : KSerializer { + override val descriptor: SerialDescriptor = + String.serializer().descriptor + + override fun serialize(encoder: Encoder, value: RelayTransferStatus) { + encoder.encodeSerializableValue( + String.serializer(), + value.wireValue, + ) + } + + override fun deserialize(decoder: Decoder): RelayTransferStatus { + return RelayTransferStatus.fromWireValue( + decoder.decodeSerializableValue( + String.serializer(), + ), + ) + } +} + + +@Serializable(with = LZTransferStatusSerializer::class) +enum class LZTransferStatus(val wireValue: String) { + UNKNOWN("UNKNOWN"), + ON_HOLD("ON_HOLD"), + PENDING("PENDING"), + FETCHING("FETCHING"), + COMPLETE("COMPLETE"), + FAILED("FAILED"), + UNKNOWN_DEFAULT("UNKNOWN_DEFAULT"); + + companion object { + fun fromWireValue(value: String): LZTransferStatus { + return values().find { it.wireValue == value } ?: UNKNOWN_DEFAULT + } + } +} + +object LZTransferStatusSerializer : KSerializer { + override val descriptor: SerialDescriptor = + String.serializer().descriptor + + override fun serialize(encoder: Encoder, value: LZTransferStatus) { + encoder.encodeSerializableValue( + String.serializer(), + value.wireValue, + ) + } + + override fun deserialize(decoder: Decoder): LZTransferStatus { + return LZTransferStatus.fromWireValue( + decoder.decodeSerializableValue( + String.serializer(), + ), + ) + } +} + + +@Serializable(with = HyperlaneTransferStatusSerializer::class) +enum class HyperlaneTransferStatus(val wireValue: String) { + UNKNOWN("UNKNOWN"), + ON_HOLD("ON_HOLD"), + PENDING("PENDING"), + FETCHING("FETCHING"), + COMPLETE("COMPLETE"), + FAILED("FAILED"), + UNKNOWN_DEFAULT("UNKNOWN_DEFAULT"); + + companion object { + fun fromWireValue(value: String): HyperlaneTransferStatus { + return values().find { it.wireValue == value } ?: UNKNOWN_DEFAULT + } + } +} + +object HyperlaneTransferStatusSerializer : KSerializer { + override val descriptor: SerialDescriptor = + String.serializer().descriptor + + override fun serialize(encoder: Encoder, value: HyperlaneTransferStatus) { + encoder.encodeSerializableValue( + String.serializer(), + value.wireValue, + ) + } + + override fun deserialize(decoder: Decoder): HyperlaneTransferStatus { + return HyperlaneTransferStatus.fromWireValue( + decoder.decodeSerializableValue( + String.serializer(), + ), + ) + } +} + + +@Serializable(with = SortOrderSerializer::class) +enum class SortOrder(val wireValue: String) { + DESC("DESC"), + ASC("ASC"), + UNKNOWN_DEFAULT("UNKNOWN_DEFAULT"); + + companion object { + fun fromWireValue(value: String): SortOrder { + return values().find { it.wireValue == value } ?: UNKNOWN_DEFAULT + } + } +} + +object SortOrderSerializer : KSerializer { + override val descriptor: SerialDescriptor = + String.serializer().descriptor + + override fun serialize(encoder: Encoder, value: SortOrder) { + encoder.encodeSerializableValue( + String.serializer(), + value.wireValue, + ) + } + + override fun deserialize(decoder: Decoder): SortOrder { + return SortOrder.fromWireValue( + decoder.decodeSerializableValue( + String.serializer(), + ), + ) + } +} + + + +@Serializable +data class QuoteIntentRequest( + @SerialName("ownerAddress") + val ownerAddress: String, + @SerialName("originChainId") + val originChainId: ULong, + @SerialName("originTokenAddress") + val originTokenAddress: String, + @SerialName("destinationChainId") + val destinationChainId: ULong, + @SerialName("destinationTokenAddress") + val destinationTokenAddress: String, + @SerialName("destinationToAddress") + val destinationToAddress: String? = null, + @SerialName("destinationApproveAddress") + val destinationApproveAddress: String? = null, + @SerialName("destinationCallData") + val destinationCallData: String? = null, + @SerialName("destinationCallValue") + val destinationCallValue: String? = null, + @SerialName("originTokenAmount") + val originTokenAmount: String? = null, + @SerialName("destinationTokenAmount") + val destinationTokenAmount: String? = null, + @SerialName("tradeType") + val tradeType: TradeType? = null, + @SerialName("fundMethod") + val fundMethod: FundMethod? = null, + @SerialName("mode") + val mode: IntentMode? = null, + @SerialName("onlyNativeGasFee") + val onlyNativeGasFee: Boolean? = null, + @SerialName("options") + val options: QuoteIntentRequestOptions? = null, +) + + + +@Serializable +data class QuoteIntentRequestOptions( + @SerialName("intentProtocol") + val intentProtocol: IntentProtocolVersion? = null, + @SerialName("swapProvider") + val swapProvider: RouteProvider? = null, + @SerialName("bridgeProvider") + val bridgeProvider: RouteProvider? = null, + @SerialName("swapProviderFallback") + val swapProviderFallback: Boolean? = null, + @SerialName("bridgeProviderFallback") + val bridgeProviderFallback: Boolean? = null, + @SerialName("preference") + val preference: RoutePreference? = null, + @SerialName("slippageTolerance") + val slippageTolerance: Double? = null, + @SerialName("trailsAddressOverrides") + val trailsAddressOverrides: TrailsAddressOverrides? = null, +) + + + +@Serializable +data class EdgeQuoteRequest( + @SerialName("rail") + val rail: EdgeRail, + @SerialName("mode") + val mode: EdgeMode, + @SerialName("provider") + val provider: RouteProvider? = null, + @SerialName("tradeType") + val tradeType: TradeType? = null, + @SerialName("originChainId") + val originChainId: ULong? = null, + @SerialName("originAddress") + val originAddress: String? = null, + @SerialName("originTokenAddress") + val originTokenAddress: String? = null, + @SerialName("originTokenAmount") + val originTokenAmount: String? = null, + @SerialName("refundAddress") + val refundAddress: String? = null, + @SerialName("destinationChainId") + val destinationChainId: ULong? = null, + @SerialName("destinationAddress") + val destinationAddress: String? = null, + @SerialName("destinationTokenAddress") + val destinationTokenAddress: String? = null, +) + + + +@Serializable +data class EdgeHandoff( + @SerialName("chainId") + val chainId: ULong, + @SerialName("tokenAddress") + val tokenAddress: String, + @SerialName("amount") + val amount: String, + @SerialName("recipientAddress") + val recipientAddress: String, +) + + + +@Serializable +data class EdgeQuoteResponse( + @SerialName("rail") + val rail: EdgeRail, + @SerialName("mode") + val mode: EdgeMode, + @SerialName("provider") + val provider: RouteProvider, + @SerialName("tradeType") + val tradeType: TradeType, + @SerialName("originTokenAmount") + val originTokenAmount: String? = null, + @SerialName("requestId") + val requestId: String, + @SerialName("handoff") + val handoff: EdgeHandoff? = null, + @SerialName("providerQuote") + val providerQuote: JsonElement, + @SerialName("executionPlan") + val executionPlan: List, +) + + + +@Serializable +data class IntentEdgeMetadata( + @SerialName("edgeId") + val edgeId: String, + @SerialName("rail") + val rail: EdgeRail, + @SerialName("mode") + val mode: EdgeMode, + @SerialName("edgeStatus") + val edgeStatus: EdgeStatus, + @SerialName("originChainId") + val originChainId: ULong, + @SerialName("relayRequestId") + val relayRequestId: String, + @SerialName("edgeTokenAmount") + val edgeTokenAmount: String? = null, + @SerialName("edgeTokenAddress") + val edgeTokenAddress: String? = null, + @SerialName("edgeUserAddress") + val edgeUserAddress: String? = null, + @SerialName("initTransactionHash") + val initTransactionHash: String? = null, + @SerialName("fillTransactionHash") + val fillTransactionHash: String? = null, + @SerialName("refundTransactionHash") + val refundTransactionHash: String? = null, + @SerialName("edgeTokenMetadata") + val edgeTokenMetadata: TokenMetadata? = null, + @SerialName("createdAt") + val createdAt: String? = null, +) + + + +@Serializable +data class PassthroughInfo( + @SerialName("eligible") + val eligible: Boolean, + @SerialName("passthroughTransaction") + val passthroughTransaction: PassThroughTransaction? = null, + @SerialName("transactionStates") + val transactionStates: List? = null, + @SerialName("quote") + val quote: IntentProviderQuote? = null, + @SerialName("fees") + val fees: IntentFees? = null, +) + + + +@Serializable +data class Intent( + @SerialName("intentId") + val intentId: String, + @SerialName("status") + val status: IntentStatus, + @SerialName("quoteRequest") + val quoteRequest: QuoteIntentRequest, + @SerialName("ownerAddress") + val ownerAddress: String, + @SerialName("originChainId") + val originChainId: ULong, + @SerialName("destinationChainId") + val destinationChainId: ULong, + @SerialName("originTokenAddress") + val originTokenAddress: String, + @SerialName("destinationTokenAddress") + val destinationTokenAddress: String, + @SerialName("originIntentAddress") + val originIntentAddress: String, + @SerialName("destinationIntentAddress") + val destinationIntentAddress: String? = null, + @SerialName("salt") + val salt: String, + @SerialName("depositTransaction") + val depositTransaction: DepositTransaction, + @SerialName("edge") + val edge: IntentEdgeMetadata? = null, + @SerialName("passthrough") + val passthrough: Boolean? = null, + @SerialName("originCalls") + val originCalls: IntentCalls, + @SerialName("destinationCalls") + val destinationCalls: IntentCalls? = null, + @SerialName("originPrecondition") + val originPrecondition: TransactionPrecondition, + @SerialName("destinationPrecondition") + val destinationPrecondition: TransactionPrecondition? = null, + @SerialName("originMetaTxn") + val originMetaTxn: MetaTxn, + @SerialName("destinationMetaTxn") + val destinationMetaTxn: MetaTxn? = null, + @SerialName("quote") + val quote: IntentProviderQuote, + @SerialName("fees") + val fees: IntentFees, + @SerialName("gasFeeOptions") + val gasFeeOptions: GasFeeOptions? = null, + @SerialName("trailsVersion") + val trailsVersion: String, + @SerialName("intentProtocol") + val intentProtocol: IntentProtocolVersion? = null, + @SerialName("trailsContracts") + val trailsContracts: TrailsContracts, + @SerialName("expiresAt") + val expiresAt: String, + @SerialName("updatedAt") + val updatedAt: String? = null, + @SerialName("createdAt") + val createdAt: String? = null, + @SerialName("isTestnet") + val isTestnet: Boolean, +) + + + +@Serializable +data class DepositTransaction( + @SerialName("toAddress") + val toAddress: String, + @SerialName("tokenAddress") + val tokenAddress: String, + @SerialName("decimals") + val decimals: UByte? = null, + @SerialName("amount") + val amount: String, + @SerialName("chainId") + val chainId: ULong, + @SerialName("to") + val to: String, + @SerialName("data") + val `data`: String, + @SerialName("value") + val value: String, +) + + + +@Serializable +data class PassThroughTransaction( + @SerialName("toAddress") + val toAddress: String, + @SerialName("tokenAddress") + val tokenAddress: String, + @SerialName("decimals") + val decimals: UByte? = null, + @SerialName("amount") + val amount: String, + @SerialName("chainId") + val chainId: ULong, + @SerialName("to") + val to: String, + @SerialName("data") + val `data`: String, + @SerialName("value") + val value: String, +) + + + +@Serializable +data class TransactionStateInfo( + @SerialName("id") + val id: String, + @SerialName("label") + val label: String, + @SerialName("chainId") + val chainId: ULong, +) + + + +@Serializable +data class IntentCalls( + @SerialName("chainId") + val chainId: ULong, + @SerialName("space") + val space: String? = null, + @SerialName("nonce") + val nonce: String? = null, + @SerialName("calls") + val calls: List, +) + + + +@Serializable +data class TransactionCall( + @SerialName("to") + val to: String, + @SerialName("value") + val value: String? = null, + @SerialName("data") + val `data`: String? = null, + @SerialName("gasLimit") + val gasLimit: String? = null, + @SerialName("delegateCall") + val delegateCall: Boolean? = null, + @SerialName("onlyFallback") + val onlyFallback: Boolean? = null, + @SerialName("behaviorOnError") + val behaviorOnError: UByte? = null, +) + + + +@Serializable +data class TransactionPrecondition( + @SerialName("type") + val type: String, + @SerialName("chainId") + val chainId: ULong, + @SerialName("ownerAddress") + val ownerAddress: String, + @SerialName("tokenAddress") + val tokenAddress: String, + @SerialName("minAmount") + val minAmount: String, +) + + + +@Serializable +data class MetaTxn( + @SerialName("id") + val id: String, + @SerialName("chainId") + val chainId: ULong, + @SerialName("walletAddress") + val walletAddress: String, + @SerialName("contract") + val contract: String, + @SerialName("input") + val input: String, + @SerialName("bridgeGas") + val bridgeGas: String? = null, +) + + + +@Serializable +data class IntentHistory( + @SerialName("intentId") + val intentId: String, + @SerialName("status") + val status: IntentStatus, + @SerialName("expiresAt") + val expiresAt: String, + @SerialName("updatedAt") + val updatedAt: String? = null, + @SerialName("createdAt") + val createdAt: String? = null, + @SerialName("receipt") + val receipt: IntentReceipt, + @SerialName("hasBalance") + val hasBalance: Boolean? = null, + @SerialName("balances") + val balances: List? = null, +) + + + +@Serializable +data class IntentAddressBalance( + @SerialName("intentAddress") + val intentAddress: String, + @SerialName("chainId") + val chainId: ULong, + @SerialName("tokens") + val tokens: List, +) + + + +@Serializable +data class IntentTokenBalance( + @SerialName("contractAddress") + val contractAddress: String, + @SerialName("balance") + val balance: String, + @SerialName("balanceUsd") + val balanceUsd: String, + @SerialName("priceUsd") + val priceUsd: String, + @SerialName("decimals") + val decimals: UByte, + @SerialName("chainId") + val chainId: ULong, + @SerialName("symbol") + val symbol: String, +) + + + +@Serializable +data class IntentReceiptSummary( + @SerialName("intentId") + val intentId: String, + @SerialName("status") + val status: IntentStatus, + @SerialName("ownerAddress") + val ownerAddress: String, + @SerialName("originChainId") + val originChainId: ULong, + @SerialName("destinationChainId") + val destinationChainId: ULong, + @SerialName("mode") + val mode: IntentMode? = null, + @SerialName("tradeType") + val tradeType: TradeType, + @SerialName("routeProviders") + val routeProviders: List, + @SerialName("originIntentAddress") + val originIntentAddress: String, + @SerialName("originTokenAddress") + val originTokenAddress: String, + @SerialName("originTokenAmount") + val originTokenAmount: String, + @SerialName("quotedOriginTokenAmount") + val quotedOriginTokenAmount: String, + @SerialName("originTokenMetadata") + val originTokenMetadata: TokenMetadata, + @SerialName("destinationIntentAddress") + val destinationIntentAddress: String, + @SerialName("destinationTokenAddress") + val destinationTokenAddress: String? = null, + @SerialName("destinationTokenAmount") + val destinationTokenAmount: String? = null, + @SerialName("quotedDestinationTokenAmount") + val quotedDestinationTokenAmount: String? = null, + @SerialName("destinationToAddress") + val destinationToAddress: String? = null, + @SerialName("destinationTokenMetadata") + val destinationTokenMetadata: TokenMetadata, + @SerialName("destinationHasCallData") + val destinationHasCallData: Boolean, + @SerialName("destinationHasCallValue") + val destinationHasCallValue: Boolean, + @SerialName("edge") + val edge: IntentEdgeMetadata? = null, + @SerialName("memo") + val memo: String? = null, + @SerialName("createdAt") + val createdAt: String, + @SerialName("expiresAt") + val expiresAt: String, + @SerialName("startedAt") + val startedAt: String? = null, + @SerialName("finishedAt") + val finishedAt: String? = null, +) + + + +@Serializable +data class IntentReceipt( + @SerialName("intentId") + val intentId: String, + @SerialName("status") + val status: IntentStatus, + @SerialName("ownerAddress") + val ownerAddress: String, + @SerialName("originChainId") + val originChainId: ULong, + @SerialName("destinationChainId") + val destinationChainId: ULong, + @SerialName("depositTransaction") + val depositTransaction: IntentTransaction, + @SerialName("originTransaction") + val originTransaction: IntentTransaction, + @SerialName("destinationTransaction") + val destinationTransaction: IntentTransaction? = null, + @SerialName("refundTransaction") + val refundTransaction: IntentTransaction? = null, + @SerialName("summary") + val summary: IntentReceiptSummary, + @SerialName("edge") + val edge: IntentEdgeMetadata? = null, + @SerialName("updatedAt") + val updatedAt: String? = null, + @SerialName("createdAt") + val createdAt: String? = null, +) + + + +@Serializable +data class IntentTransaction( + @SerialName("intentId") + val intentId: String, + @SerialName("status") + val status: TransactionStatus, + @SerialName("statusReason") + val statusReason: String? = null, + @SerialName("chainId") + val chainId: ULong, + @SerialName("type") + val type: TransactionType, + @SerialName("context") + val context: TransactionContext, + @SerialName("fromAddress") + val fromAddress: String, + @SerialName("toAddress") + val toAddress: String, + @SerialName("tokenAddress") + val tokenAddress: String, + @SerialName("tokenAmount") + val tokenAmount: String, + @SerialName("bridgeGas") + val bridgeGas: String? = null, + @SerialName("metaTxnId") + val metaTxnId: String? = null, + @SerialName("metaTxnFeeQuote") + val metaTxnFeeQuote: String? = null, + @SerialName("precondition") + val precondition: TransactionPrecondition? = null, + @SerialName("depositIntentEntry") + val depositIntentEntry: DepositIntentEntry? = null, + @SerialName("txnHash") + val txnHash: String? = null, + @SerialName("txnMinedAt") + val txnMinedAt: String? = null, + @SerialName("updatedAt") + val updatedAt: String? = null, + @SerialName("createdAt") + val createdAt: String? = null, +) + + + +@Serializable +data class PriceImpact( + @SerialName("priceImpact") + val priceImpact: Double, + @SerialName("priceImpactUsd") + val priceImpactUsd: Double, +) + + + +@Serializable +data class PriceImpactDetails( + @SerialName("executionPriceImpact") + val executionPriceImpact: PriceImpact, + @SerialName("marketPriceImpact") + val marketPriceImpact: PriceImpact, + @SerialName("providerFeesPriceImpact") + val providerFeesPriceImpact: PriceImpact, + @SerialName("trailsFeesPriceImpact") + val trailsFeesPriceImpact: PriceImpact, + @SerialName("netPriceImpact") + val netPriceImpact: PriceImpact, +) + + + +@Serializable +data class IntentProviderQuote( + @SerialName("routeProviders") + val routeProviders: List, + @SerialName("routeProvidersRequestIds") + val routeProvidersRequestIds: List, + @SerialName("routeProvidersFeeUsd") + val routeProvidersFeeUsd: List, + @SerialName("estimatedDuration") + val estimatedDuration: Double? = null, + @SerialName("fromAmount") + val fromAmount: String, + @SerialName("fromAmountMin") + val fromAmountMin: String, + @SerialName("fromAmountUsd") + val fromAmountUsd: Double, + @SerialName("fromAmountMinUsd") + val fromAmountMinUsd: Double, + @SerialName("toAmount") + val toAmount: String, + @SerialName("toAmountMin") + val toAmountMin: String, + @SerialName("toAmountUsd") + val toAmountUsd: Double, + @SerialName("toAmountMinUsd") + val toAmountMinUsd: Double, + @SerialName("maxSlippage") + val maxSlippage: Double, + @SerialName("priceImpact") + val priceImpact: Double, + @SerialName("priceImpactUsd") + val priceImpactUsd: Double, + @SerialName("priceImpactDetails") + val priceImpactDetails: PriceImpactDetails, +) + + + +@Serializable +data class IntentFees( + @SerialName("originGas") + val originGas: IntentTransactionGasFee, + @SerialName("destinationGas") + val destinationGas: IntentTransactionGasFee? = null, + @SerialName("provider") + val provider: IntentProviderFees, + @SerialName("feeTokenAddress") + val feeTokenAddress: String, + @SerialName("feeTokenAmount") + val feeTokenAmount: String, + @SerialName("feeTokenUsd") + val feeTokenUsd: Double, + @SerialName("feeTokenTotal") + val feeTokenTotal: String, + @SerialName("gasFeeTotal") + val gasFeeTotal: String, + @SerialName("gasFeeUsd") + val gasFeeUsd: Double, + @SerialName("trailsFeeTotal") + val trailsFeeTotal: String, + @SerialName("trailsFeeUsd") + val trailsFeeUsd: Double, + @SerialName("collectorFeeTotal") + val collectorFeeTotal: String, + @SerialName("collectorFeeUsd") + val collectorFeeUsd: Double, + @SerialName("providerFeeTotal") + val providerFeeTotal: String, + @SerialName("providerFeeUsd") + val providerFeeUsd: Double, + @SerialName("totalFeeAmount") + val totalFeeAmount: String, + @SerialName("totalFeeUsd") + val totalFeeUsd: Double, +) + + + +@Serializable +data class IntentProviderFees( + @SerialName("quoteProvider") + val quoteProvider: String, + @SerialName("quoteProviderFee") + val quoteProviderFee: String, + @SerialName("quoteProviderFeeUsd") + val quoteProviderFeeUsd: Double, + @SerialName("trailsFee") + val trailsFee: String, + @SerialName("trailsFeeUsd") + val trailsFeeUsd: Double, + @SerialName("quoteProviderWithTrailsFee") + val quoteProviderWithTrailsFee: String, + @SerialName("providerWithTrailsFeeUsd") + val providerWithTrailsFeeUsd: Double, + @SerialName("totalFeeAmount") + val totalFeeAmount: String, + @SerialName("totalFeeUsd") + val totalFeeUsd: Double, +) + + + +@Serializable +data class IntentSummary( + @SerialName("intentId") + val intentId: String, + @SerialName("status") + val status: IntentStatus, + @SerialName("ownerAddress") + val ownerAddress: String, + @SerialName("originChainId") + val originChainId: ULong, + @SerialName("destinationChainId") + val destinationChainId: ULong, + @SerialName("originIntentAddress") + val originIntentAddress: String, + @SerialName("destinationIntentAddress") + val destinationIntentAddress: String, + @SerialName("depositTransactionHash") + val depositTransactionHash: String? = null, + @SerialName("depositTransactionStatus") + val depositTransactionStatus: TransactionStatus, + @SerialName("originTransactionHash") + val originTransactionHash: String? = null, + @SerialName("originTransactionStatus") + val originTransactionStatus: TransactionStatus, + @SerialName("destinationTransactionHash") + val destinationTransactionHash: String? = null, + @SerialName("destinationTransactionStatus") + val destinationTransactionStatus: TransactionStatus, + @SerialName("originTokenAddress") + val originTokenAddress: String, + @SerialName("originTokenAmount") + val originTokenAmount: String, + @SerialName("quotedOriginTokenAmount") + val quotedOriginTokenAmount: String, + @SerialName("originTokenMetadata") + val originTokenMetadata: TokenMetadata, + @SerialName("destinationTokenAddress") + val destinationTokenAddress: String, + @SerialName("destinationTokenAmount") + val destinationTokenAmount: String, + @SerialName("quotedDestinationTokenAmount") + val quotedDestinationTokenAmount: String, + @SerialName("destinationTokenMetadata") + val destinationTokenMetadata: TokenMetadata, + @SerialName("destinationToAddress") + val destinationToAddress: String, + @SerialName("expiresAt") + val expiresAt: String, + @SerialName("updatedAt") + val updatedAt: String? = null, + @SerialName("createdAt") + val createdAt: String, +) + + + +@Serializable +data class IntentTransactionGasFee( + @SerialName("chainId") + val chainId: ULong, + @SerialName("totalGasLimit") + val totalGasLimit: String, + @SerialName("gasPrice") + val gasPrice: String, + @SerialName("nativeTokenSymbol") + val nativeTokenSymbol: String, + @SerialName("nativeTokenPriceUsd") + val nativeTokenPriceUsd: Double? = null, + @SerialName("chainGasUsageStatus") + val chainGasUsageStatus: ChainGasUsageStatus, + @SerialName("totalFeeAmount") + val totalFeeAmount: String, + @SerialName("totalFeeUsd") + val totalFeeUsd: Double, + @SerialName("metaTxnFeeDetails") + val metaTxnFeeDetails: MetaTxnFeeDetails, + @SerialName("metaTxnGasQuote") + val metaTxnGasQuote: String, +) + + + +@Serializable +data class MetaTxnFeeDetails( + @SerialName("metaTxnId") + val metaTxnId: String, + @SerialName("estimatedGasLimit") + val estimatedGasLimit: String, + @SerialName("feeNative") + val feeNative: String, +) + + + +@Serializable +data class ChainMetadata( + @SerialName("chainId") + val chainId: ULong, + @SerialName("name") + val name: String, + @SerialName("logoUri") + val logoUri: String? = null, + @SerialName("testnet") + val testnet: Boolean? = null, +) + + + +@Serializable +data class TokenMetadata( + @SerialName("chainId") + val chainId: ULong, + @SerialName("tokenAddress") + val tokenAddress: String, + @SerialName("name") + val name: String, + @SerialName("symbol") + val symbol: String, + @SerialName("decimals") + val decimals: UByte? = null, + @SerialName("logoUri") + val logoUri: String? = null, +) + + + +@Serializable +data class Token( + @SerialName("chainId") + val chainId: ULong, + @SerialName("tokenAddress") + val tokenAddress: String, + @SerialName("tokenSymbol") + val tokenSymbol: String? = null, +) + + + +@Serializable +data class TokenPrice( + @SerialName("token") + val token: Token, + @SerialName("priceUsd") + val priceUsd: Double? = null, + @SerialName("updatedAt") + val updatedAt: String, +) + + + +@Serializable +data class ExchangeRate( + @SerialName("name") + val name: String, + @SerialName("symbol") + val symbol: String, + @SerialName("value") + val value: Double, + @SerialName("vsCurrency") + val vsCurrency: String, + @SerialName("currencyType") + val currencyType: String, +) + + + +@Serializable +data class CCTPTransfer( + @SerialName("id") + val id: ULong, + @SerialName("intentId") + val intentId: String, + @SerialName("originChainId") + val originChainId: ULong, + @SerialName("destinationChainId") + val destinationChainId: ULong, + @SerialName("originTxnId") + val originTxnId: ULong, + @SerialName("originTxnHash") + val originTxnHash: String, + @SerialName("destinationTxnId") + val destinationTxnId: ULong, + @SerialName("message") + val message: String, + @SerialName("attestation") + val attestation: String, + @SerialName("status") + val status: UByte, + @SerialName("statusReason") + val statusReason: String? = null, + @SerialName("createdAt") + val createdAt: String, + @SerialName("updatedAt") + val updatedAt: String, +) + + + +@Serializable +data class RelayTransfer( + @SerialName("id") + val id: ULong, + @SerialName("intentId") + val intentId: String, + @SerialName("originChainId") + val originChainId: ULong, + @SerialName("destinationChainId") + val destinationChainId: ULong, + @SerialName("originTxnId") + val originTxnId: ULong, + @SerialName("originTxnHash") + val originTxnHash: String, + @SerialName("destinationTxnId") + val destinationTxnId: ULong, + @SerialName("destinationTxnHash") + val destinationTxnHash: String, + @SerialName("status") + val status: UByte, + @SerialName("statusReason") + val statusReason: String? = null, + @SerialName("createdAt") + val createdAt: String, + @SerialName("updatedAt") + val updatedAt: String, +) + + + +@Serializable +data class LZTransfer( + @SerialName("id") + val id: ULong, + @SerialName("intentId") + val intentId: String, + @SerialName("originChainId") + val originChainId: ULong, + @SerialName("destinationChainId") + val destinationChainId: ULong, + @SerialName("originTxnId") + val originTxnId: ULong, + @SerialName("originTxnHash") + val originTxnHash: String, + @SerialName("destinationTxnId") + val destinationTxnId: ULong, + @SerialName("destinationTxnHash") + val destinationTxnHash: String, + @SerialName("quoteId") + val quoteId: String? = null, + @SerialName("routeProvider") + val routeProvider: RouteProvider, + @SerialName("status") + val status: UByte, + @SerialName("statusReason") + val statusReason: String? = null, + @SerialName("retryCount") + val retryCount: UInt, + @SerialName("lastRetryAt") + val lastRetryAt: String? = null, + @SerialName("createdAt") + val createdAt: String, + @SerialName("updatedAt") + val updatedAt: String, +) + + + +@Serializable +data class HyperlaneTransfer( + @SerialName("id") + val id: ULong, + @SerialName("intentId") + val intentId: String, + @SerialName("originChainId") + val originChainId: ULong, + @SerialName("destinationChainId") + val destinationChainId: ULong, + @SerialName("originTxnId") + val originTxnId: ULong, + @SerialName("originTxnHash") + val originTxnHash: String, + @SerialName("destinationTxnId") + val destinationTxnId: ULong, + @SerialName("destinationTxnHash") + val destinationTxnHash: String, + @SerialName("expectedOriginRouter") + val expectedOriginRouter: String? = null, + @SerialName("expectedDestinationRouter") + val expectedDestinationRouter: String? = null, + @SerialName("expectedIgpAddress") + val expectedIgpAddress: String? = null, + @SerialName("expectedDestinationDomain") + val expectedDestinationDomain: ULong? = null, + @SerialName("messageId") + val messageId: String? = null, + @SerialName("igpAddress") + val igpAddress: String? = null, + @SerialName("destinationDomain") + val destinationDomain: ULong? = null, + @SerialName("gasAmount") + val gasAmount: String? = null, + @SerialName("gasPayment") + val gasPayment: String? = null, + @SerialName("topUpTransactionId") + val topUpTransactionId: ULong? = null, + @SerialName("status") + val status: UByte, + @SerialName("statusReason") + val statusReason: String? = null, + @SerialName("retryCount") + val retryCount: UInt, + @SerialName("lastRetryAt") + val lastRetryAt: String? = null, + @SerialName("dispatchedAt") + val dispatchedAt: String? = null, + @SerialName("createdAt") + val createdAt: String, + @SerialName("updatedAt") + val updatedAt: String, +) + + + +@Serializable +data class GasFeeOptions( + @SerialName("gasEstimate") + val gasEstimate: GasEstimate, + @SerialName("feeOptions") + val feeOptions: List, + @SerialName("expiresAt") + val expiresAt: String, + @SerialName("feeCollectorAddress") + val feeCollectorAddress: String, +) + + + +@Serializable +data class GasEstimate( + @SerialName("totalGas") + val totalGas: ULong, + @SerialName("gasPrice") + val gasPrice: String, + @SerialName("nativeCost") + val nativeCost: String, + @SerialName("nativeCostUsd") + val nativeCostUsd: Double, +) + + + +@Serializable +data class FeeOption( + @SerialName("tokenAddress") + val tokenAddress: String, + @SerialName("tokenSymbol") + val tokenSymbol: String, + @SerialName("tokenDecimals") + val tokenDecimals: UByte, + @SerialName("amount") + val amount: String, + @SerialName("amountUsd") + val amountUsd: Double, + @SerialName("feeCollectorAddress") + val feeCollectorAddress: String, + @SerialName("is2612") + val is2612: Boolean, + @SerialName("isPassthroughEligible") + val isPassthroughEligible: Boolean? = null, +) + + + +@Serializable +data class DepositSignature( + @SerialName("intentSignature") + val intentSignature: String? = null, + @SerialName("permitSignature") + val permitSignature: String? = null, + @SerialName("permitDeadline") + val permitDeadline: ULong? = null, + @SerialName("permitAmount") + val permitAmount: String? = null, + @SerialName("selectedGasFeeOption") + val selectedGasFeeOption: FeeOption, + @SerialName("userNonce") + val userNonce: ULong? = null, + @SerialName("deadline") + val deadline: ULong, +) + + + +@Serializable +data class DepositIntentEntry( + @SerialName("intentSignature") + val intentSignature: String? = null, + @SerialName("permitSignature") + val permitSignature: String? = null, + @SerialName("permitDeadline") + val permitDeadline: ULong? = null, + @SerialName("permitAmount") + val permitAmount: String? = null, + @SerialName("feeAmount") + val feeAmount: String, + @SerialName("feeToken") + val feeToken: String, + @SerialName("feeCollector") + val feeCollector: String, + @SerialName("userNonce") + val userNonce: ULong? = null, + @SerialName("deadline") + val deadline: ULong, +) + + + +@Serializable +data class TrailsAddressOverrides( + @SerialName("sequenceWalletFactoryAddress") + val sequenceWalletFactoryAddress: String? = null, + @SerialName("sequenceWalletMainModuleAddress") + val sequenceWalletMainModuleAddress: String? = null, + @SerialName("sequenceWalletMainModuleUpgradableAddress") + val sequenceWalletMainModuleUpgradableAddress: String? = null, + @SerialName("sequenceWalletGuestModuleAddress") + val sequenceWalletGuestModuleAddress: String? = null, + @SerialName("sequenceWalletUtilsAddress") + val sequenceWalletUtilsAddress: String? = null, +) + + + +@Serializable +data class TrailsContracts( + @SerialName("trailsIntentEntrypointAddress") + val trailsIntentEntrypointAddress: String, + @SerialName("trailsRouterAddress") + val trailsRouterAddress: String, + @SerialName("trailsRouterShimAddress") + val trailsRouterShimAddress: String, + @SerialName("trailsUtilsAddress") + val trailsUtilsAddress: String, +) + + + +@Serializable +data class NativeCurrency( + @SerialName("name") + val name: String, + @SerialName("symbol") + val symbol: String, + @SerialName("decimals") + val decimals: UByte, +) + + + +@Serializable +data class BlockExplorer( + @SerialName("name") + val name: String, + @SerialName("url") + val url: String, +) + + + +@Serializable +data class RouteChainInfo( + @SerialName("id") + val id: ULong, + @SerialName("name") + val name: String, + @SerialName("tokenName") + val tokenName: String, + @SerialName("tokenSymbol") + val tokenSymbol: String, + @SerialName("tokenDecimals") + val tokenDecimals: UByte, + @SerialName("isTestnet") + val isTestnet: Boolean, + @SerialName("supportsBridging") + val supportsBridging: Boolean, + @SerialName("logoUri") + val logoUri: String? = null, + @SerialName("blockExplorerUrl") + val blockExplorerUrl: String? = null, +) + + + +@Serializable +data class ChainInfo( + @SerialName("id") + val id: ULong, + @SerialName("name") + val name: String, + @SerialName("nativeCurrency") + val nativeCurrency: NativeCurrency, + @SerialName("logoUri") + val logoUri: String? = null, + @SerialName("blockExplorer") + val blockExplorer: BlockExplorer? = null, +) + + + +@Serializable +data class TokenInfo( + @SerialName("chainId") + val chainId: ULong, + @SerialName("address") + val address: String, + @SerialName("name") + val name: String, + @SerialName("symbol") + val symbol: String, + @SerialName("decimals") + val decimals: UByte, + @SerialName("supportsBridging") + val supportsBridging: Boolean? = null, + @SerialName("logoUri") + val logoUri: String? = null, + @SerialName("featured") + val featured: Boolean, +) + + + +@Serializable +data class EarnPool( + @SerialName("id") + val id: String, + @SerialName("name") + val name: String, + @SerialName("protocol") + val protocol: String, + @SerialName("chainId") + val chainId: ULong, + @SerialName("apy") + val apy: Double, + @SerialName("tvl") + val tvl: Double, + @SerialName("token") + val token: PoolTokenInfo, + @SerialName("depositAddress") + val depositAddress: String, + @SerialName("isActive") + val isActive: Boolean, + @SerialName("poolUrl") + val poolUrl: String? = null, + @SerialName("protocolUrl") + val protocolUrl: String? = null, + @SerialName("wrappedTokenGatewayAddress") + val wrappedTokenGatewayAddress: String? = null, +) + + + +@Serializable +data class PoolTokenInfo( + @SerialName("symbol") + val symbol: String, + @SerialName("name") + val name: String, + @SerialName("address") + val address: String, + @SerialName("decimals") + val decimals: UByte, + @SerialName("logoUrl") + val logoUrl: String? = null, +) + + + +@Serializable +data class CountryRegion( + @SerialName("regionCode") + val regionCode: String, + @SerialName("name") + val name: String, +) + + + +@Serializable +data class Country( + @SerialName("countryCode") + val countryCode: String, + @SerialName("name") + val name: String, + @SerialName("flag") + val flag: String, + @SerialName("flagImageUrl") + val flagImageUrl: String, + @SerialName("regions") + val regions: List? = null, +) + + + +@Serializable +data class FiatCurrency( + @SerialName("code") + val code: String, + @SerialName("symbol") + val symbol: String, + @SerialName("name") + val name: String, + @SerialName("flag") + val flag: String, + @SerialName("decimals") + val decimals: UByte, +) + + + +@Serializable +data class Page( + @SerialName("column") + val column: String? = null, + @SerialName("before") + val before: ULong? = null, + @SerialName("after") + val after: ULong? = null, + @SerialName("sort") + val sort: List? = null, + @SerialName("pageSize") + val pageSize: UInt? = null, + @SerialName("more") + val more: Boolean? = null, +) + + + +@Serializable +data class SortBy( + @SerialName("column") + val column: String, + @SerialName("order") + val order: SortOrder, +) + + + +@Serializable +data class YieldProvider( + @SerialName("name") + val name: String, + @SerialName("id") + val id: String, + @SerialName("logoURI") + val logoUri: String, + @SerialName("description") + val description: String, + @SerialName("website") + val website: String, + @SerialName("tvlUsd") + val tvlUsd: JsonElement, + @SerialName("type") + val type: String, + @SerialName("references") + val references: List? = null, + @SerialName("supportsBeneficiary") + val supportsBeneficiary: Boolean, +) + + + +@Serializable +data class YieldNetwork( + @SerialName("id") + val id: String, + @SerialName("name") + val name: String, + @SerialName("category") + val category: String, + @SerialName("logoURI") + val logoUri: String, +) + + + +@Serializable +data class YieldMarket( + @SerialName("id") + val id: String, + @SerialName("network") + val network: String, + @SerialName("chainId") + val chainId: String? = null, + @SerialName("inputTokens") + val inputTokens: List, + @SerialName("outputToken") + val outputToken: YieldToken? = null, + @SerialName("token") + val token: YieldToken, + @SerialName("tokens") + val tokens: List, + @SerialName("rewardRate") + val rewardRate: YieldRewardRate, + @SerialName("statistics") + val statistics: YieldStatistics? = null, + @SerialName("risk") + val risk: YieldRiskSummary? = null, + @SerialName("status") + val status: YieldStatus, + @SerialName("metadata") + val metadata: YieldMetadata, + @SerialName("mechanics") + val mechanics: YieldMechanics, + @SerialName("providerId") + val providerId: String, + @SerialName("curator") + val curator: YieldCurator? = null, + @SerialName("tags") + val tags: List? = null, + @SerialName("state") + val state: YieldState? = null, + @SerialName("supportsBeneficiary") + val supportsBeneficiary: Boolean, +) + + + +@Serializable +data class YieldToken( + @SerialName("symbol") + val symbol: String, + @SerialName("name") + val name: String, + @SerialName("decimals") + val decimals: Double, + @SerialName("network") + val network: String, + @SerialName("address") + val address: String? = null, + @SerialName("logoURI") + val logoUri: String? = null, + @SerialName("isPoints") + val isPoints: Boolean? = null, + @SerialName("coinGeckoId") + val coinGeckoId: String? = null, +) + + + +@Serializable +data class YieldRewardRate( + @SerialName("total") + val total: Double, + @SerialName("rateType") + val rateType: String, + @SerialName("components") + val components: List, +) + + + +@Serializable +data class YieldReward( + @SerialName("rate") + val rate: Double, + @SerialName("rateType") + val rateType: String, + @SerialName("token") + val token: YieldToken, + @SerialName("yieldSource") + val yieldSource: String, + @SerialName("description") + val description: String? = null, +) + + + +@Serializable +data class YieldStatistics( + @SerialName("tvlUsd") + val tvlUsd: String? = null, + @SerialName("tvl") + val tvl: String? = null, + @SerialName("tvlRaw") + val tvlRaw: String? = null, + @SerialName("uniqueUsers") + val uniqueUsers: Double? = null, + @SerialName("averagePositionSizeUsd") + val averagePositionSizeUsd: String? = null, + @SerialName("averagePositionSize") + val averagePositionSize: String? = null, +) + + + +@Serializable +data class YieldRiskSummary( + @SerialName("ratings") + val ratings: List, +) + + + +@Serializable +data class YieldRiskEntry( + @SerialName("rating") + val rating: String, + @SerialName("source") + val source: String, +) + + + +@Serializable +data class YieldStatus( + @SerialName("enter") + val enter: Boolean, + @SerialName("exit") + val exit: Boolean, +) + + + +@Serializable +data class YieldMetadata( + @SerialName("name") + val name: String, + @SerialName("logoURI") + val logoUri: String, + @SerialName("description") + val description: String, + @SerialName("documentation") + val documentation: String, + @SerialName("underMaintenance") + val underMaintenance: Boolean, + @SerialName("deprecated") + val deprecated: Boolean, + @SerialName("supportedStandards") + val supportedStandards: List, +) + + + +@Serializable +data class YieldMechanics( + @SerialName("type") + val type: String, + @SerialName("requiresValidatorSelection") + val requiresValidatorSelection: Boolean? = null, + @SerialName("rewardSchedule") + val rewardSchedule: String, + @SerialName("rewardClaiming") + val rewardClaiming: String, + @SerialName("gasFeeToken") + val gasFeeToken: YieldToken, + @SerialName("lockupPeriod") + val lockupPeriod: YieldTimePeriod? = null, + @SerialName("cooldownPeriod") + val cooldownPeriod: YieldTimePeriod? = null, + @SerialName("warmupPeriod") + val warmupPeriod: YieldTimePeriod? = null, + @SerialName("fee") + val fee: YieldFee? = null, + @SerialName("entryLimits") + val entryLimits: YieldEntryLimits? = null, + @SerialName("requirements") + val requirements: YieldRequirements? = null, + @SerialName("supportsLedgerWalletApi") + val supportsLedgerWalletApi: Boolean? = null, + @SerialName("extraTransactionFormatsSupported") + val extraTransactionFormatsSupported: List? = null, + @SerialName("arguments") + val arguments: YieldMechanicsArguments? = null, + @SerialName("possibleFeeTakingMechanisms") + val possibleFeeTakingMechanisms: YieldPossibleFeeTakingMechanisms? = null, +) + + + +@Serializable +data class YieldTimePeriod( + @SerialName("seconds") + val seconds: Double, +) + + + +@Serializable +data class YieldFee( + @SerialName("deposit") + val deposit: String? = null, + @SerialName("withdrawal") + val withdrawal: String? = null, + @SerialName("management") + val management: String? = null, + @SerialName("performance") + val performance: String? = null, +) + + + +@Serializable +data class YieldEntryLimits( + @SerialName("minimum") + val minimum: String? = null, + @SerialName("maximum") + val maximum: String? = null, +) + + + +@Serializable +data class YieldRequirements( + @SerialName("kycRequired") + val kycRequired: Boolean, + @SerialName("kycUrl") + val kycUrl: String? = null, +) + + + +@Serializable +data class YieldMechanicsArguments( + @SerialName("enter") + val enter: YieldArgumentSchema? = null, + @SerialName("exit") + val exit: YieldArgumentSchema? = null, + @SerialName("manage") + val manage: Map? = null, + @SerialName("balance") + val balance: YieldArgumentSchema? = null, +) + + + +@Serializable +data class YieldArgumentSchema( + @SerialName("fields") + val fields: List, + @SerialName("notes") + val notes: String? = null, +) + + + +@Serializable +data class YieldArgumentField( + @SerialName("name") + val name: String, + @SerialName("type") + val type: String, + @SerialName("label") + val label: String, + @SerialName("description") + val description: String? = null, + @SerialName("required") + val required: Boolean? = null, + @SerialName("options") + val options: List? = null, + @SerialName("optionsRef") + val optionsRef: String? = null, + @SerialName("default") + val default: JsonElement? = null, + @SerialName("placeholder") + val placeholder: String? = null, + @SerialName("minimum") + val minimum: String? = null, + @SerialName("maximum") + val maximum: String? = null, + @SerialName("isArray") + val isArray: Boolean? = null, +) + + + +@Serializable +data class YieldPossibleFeeTakingMechanisms( + @SerialName("depositFee") + val depositFee: Boolean, + @SerialName("managementFee") + val managementFee: Boolean, + @SerialName("performanceFee") + val performanceFee: Boolean, + @SerialName("validatorRebates") + val validatorRebates: Boolean, +) + + + +@Serializable +data class YieldCurator( + @SerialName("name") + val name: JsonElement? = null, + @SerialName("description") + val description: JsonElement? = null, + @SerialName("logoURI") + val logoUri: JsonElement? = null, +) + + + +@Serializable +data class YieldState( + @SerialName("pricePerShareState") + val pricePerShareState: YieldPricePerShareState? = null, + @SerialName("concentratedLiquidityPoolState") + val concentratedLiquidityPoolState: YieldConcentratedLiquidityPoolState? = null, + @SerialName("capacityState") + val capacityState: YieldCapacity? = null, + @SerialName("liquidityState") + val liquidityState: YieldLiquidityState? = null, + @SerialName("allocations") + val allocations: List? = null, +) + + + +@Serializable +data class YieldPricePerShareState( + @SerialName("price") + val price: Double, + @SerialName("shareToken") + val shareToken: YieldToken, + @SerialName("quoteToken") + val quoteToken: YieldToken, +) + + + +@Serializable +data class YieldConcentratedLiquidityPoolState( + @SerialName("baseApr") + val baseApr: Double, + @SerialName("price") + val price: Double, + @SerialName("tickSpacing") + val tickSpacing: Double, + @SerialName("minTick") + val minTick: Double, + @SerialName("maxTick") + val maxTick: Double, + @SerialName("volume24hUsd") + val volume24hUsd: Double? = null, + @SerialName("fee24hUsd") + val fee24hUsd: Double? = null, + @SerialName("tvlUsd") + val tvlUsd: Double? = null, + @SerialName("feeTier") + val feeTier: Double, + @SerialName("baseToken") + val baseToken: YieldToken, + @SerialName("quoteToken") + val quoteToken: YieldToken, +) + + + +@Serializable +data class YieldCapacity( + @SerialName("current") + val current: String, + @SerialName("max") + val max: String? = null, + @SerialName("remaining") + val remaining: String? = null, +) + + + +@Serializable +data class YieldLiquidityState( + @SerialName("liquidity") + val liquidity: JsonElement? = null, + @SerialName("utilization") + val utilization: JsonElement? = null, +) + + + +@Serializable +data class YieldAllocation( + @SerialName("address") + val address: String, + @SerialName("network") + val network: String, + @SerialName("name") + val name: String, + @SerialName("yieldId") + val yieldId: String? = null, + @SerialName("providerId") + val providerId: String? = null, + @SerialName("allocation") + val allocation: String, + @SerialName("allocationUsd") + val allocationUsd: String? = null, + @SerialName("weight") + val weight: Double, + @SerialName("targetWeight") + val targetWeight: Double, + @SerialName("rewardRate") + val rewardRate: YieldAllocationRewardRate? = null, + @SerialName("tvl") + val tvl: String? = null, + @SerialName("tvlUsd") + val tvlUsd: String? = null, + @SerialName("maxCapacity") + val maxCapacity: String? = null, + @SerialName("remainingCapacity") + val remainingCapacity: String? = null, +) + + + +@Serializable +data class YieldAllocationRewardRate( + @SerialName("total") + val total: Double, + @SerialName("rateType") + val rateType: String, +) + + + +@Serializable +data class YieldBalances( + @SerialName("yieldId") + val yieldId: String, + @SerialName("balances") + val balances: List, + @SerialName("outputTokenBalance") + val outputTokenBalance: YieldBalance? = null, + @SerialName("rewardRate") + val rewardRate: YieldRewardRate? = null, +) + + + +@Serializable +data class YieldBalance( + @SerialName("address") + val address: String, + @SerialName("type") + val type: String, + @SerialName("amount") + val amount: String, + @SerialName("amountRaw") + val amountRaw: String, + @SerialName("date") + val date: String? = null, + @SerialName("feeConfigurationId") + val feeConfigurationId: String? = null, + @SerialName("pendingActions") + val pendingActions: List, + @SerialName("token") + val token: YieldToken, + @SerialName("validator") + val validator: YieldValidator? = null, + @SerialName("validators") + val validators: List? = null, + @SerialName("amountUsd") + val amountUsd: String? = null, + @SerialName("isEarning") + val isEarning: Boolean, + @SerialName("priceRange") + val priceRange: JsonElement? = null, + @SerialName("tokenId") + val tokenId: String? = null, + @SerialName("shareAmount") + val shareAmount: String? = null, + @SerialName("shareAmountRaw") + val shareAmountRaw: String? = null, + @SerialName("shareToken") + val shareToken: YieldToken? = null, +) + + + +@Serializable +data class YieldPendingAction( + @SerialName("intent") + val intent: String, + @SerialName("type") + val type: String, + @SerialName("passthrough") + val passthrough: String, + @SerialName("arguments") + val arguments: YieldArgumentSchema? = null, + @SerialName("amount") + val amount: String? = null, +) + + + +@Serializable +data class YieldValidator( + @SerialName("address") + val address: String, + @SerialName("name") + val name: String? = null, + @SerialName("logoURI") + val logoUri: String? = null, + @SerialName("website") + val website: String? = null, + @SerialName("rewardRate") + val rewardRate: YieldRewardRate? = null, + @SerialName("provider") + val provider: YieldValidatorProvider? = null, + @SerialName("commission") + val commission: Double? = null, + @SerialName("tvlUsd") + val tvlUsd: String? = null, + @SerialName("tvl") + val tvl: String? = null, + @SerialName("tvlRaw") + val tvlRaw: String? = null, + @SerialName("votingPower") + val votingPower: Double? = null, + @SerialName("preferred") + val preferred: Boolean? = null, + @SerialName("minimumStake") + val minimumStake: String? = null, + @SerialName("remainingPossibleStake") + val remainingPossibleStake: String? = null, + @SerialName("remainingSlots") + val remainingSlots: Double? = null, + @SerialName("nominatorCount") + val nominatorCount: Double? = null, + @SerialName("status") + val status: String? = null, + @SerialName("providerId") + val providerId: String? = null, + @SerialName("pricePerShare") + val pricePerShare: String? = null, + @SerialName("subnetId") + val subnetId: Double? = null, + @SerialName("subnetName") + val subnetName: String? = null, + @SerialName("marketCap") + val marketCap: String? = null, + @SerialName("tokenSymbol") + val tokenSymbol: String? = null, +) + + + +@Serializable +data class YieldValidatorProvider( + @SerialName("name") + val name: String, + @SerialName("id") + val id: String, + @SerialName("logoURI") + val logoUri: String, + @SerialName("description") + val description: String, + @SerialName("website") + val website: String, + @SerialName("tvlUsd") + val tvlUsd: JsonElement, + @SerialName("type") + val type: String, + @SerialName("references") + val references: List? = null, + @SerialName("rank") + val rank: Double, + @SerialName("preferred") + val preferred: Boolean, + @SerialName("revshare") + val revshare: YieldRevShareTiers? = null, + @SerialName("uniqueId") + val uniqueId: String? = null, + @SerialName("createdAt") + val createdAt: String? = null, + @SerialName("updatedAt") + val updatedAt: String? = null, +) + + + +@Serializable +data class YieldRevShareTiers( + @SerialName("trial") + val trial: YieldRevShareDetails? = null, + @SerialName("standard") + val standard: YieldRevShareDetails? = null, + @SerialName("pro") + val pro: YieldRevShareDetails? = null, +) + + + +@Serializable +data class YieldRevShareDetails( + @SerialName("minRevShare") + val minRevShare: Double, + @SerialName("maxRevShare") + val maxRevShare: Double, +) + + + +@Serializable +data class YieldError( + @SerialName("yieldId") + val yieldId: String, + @SerialName("error") + val error: String, +) + + + +@Serializable +data class YieldAction( + @SerialName("id") + val id: String, + @SerialName("intent") + val intent: String, + @SerialName("type") + val type: String, + @SerialName("yieldId") + val yieldId: String, + @SerialName("address") + val address: String, + @SerialName("amount") + val amount: String? = null, + @SerialName("amountRaw") + val amountRaw: String? = null, + @SerialName("amountUsd") + val amountUsd: String? = null, + @SerialName("transactions") + val transactions: List, + @SerialName("executionPattern") + val executionPattern: String, + @SerialName("rawArguments") + val rawArguments: YieldActionArguments? = null, + @SerialName("createdAt") + val createdAt: String, + @SerialName("completedAt") + val completedAt: String? = null, + @SerialName("status") + val status: String, +) + + + +@Serializable +data class YieldTransaction( + @SerialName("id") + val id: String, + @SerialName("title") + val title: String, + @SerialName("network") + val network: String, + @SerialName("status") + val status: String, + @SerialName("type") + val type: String, + @SerialName("hash") + val hash: String? = null, + @SerialName("createdAt") + val createdAt: String, + @SerialName("broadcastedAt") + val broadcastedAt: String? = null, + @SerialName("signedTransaction") + val signedTransaction: String? = null, + @SerialName("unsignedTransaction") + val unsignedTransaction: JsonElement? = null, + @SerialName("annotatedTransaction") + val annotatedTransaction: JsonElement? = null, + @SerialName("structuredTransaction") + val structuredTransaction: JsonElement? = null, + @SerialName("stepIndex") + val stepIndex: Double? = null, + @SerialName("description") + val description: String? = null, + @SerialName("error") + val error: String? = null, + @SerialName("gasEstimate") + val gasEstimate: String? = null, + @SerialName("explorerUrl") + val explorerUrl: String? = null, + @SerialName("isMessage") + val isMessage: Boolean? = null, +) + + + +@Serializable +data class YieldActionArguments( + @SerialName("amount") + val amount: String? = null, + @SerialName("amounts") + val amounts: List? = null, + @SerialName("validatorAddress") + val validatorAddress: String? = null, + @SerialName("validatorAddresses") + val validatorAddresses: List? = null, + @SerialName("providerId") + val providerId: String? = null, + @SerialName("duration") + val duration: Double? = null, + @SerialName("inputToken") + val inputToken: String? = null, + @SerialName("inputTokenNetwork") + val inputTokenNetwork: String? = null, + @SerialName("outputToken") + val outputToken: String? = null, + @SerialName("outputTokenNetwork") + val outputTokenNetwork: String? = null, + @SerialName("subnetId") + val subnetId: Double? = null, + @SerialName("tronResource") + val tronResource: String? = null, + @SerialName("feeConfigurationId") + val feeConfigurationId: String? = null, + @SerialName("cosmosPubKey") + val cosmosPubKey: String? = null, + @SerialName("tezosPubKey") + val tezosPubKey: String? = null, + @SerialName("cAddressBech") + val cAddressBech: String? = null, + @SerialName("pAddressBech") + val pAddressBech: String? = null, + @SerialName("executionMode") + val executionMode: String? = null, + @SerialName("ledgerWalletApiCompatible") + val ledgerWalletApiCompatible: Boolean? = null, + @SerialName("useMaxAmount") + val useMaxAmount: Boolean? = null, + @SerialName("useInstantExecution") + val useInstantExecution: Boolean? = null, + @SerialName("skipPrechecks") + val skipPrechecks: Boolean? = null, + @SerialName("useMaxAllowance") + val useMaxAllowance: Boolean? = null, + @SerialName("feePayerAddress") + val feePayerAddress: String? = null, + @SerialName("receiverAddress") + val receiverAddress: String? = null, + @SerialName("rangeMin") + val rangeMin: String? = null, + @SerialName("rangeMax") + val rangeMax: String? = null, + @SerialName("percentage") + val percentage: Double? = null, + @SerialName("tokenId") + val tokenId: String? = null, +) + + + +@Serializable +data class YieldGetBalancesArguments( + @SerialName("cAddressBech") + val cAddressBech: String? = null, + @SerialName("pAddressBech") + val pAddressBech: String? = null, + @SerialName("autoSweepDayOfMonth") + val autoSweepDayOfMonth: Double? = null, + @SerialName("autoSweepTimezone") + val autoSweepTimezone: String? = null, +) + + + +@Serializable +data class YieldBalanceQuery( + @SerialName("yieldId") + val yieldId: String? = null, + @SerialName("address") + val address: String, + @SerialName("network") + val network: String, + @SerialName("arguments") + val arguments: YieldGetBalancesArguments? = null, +) + + + +@Serializable +data class AdminRequeueIntentTransactionRequest( + @SerialName("intentId") + val intentId: String, + @SerialName("origin") + val origin: Boolean? = null, + @SerialName("destination") + val destination: Boolean? = null, + @SerialName("originMinAmountOverride") + val originMinAmountOverride: String? = null, + @SerialName("destinationMinAmountOverride") + val destinationMinAmountOverride: String? = null, +) + + + +@Serializable +data class AdminRequeueIntentTransactionResponse( + @SerialName("status") + val status: Boolean, + @SerialName("message") + val message: String, +) + + + +@Serializable +data class AdminRebuildIntentReceiptSummaryRequest( + @SerialName("intentId") + val intentId: String, +) + + + +@Serializable +data class AdminRebuildIntentReceiptSummaryResponse( + @SerialName("status") + val status: Boolean, + @SerialName("message") + val message: String, +) + + + +@Serializable +data class AdminForceFailIntentRequest( + @SerialName("intentId") + val intentId: String, +) + + + +@Serializable +data class AdminForceFailIntentResponse( + @SerialName("status") + val status: Boolean, + @SerialName("message") + val message: String, +) + + + +@Serializable +data class AdminListExecutingIntentsRequest( + @SerialName("sinceMinDuration") + val sinceMinDuration: String? = null, + @SerialName("sinceMaxDuration") + val sinceMaxDuration: String? = null, + @SerialName("page") + val page: Page? = null, +) + + + +@Serializable +data class AdminExecutingIntentInfo( + @SerialName("intentId") + val intentId: String, + @SerialName("originChainId") + val originChainId: ULong, + @SerialName("destinationChainId") + val destinationChainId: ULong, + @SerialName("originTokenAddress") + val originTokenAddress: String, + @SerialName("destinationTokenAddress") + val destinationTokenAddress: String, + @SerialName("ownerAddress") + val ownerAddress: String, + @SerialName("createdAt") + val createdAt: String, + @SerialName("updatedAt") + val updatedAt: String, +) + + + +@Serializable +data class AdminListExecutingIntentsResponse( + @SerialName("intents") + val intents: List, + @SerialName("nextPage") + val nextPage: Page? = null, +) + + + +@Serializable +class AdminDebugAnalyticsRequest + + + +@Serializable +data class AdminDebugAnalyticsResponse( + @SerialName("status") + val status: String, + @SerialName("lastUpdatedAt") + val lastUpdatedAt: String? = null, + @SerialName("data") + val `data`: AdminDebugAnalyticsData? = null, +) + + + +@Serializable +data class AdminDebugAnalyticsData( + @SerialName("totalSucceededIntents") + val totalSucceededIntents: Long, + @SerialName("totalQuotedIntents") + val totalQuotedIntents: Long, + @SerialName("totalFailedIntents") + val totalFailedIntents: Long, + @SerialName("totalSucceededVolumeUsd") + val totalSucceededVolumeUsd: Double, + @SerialName("totalSucceededVolumeUsdFormatted") + val totalSucceededVolumeUsdFormatted: String, + @SerialName("totalPassthroughVolumeUsd") + val totalPassthroughVolumeUsd: Double, + @SerialName("totalPassthroughVolumeUsdFormatted") + val totalPassthroughVolumeUsdFormatted: String, + @SerialName("uniqueWalletsSucceeded") + val uniqueWalletsSucceeded: Long, + @SerialName("uniqueWalletsAll") + val uniqueWalletsAll: Long, +) + + + +@Serializable +data class GetMeldServiceProvidersRequest( + @SerialName("countryCode") + val countryCode: String? = null, + @SerialName("serviceProviders") + val serviceProviders: String? = null, + @SerialName("paymentMethodType") + val paymentMethodType: String? = null, + @SerialName("sourceCurrencyCode") + val sourceCurrencyCode: String? = null, + @SerialName("destinationCurrencyCode") + val destinationCurrencyCode: String? = null, +) + + + +@Serializable +data class GetMeldServiceProvidersResponse( + @SerialName("serviceProviders") + val serviceProviders: List, +) + + + +@Serializable +data class MeldServiceProvider( + @SerialName("serviceProvider") + val serviceProvider: String, + @SerialName("name") + val name: String, + @SerialName("status") + val status: String? = null, + @SerialName("categories") + val categories: List? = null, + @SerialName("categoryStatuses") + val categoryStatuses: Map? = null, + @SerialName("websiteUrl") + val websiteUrl: String? = null, + @SerialName("customerSupportUrl") + val customerSupportUrl: String? = null, + @SerialName("logos") + val logos: MeldServiceProviderLogos? = null, +) + + + +@Serializable +data class MeldServiceProviderLogos( + @SerialName("light") + val light: String? = null, + @SerialName("dark") + val dark: String? = null, + @SerialName("lightShort") + val lightShort: String? = null, + @SerialName("darkShort") + val darkShort: String? = null, +) + + + +@Serializable +data class GetMeldCountryDefaultsRequest( + @SerialName("countryCode") + val countryCode: String, +) + + + +@Serializable +data class GetMeldCountryDefaultsResponse( + @SerialName("defaults") + val defaults: List, +) + + + +@Serializable +data class MeldCountryDefault( + @SerialName("countryCode") + val countryCode: String, + @SerialName("defaultCurrencyCode") + val defaultCurrencyCode: String, + @SerialName("defaultPaymentMethods") + val defaultPaymentMethods: List, +) + + + +@Serializable +data class GetMeldFiatCurrenciesRequest( + @SerialName("countryCode") + val countryCode: String, +) + + + +@Serializable +data class GetMeldFiatCurrenciesResponse( + @SerialName("fiatCurrencies") + val fiatCurrencies: List, +) + + + +@Serializable +data class MeldFiatCurrency( + @SerialName("currencyCode") + val currencyCode: String, + @SerialName("name") + val name: String, + @SerialName("symbolImageUrl") + val symbolImageUrl: String, +) + + + +@Serializable +data class GetMeldPaymentMethodsRequest( + @SerialName("fiatCurrency") + val fiatCurrency: String, +) + + + +@Serializable +data class GetMeldPaymentMethodsResponse( + @SerialName("paymentMethods") + val paymentMethods: List, +) + + + +@Serializable +data class MeldPaymentMethod( + @SerialName("paymentMethod") + val paymentMethod: String, + @SerialName("name") + val name: String, + @SerialName("paymentType") + val paymentType: String, + @SerialName("logos") + val logos: MeldPaymentLogos, +) + + + +@Serializable +data class MeldPaymentLogos( + @SerialName("dark") + val dark: String, + @SerialName("light") + val light: String, +) + + + +@Serializable +data class GetMeldCryptoCurrenciesRequest( + @SerialName("countryCode") + val countryCode: String, +) + + + +@Serializable +data class GetMeldCryptoCurrenciesResponse( + @SerialName("cryptoCurrencies") + val cryptoCurrencies: List, +) + + + +@Serializable +data class MeldCryptoCurrency( + @SerialName("currencyCode") + val currencyCode: String, + @SerialName("name") + val name: String, + @SerialName("chainCode") + val chainCode: String, + @SerialName("chainName") + val chainName: String, + @SerialName("chainId") + val chainId: String? = null, + @SerialName("contractAddress") + val contractAddress: String? = null, + @SerialName("symbolImageUrl") + val symbolImageUrl: String, +) + + + +@Serializable +class GetMeldPurchaseLimitsRequest + + + +@Serializable +data class GetMeldPurchaseLimitsResponse( + @SerialName("limits") + val limits: Map, +) + + + +@Serializable +data class MeldCurrencyLimits( + @SerialName("defaultAmount") + val defaultAmount: Double? = null, + @SerialName("minimumAmount") + val minimumAmount: Double, + @SerialName("maximumAmount") + val maximumAmount: Double, +) + + + +@Serializable +data class GetMeldQuoteRequest( + @SerialName("sourceAmount") + val sourceAmount: String, + @SerialName("sourceCurrencyCode") + val sourceCurrencyCode: String, + @SerialName("destinationCurrencyCode") + val destinationCurrencyCode: String, + @SerialName("countryCode") + val countryCode: String, + @SerialName("walletAddress") + val walletAddress: String, + @SerialName("paymentMethodType") + val paymentMethodType: String? = null, +) + + + +@Serializable +data class GetMeldQuoteResponse( + @SerialName("quoteResponse") + val quoteResponse: String, +) + + + +@Serializable +data class MeldQuote( + @SerialName("transactionType") + val transactionType: String, + @SerialName("sourceAmount") + val sourceAmount: Double, + @SerialName("sourceAmountWithoutFees") + val sourceAmountWithoutFees: Double, + @SerialName("fiatAmountWithoutFees") + val fiatAmountWithoutFees: Double, + @SerialName("destinationAmountWithoutFees") + val destinationAmountWithoutFees: Double? = null, + @SerialName("sourceCurrencyCode") + val sourceCurrencyCode: String, + @SerialName("countryCode") + val countryCode: String, + @SerialName("totalFee") + val totalFee: Double, + @SerialName("networkFee") + val networkFee: Double, + @SerialName("transactionFee") + val transactionFee: Double, + @SerialName("destinationAmount") + val destinationAmount: Double, + @SerialName("destinationCurrencyCode") + val destinationCurrencyCode: String, + @SerialName("exchangeRate") + val exchangeRate: Double, + @SerialName("paymentMethodType") + val paymentMethodType: String, + @SerialName("customerScore") + val customerScore: Double, + @SerialName("serviceProvider") + val serviceProvider: String, + @SerialName("institutionName") + val institutionName: String? = null, + @SerialName("lowKyc") + val lowKyc: Boolean? = null, + @SerialName("partnerFee") + val partnerFee: Double, +) + + + +@Serializable +data class CreateMeldWidgetSessionRequest( + @SerialName("sessionData") + val sessionData: MeldSessionData, + @SerialName("sessionType") + val sessionType: String, + @SerialName("externalCustomerId") + val externalCustomerId: String, + @SerialName("externalSessionId") + val externalSessionId: String, +) + + + +@Serializable +data class MeldSessionData( + @SerialName("walletAddress") + val walletAddress: String, + @SerialName("countryCode") + val countryCode: String, + @SerialName("sourceCurrencyCode") + val sourceCurrencyCode: String, + @SerialName("sourceAmount") + val sourceAmount: String, + @SerialName("destinationCurrencyCode") + val destinationCurrencyCode: String, + @SerialName("serviceProvider") + val serviceProvider: String, + @SerialName("paymentMethodType") + val paymentMethodType: String? = null, + @SerialName("redirectUrl") + val redirectUrl: String? = null, + @SerialName("lockFields") + val lockFields: List? = null, +) + + + +@Serializable +data class CreateMeldWidgetSessionResponse( + @SerialName("widgetSession") + val widgetSession: String, +) + + + +@Serializable +data class GetMeldTransactionRequest( + @SerialName("transactionId") + val transactionId: String, +) + + + +@Serializable +data class GetMeldTransactionResponse( + @SerialName("transaction") + val transaction: MeldTransaction, +) + + + +@Serializable +data class SearchMeldTransactionsRequest( + @SerialName("statuses") + val statuses: String? = null, + @SerialName("externalSessionIds") + val externalSessionIds: String? = null, + @SerialName("externalCustomerIds") + val externalCustomerIds: String? = null, + @SerialName("customerIds") + val customerIds: String? = null, + @SerialName("sessionIds") + val sessionIds: String? = null, + @SerialName("sessionId") + val sessionId: String? = null, + @SerialName("from") + val from: String? = null, + @SerialName("to") + val to: String? = null, + @SerialName("limit") + val limit: UInt? = null, +) + + + +@Serializable +data class SearchMeldTransactionsResponse( + @SerialName("transactions") + val transactions: MeldTransactions, +) + + + +@Serializable +data class MeldTransaction( + @SerialName("id") + val id: String, +) + + + +@Serializable +data class MeldTransactions( + @SerialName("transactions") + val transactions: List, +) + + + +@Serializable +data class CreateMeldBankLinkingConnectionRequest( + @SerialName("externalCustomerId") + val externalCustomerId: String, + @SerialName("institutionId") + val institutionId: String? = null, + @SerialName("institutionSearchString") + val institutionSearchString: String? = null, + @SerialName("products") + val products: List? = null, + @SerialName("optionalProducts") + val optionalProducts: List? = null, + @SerialName("redirectUrl") + val redirectUrl: String? = null, + @SerialName("regions") + val regions: List? = null, + @SerialName("accountPreferenceOverride") + val accountPreferenceOverride: MeldAccountPreferenceOverride? = null, +) + + + +@Serializable +data class MeldAccountPreferenceOverride( + @SerialName("allowRedirect") + val allowRedirect: Boolean? = null, +) + + + +@Serializable +data class CreateMeldBankLinkingConnectionResponse( + @SerialName("connectionResponse") + val connectionResponse: String, +) + + + +@Serializable +data class GetMeshIntegrationsRequest( + @SerialName("environment") + val environment: String? = null, +) + + + +@Serializable +data class GetMeshIntegrationsResponse( + @SerialName("integrations") + val integrations: List, +) + + + +@Serializable +data class GetMeshSupportedTokensRequest( + @SerialName("environment") + val environment: String? = null, + @SerialName("integrationId") + val integrationId: String? = null, + @SerialName("exchangeType") + val exchangeType: String? = null, + @SerialName("chainIds") + val chainIds: List? = null, + @SerialName("accessTokens") + val accessTokens: List? = null, +) + + + +@Serializable +data class GetMeshSupportedTokensResponse( + @SerialName("tokens") + val tokens: List, + @SerialName("totalBalanceUsd") + val totalBalanceUsd: String? = null, +) + + + +@Serializable +data class MeshIntegrationAccessToken( + @SerialName("accountId") + val accountId: String, + @SerialName("accountName") + val accountName: String, + @SerialName("accessToken") + val accessToken: String, + @SerialName("brokerType") + val brokerType: String, + @SerialName("brokerName") + val brokerName: String, +) + + + +@Serializable +data class MeshSupportedToken( + @SerialName("chainId") + val chainId: String, + @SerialName("meshNetworkId") + val meshNetworkId: String, + @SerialName("assetKey") + val assetKey: String, + @SerialName("symbol") + val symbol: String, + @SerialName("integrationIds") + val integrationIds: List, + @SerialName("exchangeKeys") + val exchangeKeys: List, + @SerialName("balance") + val balance: String? = null, + @SerialName("balanceUsd") + val balanceUsd: String? = null, +) + + + +@Serializable +data class MeshIntegration( + @SerialName("id") + val id: String, + @SerialName("type") + val type: String, + @SerialName("key") + val key: String, + @SerialName("displayName") + val displayName: String, + @SerialName("imageUrl") + val imageUrl: String? = null, + @SerialName("supportsOutgoingTransfers") + val supportsOutgoingTransfers: Boolean, + @SerialName("supportsIncomingTransfers") + val supportsIncomingTransfers: Boolean, + @SerialName("networks") + val networks: List, +) + + + +@Serializable +data class MeshIntegrationNetwork( + @SerialName("id") + val id: String, + @SerialName("name") + val name: String, + @SerialName("chainId") + val chainId: String, + @SerialName("nativeSymbol") + val nativeSymbol: String? = null, + @SerialName("logoUrl") + val logoUrl: String? = null, +) + + + +@Serializable +data class CreateMeshLinkTokenRequest( + @SerialName("environment") + val environment: String? = null, + @SerialName("clientId") + val clientId: String? = null, + @SerialName("authOnly") + val authOnly: Boolean? = null, + @SerialName("userId") + val userId: String? = null, + @SerialName("recipientAddress") + val recipientAddress: String? = null, + @SerialName("tokenSymbol") + val tokenSymbol: String? = null, + @SerialName("destinationChainId") + val destinationChainId: String? = null, + @SerialName("amount") + val amount: String? = null, + @SerialName("integrationId") + val integrationId: String? = null, + @SerialName("exchangeType") + val exchangeType: String? = null, + @SerialName("transactionId") + val transactionId: String? = null, + @SerialName("restrictMultipleAccounts") + val restrictMultipleAccounts: Boolean? = null, +) + + + +@Serializable +data class CreateMeshLinkTokenResponse( + @SerialName("linkToken") + val linkToken: String, + @SerialName("integrationId") + val integrationId: String, + @SerialName("meshNetworkId") + val meshNetworkId: String, + @SerialName("clientId") + val clientId: String, + @SerialName("environment") + val environment: String, +) + + + +@Serializable +data class GetBluvoClientConfigRequest( + @SerialName("environment") + val environment: String? = null, +) + + + +@Serializable +data class GetBluvoClientConfigResponse( + @SerialName("enabled") + val enabled: Boolean, + @SerialName("orgId") + val orgId: String? = null, +) + + + +@Serializable +data class GetBluvoExchangesRequest( + @SerialName("environment") + val environment: String? = null, +) + + + +@Serializable +data class GetBluvoExchangesResponse( + @SerialName("exchanges") + val exchanges: List, +) + + + +@Serializable +data class BluvoExchange( + @SerialName("id") + val id: String, + @SerialName("name") + val name: String, + @SerialName("logoUrl") + val logoUrl: String? = null, + @SerialName("status") + val status: String? = null, +) + + + +@Serializable +data class GetBluvoOAuthURLRequest( + @SerialName("environment") + val environment: String? = null, + @SerialName("exchangeId") + val exchangeId: String, + @SerialName("userAddress") + val userAddress: String, + @SerialName("walletId") + val walletId: String, + @SerialName("idem") + val idem: String? = null, +) + + + +@Serializable +data class GetBluvoOAuthURLResponse( + @SerialName("walletId") + val walletId: String, + @SerialName("url") + val url: String, + @SerialName("isQRCode") + val isQrcOde: Boolean? = null, +) + + + +@Serializable +data class GetBluvoWalletRequest( + @SerialName("environment") + val environment: String? = null, + @SerialName("walletId") + val walletId: String, +) + + + +@Serializable +data class GetBluvoWalletResponse( + @SerialName("wallet") + val wallet: BluvoWallet, +) + + + +@Serializable +data class PingBluvoWalletRequest( + @SerialName("environment") + val environment: String? = null, + @SerialName("walletId") + val walletId: String, +) + + + +@Serializable +data class PingBluvoWalletResponse( + @SerialName("walletId") + val walletId: String, + @SerialName("exchange") + val exchange: String, + @SerialName("status") + val status: String, + @SerialName("success") + val success: Boolean, +) + + + +@Serializable +data class GetBluvoWithdrawBalancesRequest( + @SerialName("environment") + val environment: String? = null, + @SerialName("walletId") + val walletId: String, + @SerialName("refreshThresholdMinutes") + val refreshThresholdMinutes: Int? = null, + @SerialName("autoDeleteIfInvalid") + val autoDeleteIfInvalid: Boolean? = null, +) + + + +@Serializable +data class GetBluvoWithdrawBalancesResponse( + @SerialName("lastSyncAt") + val lastSyncAt: String, + @SerialName("balances") + val balances: List, +) + + + +@Serializable +data class CreateBluvoWithdrawalQuoteRequest( + @SerialName("environment") + val environment: String? = null, + @SerialName("walletId") + val walletId: String, + @SerialName("intentId") + val intentId: String, + @SerialName("tag") + val tag: String? = null, +) + + + +@Serializable +data class CreateBluvoWithdrawalQuoteResponse( + @SerialName("quote") + val quote: BluvoWithdrawalQuote, +) + + + +@Serializable +data class ExecuteBluvoWithdrawalRequest( + @SerialName("environment") + val environment: String? = null, + @SerialName("walletId") + val walletId: String, + @SerialName("quoteId") + val quoteId: String, + @SerialName("twofa") + val twofa: String? = null, + @SerialName("emailCode") + val emailCode: String? = null, + @SerialName("smsCode") + val smsCode: String? = null, + @SerialName("bizNo") + val bizNo: String? = null, + @SerialName("tag") + val tag: String? = null, + @SerialName("autoDeleteIfInvalid") + val autoDeleteIfInvalid: Boolean? = null, +) + + + +@Serializable +data class ExecuteBluvoWithdrawalResponse( + @SerialName("success") + val success: Boolean, + @SerialName("error") + val error: String? = null, + @SerialName("type") + val type: String? = null, + @SerialName("transactionId") + val transactionId: String? = null, + @SerialName("challenge") + val challenge: BluvoWithdrawalChallenge? = null, +) + + + +@Serializable +data class GetBluvoTransactionRequest( + @SerialName("environment") + val environment: String? = null, + @SerialName("walletId") + val walletId: String, + @SerialName("transactionId") + val transactionId: String, +) + + + +@Serializable +data class GetBluvoTransactionResponse( + @SerialName("transaction") + val transaction: BluvoTransaction, +) + + + +@Serializable +data class DeleteBluvoWalletRequest( + @SerialName("environment") + val environment: String? = null, + @SerialName("walletId") + val walletId: String, +) + + + +@Serializable +data class DeleteBluvoWalletResponse( + @SerialName("success") + val success: Boolean, +) + + + +@Serializable +data class BluvoWallet( + @SerialName("id") + val id: String, + @SerialName("exchange") + val exchange: String, + @SerialName("invalidApi") + val invalidApi: Boolean? = null, + @SerialName("lastSyncAt") + val lastSyncAt: String? = null, + @SerialName("expiresAt") + val expiresAt: String? = null, +) + + + +@Serializable +data class BluvoWithdrawBalance( + @SerialName("asset") + val asset: String, + @SerialName("amount") + val amount: Double, + @SerialName("amountInFiat") + val amountInFiat: Double? = null, + @SerialName("networks") + val networks: List, +) + + + +@Serializable +data class BluvoWithdrawNetwork( + @SerialName("id") + val id: String, + @SerialName("name") + val name: String, + @SerialName("displayName") + val displayName: String, + @SerialName("chainId") + val chainId: Int? = null, + @SerialName("tokenAddress") + val tokenAddress: String? = null, + @SerialName("contractAddress") + val contractAddress: String? = null, + @SerialName("contractAddressVerified") + val contractAddressVerified: Boolean? = null, + @SerialName("minWithdrawal") + val minWithdrawal: String, + @SerialName("maxWithdrawal") + val maxWithdrawal: String? = null, + @SerialName("assetName") + val assetName: String, + @SerialName("addressRegex") + val addressRegex: String? = null, +) + + + +@Serializable +data class BluvoWithdrawalQuote( + @SerialName("id") + val id: String, + @SerialName("asset") + val asset: String, + @SerialName("destinationAddress") + val destinationAddress: String, + @SerialName("expiresAt") + val expiresAt: String, + @SerialName("network") + val network: String? = null, + @SerialName("amountWithFee") + val amountWithFee: Double? = null, + @SerialName("amountNoFee") + val amountNoFee: Double? = null, + @SerialName("estimatedFee") + val estimatedFee: Double? = null, + @SerialName("estimatedTotal") + val estimatedTotal: Double? = null, + @SerialName("feeDetails") + val feeDetails: List? = null, + @SerialName("additionalInfo") + val additionalInfo: BluvoWithdrawalQuoteInfo? = null, +) + + + +@Serializable +data class BluvoWithdrawalFeeDetail( + @SerialName("category") + val category: String, + @SerialName("currency") + val currency: String, + @SerialName("amount") + val amount: Double, + @SerialName("amountInFiat") + val amountInFiat: Double? = null, + @SerialName("fiatCurrency") + val fiatCurrency: String, +) + + + +@Serializable +data class BluvoWithdrawalQuoteInfo( + @SerialName("minWithdrawal") + val minWithdrawal: String? = null, + @SerialName("maxWithdrawal") + val maxWithdrawal: String? = null, +) + + + +@Serializable +data class BluvoWithdrawalChallenge( + @SerialName("bizNo") + val bizNo: String? = null, + @SerialName("relation") + val relation: String? = null, + @SerialName("steps") + val steps: List? = null, + @SerialName("valid2faMethods") + val valid2faMethods: List? = null, +) + + + +@Serializable +data class BluvoWithdrawalChallengeStep( + @SerialName("type") + val type: String, + @SerialName("status") + val status: String, + @SerialName("required") + val required: Boolean? = null, + @SerialName("error") + val error: String? = null, + @SerialName("email") + val email: String? = null, + @SerialName("emailSent") + val emailSent: Boolean? = null, + @SerialName("qrCodeUrl") + val qrCodeUrl: String? = null, + @SerialName("qrCodeValidSeconds") + val qrCodeValidSeconds: Double? = null, + @SerialName("roamingFlowId") + val roamingFlowId: String? = null, +) + + + +@Serializable +data class BluvoTransaction( + @SerialName("id") + val id: String, + @SerialName("walletId") + val walletId: String, + @SerialName("type") + val type: String, + @SerialName("amount") + val amount: Double, + @SerialName("currency") + val currency: String, + @SerialName("status") + val status: String, + @SerialName("addressTo") + val addressTo: String? = null, + @SerialName("addressFrom") + val addressFrom: String? = null, + @SerialName("address") + val address: String? = null, + @SerialName("network") + val network: String? = null, + @SerialName("hash") + val hash: String? = null, + @SerialName("contractAddress") + val contractAddress: String? = null, +) + + + +@Serializable +data class RuntimeStatus( + @SerialName("healthOK") + val healthOk: Boolean, + @SerialName("version") + val version: String, + @SerialName("branch") + val branch: String, + @SerialName("commitHash") + val commitHash: String, + @SerialName("startTime") + val startTime: String, + @SerialName("uptime") + val uptime: String, + @SerialName("hostname") + val hostname: String, + @SerialName("runnables") + val runnables: JsonElement, + @SerialName("services") + val services: List, +) + + + +@Serializable +data class ServiceStatus( + @SerialName("name") + val name: String, + @SerialName("healthy") + val healthy: Boolean, + @SerialName("error") + val error: String? = null, + @SerialName("latency") + val latency: String, +) + + + +@Serializable +data class QuoteIntentResponse( + @SerialName("intent") + val intent: Intent, + @SerialName("originConfiguration") + val originConfiguration: JsonElement? = null, + @SerialName("destinationConfiguration") + val destinationConfiguration: JsonElement? = null, + @SerialName("gasFeeOptions") + val gasFeeOptions: GasFeeOptions, + @SerialName("transactionStates") + val transactionStates: List? = null, + @SerialName("passthrough") + val passthrough: PassthroughInfo? = null, +) + + + +@Serializable +data class QuoteIntentEdgeRequest( + @SerialName("intent") + val intent: QuoteIntentRequest, + @SerialName("edge") + val edge: EdgeQuoteRequest, +) + + + +@Serializable +data class QuoteIntentEdgeResponse( + @SerialName("edgeId") + val edgeId: String, + @SerialName("intent") + val intent: Intent? = null, + @SerialName("gasFeeOptions") + val gasFeeOptions: GasFeeOptions? = null, + @SerialName("transactionStates") + val transactionStates: List? = null, + @SerialName("passthrough") + val passthrough: PassthroughInfo? = null, + @SerialName("edge") + val edge: EdgeQuoteResponse, +) + + + +@Serializable +data class GetEdgeStatusRequest( + @SerialName("edgeId") + val edgeId: String, +) + + + +@Serializable +data class GetEdgeStatusResponse( + @SerialName("status") + val status: String, + @SerialName("initTransactionHash") + val initTransactionHash: String? = null, + @SerialName("fillTransactionHash") + val fillTransactionHash: String? = null, + @SerialName("refundTransactionHash") + val refundTransactionHash: String? = null, + @SerialName("failReason") + val failReason: String? = null, +) + + + +@Serializable +data class EdgeRailModes( + @SerialName("rail") + val rail: EdgeRail, + @SerialName("modes") + val modes: List, +) + + + +@Serializable +data class CommitIntentRequest( + @SerialName("intent") + val intent: Intent, +) + + + +@Serializable +data class CommitIntentResponse( + @SerialName("intentId") + val intentId: String, +) + + + +@Serializable +data class ExecuteIntentRequest( + @SerialName("intentId") + val intentId: String, + @SerialName("depositTransactionHash") + val depositTransactionHash: String? = null, + @SerialName("depositSignature") + val depositSignature: DepositSignature? = null, +) + + + +@Serializable +data class ExecuteIntentResponse( + @SerialName("intentId") + val intentId: String, + @SerialName("intentStatus") + val intentStatus: IntentStatus, +) + + + +@Serializable +data class RetryIntentRequest( + @SerialName("intentId") + val intentId: String, + @SerialName("depositTransactionHash") + val depositTransactionHash: String, +) + + + +@Serializable +data class RetryIntentResponse( + @SerialName("intentId") + val intentId: String, + @SerialName("intentStatus") + val intentStatus: IntentStatus, +) + + + +@Serializable +data class GetIntentReceiptRequest( + @SerialName("intentId") + val intentId: String, +) + + + +@Serializable +data class GetIntentReceiptResponse( + @SerialName("intentReceipt") + val intentReceipt: IntentReceipt, +) + + + +@Serializable +data class WaitIntentReceiptRequest( + @SerialName("intentId") + val intentId: String, + @SerialName("lastReceiptStates") + val lastReceiptStates: List? = null, +) + + + +@Serializable +data class WaitIntentReceiptResponse( + @SerialName("intentReceipt") + val intentReceipt: IntentReceipt, + @SerialName("receiptStates") + val receiptStates: List, + @SerialName("done") + val done: Boolean, +) + + + +@Serializable +data class GetIntentRequest( + @SerialName("intentId") + val intentId: String, +) + + + +@Serializable +data class GetIntentResponse( + @SerialName("intent") + val intent: Intent, +) + + + +@Serializable +data class SearchIntentsRequest( + @SerialName("byIntentId") + val byIntentId: String? = null, + @SerialName("byProjectId") + val byProjectId: ULong? = null, + @SerialName("byTransactionHash") + val byTransactionHash: String? = null, + @SerialName("byOwnerAddress") + val byOwnerAddress: String? = null, + @SerialName("byOriginIntentAddress") + val byOriginIntentAddress: String? = null, + @SerialName("byDestinationIntentAddress") + val byDestinationIntentAddress: String? = null, + @SerialName("byEdgeAddress") + val byEdgeAddress: String? = null, + @SerialName("byEdgeRail") + val byEdgeRail: EdgeRail? = null, + @SerialName("byEdgeMode") + val byEdgeMode: EdgeMode? = null, + @SerialName("byQueryString") + val byQueryString: String? = null, +) + + + +@Serializable +data class SearchIntentsResponse( + @SerialName("intents") + val intents: List, +) + + + +@Serializable +data class GetIntentHistoryRequest( + @SerialName("page") + val page: Page? = null, + @SerialName("byProjectId") + val byProjectId: ULong? = null, + @SerialName("byIntentProtocol") + val byIntentProtocol: IntentProtocolVersion? = null, + @SerialName("bySwapProvider") + val bySwapProvider: RouteProvider? = null, + @SerialName("byBridgeProvider") + val byBridgeProvider: RouteProvider? = null, + @SerialName("byOwnerAddress") + val byOwnerAddress: String? = null, + @SerialName("byEdgeAddress") + val byEdgeAddress: String? = null, + @SerialName("byEdgeRail") + val byEdgeRail: EdgeRail? = null, + @SerialName("byEdgeMode") + val byEdgeMode: EdgeMode? = null, + @SerialName("byParticipantAddresses") + val byParticipantAddresses: List? = null, + @SerialName("originChainId") + val originChainId: ULong? = null, + @SerialName("originTokenAddress") + val originTokenAddress: String? = null, + @SerialName("destinationChainId") + val destinationChainId: ULong? = null, + @SerialName("destinationTokenAddress") + val destinationTokenAddress: String? = null, + @SerialName("fromTime") + val fromTime: ULong? = null, + @SerialName("toTime") + val toTime: ULong? = null, + @SerialName("includeBalances") + val includeBalances: Boolean? = null, + @SerialName("onlyRecoverable") + val onlyRecoverable: Boolean? = null, + @SerialName("byStatus") + val byStatus: IntentStatus? = null, + @SerialName("byStatuses") + val byStatuses: List? = null, +) + + + +@Serializable +data class GetIntentHistoryResponse( + @SerialName("intents") + val intents: List, + @SerialName("nextPage") + val nextPage: Page? = null, +) + + + +@Serializable +data class AbortIntentRequest( + @SerialName("intentId") + val intentId: String, + @SerialName("chainId") + val chainId: ULong, + @SerialName("abortTransactionHash") + val abortTransactionHash: String, +) + + + +@Serializable +data class AbortIntentResponse( + @SerialName("intentId") + val intentId: String, + @SerialName("status") + val status: IntentStatus, +) + + + +@Serializable +data class BuildOIFRefundTransactionRequest( + @SerialName("intentId") + val intentId: String, +) + + + +@Serializable +data class BuildOIFRefundTransactionResponse( + @SerialName("intentId") + val intentId: String, + @SerialName("orderId") + val orderId: String? = null, + @SerialName("to") + val to: String, + @SerialName("data") + val `data`: String, + @SerialName("value") + val value: String, + @SerialName("chainId") + val chainId: ULong, + @SerialName("orderExpiresAt") + val orderExpiresAt: String? = null, + @SerialName("ready") + val ready: Boolean, + @SerialName("status") + val status: String, +) + + + +@Serializable +data class PrepareIntentRecoveryRequest( + @SerialName("intentId") + val intentId: String, + @SerialName("intentAddress") + val intentAddress: String? = null, + @SerialName("refundToAddress") + val refundToAddress: String? = null, + @SerialName("tokenAddress") + val tokenAddress: String? = null, +) + + + +@Serializable +data class PrepareIntentRecoveryResponse( + @SerialName("intentId") + val intentId: String, + @SerialName("intentProtocol") + val intentProtocol: IntentProtocolVersion, + @SerialName("intentAddress") + val intentAddress: String, + @SerialName("chainId") + val chainId: ULong, + @SerialName("intentSource") + val intentSource: String, + @SerialName("recoveryTokens") + val recoveryTokens: List? = null, + @SerialName("payload") + val payload: JsonElement, + @SerialName("typedData") + val typedData: JsonElement, + @SerialName("payloadHash") + val payloadHash: String, +) + + + +@Serializable +data class BuildIntentRecoveryTransactionRequest( + @SerialName("intentId") + val intentId: String, + @SerialName("payload") + val payload: JsonElement, + @SerialName("signature") + val signature: String, + @SerialName("intentAddress") + val intentAddress: String, + @SerialName("refundToAddress") + val refundToAddress: String? = null, +) + + + +@Serializable +data class BuildIntentRecoveryTransactionResponse( + @SerialName("to") + val to: String, + @SerialName("data") + val `data`: String, + @SerialName("value") + val value: String, + @SerialName("chainId") + val chainId: ULong, + @SerialName("intentAddress") + val intentAddress: String, + @SerialName("requiresDeploy") + val requiresDeploy: Boolean, + @SerialName("payloadHash") + val payloadHash: String? = null, +) + + + +@Serializable +data class GetTokenPricesRequest( + @SerialName("tokens") + val tokens: List, +) + + + +@Serializable +data class GetTokenPricesResponse( + @SerialName("tokenPrices") + val tokenPrices: List, +) + + + +@Serializable +data class GetChainsRequest( + @SerialName("routeProvider") + val routeProvider: RouteProvider? = null, +) + + + +@Serializable +data class GetChainsResponse( + @SerialName("chains") + val chains: List, +) + + + +@Serializable +data class GetExactOutputRoutesRequest( + @SerialName("destinationChainId") + val destinationChainId: ULong, + @SerialName("destinationTokenAddress") + val destinationTokenAddress: String, + @SerialName("originChainId") + val originChainId: ULong? = null, + @SerialName("originTokenAddress") + val originTokenAddress: String? = null, + @SerialName("ownerAddress") + val ownerAddress: String? = null, +) + + + +@Serializable +data class GetExactOutputRoutesResponse( + @SerialName("tokens") + val tokens: List, +) + + + +@Serializable +data class GetExactInputRoutesRequest( + @SerialName("originChainId") + val originChainId: ULong, + @SerialName("originTokenAddress") + val originTokenAddress: String, + @SerialName("destinationChainId") + val destinationChainId: ULong? = null, + @SerialName("destinationTokenAddress") + val destinationTokenAddress: String? = null, +) + + + +@Serializable +data class GetExactInputRoutesResponse( + @SerialName("tokens") + val tokens: List, +) + + + +@Serializable +data class GetTokenListRequest( + @SerialName("chainIds") + val chainIds: List, + @SerialName("searchQuery") + val searchQuery: String? = null, + @SerialName("limit") + val limit: Int? = null, + @SerialName("tokenAddress") + val tokenAddress: String? = null, + @SerialName("includeAllListed") + val includeAllListed: Boolean? = null, + @SerialName("includeExternal") + val includeExternal: Boolean? = null, + @SerialName("excludeTokens") + val excludeTokens: List? = null, +) + + + +@Serializable +data class GetTokenListResponse( + @SerialName("tokens") + val tokens: List, +) + + + +@Serializable +data class GetEarnPoolsRequest( + @SerialName("chainIds") + val chainIds: List? = null, + @SerialName("protocols") + val protocols: List? = null, + @SerialName("minTvl") + val minTvl: Double? = null, + @SerialName("maxApy") + val maxApy: Double? = null, +) + + + +@Serializable +data class GetEarnPoolsResponse( + @SerialName("pools") + val pools: List, + @SerialName("timestamp") + val timestamp: String, + @SerialName("cached") + val cached: Boolean, +) + + + +@Serializable +data class GetYieldProvidersRequest( + @SerialName("limit") + val limit: UInt? = null, + @SerialName("offset") + val offset: UInt? = null, +) + + + +@Serializable +data class GetYieldProvidersResponse( + @SerialName("items") + val items: List, + @SerialName("total") + val total: Double, + @SerialName("offset") + val offset: Double, + @SerialName("limit") + val limit: Double, +) + + + +@Serializable +data class GetYieldProviderRequest( + @SerialName("providerId") + val providerId: String, +) + + + +@Serializable +data class GetYieldProviderResponse( + @SerialName("provider") + val provider: YieldProvider, +) + + + +@Serializable +class GetYieldNetworksRequest + + + +@Serializable +data class GetYieldNetworksResponse( + @SerialName("networks") + val networks: List, +) + + + +@Serializable +data class GetYieldMarketsRequest( + @SerialName("provider") + val provider: String? = null, + @SerialName("chainId") + val chainId: String? = null, + @SerialName("type") + val type: String? = null, + @SerialName("search") + val search: String? = null, + @SerialName("sort") + val sort: String? = null, + @SerialName("limit") + val limit: UInt? = null, + @SerialName("offset") + val offset: UInt? = null, +) + + + +@Serializable +data class GetYieldMarketsResponse( + @SerialName("items") + val items: List, + @SerialName("total") + val total: Double, + @SerialName("offset") + val offset: Double, + @SerialName("limit") + val limit: Double, +) + + + +@Serializable +data class GetYieldMarketByIdRequest( + @SerialName("marketId") + val marketId: String, +) + + + +@Serializable +data class GetYieldMarketByIdResponse( + @SerialName("market") + val market: YieldMarket, +) + + + +@Serializable +data class GetYieldAggregateBalancesRequest( + @SerialName("queries") + val queries: List, +) + + + +@Serializable +data class GetYieldAggregateBalancesResponse( + @SerialName("items") + val items: List, + @SerialName("errors") + val errors: List, +) + + + +@Serializable +data class CreateYieldActionRequest( + @SerialName("earnMarketId") + val earnMarketId: String, + @SerialName("userWalletAddress") + val userWalletAddress: String, + @SerialName("args") + val args: YieldActionArguments? = null, +) + + + +@Serializable +data class CreateYieldActionResponse( + @SerialName("action") + val action: YieldAction, +) + + + +@Serializable +data class GetIntentTransactionHistoryRequest( + @SerialName("page") + val page: Page? = null, + @SerialName("byProjectId") + val byProjectId: ULong? = null, + @SerialName("byOwnerAddress") + val byOwnerAddress: String? = null, +) + + + +@Serializable +data class GetIntentTransactionHistoryResponse( + @SerialName("intents") + val intents: List, + @SerialName("nextPage") + val nextPage: Page? = null, +) + + + +// endregion + +// region Runtime +val WebRpcJson: Json = Json { + ignoreUnknownKeys = true +} + +data class WebRpcHttpResponse( + val statusCode: Int, + val body: String, + val headers: Map = emptyMap(), +) + +interface WebRpcTransport { + suspend fun post( + baseUrl: String, + path: String, + body: String, + headers: Map = emptyMap(), + ): WebRpcHttpResponse +} + +class WebRpcTransportException( + message: String, + cause: Throwable? = null, +) : IOException(message, cause) +class OkHttpWebRpcTransport( + private val okHttpClient: OkHttpClient = OkHttpClient(), +) : WebRpcTransport { + override suspend fun post( + baseUrl: String, + path: String, + body: String, + headers: Map, + ): WebRpcHttpResponse = withContext(Dispatchers.IO) { + val request = Request.Builder() + .url(joinUrl(baseUrl, path)) + .post(body.toRequestBody(jsonMediaType)) + .apply { + headers.forEach { (name, value) -> addHeader(name, value) } + } + .build() + + try { + okHttpClient.newCall(request).execute().use { response -> + val responseBody = response.body?.string().orEmpty() + val responseHeaders = response.headers.toMultimap() + .mapValues { (_, values) -> values.lastOrNull().orEmpty() } + WebRpcHttpResponse( + statusCode = response.code, + body = responseBody, + headers = responseHeaders, + ) + } + } catch (exception: IOException) { + throw WebRpcTransportException("WebRPC HTTP request failed", exception) + } + } + + companion object { + private val jsonMediaType = "application/json; charset=utf-8".toMediaType() + } +} + +private fun joinUrl(baseUrl: String, path: String): String = + baseUrl.trimEnd('/') + "/" + path.trimStart('/') + +suspend inline fun executeWebRpc( + baseUrl: String, + urlPath: String, + body: String, + transport: WebRpcTransport, + headers: Map = emptyMap(), + json: Json = WebRpcJson, + crossinline decodeSuccess: (body: String, json: Json) -> O, +): O { + val response = try { + transport.post( + baseUrl = baseUrl, + path = urlPath, + body = body, + headers = headers, + ) + } catch (e: CancellationException) { + throw e + } catch (e: WebRpcTransportException) { + throw e + } catch (e: Throwable) { + throw WebRpcTransportException("WebRPC request failed", e) + } + + if (response.statusCode !in 200..299) { + throw decodeWebRpcError(response.statusCode, response.body, json) + } + + return decodeSuccess(response.body, json) +} +// endregion + +// region Errors +enum class ErrorKind(val code: Int) { + WEBRPC_ENDPOINT(0), + WEBRPC_REQUEST_FAILED(-1), + WEBRPC_BAD_ROUTE(-2), + WEBRPC_BAD_METHOD(-3), + WEBRPC_BAD_REQUEST(-4), + WEBRPC_BAD_RESPONSE(-5), + WEBRPC_SERVER_PANIC(-6), + WEBRPC_INTERNAL_ERROR(-7), + WEBRPC_CLIENT_ABORTED(-8), + WEBRPC_STREAM_LOST(-9), + WEBRPC_STREAM_FINISHED(-10), + UNAUTHORIZED(1000), + PERMISSION_DENIED(1001), + SESSION_EXPIRED(1002), + METHOD_NOT_FOUND(1003), + REQUEST_CONFLICT(1004), + ABORTED(1005), + GEOBLOCKED(1006), + RATE_LIMITED(1007), + PROJECT_NOT_FOUND(1008), + ACCESS_KEY_NOT_FOUND(1101), + ACCESS_KEY_MISMATCH(1102), + INVALID_ORIGIN(1103), + INVALID_SERVICE(1104), + UNAUTHORIZED_USER(1105), + QUOTA_EXCEEDED(1200), + QUOTA_RATE_LIMIT(1201), + NO_DEFAULT_KEY(1300), + MAX_ACCESS_KEYS(1301), + AT_LEAST_ONE_KEY(1302), + TIMEOUT(1900), + INVALID_ARGUMENT(2000), + UNEXPECTED(2001), + UNAVAILABLE(2002), + QUERY_FAILED(2003), + INTENT_STATUS(2004), + NOT_FOUND(8000), + UNSUPPORTED_NETWORK(8008), + CLIENT_OUTDATED(8009), + INTENTS_SKIPPED(7000), + QUOTE_EXPIRED(7001), + HIGH_PRICE_IMPACT(7002), + INTENTS_DISABLED(9000), + CHAIN_NODE_HEALTH(9001), + UNKNOWN(-999); + + companion object { + fun fromCode(code: Int): ErrorKind { + return ErrorKind.values().find { it.code == code } ?: UNKNOWN + } + } +} + +data class WebRpcError( + val error: String, + val code: Int, + override val message: String, + val causeString: String, + val status: Int, + val errorKind: ErrorKind = ErrorKind.fromCode(code), +) : Exception(message) + +@Serializable +private data class WebRpcErrorPayload( + @SerialName("error") val error: String? = null, + @SerialName("code") val code: Int? = null, + @SerialName("msg") val message: String? = null, + @SerialName("cause") val causeString: String? = null, + @SerialName("status") val status: Int? = null, +) + +fun decodeWebRpcError( + statusCode: Int, + body: String, + json: Json = WebRpcJson, +): WebRpcError { + return try { + val payload = json.decodeFromString(body) + val code = payload.code ?: ErrorKind.UNKNOWN.code + WebRpcError( + error = payload.error ?: "WebrpcEndpoint", + code = code, + message = payload.message ?: "endpoint error", + causeString = payload.causeString.orEmpty(), + status = payload.status ?: statusCode, + errorKind = ErrorKind.fromCode(code), + ) + } catch (_: Throwable) { + WebRpcError( + error = "WebrpcBadResponse", + code = ErrorKind.UNKNOWN.code, + message = "Unable to decode error response", + causeString = body, + status = statusCode, + errorKind = ErrorKind.UNKNOWN, + ) + } +} +// endregion + +// region Service Metadata + +object TrailsApiTrailsAdminApi { + const val basePath: String = "/rpc/TrailsAdmin" + + + object AdminRequeueIntentTransaction { + const val path: String = "/AdminRequeueIntentTransaction" + const val urlPath: String = "/rpc/TrailsAdmin/AdminRequeueIntentTransaction" + fun encodeRequest(request: AdminRequeueIntentTransactionRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): AdminRequeueIntentTransactionResponse { + return json.decodeFromString(body) + } + } + + object AdminRebuildIntentReceiptSummary { + const val path: String = "/AdminRebuildIntentReceiptSummary" + const val urlPath: String = "/rpc/TrailsAdmin/AdminRebuildIntentReceiptSummary" + fun encodeRequest(request: AdminRebuildIntentReceiptSummaryRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): AdminRebuildIntentReceiptSummaryResponse { + return json.decodeFromString(body) + } + } + + object AdminForceFailIntent { + const val path: String = "/AdminForceFailIntent" + const val urlPath: String = "/rpc/TrailsAdmin/AdminForceFailIntent" + fun encodeRequest(request: AdminForceFailIntentRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): AdminForceFailIntentResponse { + return json.decodeFromString(body) + } + } + + object AdminListExecutingIntents { + const val path: String = "/AdminListExecutingIntents" + const val urlPath: String = "/rpc/TrailsAdmin/AdminListExecutingIntents" + fun encodeRequest(request: AdminListExecutingIntentsRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): AdminListExecutingIntentsResponse { + return json.decodeFromString(body) + } + } + + object AdminDebugAnalytics { + const val path: String = "/AdminDebugAnalytics" + const val urlPath: String = "/rpc/TrailsAdmin/AdminDebugAnalytics" + fun encodeRequest(request: AdminDebugAnalyticsRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): AdminDebugAnalyticsResponse { + return json.decodeFromString(body) + } + } +} + +class TrailsApiTrailsAdminClient( + private val baseUrl: String, + private val transport: WebRpcTransport, + private val json: Json = WebRpcJson, + private val headers: () -> Map = { emptyMap() }, +) { + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun adminRequeueIntentTransaction(request:AdminRequeueIntentTransactionRequest): AdminRequeueIntentTransactionResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsAdminApi.AdminRequeueIntentTransaction.urlPath, + body = TrailsApiTrailsAdminApi.AdminRequeueIntentTransaction.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsAdminApi.AdminRequeueIntentTransaction.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun adminRebuildIntentReceiptSummary(request:AdminRebuildIntentReceiptSummaryRequest): AdminRebuildIntentReceiptSummaryResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsAdminApi.AdminRebuildIntentReceiptSummary.urlPath, + body = TrailsApiTrailsAdminApi.AdminRebuildIntentReceiptSummary.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsAdminApi.AdminRebuildIntentReceiptSummary.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun adminForceFailIntent(request:AdminForceFailIntentRequest): AdminForceFailIntentResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsAdminApi.AdminForceFailIntent.urlPath, + body = TrailsApiTrailsAdminApi.AdminForceFailIntent.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsAdminApi.AdminForceFailIntent.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun adminListExecutingIntents(request:AdminListExecutingIntentsRequest): AdminListExecutingIntentsResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsAdminApi.AdminListExecutingIntents.urlPath, + body = TrailsApiTrailsAdminApi.AdminListExecutingIntents.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsAdminApi.AdminListExecutingIntents.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun adminDebugAnalytics(request:AdminDebugAnalyticsRequest): AdminDebugAnalyticsResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsAdminApi.AdminDebugAnalytics.urlPath, + body = TrailsApiTrailsAdminApi.AdminDebugAnalytics.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsAdminApi.AdminDebugAnalytics.decodeResponse(body, decodeJson) + }, + ) + } +} + + + +object TrailsApiTrailsOnrampApi { + const val basePath: String = "/rpc/TrailsOnramp" + + + object GetMeldServiceProviders { + const val path: String = "/GetMeldServiceProviders" + const val urlPath: String = "/rpc/TrailsOnramp/GetMeldServiceProviders" + fun encodeRequest(request: GetMeldServiceProvidersRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetMeldServiceProvidersResponse { + return json.decodeFromString(body) + } + } + + object GetMeldCountryDefaults { + const val path: String = "/GetMeldCountryDefaults" + const val urlPath: String = "/rpc/TrailsOnramp/GetMeldCountryDefaults" + fun encodeRequest(request: GetMeldCountryDefaultsRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetMeldCountryDefaultsResponse { + return json.decodeFromString(body) + } + } + + object GetMeldFiatCurrencies { + const val path: String = "/GetMeldFiatCurrencies" + const val urlPath: String = "/rpc/TrailsOnramp/GetMeldFiatCurrencies" + fun encodeRequest(request: GetMeldFiatCurrenciesRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetMeldFiatCurrenciesResponse { + return json.decodeFromString(body) + } + } + + object GetMeldPaymentMethods { + const val path: String = "/GetMeldPaymentMethods" + const val urlPath: String = "/rpc/TrailsOnramp/GetMeldPaymentMethods" + fun encodeRequest(request: GetMeldPaymentMethodsRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetMeldPaymentMethodsResponse { + return json.decodeFromString(body) + } + } + + object GetMeldCryptoCurrencies { + const val path: String = "/GetMeldCryptoCurrencies" + const val urlPath: String = "/rpc/TrailsOnramp/GetMeldCryptoCurrencies" + fun encodeRequest(request: GetMeldCryptoCurrenciesRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetMeldCryptoCurrenciesResponse { + return json.decodeFromString(body) + } + } + + object GetMeldPurchaseLimits { + const val path: String = "/GetMeldPurchaseLimits" + const val urlPath: String = "/rpc/TrailsOnramp/GetMeldPurchaseLimits" + fun encodeRequest(request: GetMeldPurchaseLimitsRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetMeldPurchaseLimitsResponse { + return json.decodeFromString(body) + } + } + + object GetMeldQuote { + const val path: String = "/GetMeldQuote" + const val urlPath: String = "/rpc/TrailsOnramp/GetMeldQuote" + fun encodeRequest(request: GetMeldQuoteRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetMeldQuoteResponse { + return json.decodeFromString(body) + } + } + + object CreateMeldWidgetSession { + const val path: String = "/CreateMeldWidgetSession" + const val urlPath: String = "/rpc/TrailsOnramp/CreateMeldWidgetSession" + fun encodeRequest(request: CreateMeldWidgetSessionRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): CreateMeldWidgetSessionResponse { + return json.decodeFromString(body) + } + } + + object GetMeldTransaction { + const val path: String = "/GetMeldTransaction" + const val urlPath: String = "/rpc/TrailsOnramp/GetMeldTransaction" + fun encodeRequest(request: GetMeldTransactionRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetMeldTransactionResponse { + return json.decodeFromString(body) + } + } + + object SearchMeldTransactions { + const val path: String = "/SearchMeldTransactions" + const val urlPath: String = "/rpc/TrailsOnramp/SearchMeldTransactions" + fun encodeRequest(request: SearchMeldTransactionsRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): SearchMeldTransactionsResponse { + return json.decodeFromString(body) + } + } + + object CreateMeldBankLinkingConnection { + const val path: String = "/CreateMeldBankLinkingConnection" + const val urlPath: String = "/rpc/TrailsOnramp/CreateMeldBankLinkingConnection" + fun encodeRequest(request: CreateMeldBankLinkingConnectionRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): CreateMeldBankLinkingConnectionResponse { + return json.decodeFromString(body) + } + } + + object GetMeshIntegrations { + const val path: String = "/GetMeshIntegrations" + const val urlPath: String = "/rpc/TrailsOnramp/GetMeshIntegrations" + fun encodeRequest(request: GetMeshIntegrationsRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetMeshIntegrationsResponse { + return json.decodeFromString(body) + } + } + + object GetMeshSupportedTokens { + const val path: String = "/GetMeshSupportedTokens" + const val urlPath: String = "/rpc/TrailsOnramp/GetMeshSupportedTokens" + fun encodeRequest(request: GetMeshSupportedTokensRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetMeshSupportedTokensResponse { + return json.decodeFromString(body) + } + } + + object CreateMeshLinkToken { + const val path: String = "/CreateMeshLinkToken" + const val urlPath: String = "/rpc/TrailsOnramp/CreateMeshLinkToken" + fun encodeRequest(request: CreateMeshLinkTokenRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): CreateMeshLinkTokenResponse { + return json.decodeFromString(body) + } + } + + object GetBluvoClientConfig { + const val path: String = "/GetBluvoClientConfig" + const val urlPath: String = "/rpc/TrailsOnramp/GetBluvoClientConfig" + fun encodeRequest(request: GetBluvoClientConfigRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetBluvoClientConfigResponse { + return json.decodeFromString(body) + } + } + + object GetBluvoExchanges { + const val path: String = "/GetBluvoExchanges" + const val urlPath: String = "/rpc/TrailsOnramp/GetBluvoExchanges" + fun encodeRequest(request: GetBluvoExchangesRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetBluvoExchangesResponse { + return json.decodeFromString(body) + } + } + + object GetBluvoOAuthURL { + const val path: String = "/GetBluvoOAuthURL" + const val urlPath: String = "/rpc/TrailsOnramp/GetBluvoOAuthURL" + fun encodeRequest(request: GetBluvoOAuthURLRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetBluvoOAuthURLResponse { + return json.decodeFromString(body) + } + } + + object GetBluvoWallet { + const val path: String = "/GetBluvoWallet" + const val urlPath: String = "/rpc/TrailsOnramp/GetBluvoWallet" + fun encodeRequest(request: GetBluvoWalletRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetBluvoWalletResponse { + return json.decodeFromString(body) + } + } + + object PingBluvoWallet { + const val path: String = "/PingBluvoWallet" + const val urlPath: String = "/rpc/TrailsOnramp/PingBluvoWallet" + fun encodeRequest(request: PingBluvoWalletRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): PingBluvoWalletResponse { + return json.decodeFromString(body) + } + } + + object GetBluvoWithdrawBalances { + const val path: String = "/GetBluvoWithdrawBalances" + const val urlPath: String = "/rpc/TrailsOnramp/GetBluvoWithdrawBalances" + fun encodeRequest(request: GetBluvoWithdrawBalancesRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetBluvoWithdrawBalancesResponse { + return json.decodeFromString(body) + } + } + + object CreateBluvoWithdrawalQuote { + const val path: String = "/CreateBluvoWithdrawalQuote" + const val urlPath: String = "/rpc/TrailsOnramp/CreateBluvoWithdrawalQuote" + fun encodeRequest(request: CreateBluvoWithdrawalQuoteRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): CreateBluvoWithdrawalQuoteResponse { + return json.decodeFromString(body) + } + } + + object ExecuteBluvoWithdrawal { + const val path: String = "/ExecuteBluvoWithdrawal" + const val urlPath: String = "/rpc/TrailsOnramp/ExecuteBluvoWithdrawal" + fun encodeRequest(request: ExecuteBluvoWithdrawalRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): ExecuteBluvoWithdrawalResponse { + return json.decodeFromString(body) + } + } + + object GetBluvoTransaction { + const val path: String = "/GetBluvoTransaction" + const val urlPath: String = "/rpc/TrailsOnramp/GetBluvoTransaction" + fun encodeRequest(request: GetBluvoTransactionRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetBluvoTransactionResponse { + return json.decodeFromString(body) + } + } + + object DeleteBluvoWallet { + const val path: String = "/DeleteBluvoWallet" + const val urlPath: String = "/rpc/TrailsOnramp/DeleteBluvoWallet" + fun encodeRequest(request: DeleteBluvoWalletRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): DeleteBluvoWalletResponse { + return json.decodeFromString(body) + } + } +} + +class TrailsApiTrailsOnrampClient( + private val baseUrl: String, + private val transport: WebRpcTransport, + private val json: Json = WebRpcJson, + private val headers: () -> Map = { emptyMap() }, +) { + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getMeldServiceProviders(request:GetMeldServiceProvidersRequest): GetMeldServiceProvidersResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.GetMeldServiceProviders.urlPath, + body = TrailsApiTrailsOnrampApi.GetMeldServiceProviders.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.GetMeldServiceProviders.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getMeldCountryDefaults(request:GetMeldCountryDefaultsRequest): GetMeldCountryDefaultsResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.GetMeldCountryDefaults.urlPath, + body = TrailsApiTrailsOnrampApi.GetMeldCountryDefaults.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.GetMeldCountryDefaults.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getMeldFiatCurrencies(request:GetMeldFiatCurrenciesRequest): GetMeldFiatCurrenciesResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.GetMeldFiatCurrencies.urlPath, + body = TrailsApiTrailsOnrampApi.GetMeldFiatCurrencies.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.GetMeldFiatCurrencies.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getMeldPaymentMethods(request:GetMeldPaymentMethodsRequest): GetMeldPaymentMethodsResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.GetMeldPaymentMethods.urlPath, + body = TrailsApiTrailsOnrampApi.GetMeldPaymentMethods.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.GetMeldPaymentMethods.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getMeldCryptoCurrencies(request:GetMeldCryptoCurrenciesRequest): GetMeldCryptoCurrenciesResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.GetMeldCryptoCurrencies.urlPath, + body = TrailsApiTrailsOnrampApi.GetMeldCryptoCurrencies.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.GetMeldCryptoCurrencies.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getMeldPurchaseLimits(request:GetMeldPurchaseLimitsRequest): GetMeldPurchaseLimitsResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.GetMeldPurchaseLimits.urlPath, + body = TrailsApiTrailsOnrampApi.GetMeldPurchaseLimits.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.GetMeldPurchaseLimits.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getMeldQuote(request:GetMeldQuoteRequest): GetMeldQuoteResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.GetMeldQuote.urlPath, + body = TrailsApiTrailsOnrampApi.GetMeldQuote.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.GetMeldQuote.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun createMeldWidgetSession(request:CreateMeldWidgetSessionRequest): CreateMeldWidgetSessionResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.CreateMeldWidgetSession.urlPath, + body = TrailsApiTrailsOnrampApi.CreateMeldWidgetSession.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.CreateMeldWidgetSession.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getMeldTransaction(request:GetMeldTransactionRequest): GetMeldTransactionResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.GetMeldTransaction.urlPath, + body = TrailsApiTrailsOnrampApi.GetMeldTransaction.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.GetMeldTransaction.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun searchMeldTransactions(request:SearchMeldTransactionsRequest): SearchMeldTransactionsResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.SearchMeldTransactions.urlPath, + body = TrailsApiTrailsOnrampApi.SearchMeldTransactions.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.SearchMeldTransactions.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun createMeldBankLinkingConnection(request:CreateMeldBankLinkingConnectionRequest): CreateMeldBankLinkingConnectionResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.CreateMeldBankLinkingConnection.urlPath, + body = TrailsApiTrailsOnrampApi.CreateMeldBankLinkingConnection.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.CreateMeldBankLinkingConnection.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getMeshIntegrations(request:GetMeshIntegrationsRequest): GetMeshIntegrationsResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.GetMeshIntegrations.urlPath, + body = TrailsApiTrailsOnrampApi.GetMeshIntegrations.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.GetMeshIntegrations.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getMeshSupportedTokens(request:GetMeshSupportedTokensRequest): GetMeshSupportedTokensResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.GetMeshSupportedTokens.urlPath, + body = TrailsApiTrailsOnrampApi.GetMeshSupportedTokens.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.GetMeshSupportedTokens.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun createMeshLinkToken(request:CreateMeshLinkTokenRequest): CreateMeshLinkTokenResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.CreateMeshLinkToken.urlPath, + body = TrailsApiTrailsOnrampApi.CreateMeshLinkToken.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.CreateMeshLinkToken.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getBluvoClientConfig(request:GetBluvoClientConfigRequest): GetBluvoClientConfigResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.GetBluvoClientConfig.urlPath, + body = TrailsApiTrailsOnrampApi.GetBluvoClientConfig.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.GetBluvoClientConfig.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getBluvoExchanges(request:GetBluvoExchangesRequest): GetBluvoExchangesResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.GetBluvoExchanges.urlPath, + body = TrailsApiTrailsOnrampApi.GetBluvoExchanges.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.GetBluvoExchanges.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getBluvoOAuthURL(request:GetBluvoOAuthURLRequest): GetBluvoOAuthURLResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.GetBluvoOAuthURL.urlPath, + body = TrailsApiTrailsOnrampApi.GetBluvoOAuthURL.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.GetBluvoOAuthURL.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getBluvoWallet(request:GetBluvoWalletRequest): GetBluvoWalletResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.GetBluvoWallet.urlPath, + body = TrailsApiTrailsOnrampApi.GetBluvoWallet.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.GetBluvoWallet.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun pingBluvoWallet(request:PingBluvoWalletRequest): PingBluvoWalletResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.PingBluvoWallet.urlPath, + body = TrailsApiTrailsOnrampApi.PingBluvoWallet.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.PingBluvoWallet.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getBluvoWithdrawBalances(request:GetBluvoWithdrawBalancesRequest): GetBluvoWithdrawBalancesResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.GetBluvoWithdrawBalances.urlPath, + body = TrailsApiTrailsOnrampApi.GetBluvoWithdrawBalances.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.GetBluvoWithdrawBalances.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun createBluvoWithdrawalQuote(request:CreateBluvoWithdrawalQuoteRequest): CreateBluvoWithdrawalQuoteResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.CreateBluvoWithdrawalQuote.urlPath, + body = TrailsApiTrailsOnrampApi.CreateBluvoWithdrawalQuote.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.CreateBluvoWithdrawalQuote.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun executeBluvoWithdrawal(request:ExecuteBluvoWithdrawalRequest): ExecuteBluvoWithdrawalResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.ExecuteBluvoWithdrawal.urlPath, + body = TrailsApiTrailsOnrampApi.ExecuteBluvoWithdrawal.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.ExecuteBluvoWithdrawal.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getBluvoTransaction(request:GetBluvoTransactionRequest): GetBluvoTransactionResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.GetBluvoTransaction.urlPath, + body = TrailsApiTrailsOnrampApi.GetBluvoTransaction.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.GetBluvoTransaction.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun deleteBluvoWallet(request:DeleteBluvoWalletRequest): DeleteBluvoWalletResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsOnrampApi.DeleteBluvoWallet.urlPath, + body = TrailsApiTrailsOnrampApi.DeleteBluvoWallet.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsOnrampApi.DeleteBluvoWallet.decodeResponse(body, decodeJson) + }, + ) + } +} + + + +object TrailsApiTrailsApi { + const val basePath: String = "/rpc/Trails" + + + object Ping { + const val path: String = "/Ping" + const val urlPath: String = "/rpc/Trails/Ping" + + @Serializable + data class Response( + @SerialName("version") + val version: String, + ) + + @Suppress("UNUSED_PARAMETER") + fun encodeRequest(json: Json = WebRpcJson): String { + return "{}" + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): Response { + return json.decodeFromString(body) + } + } + + object RuntimeStatusMethod { + const val path: String = "/RuntimeStatus" + const val urlPath: String = "/rpc/Trails/RuntimeStatus" + + @Serializable + data class Response( + @SerialName("status") + val status: RuntimeStatus, + ) + + @Suppress("UNUSED_PARAMETER") + fun encodeRequest(json: Json = WebRpcJson): String { + return "{}" + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): Response { + return json.decodeFromString(body) + } + } + + object Clock { + const val path: String = "/Clock" + const val urlPath: String = "/rpc/Trails/Clock" + + @Serializable + data class Response( + @SerialName("serverTime") + val serverTime: String, + ) + + @Suppress("UNUSED_PARAMETER") + fun encodeRequest(json: Json = WebRpcJson): String { + return "{}" + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): Response { + return json.decodeFromString(body) + } + } + + object QuoteIntent { + const val path: String = "/QuoteIntent" + const val urlPath: String = "/rpc/Trails/QuoteIntent" + fun encodeRequest(request: QuoteIntentRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): QuoteIntentResponse { + return json.decodeFromString(body) + } + } + + object QuoteIntentEdge { + const val path: String = "/QuoteIntentEdge" + const val urlPath: String = "/rpc/Trails/QuoteIntentEdge" + fun encodeRequest(request: QuoteIntentEdgeRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): QuoteIntentEdgeResponse { + return json.decodeFromString(body) + } + } + + object GetEdgeStatus { + const val path: String = "/GetEdgeStatus" + const val urlPath: String = "/rpc/Trails/GetEdgeStatus" + fun encodeRequest(request: GetEdgeStatusRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetEdgeStatusResponse { + return json.decodeFromString(body) + } + } + + object GetEdges { + const val path: String = "/GetEdges" + const val urlPath: String = "/rpc/Trails/GetEdges" + + @Serializable + data class Response( + @SerialName("edges") + val edges: List, + ) + + @Suppress("UNUSED_PARAMETER") + fun encodeRequest(json: Json = WebRpcJson): String { + return "{}" + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): Response { + return json.decodeFromString(body) + } + } + + object CommitIntent { + const val path: String = "/CommitIntent" + const val urlPath: String = "/rpc/Trails/CommitIntent" + fun encodeRequest(request: CommitIntentRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): CommitIntentResponse { + return json.decodeFromString(body) + } + } + + object ExecuteIntent { + const val path: String = "/ExecuteIntent" + const val urlPath: String = "/rpc/Trails/ExecuteIntent" + fun encodeRequest(request: ExecuteIntentRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): ExecuteIntentResponse { + return json.decodeFromString(body) + } + } + + object RetryIntent { + const val path: String = "/RetryIntent" + const val urlPath: String = "/rpc/Trails/RetryIntent" + fun encodeRequest(request: RetryIntentRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): RetryIntentResponse { + return json.decodeFromString(body) + } + } + + object WaitIntentReceipt { + const val path: String = "/WaitIntentReceipt" + const val urlPath: String = "/rpc/Trails/WaitIntentReceipt" + fun encodeRequest(request: WaitIntentReceiptRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): WaitIntentReceiptResponse { + return json.decodeFromString(body) + } + } + + object GetIntentReceipt { + const val path: String = "/GetIntentReceipt" + const val urlPath: String = "/rpc/Trails/GetIntentReceipt" + fun encodeRequest(request: GetIntentReceiptRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetIntentReceiptResponse { + return json.decodeFromString(body) + } + } + + object GetIntent { + const val path: String = "/GetIntent" + const val urlPath: String = "/rpc/Trails/GetIntent" + fun encodeRequest(request: GetIntentRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetIntentResponse { + return json.decodeFromString(body) + } + } + + object SearchIntents { + const val path: String = "/SearchIntents" + const val urlPath: String = "/rpc/Trails/SearchIntents" + fun encodeRequest(request: SearchIntentsRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): SearchIntentsResponse { + return json.decodeFromString(body) + } + } + + object GetIntentHistory { + const val path: String = "/GetIntentHistory" + const val urlPath: String = "/rpc/Trails/GetIntentHistory" + fun encodeRequest(request: GetIntentHistoryRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetIntentHistoryResponse { + return json.decodeFromString(body) + } + } + + object AbortIntent { + const val path: String = "/AbortIntent" + const val urlPath: String = "/rpc/Trails/AbortIntent" + fun encodeRequest(request: AbortIntentRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): AbortIntentResponse { + return json.decodeFromString(body) + } + } + + object PrepareIntentRecovery { + const val path: String = "/PrepareIntentRecovery" + const val urlPath: String = "/rpc/Trails/PrepareIntentRecovery" + fun encodeRequest(request: PrepareIntentRecoveryRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): PrepareIntentRecoveryResponse { + return json.decodeFromString(body) + } + } + + object BuildIntentRecoveryTransaction { + const val path: String = "/BuildIntentRecoveryTransaction" + const val urlPath: String = "/rpc/Trails/BuildIntentRecoveryTransaction" + fun encodeRequest(request: BuildIntentRecoveryTransactionRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): BuildIntentRecoveryTransactionResponse { + return json.decodeFromString(body) + } + } + + object BuildOIFRefundTransaction { + const val path: String = "/BuildOIFRefundTransaction" + const val urlPath: String = "/rpc/Trails/BuildOIFRefundTransaction" + fun encodeRequest(request: BuildOIFRefundTransactionRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): BuildOIFRefundTransactionResponse { + return json.decodeFromString(body) + } + } + + object GetChains { + const val path: String = "/GetChains" + const val urlPath: String = "/rpc/Trails/GetChains" + fun encodeRequest(request: GetChainsRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetChainsResponse { + return json.decodeFromString(body) + } + } + + object GetExactOutputRoutes { + const val path: String = "/GetExactOutputRoutes" + const val urlPath: String = "/rpc/Trails/GetExactOutputRoutes" + fun encodeRequest(request: GetExactOutputRoutesRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetExactOutputRoutesResponse { + return json.decodeFromString(body) + } + } + + object GetExactInputRoutes { + const val path: String = "/GetExactInputRoutes" + const val urlPath: String = "/rpc/Trails/GetExactInputRoutes" + fun encodeRequest(request: GetExactInputRoutesRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetExactInputRoutesResponse { + return json.decodeFromString(body) + } + } + + object GetTokenList { + const val path: String = "/GetTokenList" + const val urlPath: String = "/rpc/Trails/GetTokenList" + fun encodeRequest(request: GetTokenListRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetTokenListResponse { + return json.decodeFromString(body) + } + } + + object GetTokenPrices { + const val path: String = "/GetTokenPrices" + const val urlPath: String = "/rpc/Trails/GetTokenPrices" + fun encodeRequest(request: GetTokenPricesRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetTokenPricesResponse { + return json.decodeFromString(body) + } + } + + object GetExchangeRate { + const val path: String = "/GetExchangeRate" + const val urlPath: String = "/rpc/Trails/GetExchangeRate" + + @Serializable + data class Request( + @SerialName("toCurrency") + val toCurrency: String, + ) + + + @Serializable + data class Response( + @SerialName("exchangeRate") + val exchangeRate: ExchangeRate, + ) + + fun encodeRequest(request: Request, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): Response { + return json.decodeFromString(body) + } + } + + object GetCountryList { + const val path: String = "/GetCountryList" + const val urlPath: String = "/rpc/Trails/GetCountryList" + + @Serializable + data class Response( + @SerialName("countries") + val countries: List, + ) + + @Suppress("UNUSED_PARAMETER") + fun encodeRequest(json: Json = WebRpcJson): String { + return "{}" + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): Response { + return json.decodeFromString(body) + } + } + + object GetTrailsContracts { + const val path: String = "/GetTrailsContracts" + const val urlPath: String = "/rpc/Trails/GetTrailsContracts" + + @Serializable + data class Response( + @SerialName("TrailsContracts") + val trailsContracts: TrailsContracts, + ) + + @Suppress("UNUSED_PARAMETER") + fun encodeRequest(json: Json = WebRpcJson): String { + return "{}" + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): Response { + return json.decodeFromString(body) + } + } + + object GetProtocolContracts { + const val path: String = "/GetProtocolContracts" + const val urlPath: String = "/rpc/Trails/GetProtocolContracts" + + @Serializable + data class Request( + @SerialName("intentProtocol") + val intentProtocol: IntentProtocolVersion? = null, + ) + + + @Serializable + data class Response( + @SerialName("TrailsContracts") + val trailsContracts: TrailsContracts, + ) + + fun encodeRequest(request: Request, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): Response { + return json.decodeFromString(body) + } + } + + object GetSupportedIntentProtocols { + const val path: String = "/GetSupportedIntentProtocols" + const val urlPath: String = "/rpc/Trails/GetSupportedIntentProtocols" + + @Serializable + data class Response( + @SerialName("versions") + val versions: List, + ) + + @Suppress("UNUSED_PARAMETER") + fun encodeRequest(json: Json = WebRpcJson): String { + return "{}" + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): Response { + return json.decodeFromString(body) + } + } + + object GetDefaultIntentProtocol { + const val path: String = "/GetDefaultIntentProtocol" + const val urlPath: String = "/rpc/Trails/GetDefaultIntentProtocol" + + @Serializable + data class Response( + @SerialName("version") + val version: IntentProtocolVersion, + ) + + @Suppress("UNUSED_PARAMETER") + fun encodeRequest(json: Json = WebRpcJson): String { + return "{}" + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): Response { + return json.decodeFromString(body) + } + } + + object GetEarnPools { + const val path: String = "/GetEarnPools" + const val urlPath: String = "/rpc/Trails/GetEarnPools" + fun encodeRequest(request: GetEarnPoolsRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetEarnPoolsResponse { + return json.decodeFromString(body) + } + } + + object YieldGetProviders { + const val path: String = "/YieldGetProviders" + const val urlPath: String = "/rpc/Trails/YieldGetProviders" + fun encodeRequest(request: GetYieldProvidersRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetYieldProvidersResponse { + return json.decodeFromString(body) + } + } + + object YieldGetProvider { + const val path: String = "/YieldGetProvider" + const val urlPath: String = "/rpc/Trails/YieldGetProvider" + fun encodeRequest(request: GetYieldProviderRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetYieldProviderResponse { + return json.decodeFromString(body) + } + } + + object YieldGetNetworks { + const val path: String = "/YieldGetNetworks" + const val urlPath: String = "/rpc/Trails/YieldGetNetworks" + fun encodeRequest(request: GetYieldNetworksRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetYieldNetworksResponse { + return json.decodeFromString(body) + } + } + + object YieldGetMarkets { + const val path: String = "/YieldGetMarkets" + const val urlPath: String = "/rpc/Trails/YieldGetMarkets" + fun encodeRequest(request: GetYieldMarketsRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetYieldMarketsResponse { + return json.decodeFromString(body) + } + } + + object YieldGetMarketById { + const val path: String = "/YieldGetMarketById" + const val urlPath: String = "/rpc/Trails/YieldGetMarketById" + fun encodeRequest(request: GetYieldMarketByIdRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetYieldMarketByIdResponse { + return json.decodeFromString(body) + } + } + + object YieldGetAggregateBalances { + const val path: String = "/YieldGetAggregateBalances" + const val urlPath: String = "/rpc/Trails/YieldGetAggregateBalances" + fun encodeRequest(request: GetYieldAggregateBalancesRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetYieldAggregateBalancesResponse { + return json.decodeFromString(body) + } + } + + object YieldCreateEnterAction { + const val path: String = "/YieldCreateEnterAction" + const val urlPath: String = "/rpc/Trails/YieldCreateEnterAction" + fun encodeRequest(request: CreateYieldActionRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): CreateYieldActionResponse { + return json.decodeFromString(body) + } + } + + object YieldCreateExitAction { + const val path: String = "/YieldCreateExitAction" + const val urlPath: String = "/rpc/Trails/YieldCreateExitAction" + fun encodeRequest(request: CreateYieldActionRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): CreateYieldActionResponse { + return json.decodeFromString(body) + } + } + + object GetFiatCurrencyList { + const val path: String = "/GetFiatCurrencyList" + const val urlPath: String = "/rpc/Trails/GetFiatCurrencyList" + + @Serializable + data class Response( + @SerialName("currencies") + val currencies: List, + ) + + @Suppress("UNUSED_PARAMETER") + fun encodeRequest(json: Json = WebRpcJson): String { + return "{}" + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): Response { + return json.decodeFromString(body) + } + } + + object GetIntentTransactionHistory { + const val path: String = "/GetIntentTransactionHistory" + const val urlPath: String = "/rpc/Trails/GetIntentTransactionHistory" + fun encodeRequest(request: GetIntentTransactionHistoryRequest, json: Json = WebRpcJson): String { + return json.encodeToString(request) + } + + fun decodeResponse(body: String, json: Json = WebRpcJson): GetIntentTransactionHistoryResponse { + return json.decodeFromString(body) + } + } +} + +class TrailsApiTrailsClient( + private val baseUrl: String, + private val transport: WebRpcTransport, + private val json: Json = WebRpcJson, + private val headers: () -> Map = { emptyMap() }, +) { + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun ping(): TrailsApiTrailsApi.Ping.Response { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.Ping.urlPath, + body = TrailsApiTrailsApi.Ping.encodeRequest(json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.Ping.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun runtimeStatus(): TrailsApiTrailsApi.RuntimeStatusMethod.Response { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.RuntimeStatusMethod.urlPath, + body = TrailsApiTrailsApi.RuntimeStatusMethod.encodeRequest(json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.RuntimeStatusMethod.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun clock(): TrailsApiTrailsApi.Clock.Response { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.Clock.urlPath, + body = TrailsApiTrailsApi.Clock.encodeRequest(json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.Clock.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun quoteIntent(request:QuoteIntentRequest): QuoteIntentResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.QuoteIntent.urlPath, + body = TrailsApiTrailsApi.QuoteIntent.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.QuoteIntent.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun quoteIntentEdge(request:QuoteIntentEdgeRequest): QuoteIntentEdgeResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.QuoteIntentEdge.urlPath, + body = TrailsApiTrailsApi.QuoteIntentEdge.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.QuoteIntentEdge.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getEdgeStatus(request:GetEdgeStatusRequest): GetEdgeStatusResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.GetEdgeStatus.urlPath, + body = TrailsApiTrailsApi.GetEdgeStatus.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.GetEdgeStatus.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getEdges(): TrailsApiTrailsApi.GetEdges.Response { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.GetEdges.urlPath, + body = TrailsApiTrailsApi.GetEdges.encodeRequest(json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.GetEdges.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun commitIntent(request:CommitIntentRequest): CommitIntentResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.CommitIntent.urlPath, + body = TrailsApiTrailsApi.CommitIntent.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.CommitIntent.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun executeIntent(request:ExecuteIntentRequest): ExecuteIntentResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.ExecuteIntent.urlPath, + body = TrailsApiTrailsApi.ExecuteIntent.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.ExecuteIntent.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun retryIntent(request:RetryIntentRequest): RetryIntentResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.RetryIntent.urlPath, + body = TrailsApiTrailsApi.RetryIntent.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.RetryIntent.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun waitIntentReceipt(request:WaitIntentReceiptRequest): WaitIntentReceiptResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.WaitIntentReceipt.urlPath, + body = TrailsApiTrailsApi.WaitIntentReceipt.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.WaitIntentReceipt.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getIntentReceipt(request:GetIntentReceiptRequest): GetIntentReceiptResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.GetIntentReceipt.urlPath, + body = TrailsApiTrailsApi.GetIntentReceipt.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.GetIntentReceipt.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getIntent(request:GetIntentRequest): GetIntentResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.GetIntent.urlPath, + body = TrailsApiTrailsApi.GetIntent.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.GetIntent.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun searchIntents(request:SearchIntentsRequest): SearchIntentsResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.SearchIntents.urlPath, + body = TrailsApiTrailsApi.SearchIntents.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.SearchIntents.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getIntentHistory(request:GetIntentHistoryRequest): GetIntentHistoryResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.GetIntentHistory.urlPath, + body = TrailsApiTrailsApi.GetIntentHistory.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.GetIntentHistory.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun abortIntent(request:AbortIntentRequest): AbortIntentResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.AbortIntent.urlPath, + body = TrailsApiTrailsApi.AbortIntent.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.AbortIntent.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun prepareIntentRecovery(request:PrepareIntentRecoveryRequest): PrepareIntentRecoveryResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.PrepareIntentRecovery.urlPath, + body = TrailsApiTrailsApi.PrepareIntentRecovery.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.PrepareIntentRecovery.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun buildIntentRecoveryTransaction(request:BuildIntentRecoveryTransactionRequest): BuildIntentRecoveryTransactionResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.BuildIntentRecoveryTransaction.urlPath, + body = TrailsApiTrailsApi.BuildIntentRecoveryTransaction.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.BuildIntentRecoveryTransaction.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun buildOIFRefundTransaction(request:BuildOIFRefundTransactionRequest): BuildOIFRefundTransactionResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.BuildOIFRefundTransaction.urlPath, + body = TrailsApiTrailsApi.BuildOIFRefundTransaction.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.BuildOIFRefundTransaction.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getChains(request:GetChainsRequest): GetChainsResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.GetChains.urlPath, + body = TrailsApiTrailsApi.GetChains.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.GetChains.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getExactOutputRoutes(request:GetExactOutputRoutesRequest): GetExactOutputRoutesResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.GetExactOutputRoutes.urlPath, + body = TrailsApiTrailsApi.GetExactOutputRoutes.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.GetExactOutputRoutes.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getExactInputRoutes(request:GetExactInputRoutesRequest): GetExactInputRoutesResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.GetExactInputRoutes.urlPath, + body = TrailsApiTrailsApi.GetExactInputRoutes.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.GetExactInputRoutes.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getTokenList(request:GetTokenListRequest): GetTokenListResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.GetTokenList.urlPath, + body = TrailsApiTrailsApi.GetTokenList.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.GetTokenList.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getTokenPrices(request:GetTokenPricesRequest): GetTokenPricesResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.GetTokenPrices.urlPath, + body = TrailsApiTrailsApi.GetTokenPrices.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.GetTokenPrices.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getExchangeRate(request:TrailsApiTrailsApi.GetExchangeRate.Request): TrailsApiTrailsApi.GetExchangeRate.Response { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.GetExchangeRate.urlPath, + body = TrailsApiTrailsApi.GetExchangeRate.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.GetExchangeRate.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getCountryList(): TrailsApiTrailsApi.GetCountryList.Response { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.GetCountryList.urlPath, + body = TrailsApiTrailsApi.GetCountryList.encodeRequest(json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.GetCountryList.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getTrailsContracts(): TrailsApiTrailsApi.GetTrailsContracts.Response { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.GetTrailsContracts.urlPath, + body = TrailsApiTrailsApi.GetTrailsContracts.encodeRequest(json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.GetTrailsContracts.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getProtocolContracts(request:TrailsApiTrailsApi.GetProtocolContracts.Request): TrailsApiTrailsApi.GetProtocolContracts.Response { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.GetProtocolContracts.urlPath, + body = TrailsApiTrailsApi.GetProtocolContracts.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.GetProtocolContracts.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getSupportedIntentProtocols(): TrailsApiTrailsApi.GetSupportedIntentProtocols.Response { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.GetSupportedIntentProtocols.urlPath, + body = TrailsApiTrailsApi.GetSupportedIntentProtocols.encodeRequest(json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.GetSupportedIntentProtocols.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getDefaultIntentProtocol(): TrailsApiTrailsApi.GetDefaultIntentProtocol.Response { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.GetDefaultIntentProtocol.urlPath, + body = TrailsApiTrailsApi.GetDefaultIntentProtocol.encodeRequest(json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.GetDefaultIntentProtocol.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getEarnPools(request:GetEarnPoolsRequest): GetEarnPoolsResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.GetEarnPools.urlPath, + body = TrailsApiTrailsApi.GetEarnPools.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.GetEarnPools.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun yieldGetProviders(request:GetYieldProvidersRequest): GetYieldProvidersResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.YieldGetProviders.urlPath, + body = TrailsApiTrailsApi.YieldGetProviders.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.YieldGetProviders.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun yieldGetProvider(request:GetYieldProviderRequest): GetYieldProviderResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.YieldGetProvider.urlPath, + body = TrailsApiTrailsApi.YieldGetProvider.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.YieldGetProvider.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun yieldGetNetworks(request:GetYieldNetworksRequest): GetYieldNetworksResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.YieldGetNetworks.urlPath, + body = TrailsApiTrailsApi.YieldGetNetworks.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.YieldGetNetworks.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun yieldGetMarkets(request:GetYieldMarketsRequest): GetYieldMarketsResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.YieldGetMarkets.urlPath, + body = TrailsApiTrailsApi.YieldGetMarkets.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.YieldGetMarkets.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun yieldGetMarketById(request:GetYieldMarketByIdRequest): GetYieldMarketByIdResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.YieldGetMarketById.urlPath, + body = TrailsApiTrailsApi.YieldGetMarketById.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.YieldGetMarketById.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun yieldGetAggregateBalances(request:GetYieldAggregateBalancesRequest): GetYieldAggregateBalancesResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.YieldGetAggregateBalances.urlPath, + body = TrailsApiTrailsApi.YieldGetAggregateBalances.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.YieldGetAggregateBalances.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun yieldCreateEnterAction(request:CreateYieldActionRequest): CreateYieldActionResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.YieldCreateEnterAction.urlPath, + body = TrailsApiTrailsApi.YieldCreateEnterAction.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.YieldCreateEnterAction.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun yieldCreateExitAction(request:CreateYieldActionRequest): CreateYieldActionResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.YieldCreateExitAction.urlPath, + body = TrailsApiTrailsApi.YieldCreateExitAction.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.YieldCreateExitAction.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getFiatCurrencyList(): TrailsApiTrailsApi.GetFiatCurrencyList.Response { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.GetFiatCurrencyList.urlPath, + body = TrailsApiTrailsApi.GetFiatCurrencyList.encodeRequest(json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.GetFiatCurrencyList.decodeResponse(body, decodeJson) + }, + ) + } + + @Throws(WebRpcError::class, WebRpcTransportException::class) + suspend fun getIntentTransactionHistory(request:GetIntentTransactionHistoryRequest): GetIntentTransactionHistoryResponse { + return executeWebRpc( + baseUrl = baseUrl, + urlPath = TrailsApiTrailsApi.GetIntentTransactionHistory.urlPath, + body = TrailsApiTrailsApi.GetIntentTransactionHistory.encodeRequest(request, json), + transport = transport, + headers = headers(), + json = json, + decodeSuccess = { body, decodeJson -> + TrailsApiTrailsApi.GetIntentTransactionHistory.decodeResponse(body, decodeJson) + }, + ) + } +} + +// endregion diff --git a/trails-actions/src/main/res/values/colors.xml b/trails-actions/src/main/res/values/colors.xml new file mode 100644 index 0000000..d2798c7 --- /dev/null +++ b/trails-actions/src/main/res/values/colors.xml @@ -0,0 +1,17 @@ + + + #05070A + #F8FAFC + #E2E8F0 + #CBD5E1 + #94A3B8 + #0B0D12 + #11141B + #171B24 + #303644 + #FFFFFF + #D8DEE9 + #22C55E + #7DD3FC + #FF000000 + diff --git a/trails-actions/src/main/res/values/strings.xml b/trails-actions/src/main/res/values/strings.xml new file mode 100644 index 0000000..c417956 --- /dev/null +++ b/trails-actions/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + trails-actions + diff --git a/trails-actions/src/main/res/values/styles.xml b/trails-actions/src/main/res/values/styles.xml new file mode 100644 index 0000000..333e8b4 --- /dev/null +++ b/trails-actions/src/main/res/values/styles.xml @@ -0,0 +1,50 @@ + + + + + + + + + + +