Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Solana]: Add Android, iOS tests
Browse files Browse the repository at this point in the history
satoshiotomakan committed Oct 31, 2024
1 parent 05f5b6a commit 75802b9
Showing 3 changed files with 83 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
package com.trustwallet.core.app.blockchains.solana

import com.google.protobuf.ByteString
import com.trustwallet.core.app.utils.toHex
import com.trustwallet.core.app.utils.toHexByteArray
import org.junit.Assert.assertEquals
import org.junit.Test
import wallet.core.jni.Base58
import wallet.core.java.AnySigner
import wallet.core.jni.Base64
import wallet.core.jni.CoinType
import wallet.core.jni.CoinType.SOLANA
import wallet.core.jni.SolanaTransaction
import wallet.core.jni.DataVector
@@ -18,6 +15,7 @@ import wallet.core.jni.proto.Solana
import wallet.core.jni.proto.Solana.DecodingTransactionOutput
import wallet.core.jni.proto.Solana.SigningInput
import wallet.core.jni.proto.Solana.SigningOutput
import wallet.core.jni.proto.Solana.Encoding

class TestSolanaTransaction {

@@ -81,4 +79,43 @@ class TestSolanaTransaction {
val expectedString = "Ajzc/Tke0CG8Cew5qFa6xZI/7Ya3DN0M8Ige6tKPsGzhg8Bw9DqL18KUrEZZ1F4YqZBo4Rv+FsDT8A7Nss7p4A6BNVZzzGprCJqYQeNg0EVIbmPc6mDitNniHXGeKgPZ6QZbM4FElw9O7IOFTpOBPvQFeqy0vZf/aayncL8EK/UEAgACBssq8Im1alV3N7wXGODL8jLPWwLhTuCqfGZ1Iz9fb5tXlMOJD6jUvASrKmdtLK/qXNyJns2Vqcvlk+nfJYdZaFpIWiT/tAcEYbttfxyLdYxrLckAKdVRtf1OrNgtZeMCII4SAn6SYaaidrX/AN3s/aVn/zrlEKW0cEUIatHVDKtXO0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqcG3fbh12Whk9nL4UbO63msHLSF7V9bN5E6jPWFfv8AqbHiki6ThNH3auuyZPQpJntnN0mA//56nMpK/6HIuu8xAQUEAgQDAQoMoA8AAAAAAAAG"
assertEquals(output.encoded, expectedString)
}

@Test
fun testSetPriorityFee() {
val privateKey = ByteString.copyFrom("baf2b2dbbbad7ca96c1fa199c686f3d8fbd2c7b352f307e37e04f33df6741f18".toHexByteArray())
val originalTx = "AX43+Ir2EDqf2zLEvgzFrCZKRjdr3wCdp8CnvYh6N0G/s86IueX9BbiNUl16iLRGvwREDfi2Srb0hmLNBFw1BwABAAEDODI+iWe7g68B9iwCy8bFkJKvsIEj350oSOpcv4gNnv/st+6qmqipl9lwMK6toB9TiL7LrJVfij+pKwr+pUKxfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG6GdPcA92ORzVJe2jfG8KQqqMHr9YTLu30oM4i7MFEoBAgIAAQwCAAAA6AMAAAAAAAA="

// Step 1 - Check if there are no price and limit instructions in the original transaction.
assertEquals(SolanaTransaction.getComputeUnitPrice(originalTx), null)
assertEquals(SolanaTransaction.getComputeUnitLimit(originalTx), null)

// Step 2 - Set price and limit instructions.
val txWithPrice = SolanaTransaction.setComputeUnitPrice(originalTx, "1000")
val updatedTx = SolanaTransaction.setComputeUnitLimit(txWithPrice, "10000")

assertEquals(updatedTx, "AX43+Ir2EDqf2zLEvgzFrCZKRjdr3wCdp8CnvYh6N0G/s86IueX9BbiNUl16iLRGvwREDfi2Srb0hmLNBFw1BwABAAIEODI+iWe7g68B9iwCy8bFkJKvsIEj350oSOpcv4gNnv/st+6qmqipl9lwMK6toB9TiL7LrJVfij+pKwr+pUKxfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwZGb+UhFzL/7K26csOb57yM5bvF9xJrLEObOkAAAAAboZ09wD3Y5HNUl7aN8bwpCqowev1hMu7fSgziLswUSgMDAAUCECcAAAICAAEMAgAAAOgDAAAAAAAAAwAJA+gDAAAAAAAA")

// Step 3 - Check if price and limit instructions are set successfully.
assertEquals(SolanaTransaction.getComputeUnitPrice(updatedTx), "1000")
assertEquals(SolanaTransaction.getComputeUnitLimit(updatedTx), "10000")

// Step 4 - Decode transaction into a `RawMessage` Protobuf.
val updatedTxData = Base64.decode(updatedTx)
val decodedData = TransactionDecoder.decode(SOLANA, updatedTxData)
val decodedOutput = DecodingTransactionOutput.parseFrom(decodedData)

assertEquals(decodedOutput.error, SigningError.OK)

// Step 5 - Sign the decoded `RawMessage` transaction.
val signingInput = SigningInput.newBuilder()
.setPrivateKey(privateKey)
.setRawMessage(decodedOutput.transaction)
.setTxEncoding(Encoding.Base64)
.build()
val output = AnySigner.sign(signingInput, SOLANA, SigningOutput.parser())
// Successfully broadcasted tx:
// https://explorer.solana.com/tx/2ho7wZUXbDNz12xGfsXg2kcNMqkBAQjv7YNXNcVcuCmbC4p9FZe9ELeM2gMjq9MKQPpmE3nBW5pbdgwVCfNLr1h8
val expectedString = "AVUye82Mv+/aWeU2G+B6Nes365mUU2m8iqcGZn/8kFJvw4wY6AgKGG+vJHaknHlCDwE1yi1SIMVUUtNCOm3kHg8BAAIEODI+iWe7g68B9iwCy8bFkJKvsIEj350oSOpcv4gNnv/st+6qmqipl9lwMK6toB9TiL7LrJVfij+pKwr+pUKxfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwZGb+UhFzL/7K26csOb57yM5bvF9xJrLEObOkAAAAAboZ09wD3Y5HNUl7aN8bwpCqowev1hMu7fSgziLswUSgMDAAUCECcAAAICAAEMAgAAAOgDAAAAAAAAAwAJA+gDAAAAAAAA"
assertEquals(output.encoded, expectedString)
}
}
4 changes: 4 additions & 0 deletions include/TrustWalletCore/TWSolanaTransaction.h
Original file line number Diff line number Diff line change
@@ -35,13 +35,15 @@ TWData *_Nonnull TWSolanaTransactionUpdateBlockhashAndSign(TWString *_Nonnull en
///
/// \param encodedTx base64 encoded Solana transaction.
/// \return nullable Unit Price as a decimal string. Null if no instruction found.
TW_EXPORT_STATIC_METHOD
TWString *_Nullable TWSolanaTransactionGetComputeUnitPrice(TWString *_Nonnull encodedTx);

/// Try to find a `ComputeBudgetInstruction::SetComputeUnitLimit` instruction in the given transaction,
/// and returns the specified Unit Limit.
///
/// \param encodedTx base64 encoded Solana transaction.
/// \return nullable Unit Limit as a decimal string. Null if no instruction found.
TW_EXPORT_STATIC_METHOD
TWString *_Nullable TWSolanaTransactionGetComputeUnitLimit(TWString *_Nonnull encodedTx);

/// Adds or updates a `ComputeBudgetInstruction::SetComputeUnitPrice` instruction of the given transaction,
@@ -50,6 +52,7 @@ TWString *_Nullable TWSolanaTransactionGetComputeUnitLimit(TWString *_Nonnull en
/// \param encodedTx base64 encoded Solana transaction.
/// \price Unit Price as a decimal string.
/// \return base64 encoded Solana transaction. Null if an error occurred.
TW_EXPORT_STATIC_METHOD
TWString *_Nullable TWSolanaTransactionSetComputeUnitPrice(TWString *_Nonnull encodedTx, TWString *_Nonnull price);

/// Adds or updates a `ComputeBudgetInstruction::SetComputeUnitLimit` instruction of the given transaction,
@@ -58,6 +61,7 @@ TWString *_Nullable TWSolanaTransactionSetComputeUnitPrice(TWString *_Nonnull en
/// \param encodedTx base64 encoded Solana transaction.
/// \limit Unit Limit as a decimal string.
/// \return base64 encoded Solana transaction. Null if an error occurred.
TW_EXPORT_STATIC_METHOD
TWString *_Nullable TWSolanaTransactionSetComputeUnitLimit(TWString *_Nonnull encodedTx, TWString *_Nonnull limit);

TW_EXTERN_C_END
39 changes: 39 additions & 0 deletions swift/Tests/Blockchains/SolanaTests.swift
Original file line number Diff line number Diff line change
@@ -290,4 +290,43 @@ class SolanaTests: XCTestCase {
let expected = "AQPWaOi7dMdmQpXi8HyQQKwiqIftrg1igGQxGtZeT50ksn4wAnyH4DtDrkkuE0fqgx80LTp4LwNN9a440SrmoA8BAAEDZsL1CMnFVcrMn7JtiOiN1U4hC7WovOVof2DX51xM0H/GizyJTHgrBanCf8bGbrFNTn0x3pCGq30hKbywSTr6AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAgIAAQwCAAAAKgAAAAAAAAA="
XCTAssertEqual(output.encoded, expected)
}

func testSetPriorityFee() throws {
let privateKey = Data(hexString: "baf2b2dbbbad7ca96c1fa199c686f3d8fbd2c7b352f307e37e04f33df6741f18")!
let originalTx = "AX43+Ir2EDqf2zLEvgzFrCZKRjdr3wCdp8CnvYh6N0G/s86IueX9BbiNUl16iLRGvwREDfi2Srb0hmLNBFw1BwABAAEDODI+iWe7g68B9iwCy8bFkJKvsIEj350oSOpcv4gNnv/st+6qmqipl9lwMK6toB9TiL7LrJVfij+pKwr+pUKxfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG6GdPcA92ORzVJe2jfG8KQqqMHr9YTLu30oM4i7MFEoBAgIAAQwCAAAA6AMAAAAAAAA="

// Step 1 - Check if there are no price and limit instructions in the original transaction.
XCTAssertEqual(SolanaTransaction.getComputeUnitPrice(encodedTx: originalTx), nil)
XCTAssertEqual(SolanaTransaction.getComputeUnitLimit(encodedTx: originalTx), nil)

// Step 2 - Set price and limit instructions.
let txWithPrice = SolanaTransaction.setComputeUnitPrice(encodedTx: originalTx, price: "1000")!
let updatedTx = SolanaTransaction.setComputeUnitLimit(encodedTx: txWithPrice, limit: "10000")!

XCTAssertEqual(updatedTx, "AX43+Ir2EDqf2zLEvgzFrCZKRjdr3wCdp8CnvYh6N0G/s86IueX9BbiNUl16iLRGvwREDfi2Srb0hmLNBFw1BwABAAIEODI+iWe7g68B9iwCy8bFkJKvsIEj350oSOpcv4gNnv/st+6qmqipl9lwMK6toB9TiL7LrJVfij+pKwr+pUKxfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwZGb+UhFzL/7K26csOb57yM5bvF9xJrLEObOkAAAAAboZ09wD3Y5HNUl7aN8bwpCqowev1hMu7fSgziLswUSgMDAAUCECcAAAICAAEMAgAAAOgDAAAAAAAAAwAJA+gDAAAAAAAA")

// Step 3 - Check if price and limit instructions are set successfully.
XCTAssertEqual(SolanaTransaction.getComputeUnitPrice(encodedTx: updatedTx), "1000")
XCTAssertEqual(SolanaTransaction.getComputeUnitLimit(encodedTx: updatedTx), "10000")

// Step 4 - Decode transaction into a `RawMessage` Protobuf.
let updatedTxData = Base64.decode(string: updatedTx)!
let decodeOutputData = TransactionDecoder.decode(coinType: .solana, encodedTx: updatedTxData)
var decodeOutput = try SolanaDecodingTransactionOutput(serializedData: decodeOutputData)

XCTAssertEqual(decodeOutput.error, .ok)

// Step 5 - Sign the decoded `RawMessage` transaction.
let signingInput = SolanaSigningInput.with {
$0.privateKey = privateKey
$0.rawMessage = decodeOutput.transaction
$0.txEncoding = .base64
}

let output: SolanaSigningOutput = AnySigner.sign(input: signingInput, coin: .solana)
XCTAssertEqual(output.error, .ok)
// Successfully broadcasted tx:
// https://explorer.solana.com/tx/2ho7wZUXbDNz12xGfsXg2kcNMqkBAQjv7YNXNcVcuCmbC4p9FZe9ELeM2gMjq9MKQPpmE3nBW5pbdgwVCfNLr1h8
XCTAssertEqual(output.encoded, "AVUye82Mv+/aWeU2G+B6Nes365mUU2m8iqcGZn/8kFJvw4wY6AgKGG+vJHaknHlCDwE1yi1SIMVUUtNCOm3kHg8BAAIEODI+iWe7g68B9iwCy8bFkJKvsIEj350oSOpcv4gNnv/st+6qmqipl9lwMK6toB9TiL7LrJVfij+pKwr+pUKxfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwZGb+UhFzL/7K26csOb57yM5bvF9xJrLEObOkAAAAAboZ09wD3Y5HNUl7aN8bwpCqowev1hMu7fSgziLswUSgMDAAUCECcAAAICAAEMAgAAAOgDAAAAAAAAAwAJA+gDAAAAAAAA")
}
}

0 comments on commit 75802b9

Please sign in to comment.