From 53279937f99d56a8c856e7604a76965bac06cb17 Mon Sep 17 00:00:00 2001 From: Andrey Pfau Date: Tue, 16 Jan 2024 15:26:10 +0400 Subject: [PATCH] Fix transaction text message (#117) --- README.md | 34 ++++---- block-tlb/test/TextTest.kt | 25 ++++++ build.gradle.kts | 3 +- contract/src/wallet/MessageText.kt | 4 +- contract/test/wallet/LiteClient.kt | 10 ++- contract/test/wallet/WalletV4Example.kt | 78 +++++++++++++++++++ .../{LiteServerException.kt => exceptions.kt} | 0 settings.gradle.kts | 4 +- 8 files changed, 132 insertions(+), 26 deletions(-) create mode 100644 block-tlb/test/TextTest.kt create mode 100644 contract/test/wallet/WalletV4Example.kt rename liteapi-tl/src/exception/{LiteServerException.kt => exceptions.kt} (100%) diff --git a/README.md b/README.md index c647d072..3cd6f4ac 100644 --- a/README.md +++ b/README.md @@ -6,24 +6,24 @@ [![Telegram][telegram-svg]][telegram] [![Based on TON][ton-svg]][ton] -## Gradle Kotlin DSL +## Modules -```kotlin -dependencies { - implementation("org.ton:ton-kotlin:0.2.18") -} -``` +### Core components -## Maven +* `org.ton:ton-kotlin-tvm:0.3.0` - TVM Primitives (Cells, BOC, etc.) +* `org.ton:ton-kotlin-crypto:0.3.0` - Crypto primitives for TON (ED25519, SHA, etc.) +* `org.ton:ton-kotlin-adnl:0.3.0` - ADNL (Abstract Datagram Network Layer) TON Network implementation -```xml +### API Interfaces - - org.ton - ton-kotlin-jvm - 0.2.18 - -``` +* `org.ton:ton-kotlin-contract:0.3.0` - Smart-contracts API interface +* `org.ton:ton-kotlin-liteclient:0.3.0` - Lite-client API implementation + +### TL-B (TL-Binary) + +* `org.ton:ton-kotlin-tlb:0.3.0` - TON TL-B (TL-Binary) serialization/deserialization +* `org.ton:ton-kotlin-block-tlb:0.3.0` - Pre-generated TL-B schemas for TON Blockchain +* `org.ton:ton-kotlin-hashmap-tlb:0.3.0` - Pre-generated TL-B schemas for TON Hashmap (also known as Dictionary) ## Documentation @@ -31,7 +31,7 @@ https://github.com/andreypfau/ton-kotlin/wiki/TON-Kotlin-documentation -[maven-central]: https://central.sonatype.com/artifact/org.ton/ton-kotlin/0.2.18 +[maven-central]: https://central.sonatype.com/artifact/org.ton/ton-kotlin-tvm/0.3.0 [license]: LICENSE @@ -41,9 +41,9 @@ https://github.com/andreypfau/ton-kotlin/wiki/TON-Kotlin-documentation [telegram]: https://t.me/tonkotlin -[maven-central-svg]: https://img.shields.io/maven-central/v/org.ton/ton-kotlin?color=blue +[maven-central-svg]: https://img.shields.io/maven-central/v/org.ton/ton-kotlin-tvm?color=blue -[kotlin-svg]: https://img.shields.io/badge/Kotlin-1.8.0-blue.svg?logo=kotlin +[kotlin-svg]: https://img.shields.io/badge/Kotlin-1.9.22-blue.svg?logo=kotlin [telegram-svg]: https://img.shields.io/badge/Telegram-join%20chat-blue.svg?logo=telegram diff --git a/block-tlb/test/TextTest.kt b/block-tlb/test/TextTest.kt new file mode 100644 index 00000000..c05efd7c --- /dev/null +++ b/block-tlb/test/TextTest.kt @@ -0,0 +1,25 @@ +package org.ton.block + +import org.ton.bitstring.toBitString +import kotlin.test.Test + +class TextTest { + @Test + fun foo() { + + val string = + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + + val chunks = string.encodeToByteArray().toList().chunked(127).reversed() + var next: TextChunk? = null + chunks.forEach { chunk -> + val textChunk = TextChunk( + chunk.size.toUByte(), + chunk.toByteArray().toBitString(), + next?.let { ChunkRef(it) } ?: ChunkRefEmpty + ) + next = textChunk + } + val result = Text(chunks.size.toUByte(), next ?: TextChunkEmpty) + } +} diff --git a/build.gradle.kts b/build.gradle.kts index a4fe8c87..221f9c9f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,4 @@ +import org.gradle.internal.impldep.org.bouncycastle.cms.RecipientId.password import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile @@ -11,7 +12,7 @@ plugins { allprojects { group = "org.ton" - version = "0.3.0" + version = "0.3.1" repositories { mavenCentral() diff --git a/contract/src/wallet/MessageText.kt b/contract/src/wallet/MessageText.kt index 29d26123..cec72393 100644 --- a/contract/src/wallet/MessageText.kt +++ b/contract/src/wallet/MessageText.kt @@ -47,7 +47,7 @@ private object MessageTextTlbCombinator : TlbCombinator( ) private object TextTlbConstructor : TlbConstructor( - "raw#00 text:BitString = MessageText" + "raw#00000000 text:BitString = MessageText" ) { override fun loadTlb(cellSlice: CellSlice): MessageText.Raw { val text = cellSlice.loadTlb(CellStringTlbConstructor) @@ -60,7 +60,7 @@ private object TextTlbConstructor : TlbConstructor( } private object EncryptedTextTlbConstructor : TlbConstructor( - "encrypted#01 text:BitString = MessageText" + "encrypted#00000001 text:BitString = MessageText" ) { override fun loadTlb(cellSlice: CellSlice): MessageText.Encrypted { val text = cellSlice.loadTlb(CellStringTlbConstructor) diff --git a/contract/test/wallet/LiteClient.kt b/contract/test/wallet/LiteClient.kt index 329071fb..94653222 100644 --- a/contract/test/wallet/LiteClient.kt +++ b/contract/test/wallet/LiteClient.kt @@ -8,13 +8,15 @@ import org.ton.api.pub.PublicKeyEd25519 import org.ton.lite.client.LiteClient import org.ton.tl.asByteString -fun liteClient() = LiteClient( +fun liteClientTestnet() = LiteClient( liteClientConfigGlobal = LiteClientConfigGlobal( liteServers = listOf( LiteServerDesc( - id = PublicKeyEd25519("n4VDnSCUuSpjnCyUk9e3QOOd6o0ItSWYbTnW3Wnn8wk=".decodeBase64Bytes().asByteString()), - ip = 84478511, - port = 19949 + id = PublicKeyEd25519( + "B07X5mudyWG3zZu+Ad69+A3jHFkp+0mTrnX5sw+s3ZU=".decodeBase64Bytes().asByteString() + ), + ip = -1178753158, + port = 15400 ) ) ), diff --git a/contract/test/wallet/WalletV4Example.kt b/contract/test/wallet/WalletV4Example.kt new file mode 100644 index 00000000..45dbdf37 --- /dev/null +++ b/contract/test/wallet/WalletV4Example.kt @@ -0,0 +1,78 @@ +package org.ton.contract.wallet + +import io.github.andreypfau.kotlinx.crypto.sha2.sha256 +import kotlinx.coroutines.delay +import kotlinx.coroutines.runBlocking +import org.ton.api.pk.PrivateKeyEd25519 +import org.ton.block.AccountInfo +import org.ton.block.AddrStd +import org.ton.block.Coins +import kotlin.test.Ignore +import kotlin.test.Test + +class WalletV4Example { + @Ignore + @Test + fun walletExample(): Unit = runBlocking { + val liteClient = liteClientTestnet() + + val pk = PrivateKeyEd25519(sha256("example-key".encodeToByteArray())) + val contract = WalletV4R2Contract( + liteClient, + WalletV4R2Contract.address(pk) + ) + val testnetNonBounceAddr = contract.address.toString(userFriendly = true, testOnly = true, bounceable = false) + println("Wallet Address: $testnetNonBounceAddr") + + var accountState = liteClient.getAccountState(contract.address) + val account = accountState.account.value as? AccountInfo + if (account == null) { + println("Account $testnetNonBounceAddr not initialized") + return@runBlocking + } + + val balance = account.storage.balance.coins + println("Account balance: $balance toncoins") + + contract.transfer(pk) { + coins = Coins.Companion.ofNano(100) // 100 nanoton + destination = AddrStd("kf8ZzXwnCm23GeqkK8ekU0Dxzu_fiXqIYO48FElkd7rVnoix") + messageData = MessageData.text("Hello, World!") + } + + while (true) { + println("Wait for transaction to be processed...") + delay(6000) + val newAccountState = liteClient.getAccountState(contract.address) + if (newAccountState != accountState) { + accountState = newAccountState + println("Got new account state with last transaction: ${accountState.lastTransactionId}") + break + } + } + + val lastTransactionId = accountState.lastTransactionId + if (lastTransactionId == null) { + println("No transactions found") + return@runBlocking + } + + val transaction = liteClient.getTransactions(accountState.address, lastTransactionId, 1) + .first().transaction.value + println("Transaction: $lastTransactionId") + + transaction.r1.value.outMsgs.forEach { (hash, outMsgCell) -> + val outMsgBody = outMsgCell.value.body.let { + requireNotNull(it.x ?: it.y?.value) { "Body for message $hash is empty!" } + } + + val rawMessageText = try { + MessageText.loadTlb(outMsgBody) + } catch (e: Exception) { + null + } + + println("Message text: $rawMessageText") + } + } +} diff --git a/liteapi-tl/src/exception/LiteServerException.kt b/liteapi-tl/src/exception/exceptions.kt similarity index 100% rename from liteapi-tl/src/exception/LiteServerException.kt rename to liteapi-tl/src/exception/exceptions.kt diff --git a/settings.gradle.kts b/settings.gradle.kts index 9f943357..d51c838c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -10,8 +10,8 @@ pluginManagement { } plugins { - kotlin("multiplatform") version "1.9.20" - kotlin("plugin.serialization") version "1.9.20" + kotlin("multiplatform") version "1.9.22" + kotlin("plugin.serialization") version "1.9.22" } }