Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .idea/androidTestResultsUserPreferences.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions .idea/deploymentTargetSelector.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class ExampleInstrumentedTest {
result
.onSuccess {
println("✅ Sent: $it")
assert(it.signature.isNotEmpty())
assert(it.Signature.isNotEmpty())
}
.onFailure {
println("❌ Failed: ${it.message}")
Expand All @@ -74,7 +74,7 @@ class ExampleInstrumentedTest {
closeresult
.onSuccess {
println("✅ Sent: $it")
assert(it.signature.isNotEmpty())
assert(it.Signature.isNotEmpty())
}
.onFailure {
println("❌ Failed: ${it.message}")
Expand Down
63 changes: 63 additions & 0 deletions core/src/main/java/com/altude/core/Programs/Jupiter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.altude.core.Programs

import android.os.Build
import androidx.annotation.RequiresApi
import com.altude.core.data.JupiterInstruction
import com.altude.core.data.JupiterSwapResponse
import com.altude.core.model.AltudeTransactionBuilder
import com.altude.core.network.QuickNodeRpc
import foundation.metaplex.base58.decodeBase58
import foundation.metaplex.solana.transactions.AccountMeta
import foundation.metaplex.solana.transactions.SolanaTransaction
import foundation.metaplex.solana.transactions.Transaction
import foundation.metaplex.solana.transactions.TransactionInstruction
import foundation.metaplex.solanapublickeys.PublicKey
import okio.ByteString.Companion.decodeBase64
import java.util.Base64

object Jupiter {
suspend fun buildJupiterTransaction(
jupiterResponse: JupiterSwapResponse
): List<TransactionInstruction> {
val instructions = mutableListOf<TransactionInstruction>()

// Helper function to convert JSON instruction objects into TransactionInstruction
@RequiresApi(Build.VERSION_CODES.O)
fun parseInstruction(obj: JupiterInstruction): TransactionInstruction {
val programId = PublicKey(obj.ProgramId)
val accounts = obj.Accounts.map {
AccountMeta(PublicKey(it.Pubkey), it.IsSigner, it.IsWritable)
}
val data = Base64.getDecoder().decode(obj.Data)
return TransactionInstruction(programId, accounts, data)
}

// 1️⃣ Add compute budget instructions
jupiterResponse.ComputeBudgetInstructions?.forEach {
instructions.add(parseInstruction(it))
}

// 2️⃣ Add setup instructions
jupiterResponse.SetupInstructions?.forEach {
instructions.add(parseInstruction(it))
}

// 3️⃣ Add swap instruction
jupiterResponse.SwapInstruction?.let {
instructions.add(parseInstruction(it))
}

// 4️⃣ Add cleanup instruction
jupiterResponse.CleanupInstruction?.let {
instructions.add(parseInstruction(it))
}

// 5️⃣ Add any "other" instructions
jupiterResponse.OtherInstructions?.forEach {
instructions.add(parseInstruction(it))
}


return instructions
}
}
10 changes: 9 additions & 1 deletion core/src/main/java/com/altude/core/api/TransactionService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.altude.core.api
import com.altude.core.data.BatchTransactionRequest
import com.altude.core.data.MintData
import com.altude.core.data.SendTransactionRequest
import com.altude.core.data.SwapTransactionRequest
import kotlinx.serialization.Contextual
import retrofit2.Call
import retrofit2.http.Body
Expand Down Expand Up @@ -65,6 +66,10 @@ interface TransactionService {
fun sendTransaction(
@Body body: SendTransactionRequest
): Call<JsonElement>
@POST("api/transaction/swap")
fun swapTransaction(
@Body body: SwapTransactionRequest
): Call<JsonElement>

@POST("api/transaction/sendbatch")
fun sendBatchTransaction(
Expand Down Expand Up @@ -107,7 +112,10 @@ interface TransactionService {
fun postCreateCollectionNft(
@Body body: ISendTransactionRequest
): Call<JsonElement>

@POST("api/jupiter/swap")
fun jupiterSwap(
@Body body: JsonElement
): Call<JsonElement>
@GET("api/transaction/config")
fun getConfig(): Call<ConfigResponse>
}
Expand Down
68 changes: 68 additions & 0 deletions core/src/main/java/com/altude/core/data/JupiterSwapRequest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.altude.core.data
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement

@Serializable
data class JupiterSwapRequest(
val userPublicKey: String,
val quoteResponse: QuoteResponse,
val prioritizationFeeLamports: PrioritizationFeeLamports,
val dynamicComputeUnitLimit: Boolean = false,
val wrapAndUnwrapSol: Boolean = true,
val asLegacyTransaction: Boolean = false,
val skipUserAccountsRpcCalls: Boolean = false,
val dynamicSlippage: Boolean = false
)

@Serializable
data class SwapRequest(
val UserPublicKey: String,
val InputMint: String,
val OutputMint: String,
val Amount: Int,
val SlippageBps: Int = 50,
)

@Serializable
data class QuoteResponse(
val inputMint: String,
val inAmount: String,
val outputMint: String,
val outAmount: String,
val otherAmountThreshold: String,
val swapMode: String,
val slippageBps: Int,
val platformFee: JsonElement? = null,
val priceImpactPct: String,
val routePlan: List<RoutePlan>
)

@Serializable
data class RoutePlan(
val swapInfo: SwapInfo,
val percent: Int
)

@Serializable
data class SwapInfo(
val ammKey: String,
val label: String,
val inputMint: String,
val outputMint: String,
val inAmount: String,
val outAmount: String,
val feeAmount: String,
val feeMint: String
)

@Serializable
data class PrioritizationFeeLamports(
val priorityLevelWithMaxLamports: PriorityLevelWithMaxLamports
)

@Serializable
data class PriorityLevelWithMaxLamports(
val maxLamports: Long,
val priorityLevel: String,
val global: Boolean
)
26 changes: 26 additions & 0 deletions core/src/main/java/com/altude/core/data/JupiterSwapResponse.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.altude.core.data
import kotlinx.serialization.Serializable

@Serializable
data class JupiterSwapResponse(
val OtherInstructions: List<JupiterInstruction>? = null,
val ComputeBudgetInstructions: List<JupiterInstruction>? = null,
val SetupInstructions: List<JupiterInstruction>? = null,
val SwapInstruction: JupiterInstruction? = null,
val CleanupInstruction: JupiterInstruction? = null,
val AddressLookupTableAddresses: List<String>? = null
)

@Serializable
data class JupiterInstruction(
val ProgramId: String,
val Accounts: List<JupiterAccountMeta>,
val Data: String
)

@Serializable
data class JupiterAccountMeta(
val Pubkey: String,
val IsSigner: Boolean,
val IsWritable: Boolean
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.altude.core.data

import com.altude.core.api.ISendTransactionRequest
import kotlinx.serialization.Serializable

@Serializable
data class SwapTransactionRequest(override val SignedTransaction: String): ISendTransactionRequest
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package com.altude.gasstation
import android.content.Context
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.altude.core.Programs.AssociatedTokenAccountProgram
import com.altude.core.Programs.MPLCore
import com.altude.gasstation.data.CloseAccountOption
import com.altude.gasstation.data.CreateAccountOption
import com.altude.gasstation.data.GetAccountInfoOption
Expand All @@ -14,10 +12,9 @@ import com.altude.gasstation.data.SendOptions
import com.altude.core.helper.Mnemonic
import com.altude.gasstation.data.KeyPair
import com.altude.gasstation.data.Token
import com.altude.core.network.QuickNodeRpc
import com.altude.core.service.StorageService
import com.altude.gasstation.data.Commitment
import foundation.metaplex.solanapublickeys.PublicKey
import com.altude.gasstation.data.SwapOption
import kotlinx.coroutines.runBlocking
import org.junit.Before

Expand All @@ -43,7 +40,7 @@ class ExampleInstrumentedTest {
@Before
fun setup()=runBlocking{
context = InstrumentationRegistry.getInstrumentation().targetContext//ApplicationProvider.getApplicationContext()
Altude.setApiKey(context,"ak_acGsSti_GD9jaIisAf1a2_PhtOD5cJ3qq1u-PGYZo7k")
Altude.setApiKey(context,"ak_7KRePt6yFlsv_DYkuNGznpzpKFJTecsagXZwwSB0U2o")
}

// @Test
Expand Down Expand Up @@ -115,7 +112,7 @@ class ExampleInstrumentedTest {
result
.onSuccess {
println("✅ Sent: $it")
assert(it.signature.isNotEmpty())
assert(it.Signature.isNotEmpty())
}
.onFailure {
println("❌ Failed: ${it.message}")
Expand All @@ -136,7 +133,7 @@ class ExampleInstrumentedTest {
closeresult
.onSuccess {
println("✅ Sent: $it")
assert(it.signature.isNotEmpty())
assert(it.Signature.isNotEmpty())
}
.onFailure {
println("❌ Failed: ${it.message}")
Expand Down Expand Up @@ -221,7 +218,7 @@ class ExampleInstrumentedTest {
val result = Altude.send(options)

result
.onSuccess { println("✅ Sent: ${it.signature}") }
.onSuccess { println("✅ Sent: ${it.Signature}") }
.onFailure {
println("❌ Failed: ${it.message}")
}
Expand Down Expand Up @@ -259,7 +256,7 @@ class ExampleInstrumentedTest {
val result = Altude.sendBatch(options)

result
.onSuccess { println("✅ Sent: ${it.signature}") }
.onSuccess { println("✅ Sent: ${it.Signature}") }
.onFailure {
println("❌ Failed: ${it.message}")
}
Expand All @@ -281,6 +278,21 @@ class ExampleInstrumentedTest {
println("Balance: $result")
}
@Test
fun testSwap() = runBlocking {
Altude.savePrivateKey(accountPrivateKey )
val option = SwapOption(
account = "chenGqdufWByiUyxqg7xEhUVMqF3aS9sxYLSzDNmwqu",
inputMint = Token.SOL.mint(),
outputMint = Token.USDT.mint(),
amount = 100,
commitment = Commitment.finalized
)

// Wrap the callback in a suspendable way (like a suspendCoroutine)
val result = Altude.swap(option)
println("Balance: $result")
}
@Test
fun testGetAccountInfo() = runBlocking {
// val pda1 = MPLCore.findTreeConfigPda(PublicKey("14QSPv5BtZCh8itGrUCu2j7e7A88fwZo3cAjxi4R5Fgj"))
Altude.savePrivateKey(accountPrivateKey )
Expand Down
21 changes: 21 additions & 0 deletions gasstation/src/main/java/com/altude/gasstation/Altude.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ import com.altude.gasstation.data.SolanaKeypair
import com.altude.core.service.StorageService
import com.altude.core.data.BatchTransactionRequest
import com.altude.core.data.SendTransactionRequest
import com.altude.core.data.SwapTransactionRequest
import com.altude.gasstation.data.GetAccountResponse
import com.altude.gasstation.data.GetBalanceResponse
import com.altude.gasstation.data.SwapOption
import com.altude.gasstation.data.TransactionResponse
import foundation.metaplex.solanapublickeys.PublicKey
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -133,6 +135,25 @@ object Altude {
}
}
@OptIn(ExperimentalCoroutinesApi::class)
suspend fun swap(
options: SwapOption
): Result<TransactionResponse> = withContext(Dispatchers.IO) {
try {
val result = GaslessManager.jupiterSwap(options)

if (result.isFailure) return@withContext Result.failure(result.exceptionOrNull()!!)

val signedTransaction = result.getOrThrow()
val service = SdkConfig.createService(TransactionService::class.java)
val request = SwapTransactionRequest(signedTransaction)

val res = service.swapTransaction(request).await()
Result.success(deCodeJson<TransactionResponse>(res))
} catch (e: Exception) {
return@withContext Result.failure(e)
}
}
@OptIn(ExperimentalCoroutinesApi::class)
suspend fun getHistory(
options: GetHistoryOption
): Result<GetHistoryData> = withContext(Dispatchers.IO) {
Expand Down
Loading