diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/SmartContract.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/SmartContract.kt index 1bd814a9..1ca5c0a9 100644 --- a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/SmartContract.kt +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/SmartContract.kt @@ -10,32 +10,43 @@ import org.ton.lite.api.liteserver.LiteServerSendMsgStatus import org.ton.tlb.TlbCodec import org.ton.tlb.storeTlb +/** + * Basic interface to any smart-contract that can be used to either deploy new contracts to the network or work with + * already deployed contracts. + * Only fields that are by definition known for all contracts are present here, more can be freely added by specific implementations + */ interface SmartContract { - val liteApi: LiteApi - val workchainId: Int - val name: String - val code: Cell - + /** + * Different workchains may define own mechanisms, therefore it is important to know workchain id. + * + * Note: This particular smart-contract interface is only valid for basic workchain (id=0) and masterchain (id=1) + */ + val workchain_id: Int + + /** + * Create initial code cell + */ + fun createCodeInit(): Cell + + /** + * Create initial data cell + */ fun createDataInit(): Cell - fun createStateInit(): StateInit = StateInit( - code, createDataInit() - ) - - fun address(stateInit: StateInit = createStateInit()): AddrStd = - address(workchainId, stateInit) - - fun createExternalInitMessage(): Message + /** + * Create state_init structure based on [createCodeInit] and [createDataInit] + */ + fun createStateInit(): StateInit = StateInit(createCodeInit(), createDataInit()) - suspend fun deploy(): LiteServerSendMsgStatus - - override fun toString(): String + /** + * Compute address of a smart-contract based on its [createStateInit] + */ + fun address(): AddrStd = address(workchain_id, createStateInit()) companion object { - private val stateInitCodec: TlbCodec by lazy { - StateInit.tlbCodec() - } + private val stateInitCodec: TlbCodec by lazy { StateInit.tlbCodec() } + /** Compute address of a smart-contract by its [workchainId] and [stateInit] */ @JvmStatic fun address(workchainId: Int, stateInit: StateInit): AddrStd { val cell = CellBuilder.createCell { diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/BasicTransferWallet.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/BasicTransferWallet.kt new file mode 100644 index 00000000..574a4307 --- /dev/null +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/BasicTransferWallet.kt @@ -0,0 +1,19 @@ +package org.ton.smartcontract.wallet + +import org.ton.api.pk.PrivateKeyEd25519 +import org.ton.api.pub.PublicKeyEd25519 +import org.ton.cell.Cell +import org.ton.cell.CellBuilder +import org.ton.smartcontract.wallet.builder.SignedSeqnoTransferBuilder + +abstract class BasicTransferWallet( + private val private_key: PrivateKeyEd25519, + override val workchain_id: Int = 0 +) : SignedSeqnoTransferWallet { + override fun publicKey(): PublicKeyEd25519 = private_key.publicKey() + + override fun createDataInit(): Cell = CellBuilder.createCell { + storeUInt(0, 32) // seqno + storeBytes(publicKey().key) + } +} diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/GetPublicKeyWallet.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/GetPublicKeyWallet.kt deleted file mode 100644 index 2b0effb0..00000000 --- a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/GetPublicKeyWallet.kt +++ /dev/null @@ -1,18 +0,0 @@ -package org.ton.smartcontract.wallet - -import org.ton.api.pub.PublicKeyEd25519 -import org.ton.api.tonnode.TonNodeBlockIdExt -import org.ton.block.VmStackValue -import org.ton.lite.api.liteserver.LiteServerAccountId -import org.ton.smartcontract.SmartContract - -interface GetPublicKeyWallet : SmartContract { - suspend fun getPublicKey(): PublicKeyEd25519 = getPublicKey(liteApi.getMasterchainInfo().last) - - suspend fun getPublicKey(blockIdExt: TonNodeBlockIdExt): PublicKeyEd25519 { - val liteServerAccountId = LiteServerAccountId(address()) - val result = liteApi.runSmcMethod(4, blockIdExt, liteServerAccountId, "get_public_key") - val rawPublicKey = (result.first() as VmStackValue.Int).value.toByteArray() - return PublicKeyEd25519(rawPublicKey) - } -} diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/SeqnoTransferWallet.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/SeqnoTransferWallet.kt new file mode 100644 index 00000000..74514a66 --- /dev/null +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/SeqnoTransferWallet.kt @@ -0,0 +1,9 @@ +package org.ton.smartcontract.wallet + +import org.ton.smartcontract.wallet.builder.SeqnoTransferBuilder + +/** + * A wallet which requires you to supply seqno in order to + */ +interface SeqnoTransferWallet : TransferWallet, + SeqnoWallet diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/SeqnoWallet.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/SeqnoWallet.kt index ceab6dcf..9e26a533 100644 --- a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/SeqnoWallet.kt +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/SeqnoWallet.kt @@ -2,15 +2,27 @@ package org.ton.smartcontract.wallet import org.ton.api.tonnode.TonNodeBlockIdExt import org.ton.block.VmStackValue +import org.ton.lite.api.LiteApi import org.ton.lite.api.liteserver.LiteServerAccountId -import org.ton.smartcontract.SmartContract -interface SeqnoWallet : SmartContract { - suspend fun seqno(): Int = seqno(liteApi.getMasterchainInfo().last) +/** + * Most wallets implement sequence number (seqno) in order to circumvent replay attacks + */ +interface SeqnoWallet : Wallet { + /** + * Get most recent seqno + */ + suspend fun seqno(liteApi: LiteApi): Int = seqno(liteApi, liteApi.getMasterchainInfo().last) - suspend fun seqno(blockIdExt: TonNodeBlockIdExt): Int { + /** + * Get seqno value as of [referenceBlockId] + */ + suspend fun seqno(liteApi: LiteApi, referenceBlockId: TonNodeBlockIdExt): Int { val liteServerAccountId = LiteServerAccountId(address()) - val result = liteApi.runSmcMethod(4, blockIdExt, liteServerAccountId, "seqno") + val result = liteApi.runSmcMethod(4, referenceBlockId, liteServerAccountId, "seqno") + require(result.exitCode == 0) { "failed to run smc method `seqno` with exit code ${result.exitCode}" } + require(result.resultValues().orEmpty().size == 1 && (result.first() !is VmStackValue.TinyInt)) + { "failed to get proper result for `seqno` smc method" } return (result.first() as VmStackValue.TinyInt).value.toInt() } } diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/SignedSeqnoTransferWallet.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/SignedSeqnoTransferWallet.kt new file mode 100644 index 00000000..69b42b19 --- /dev/null +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/SignedSeqnoTransferWallet.kt @@ -0,0 +1,9 @@ +package org.ton.smartcontract.wallet + +import org.ton.smartcontract.wallet.builder.SignedSeqnoTransferBuilder + +/** + * Base class for almost every wallet contract out there, uses private key for authorization but also requires seqno + */ +interface SignedSeqnoTransferWallet : SignedTransferWallet, + SeqnoTransferWallet diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/SignedTransferWallet.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/SignedTransferWallet.kt new file mode 100644 index 00000000..b72ab68e --- /dev/null +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/SignedTransferWallet.kt @@ -0,0 +1,14 @@ +package org.ton.smartcontract.wallet + +import org.ton.api.pub.PublicKeyEd25519 +import org.ton.smartcontract.wallet.builder.SignedTransferBuilder + +/** + * Most often operations on wallets are authorized using a single Ed25519 private key + */ +interface SignedTransferWallet : TransferWallet { + /** + * Get wallet's public key + */ + fun publicKey(): PublicKeyEd25519 +} diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/SignedWallet.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/SignedWallet.kt new file mode 100644 index 00000000..e333ce52 --- /dev/null +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/SignedWallet.kt @@ -0,0 +1,31 @@ +package org.ton.smartcontract.wallet + +import org.ton.api.pub.PublicKeyEd25519 +import org.ton.api.tonnode.TonNodeBlockIdExt +import org.ton.block.VmStackValue +import org.ton.lite.api.LiteApi +import org.ton.lite.api.liteserver.LiteServerAccountId + +/** + * Most wallets implement method `get_public_key` + */ +interface SignedWallet : Wallet { + /** + * Get most recent public_key + */ + suspend fun getPublicKey(liteApi: LiteApi): PublicKeyEd25519 = + getPublicKey(liteApi, liteApi.getMasterchainInfo().last) + + /** + * Get public key value as of [referenceBlockId] + */ + suspend fun getPublicKey(liteApi: LiteApi, referenceBlockId: TonNodeBlockIdExt): PublicKeyEd25519 { + val liteServerAccountId = LiteServerAccountId(address()) + val result = liteApi.runSmcMethod(4, referenceBlockId, liteServerAccountId, "get_public_key") + require(result.exitCode == 0) { "failed to run smc method `get_public_key` with exit code ${result.exitCode}" } + require(result.resultValues().orEmpty().size == 1 && (result.first() !is VmStackValue.Int)) + { "failed to get proper result for `get_public_key` smc method" } + val rawPublicKey = (result.first() as VmStackValue.Int).value.toByteArray() + return PublicKeyEd25519(rawPublicKey) + } +} diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/TransferWallet.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/TransferWallet.kt new file mode 100644 index 00000000..02606bce --- /dev/null +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/TransferWallet.kt @@ -0,0 +1,19 @@ +package org.ton.smartcontract.wallet + +import org.ton.lite.api.LiteApi +import org.ton.smartcontract.wallet.builder.TransferBuilder + +/** + * Wallet contract we have a permission to perform operations on, such as transfers etc. + */ +interface TransferWallet : Wallet { + suspend fun beginTransfer(lite_api: LiteApi): TMB + + /** + * Perform a transfer of funds + */ + suspend fun transfer(lite_api: LiteApi, builder: TMB.() -> Unit) { + val msg = beginTransfer(lite_api).apply(builder).createMessage() + lite_api.sendMessage(msg) + } +} diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/Wallet.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/Wallet.kt new file mode 100644 index 00000000..19cf9b9a --- /dev/null +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/Wallet.kt @@ -0,0 +1,13 @@ +package org.ton.smartcontract.wallet + +import org.ton.cell.Cell +import org.ton.smartcontract.SmartContract + +/** + * Base interface for all wallet contracts, any externally-controlled contract whose main purpose is sending and receiving funds. + */ +interface Wallet : SmartContract { + override fun createDataInit(): Cell { + throw Exception("cannot create data cell") + } +} diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/WalletContract.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/WalletContract.kt deleted file mode 100644 index 5c10c723..00000000 --- a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/WalletContract.kt +++ /dev/null @@ -1,150 +0,0 @@ -package org.ton.smartcontract.wallet - -import org.ton.api.pk.PrivateKeyEd25519 -import org.ton.block.* -import org.ton.cell.Cell -import org.ton.cell.CellBuilder -import org.ton.cell.exception.CellOverflowException -import org.ton.cell.storeRef -import org.ton.lite.api.LiteApi -import org.ton.lite.api.liteserver.LiteServerSendMsgStatus -import org.ton.logger.Logger -import org.ton.smartcontract.SmartContract -import org.ton.tlb.constructor.AnyTlbConstructor -import org.ton.tlb.storeTlb - -abstract class WalletContract( - override val liteApi: LiteApi, - val privateKey: PrivateKeyEd25519, - override val workchainId: Int = 0 -) : SmartContract { - val logger: Logger by lazy { - Logger.println(name, Logger.Level.DEBUG) - } - - override suspend fun deploy(): LiteServerSendMsgStatus { - val initMessage = createExternalInitMessage() - logger.info { "Deploy: $initMessage" } - return liteApi.sendMessage(initMessage) - } - - suspend fun transfer( - dest: MsgAddressInt, - bounce: Boolean, - coins: Coins, - seqno: Int, - comment: String? - ): LiteServerSendMsgStatus = transfer(dest, bounce, coins, seqno, createCommentPayload(comment)) - - suspend fun transfer( - dest: MsgAddressInt, - bounce: Boolean, - coins: Coins, - seqno: Int, - payload: Cell, - destinationStateInit: StateInit? = null, - ): LiteServerSendMsgStatus { - val transferMessage = createTransferMessage(dest, bounce, coins, seqno, payload, destinationStateInit = destinationStateInit) - logger.info { "Transfer: $transferMessage" } - return liteApi.sendMessage(transferMessage) - } - - override fun createDataInit(): Cell = CellBuilder.createCell { - storeUInt(0, 32) // seqno - storeBytes(privateKey.publicKey().key) - } - - open fun createSigningMessage(seqno: Int, builder: CellBuilder.() -> Unit = {}): Cell = CellBuilder.createCell { - storeUInt(seqno, 32) - apply(builder) - } - - override fun createExternalInitMessage(): Message { - val stateInit = createStateInit() - val dest = address(stateInit) - val signingMessage = createSigningMessage(0) - val signature = privateKey.sign(signingMessage.hash()) - val body = CellBuilder.createCell { - storeBytes(signature) - storeBits(signingMessage.bits) - storeRefs(signingMessage.refs) - } - val info = ExtInMsgInfo(dest) - return Message( - info, - stateInit to null, - body to null - ) - } - - fun createTransferMessage( - dest: MsgAddressInt, - bounce: Boolean, - amount: Coins, - seqno: Int, - payload: Cell, - sendMode: Int = 3, - destinationStateInit: StateInit? = null, - ): Message { - val stateInit = createStateInit() - val address = address(stateInit) - val info = ExtInMsgInfo(address) - val signingMessage = createSigningMessage(seqno) { - storeUInt(sendMode, 8) - storeRef { - val messageRelaxed = MessageRelaxed( - info = CommonMsgInfoRelaxed.IntMsgInfoRelaxed( - ihrDisabled = true, - bounce = bounce, - bounced = false, - src = AddrNone, - dest = dest, - value = CurrencyCollection( - coins = amount - ) - ), - init = destinationStateInit, - body = payload, - storeBodyInRef = false - ) - try { - storeTlb(MessageRelaxed.tlbCodec(AnyTlbConstructor), messageRelaxed) - } catch (e: CellOverflowException) { - storeTlb( - MessageRelaxed.tlbCodec(AnyTlbConstructor), messageRelaxed.copy( - body = Either.of(null, payload) - ) - ) - } - } - } - val signature = privateKey.sign(signingMessage.hash()) - val body = CellBuilder.createCell { - storeBytes(signature) - storeBits(signingMessage.bits) - storeRefs(signingMessage.refs) - } - return Message( - info = info, - init = null, - body = body, - storeInitInRef = false, - storeBodyInRef = false - ) - } - - fun createCommentPayload(comment: String? = null): Cell { - return if (comment == null) { - Cell.of() - } else { - val commentBytes = comment.encodeToByteArray() - require(commentBytes.size <= 123) { TODO("Commentaries with more than 123 bytes not supported yet. Provided: ${commentBytes.size}") } - CellBuilder.createCell { - storeUInt(0, 32) - storeBytes(commentBytes) - } - } - } - - override fun toString(): String = name -} diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/builder/BasicTransferBuilder.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/builder/BasicTransferBuilder.kt new file mode 100644 index 00000000..63a6f47b --- /dev/null +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/builder/BasicTransferBuilder.kt @@ -0,0 +1,24 @@ +package org.ton.smartcontract.wallet.builder + +import org.ton.api.pk.PrivateKeyEd25519 +import org.ton.block.Coins +import org.ton.block.MsgAddressInt +import org.ton.block.StateInit +import org.ton.cell.Cell +import org.ton.lite.api.LiteApi + +abstract class BasicTransferBuilder( + private val private_key: PrivateKeyEd25519, + override val lite_api: LiteApi, + override val src: MsgAddressInt, + override var seqno: Int, + override var payload: Cell = Cell.of(), + override var bounce: Boolean = true, + override var send_mode: Int = 3, + override var dest_state_init: StateInit? = null, +) : SignedSeqnoTransferBuilder { + override lateinit var dest: MsgAddressInt + override lateinit var amount: Coins + + override fun signCell(data: Cell): ByteArray = private_key.sign(data.hash()) +} diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/builder/SeqnoTransferBuilder.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/builder/SeqnoTransferBuilder.kt new file mode 100644 index 00000000..bf1a5ef7 --- /dev/null +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/builder/SeqnoTransferBuilder.kt @@ -0,0 +1,13 @@ +package org.ton.smartcontract.wallet.builder + +import org.ton.cell.Cell +import org.ton.cell.CellBuilder + +interface SeqnoTransferBuilder : TransferBuilder { + var seqno: Int + + override fun createData(builder: CellBuilder.() -> Unit): Cell = super.createData { + storeUInt(seqno, 32) + apply(builder) + } +} diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/builder/SignedSeqnoTransferBuilder.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/builder/SignedSeqnoTransferBuilder.kt new file mode 100644 index 00000000..21d76a9b --- /dev/null +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/builder/SignedSeqnoTransferBuilder.kt @@ -0,0 +1,11 @@ +package org.ton.smartcontract.wallet.builder + +import org.ton.cell.Cell +import org.ton.cell.CellBuilder + +interface SignedSeqnoTransferBuilder : SignedTransferBuilder, SeqnoTransferBuilder { + override fun createData(builder: CellBuilder.() -> Unit): Cell = + super.createData { + super.createData(builder) + } +} diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/builder/SignedTransferBuilder.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/builder/SignedTransferBuilder.kt new file mode 100644 index 00000000..97f30c97 --- /dev/null +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/builder/SignedTransferBuilder.kt @@ -0,0 +1,17 @@ +package org.ton.smartcontract.wallet.builder + +import org.ton.cell.Cell +import org.ton.cell.CellBuilder + +interface SignedTransferBuilder : TransferBuilder { + fun signCell(data: Cell): ByteArray + + override fun createData(builder: CellBuilder.() -> Unit): Cell { + val data = CellBuilder.createCell { apply(builder) } + return super.createData { + storeBytes(signCell(data)) + storeBits(data.bits) + storeRefs(data.refs) + } + } +} diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/builder/TransferBuilder.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/builder/TransferBuilder.kt new file mode 100644 index 00000000..bcb8672a --- /dev/null +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/builder/TransferBuilder.kt @@ -0,0 +1,71 @@ +package org.ton.smartcontract.wallet.builder + +import org.ton.block.* +import org.ton.cell.Cell +import org.ton.cell.CellBuilder +import org.ton.cell.exception.CellOverflowException +import org.ton.cell.storeRef +import org.ton.lite.api.LiteApi +import org.ton.tlb.constructor.AnyTlbConstructor +import org.ton.tlb.storeTlb + +interface TransferBuilder { + val lite_api: LiteApi + val src: MsgAddressInt + + var dest: MsgAddressInt + var amount: Coins + var payload: Cell + var bounce: Boolean + var send_mode: Int + var dest_state_init: StateInit? + + var comment: String + get() = TODO() + set(value) { + val commentBytes = comment.encodeToByteArray() + require(commentBytes.size <= 123) { TODO("comment is too long: ${commentBytes.size} bytes provided, 123 max supported") } + payload = CellBuilder.createCell { + storeUInt(0, 32) // op == 0 for comments + storeBytes(commentBytes) + } + } + + fun createData(builder: CellBuilder.() -> Unit = {}): Cell = CellBuilder.createCell { apply(builder) } + + fun createMessage(): Message = Message( + info = ExtInMsgInfo(src), + init = null, + body = createData { + storeUInt(send_mode, 8) + storeRef { + val messageRelaxed = MessageRelaxed( + info = CommonMsgInfoRelaxed.IntMsgInfoRelaxed( + ihrDisabled = true, + bounce = bounce, + bounced = false, + src = AddrNone, + dest = dest, + value = CurrencyCollection( + coins = amount + ) + ), + init = dest_state_init, + body = payload, + storeBodyInRef = false + ) + try { + storeTlb(MessageRelaxed.tlbCodec(AnyTlbConstructor), messageRelaxed) + } catch (e: CellOverflowException) { + storeTlb( + MessageRelaxed.tlbCodec(AnyTlbConstructor), messageRelaxed.copy( + body = Either.of(null, payload) + ) + ) + } + } + }, + storeInitInRef = false, + storeBodyInRef = false + ) +} diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/AbstractWalletV1.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/AbstractWalletV1.kt deleted file mode 100644 index ce680f4d..00000000 --- a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/AbstractWalletV1.kt +++ /dev/null @@ -1,11 +0,0 @@ -package org.ton.smartcontract.wallet.v1 - -import org.ton.api.pk.PrivateKeyEd25519 -import org.ton.lite.api.LiteApi -import org.ton.smartcontract.wallet.WalletContract - -abstract class AbstractWalletV1( - liteApi: LiteApi, - privateKey: PrivateKeyEd25519, - workchainId: Int = 0 -) : WalletContract(liteApi, privateKey, workchainId) diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/TransferWalletV1R1.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/TransferWalletV1R1.kt new file mode 100644 index 00000000..3cfbb7c3 --- /dev/null +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/TransferWalletV1R1.kt @@ -0,0 +1,6 @@ +package org.ton.smartcontract.wallet.v1 + +import org.ton.api.pk.PrivateKeyEd25519 + +class TransferWalletV1R1(private_key: PrivateKeyEd25519, override val workchain_id: Int = 0) : + V1TransferWallet(private_key, workchain_id), WalletV1R1 diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/TransferWalletV1R2.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/TransferWalletV1R2.kt new file mode 100644 index 00000000..aedaaebc --- /dev/null +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/TransferWalletV1R2.kt @@ -0,0 +1,6 @@ +package org.ton.smartcontract.wallet.v1 + +import org.ton.api.pk.PrivateKeyEd25519 + +class TransferWalletV1R2(private_key: PrivateKeyEd25519, override val workchain_id: Int = 0) : + V1TransferWallet(private_key, workchain_id), WalletV1R2 diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/TransferWalletV1R3.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/TransferWalletV1R3.kt new file mode 100644 index 00000000..eb32903b --- /dev/null +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/TransferWalletV1R3.kt @@ -0,0 +1,6 @@ +package org.ton.smartcontract.wallet.v1 + +import org.ton.api.pk.PrivateKeyEd25519 + +class TransferWalletV1R3(private_key: PrivateKeyEd25519, override val workchain_id: Int = 0) : + V1TransferWallet(private_key, workchain_id), WalletV1R3 diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/V1TransferBuilder.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/V1TransferBuilder.kt new file mode 100644 index 00000000..2a2e9823 --- /dev/null +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/V1TransferBuilder.kt @@ -0,0 +1,33 @@ +package org.ton.smartcontract.wallet.v1 + +import org.ton.api.pk.PrivateKeyEd25519 +import org.ton.block.Coins +import org.ton.block.MsgAddressInt +import org.ton.block.StateInit +import org.ton.cell.Cell +import org.ton.lite.api.LiteApi +import org.ton.smartcontract.wallet.builder.BasicTransferBuilder + +class V1TransferBuilder( + private_key: PrivateKeyEd25519, + override val lite_api: LiteApi, + override val src: MsgAddressInt, + override var seqno: Int = 0, + override var payload: Cell = Cell.of(), + override var bounce: Boolean = true, + override var send_mode: Int = 3, + override var dest_state_init: StateInit? = null, +) : + BasicTransferBuilder( + private_key, + lite_api, + src, + seqno, + payload, + bounce, + send_mode, + dest_state_init + ) { + override lateinit var dest: MsgAddressInt + override lateinit var amount: Coins +} diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/V1TransferWallet.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/V1TransferWallet.kt new file mode 100644 index 00000000..facafdec --- /dev/null +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/V1TransferWallet.kt @@ -0,0 +1,16 @@ +package org.ton.smartcontract.wallet.v1 + +import org.ton.api.pk.PrivateKeyEd25519 +import org.ton.lite.api.LiteApi +import org.ton.smartcontract.wallet.BasicTransferWallet + +abstract class V1TransferWallet(private val private_key: PrivateKeyEd25519, override val workchain_id: Int) : + BasicTransferWallet(private_key) { + override suspend fun beginTransfer(lite_api: LiteApi): V1TransferBuilder = + V1TransferBuilder( + private_key = private_key, + lite_api = lite_api, + src = address(), + seqno = seqno(lite_api) + ) +} diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/WalletV1R1.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/WalletV1R1.kt index 0d92fb6d..7db7d358 100644 --- a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/WalletV1R1.kt +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/WalletV1R1.kt @@ -1,24 +1,20 @@ package org.ton.smartcontract.wallet.v1 -import org.ton.api.pk.PrivateKeyEd25519 import org.ton.cell.Cell -import org.ton.lite.api.LiteApi +import org.ton.smartcontract.wallet.SeqnoWallet +import org.ton.smartcontract.wallet.SignedWallet +import org.ton.smartcontract.wallet.Wallet /** * Wallet v1 revision 1 * * [Fift-ASM source-code](https://github.com/ton-blockchain/ton/blob/c2da007f4065e2520e0d948b146e0fb12fa75751/crypto/smartcont/new-wallet.fif) */ -class WalletV1R1( - liteApi: LiteApi, - privateKey: PrivateKeyEd25519, - workchainId: Int = 0 -) : AbstractWalletV1(liteApi, privateKey, workchainId) { - override val name: String = "v1r1" - override val code: Cell = CODE - - companion object { - val CODE: Cell = - Cell("FF0020DDA4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54") - } +interface WalletV1R1 : Wallet, SeqnoWallet, SignedWallet { + override fun createCodeInit(): Cell = + Cell("FF0020DDA4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54") } + +private class WalletV1R1Impl( + override val workchain_id: Int = 0 +) : WalletV1R1 diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/WalletV1R2.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/WalletV1R2.kt index 6fc6485a..cadbc643 100644 --- a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/WalletV1R2.kt +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/WalletV1R2.kt @@ -1,9 +1,9 @@ package org.ton.smartcontract.wallet.v1 -import org.ton.api.pk.PrivateKeyEd25519 import org.ton.cell.Cell -import org.ton.lite.api.LiteApi import org.ton.smartcontract.wallet.SeqnoWallet +import org.ton.smartcontract.wallet.SignedWallet +import org.ton.smartcontract.wallet.Wallet /** * Wallet v1 revision 2 @@ -12,16 +12,11 @@ import org.ton.smartcontract.wallet.SeqnoWallet * * [Fift-ASM source-code](https://github.com/ton-blockchain/ton/blob/47814dca3d4d7d253f0dcbb2ef176f45aafc6871/crypto/smartcont/new-wallet.fif) */ -class WalletV1R2( - liteApi: LiteApi, - privateKey: PrivateKeyEd25519, - workchainId: Int = 0 -) : AbstractWalletV1(liteApi, privateKey, workchainId), SeqnoWallet { - override val name: String = "v1r2" - override val code: Cell = CODE - - companion object { - val CODE: Cell = - Cell("FF0020DD2082014C97BA9730ED44D0D70B1FE0A4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54") - } +interface WalletV1R2 : Wallet, SeqnoWallet, SignedWallet { + override fun createCodeInit(): Cell = + Cell("FF0020DD2082014C97BA9730ED44D0D70B1FE0A4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54") } + +private class WalletV1R2Impl( + override val workchain_id: Int = 0 +) : WalletV1R2 diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/WalletV1R3.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/WalletV1R3.kt index d0391c31..f817f382 100644 --- a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/WalletV1R3.kt +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v1/WalletV1R3.kt @@ -1,10 +1,9 @@ package org.ton.smartcontract.wallet.v1 -import org.ton.api.pk.PrivateKeyEd25519 import org.ton.cell.Cell -import org.ton.lite.api.LiteApi -import org.ton.smartcontract.wallet.GetPublicKeyWallet import org.ton.smartcontract.wallet.SeqnoWallet +import org.ton.smartcontract.wallet.SignedWallet +import org.ton.smartcontract.wallet.Wallet /** * Wallet v1 revision 3 @@ -13,16 +12,11 @@ import org.ton.smartcontract.wallet.SeqnoWallet * * [Fift-ASM source-code](https://github.com/ton-blockchain/ton/blob/master/crypto/smartcont/new-wallet.fif) */ -class WalletV1R3( - liteApi: LiteApi, - privateKey: PrivateKeyEd25519, - workchainId: Int = 0 -) : AbstractWalletV1(liteApi, privateKey, workchainId), SeqnoWallet, GetPublicKeyWallet { - override val name: String = "v1r3" - override val code: Cell = CODE - - companion object { - val CODE: Cell = - Cell("FF0020DD2082014C97BA218201339CBAB19C71B0ED44D0D31FD70BFFE304E0A4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54") - } +interface WalletV1R3 : Wallet, SeqnoWallet, SignedWallet { + override fun createCodeInit(): Cell = + Cell("FF0020DD2082014C97BA218201339CBAB19C71B0ED44D0D31FD70BFFE304E0A4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54") } + +private class WalletV1R3Impl( + override val workchain_id: Int = 0 +) : WalletV1R3 diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v2/AbstractAuthorizedWalletV2.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v2/AbstractAuthorizedWalletV2.kt new file mode 100644 index 00000000..81d9fbfa --- /dev/null +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v2/AbstractAuthorizedWalletV2.kt @@ -0,0 +1,25 @@ +package org.ton.smartcontract.wallet.v2 + +import kotlinx.datetime.Clock +import org.ton.api.pk.PrivateKeyEd25519 +import org.ton.bitstring.BitString +import org.ton.cell.Cell +import org.ton.cell.CellBuilder +import org.ton.smartcontract.wallet.AuthorizedEd25519SeqnoWalletContract + +abstract class AbstractAuthorizedWalletV2( + private_key: PrivateKeyEd25519, + workchain_id: Int = 0, + private val timeout: Long = 60 +) : AuthorizedEd25519SeqnoWalletContract(private_key, workchain_id) { + override fun createMessageData(seqno: Int, builder: CellBuilder.() -> Unit): Cell = + super.createMessageData(seqno) { + if (seqno == 0) { + storeBits(BitString("FFFFFFFF")) + } else { + val now = Clock.System.now().toEpochMilliseconds() / 1000 + storeUInt(now + timeout, 32) + } + apply(builder) + } +} diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v2/AbstractWalletV2.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v2/AbstractWalletV2.kt deleted file mode 100644 index 61a0c1b0..00000000 --- a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v2/AbstractWalletV2.kt +++ /dev/null @@ -1,29 +0,0 @@ -package org.ton.smartcontract.wallet.v2 - -import kotlinx.datetime.Clock -import org.ton.api.pk.PrivateKeyEd25519 -import org.ton.bitstring.BitString -import org.ton.cell.Cell -import org.ton.cell.CellBuilder -import org.ton.lite.api.LiteApi -import org.ton.smartcontract.wallet.SeqnoWallet -import org.ton.smartcontract.wallet.WalletContract - -abstract class AbstractWalletV2( - liteApi: LiteApi, - privateKey: PrivateKeyEd25519, - workchainId: Int = 0, - private val timeout: Long = 60 -) : WalletContract(liteApi, privateKey, workchainId), SeqnoWallet { - - override fun createSigningMessage(seqno: Int, builder: CellBuilder.() -> Unit): Cell = CellBuilder.createCell { - storeUInt(seqno, 32) - if (seqno == 0) { - storeBits(BitString("FFFFFFFF")) - } else { - val now = Clock.System.now().toEpochMilliseconds() / 1000 - storeUInt(now + timeout, 32) - } - apply(builder) - } -} diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v2/WalletV2R1.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v2/WalletV2R1.kt index b0eb696a..1e599c18 100644 --- a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v2/WalletV2R1.kt +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v2/WalletV2R1.kt @@ -2,7 +2,6 @@ package org.ton.smartcontract.wallet.v2 import org.ton.api.pk.PrivateKeyEd25519 import org.ton.cell.Cell -import org.ton.lite.api.LiteApi /** * Wallet v2 revision 1 @@ -12,16 +11,10 @@ import org.ton.lite.api.LiteApi * [Fift-ASM source-code](https://github.com/ton-blockchain/ton/blob/fd7a8de9708c9ece8d802890519735b55bc99a8e/crypto/smartcont/new-wallet-v2.fif) */ class WalletV2R1( - liteApi: LiteApi, - privateKey: PrivateKeyEd25519, - workchainId: Int = 0, - timeout: Long = 60 -) : AbstractWalletV2(liteApi, privateKey, workchainId, timeout) { - override val name: String = "v2R1" - override val code: Cell = CODE - - companion object { - val CODE: Cell = - Cell("FF0020DD2082014C97BA9730ED44D0D70B1FE0A4F2608308D71820D31FD31F01F823BBF263ED44D0D31FD3FFD15131BAF2A103F901541042F910F2A2F800029320D74A96D307D402FB00E8D1A4C8CB1FCBFFC9ED54") - } + private_key: PrivateKeyEd25519, + workchain_id: Int = 0, + timeout: Long = 60, +) : AbstractAuthorizedWalletV2(private_key, workchain_id, timeout) { + override fun createCodeInit(): Cell = + Cell("FF0020DD2082014C97BA9730ED44D0D70B1FE0A4F2608308D71820D31FD31F01F823BBF263ED44D0D31FD3FFD15131BAF2A103F901541042F910F2A2F800029320D74A96D307D402FB00E8D1A4C8CB1FCBFFC9ED54") } diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v2/WalletV2R2.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v2/WalletV2R2.kt index 0565eb80..86499d79 100644 --- a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v2/WalletV2R2.kt +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v2/WalletV2R2.kt @@ -2,8 +2,6 @@ package org.ton.smartcontract.wallet.v2 import org.ton.api.pk.PrivateKeyEd25519 import org.ton.cell.Cell -import org.ton.lite.api.LiteApi -import org.ton.smartcontract.wallet.GetPublicKeyWallet /** * Wallet v2 revision 2 @@ -13,16 +11,11 @@ import org.ton.smartcontract.wallet.GetPublicKeyWallet * [Fift-ASM source-code](https://github.com/ton-blockchain/ton/blob/master/crypto/smartcont/new-wallet-v2.fif) */ class WalletV2R2( - liteApi: LiteApi, - privateKey: PrivateKeyEd25519, - workchainId: Int = 0, - timeout: Long = 60 -) : AbstractWalletV2(liteApi, privateKey, workchainId, timeout), GetPublicKeyWallet { - override val name: String = "v2R2" - override val code: Cell = CODE - - companion object { - val CODE: Cell = - Cell("FF0020DD2082014C97BA218201339CBAB19C71B0ED44D0D31FD70BFFE304E0A4F2608308D71820D31FD31F01F823BBF263ED44D0D31FD3FFD15131BAF2A103F901541042F910F2A2F800029320D74A96D307D402FB00E8D1A4C8CB1FCBFFC9ED54") - } + private_key: PrivateKeyEd25519, + workchain_id: Int = 0, + timeout: Long = 60, +) : AbstractAuthorizedWalletV2(private_key, workchain_id, timeout) { + override fun createCodeInit(): Cell = + Cell("FF0020DD2082014C97BA218201339CBAB19C71B0ED44D0D31FD70BFFE304E0A4F2608308D71820D31FD31F01F823BBF263ED44D0D31FD3FFD15131BAF2A103F901541042F910F2A2F800029320D74A96D307D402FB00E8D1A4C8CB1FCBFFC9ED54") } + diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v3/AbstractAuthorizedWalletV3.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v3/AbstractAuthorizedWalletV3.kt new file mode 100644 index 00000000..18a1a11b --- /dev/null +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v3/AbstractAuthorizedWalletV3.kt @@ -0,0 +1,39 @@ +package org.ton.smartcontract.wallet.v3 + +import kotlinx.datetime.Clock +import org.ton.api.pk.PrivateKeyEd25519 +import org.ton.bitstring.BitString +import org.ton.cell.Cell +import org.ton.cell.CellBuilder +import org.ton.smartcontract.wallet.AuthorizedEd25519SeqnoWalletContract + +abstract class AbstractAuthorizedWalletV3( + private_key: PrivateKeyEd25519, + workchain_id: Int = 0, + val subwallet_id: Int = DEFAULT_WALLET_ID + workchain_id, + private val timeout: Long = 60 +) : AuthorizedEd25519SeqnoWalletContract(private_key, workchain_id) { + override fun createDataInit(): Cell = CellBuilder.createCell { + storeUInt(0, 32) // seqno + storeUInt(subwallet_id, 32) + storeBytes(publicKey().key) + } + + override fun createMessageData(seqno: Int, builder: CellBuilder.() -> Unit): Cell = + createSignedMessageData { + storeUInt(subwallet_id, 32) + if (seqno == 0) { + storeBits(BitString("FFFFFFFF")) + } else { + val now = Clock.System.now().toEpochMilliseconds() / 1000 + storeUInt(now + timeout, 32) + } + storeUInt(seqno, 32) + apply(builder) + } + + companion object { + const val DEFAULT_WALLET_ID = 698983191 + } +} + diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v3/AbstractWalletV3.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v3/AbstractWalletV3.kt deleted file mode 100644 index 8613bc04..00000000 --- a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v3/AbstractWalletV3.kt +++ /dev/null @@ -1,41 +0,0 @@ -package org.ton.smartcontract.wallet.v3 - -import kotlinx.datetime.Clock -import org.ton.api.pk.PrivateKeyEd25519 -import org.ton.bitstring.BitString -import org.ton.cell.Cell -import org.ton.cell.CellBuilder -import org.ton.lite.api.LiteApi -import org.ton.smartcontract.wallet.SeqnoWallet -import org.ton.smartcontract.wallet.WalletContract - -abstract class AbstractWalletV3( - liteApi: LiteApi, - privateKey: PrivateKeyEd25519, - workchainId: Int = 0, - val subwalletId: Int = DEFAULT_WALLET_ID + workchainId, - private val timeout: Long = 60 -) : WalletContract(liteApi, privateKey, workchainId), SeqnoWallet { - - override fun createDataInit(): Cell = CellBuilder.createCell { - storeUInt(0, 32) // seqno - storeUInt(subwalletId, 32) - storeBytes(privateKey.publicKey().key) - } - - override fun createSigningMessage(seqno: Int, builder: CellBuilder.() -> Unit): Cell = CellBuilder.createCell { - storeUInt(subwalletId, 32) - if (seqno == 0) { - storeBits(BitString("FFFFFFFF")) - } else { - val now = Clock.System.now().toEpochMilliseconds() / 1000 - storeUInt(now + timeout, 32) - } - storeUInt(seqno, 32) - apply(builder) - } - - companion object { - const val DEFAULT_WALLET_ID = 698983191 - } -} diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v3/WalletV3R1.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v3/WalletV3R1.kt index 414c7b34..920c8f53 100644 --- a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v3/WalletV3R1.kt +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v3/WalletV3R1.kt @@ -1,8 +1,8 @@ package org.ton.smartcontract.wallet.v3 +import io.ktor.http.* import org.ton.api.pk.PrivateKeyEd25519 import org.ton.cell.Cell -import org.ton.lite.api.LiteApi /** * Wallet v3 revision 1 @@ -13,17 +13,11 @@ import org.ton.lite.api.LiteApi * [Fift-ASM source-code](https://github.com/ton-blockchain/ton/blob/3002321eb779e9936243e3b5f00be7579fb07654/crypto/smartcont/new-wallet-v3.fif) */ class WalletV3R1( - liteApi: LiteApi, - privateKey: PrivateKeyEd25519, - workchainId: Int = 0, - subwalletId: Int = DEFAULT_WALLET_ID + workchainId, - timeout: Long = 60 -) : AbstractWalletV3(liteApi, privateKey, workchainId, subwalletId, timeout) { - override val name: String = "v3r1" - override val code: Cell = CODE - - companion object { - val CODE: Cell = - Cell("FF0020DD2082014C97BA9730ED44D0D70B1FE0A4F2608308D71820D31FD31FD31FF82313BBF263ED44D0D31FD31FD3FFD15132BAF2A15144BAF2A204F901541055F910F2A3F8009320D74A96D307D402FB00E8D101A4C8CB1FCB1FCBFFC9ED54") - } + private_key: PrivateKeyEd25519, + workchain_id: Int = 0, + subwallet_id: Int = DEFAULT_PORT + workchain_id, + timeout: Long = 60, +) : AbstractAuthorizedWalletV3(private_key, workchain_id, subwallet_id, timeout) { + override fun createCodeInit(): Cell = + Cell("FF0020DD2082014C97BA9730ED44D0D70B1FE0A4F2608308D71820D31FD31FD31FF82313BBF263ED44D0D31FD31FD3FFD15132BAF2A15144BAF2A204F901541055F910F2A3F8009320D74A96D307D402FB00E8D101A4C8CB1FCB1FCBFFC9ED54") } diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v3/WalletV3R2.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v3/WalletV3R2.kt index 48477d37..9116b8b9 100644 --- a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v3/WalletV3R2.kt +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v3/WalletV3R2.kt @@ -1,9 +1,8 @@ package org.ton.smartcontract.wallet.v3 +import io.ktor.http.* import org.ton.api.pk.PrivateKeyEd25519 import org.ton.cell.Cell -import org.ton.lite.api.LiteApi -import org.ton.smartcontract.wallet.GetPublicKeyWallet /** * Wallet v3 revision 1 @@ -13,17 +12,11 @@ import org.ton.smartcontract.wallet.GetPublicKeyWallet * [Fift-ASM source-code](https://github.com/ton-blockchain/ton/blob/3002321eb779e9936243e3b5f00be7579fb07654/crypto/smartcont/new-wallet-v3.fif) */ class WalletV3R2( - liteApi: LiteApi, - privateKey: PrivateKeyEd25519, - workchainId: Int = 0, - subwalletId: Int = DEFAULT_WALLET_ID + workchainId, - timeout: Long = 60 -) : AbstractWalletV3(liteApi, privateKey, workchainId, subwalletId, timeout), GetPublicKeyWallet { - override val name: String = "v3r2" - override val code: Cell = CODE - - companion object { - val CODE: Cell = - Cell("FF0020DD2082014C97BA218201339CBAB19F71B0ED44D0D31FD31F31D70BFFE304E0A4F2608308D71820D31FD31FD31FF82313BBF263ED44D0D31FD31FD3FFD15132BAF2A15144BAF2A204F901541055F910F2A3F8009320D74A96D307D402FB00E8D101A4C8CB1FCB1FCBFFC9ED54") - } + private_key: PrivateKeyEd25519, + workchain_id: Int = 0, + subwallet_id: Int = DEFAULT_PORT + workchain_id, + timeout: Long = 60, +) : AbstractAuthorizedWalletV3(private_key, workchain_id, subwallet_id, timeout) { + override fun createCodeInit(): Cell = + Cell("FF0020DD2082014C97BA218201339CBAB19F71B0ED44D0D31FD31F31D70BFFE304E0A4F2608308D71820D31FD31FD31FF82313BBF263ED44D0D31FD31FD3FFD15132BAF2A15144BAF2A204F901541055F910F2A3F8009320D74A96D307D402FB00E8D101A4C8CB1FCB1FCBFFC9ED54") } diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v4/AbstractAuthorizedWalletV4.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v4/AbstractAuthorizedWalletV4.kt new file mode 100644 index 00000000..f32f6841 --- /dev/null +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v4/AbstractAuthorizedWalletV4.kt @@ -0,0 +1,41 @@ +package org.ton.smartcontract.wallet.v4 + +import kotlinx.datetime.Clock +import org.ton.api.pk.PrivateKeyEd25519 +import org.ton.bitstring.BitString +import org.ton.cell.Cell +import org.ton.cell.CellBuilder +import org.ton.smartcontract.wallet.AuthorizedEd25519SeqnoWalletContract + +abstract class AbstractAuthorizedWalletV4( + private_key: PrivateKeyEd25519, + workchain_id: Int = 0, + val subwallet_id: Int = DEFAULT_WALLET_ID + workchain_id, + private val timeout: Long = 60 +) : AuthorizedEd25519SeqnoWalletContract(private_key, workchain_id) { + override fun createDataInit(): Cell = CellBuilder.createCell { + storeUInt(0, 32) // seqno + storeUInt(subwallet_id, 32) + storeBytes(publicKey().key) + storeUInt(0, 1) // plugins dict empty + } + + override fun createMessageData(seqno: Int, builder: CellBuilder.() -> Unit): Cell = + createSignedMessageData { + storeUInt(subwallet_id, 32) + if (seqno == 0) { + storeBits(BitString("FFFFFFFF")) + } else { + val now = Clock.System.now().toEpochMilliseconds() / 1000 + storeUInt(now + timeout, 32) + } + storeUInt(seqno, 32) + storeUInt(0, 8) // op + apply(builder) + } + + companion object { + const val DEFAULT_WALLET_ID = 698983191 + } +} + diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v4/AbstractWalletV4.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v4/AbstractWalletV4.kt deleted file mode 100644 index a084675b..00000000 --- a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v4/AbstractWalletV4.kt +++ /dev/null @@ -1,44 +0,0 @@ -package org.ton.smartcontract.wallet.v4 - -import kotlinx.datetime.Clock -import org.ton.api.pk.PrivateKeyEd25519 -import org.ton.bitstring.BitString -import org.ton.cell.Cell -import org.ton.cell.CellBuilder -import org.ton.lite.api.LiteApi -import org.ton.smartcontract.wallet.GetPublicKeyWallet -import org.ton.smartcontract.wallet.SeqnoWallet -import org.ton.smartcontract.wallet.WalletContract - -abstract class AbstractWalletV4( - liteApi: LiteApi, - privateKey: PrivateKeyEd25519, - workchainId: Int = 0, - val subwalletId: Int = DEFAULT_WALLET_ID + workchainId, - private val timeout: Long = 60 -) : WalletContract(liteApi, privateKey, workchainId), SeqnoWallet, GetPublicKeyWallet { - - override fun createDataInit(): Cell = CellBuilder.createCell { - storeUInt(0, 32) // seqno - storeUInt(subwalletId, 32) - storeBytes(privateKey.publicKey().key) - storeUInt(0, 1) // plugins dict empty - } - - override fun createSigningMessage(seqno: Int, builder: CellBuilder.() -> Unit): Cell = CellBuilder.createCell { - storeUInt(subwalletId, 32) - if (seqno == 0) { - storeBits(BitString("FFFFFFFF")) - } else { - val now = Clock.System.now().toEpochMilliseconds() / 1000 - storeUInt(now + timeout, 32) - } - storeUInt(seqno, 32) - storeUInt(0, 8) // op - apply(builder) - } - - companion object { - const val DEFAULT_WALLET_ID = 698983191 - } -} diff --git a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v4/WalletV4R2.kt b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v4/WalletV4R2.kt index 1010ec03..3b09d385 100644 --- a/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v4/WalletV4R2.kt +++ b/ton-smartcontract/src/commonMain/kotlin/org/ton/smartcontract/wallet/v4/WalletV4R2.kt @@ -1,30 +1,23 @@ package org.ton.smartcontract.wallet.v4 +import io.ktor.http.* import org.ton.api.pk.PrivateKeyEd25519 import org.ton.boc.BagOfCells import org.ton.cell.Cell import org.ton.crypto.hex -import org.ton.lite.api.LiteApi -import org.ton.smartcontract.wallet.GetPublicKeyWallet /** * Wallet v4 revision 1 */ class WalletV4R2( - liteApi: LiteApi, - privateKey: PrivateKeyEd25519, - workchainId: Int = 0, - subwalletId: Int = DEFAULT_WALLET_ID + workchainId, - timeout: Long = 60 -) : AbstractWalletV4(liteApi, privateKey, workchainId, subwalletId, timeout), GetPublicKeyWallet { - override val name: String = "v4r2" - override val code: Cell = CODE - - companion object { - val CODE: Cell = BagOfCells( - hex( - "B5EE9C72410214010002D4000114FF00F4A413F4BCF2C80B010201200203020148040504F8F28308D71820D31FD31FD31F02F823BBF264ED44D0D31FD31FD3FFF404D15143BAF2A15151BAF2A205F901541064F910F2A3F80024A4C8CB1F5240CB1F5230CBFF5210F400C9ED54F80F01D30721C0009F6C519320D74A96D307D402FB00E830E021C001E30021C002E30001C0039130E30D03A4C8CB1F12CB1FCBFF1011121302E6D001D0D3032171B0925F04E022D749C120925F04E002D31F218210706C7567BD22821064737472BDB0925F05E003FA403020FA4401C8CA07CBFFC9D0ED44D0810140D721F404305C810108F40A6FA131B3925F07E005D33FC8258210706C7567BA923830E30D03821064737472BA925F06E30D06070201200809007801FA00F40430F8276F2230500AA121BEF2E0508210706C7567831EB17080185004CB0526CF1658FA0219F400CB6917CB1F5260CB3F20C98040FB0006008A5004810108F45930ED44D0810140D720C801CF16F400C9ED540172B08E23821064737472831EB17080185005CB055003CF1623FA0213CB6ACB1FCB3FC98040FB00925F03E20201200A0B0059BD242B6F6A2684080A06B90FA0218470D4080847A4937D29910CE6903E9FF9837812801B7810148987159F31840201580C0D0011B8C97ED44D0D70B1F8003DB29DFB513420405035C87D010C00B23281F2FFF274006040423D029BE84C600201200E0F0019ADCE76A26840206B90EB85FFC00019AF1DF6A26840106B90EB858FC0006ED207FA00D4D422F90005C8CA0715CBFFC9D077748018C8CB05CB0222CF165005FA0214CB6B12CCCCC973FB00C84014810108F451F2A7020070810108D718FA00D33FC8542047810108F451F2A782106E6F746570748018C8CB05CB025006CF165004FA0214CB6A12CB1FCB3FC973FB0002006C810108D718FA00D33F305224810108F459F2A782106473747270748018C8CB05CB025005CF165003FA0213CB6ACB1F12CB3FC973FB00000AF400C9ED54696225E5" - ) - ).first() - } + private_key: PrivateKeyEd25519, + workchain_id: Int = 0, + subwallet_id: Int = DEFAULT_PORT + workchain_id, + timeout: Long = 60, +) : AbstractAuthorizedWalletV4(private_key, workchain_id, subwallet_id, timeout) { + override fun createCodeInit(): Cell = BagOfCells( + hex( + "B5EE9C72410214010002D4000114FF00F4A413F4BCF2C80B010201200203020148040504F8F28308D71820D31FD31FD31F02F823BBF264ED44D0D31FD31FD3FFF404D15143BAF2A15151BAF2A205F901541064F910F2A3F80024A4C8CB1F5240CB1F5230CBFF5210F400C9ED54F80F01D30721C0009F6C519320D74A96D307D402FB00E830E021C001E30021C002E30001C0039130E30D03A4C8CB1F12CB1FCBFF1011121302E6D001D0D3032171B0925F04E022D749C120925F04E002D31F218210706C7567BD22821064737472BDB0925F05E003FA403020FA4401C8CA07CBFFC9D0ED44D0810140D721F404305C810108F40A6FA131B3925F07E005D33FC8258210706C7567BA923830E30D03821064737472BA925F06E30D06070201200809007801FA00F40430F8276F2230500AA121BEF2E0508210706C7567831EB17080185004CB0526CF1658FA0219F400CB6917CB1F5260CB3F20C98040FB0006008A5004810108F45930ED44D0810140D720C801CF16F400C9ED540172B08E23821064737472831EB17080185005CB055003CF1623FA0213CB6ACB1FCB3FC98040FB00925F03E20201200A0B0059BD242B6F6A2684080A06B90FA0218470D4080847A4937D29910CE6903E9FF9837812801B7810148987159F31840201580C0D0011B8C97ED44D0D70B1F8003DB29DFB513420405035C87D010C00B23281F2FFF274006040423D029BE84C600201200E0F0019ADCE76A26840206B90EB85FFC00019AF1DF6A26840106B90EB858FC0006ED207FA00D4D422F90005C8CA0715CBFFC9D077748018C8CB05CB0222CF165005FA0214CB6B12CCCCC973FB00C84014810108F451F2A7020070810108D718FA00D33FC8542047810108F451F2A782106E6F746570748018C8CB05CB025006CF165004FA0214CB6A12CB1FCB3FC973FB0002006C810108D718FA00D33F305224810108F459F2A782106473747270748018C8CB05CB025005CF165003FA0213CB6ACB1F12CB3FC973FB00000AF400C9ED54696225E5" + ) + ).first() } diff --git a/ton-smartcontract/src/jvmTest/kotlin/org/ton/smartcontract/wallet/v1/WalletV1R3Example.kt b/ton-smartcontract/src/jvmTest/kotlin/org/ton/smartcontract/wallet/v1/WalletV1R3Example.kt index cda92802..ea6919dc 100644 --- a/ton-smartcontract/src/jvmTest/kotlin/org/ton/smartcontract/wallet/v1/WalletV1R3Example.kt +++ b/ton-smartcontract/src/jvmTest/kotlin/org/ton/smartcontract/wallet/v1/WalletV1R3Example.kt @@ -18,16 +18,16 @@ private fun liteClient() = LiteClient( suspend fun main() { val liteClient = liteClient() - val wallet = WalletV1R3(liteClient, privateKey) + val wallet = TransferWalletV1R3(privateKey) val address = wallet.address() println("Source wallet address = ${address.toString(userFriendly = false)}") println("Non-bounceable address (for init only): ${address.toString(bounceable = false, testOnly = true)}") println("Bounceable address (for later access): ${address.toString(bounceable = true, testOnly = true)}") - println("Corresponding public key is ${hex(wallet.privateKey.publicKey().key).uppercase()}") + println("Corresponding public key is ${hex(wallet.publicKey().key).uppercase()}") liteClient.connect() val block = liteClient.getMasterchainInfo().last - println("seqno: ${wallet.seqno(block)}") - println("get_public_key: ${wallet.getPublicKey(block)}") + println("seqno: ${wallet.seqno(liteClient, block)}") + println("get_public_key: ${wallet.getPublicKey(liteClient, block)}") } diff --git a/ton-smartcontract/src/jvmTest/kotlin/org/ton/smartcontract/wallet/v1/WalletV1R3Test.kt b/ton-smartcontract/src/jvmTest/kotlin/org/ton/smartcontract/wallet/v1/WalletV1R3Test.kt index 9115b789..55b0f194 100644 --- a/ton-smartcontract/src/jvmTest/kotlin/org/ton/smartcontract/wallet/v1/WalletV1R3Test.kt +++ b/ton-smartcontract/src/jvmTest/kotlin/org/ton/smartcontract/wallet/v1/WalletV1R3Test.kt @@ -1,5 +1,6 @@ package org.ton.smartcontract.wallet.v1 +import kotlinx.coroutines.runBlocking import org.ton.api.pk.PrivateKeyEd25519 import org.ton.block.Coins import org.ton.block.Message @@ -29,7 +30,7 @@ class WalletV1R3Test { logger = PrintLnLogger("TON SimpleWalletR3", Logger.Level.DEBUG) ) - private fun wallet() = WalletV1R3(liteClient(), privateKey) + private fun wallet() = TransferWalletV1R3(privateKey) @Test fun `test private key`() { @@ -116,18 +117,19 @@ class WalletV1R3Test { assertContentEquals(expected, actual) } - private fun WalletV1R3.exampleTransferMessage(comment: String) = createTransferMessage( - dest = MsgAddressInt.parse("kQDzHsXMkamiJeqCLcrNDUuyBn78Jr7NUcx075WhEfqIPpwm"), - bounce = true, - amount = Coins.of(1), - seqno = 1, - payload = createCommentPayload(comment) - ) + private fun V1TransferBuilder.exampleTransferMessage(text: String) = this.apply { + dest = MsgAddressInt.parse("kQDzHsXMkamiJeqCLcrNDUuyBn78Jr7NUcx075WhEfqIPpwm") + bounce = true + amount = Coins.of(1) + seqno = 1 + comment = text + } @Test fun `test transfer message with 'Hello TON' comment`() { val wallet = wallet() - val message = wallet.exampleTransferMessage("Hello TON") + val message = + runBlocking { wallet.beginTransfer(liteClient()).exampleTransferMessage("Hello TON").createMessage() } val actual = CellBuilder.createCell { storeTlb(Message.tlbCodec(AnyTlbConstructor), message) } @@ -142,7 +144,8 @@ class WalletV1R3Test { @Test fun `test transfer BOC with 'Hello TON' comment`() { val wallet = wallet() - val message = wallet.exampleTransferMessage("Hello TON") + val message = + runBlocking { wallet.beginTransfer(liteClient()).exampleTransferMessage("Hello TON").createMessage() } val actual = BagOfCells(CellBuilder.createCell { storeTlb(Message.tlbCodec(AnyTlbConstructor), message)