+ *
+ */
+@Log
+@Builder
+public class TxEmulator {
+
+ private String pathToEmulatorSharedLib;
+ private final TxEmulatorI txEmulatorI;
+ private final long txEmulator;
+
+ private String configBoc;
+ private TxVerbosityLevel verbosityLevel;
+
+ public static class TxEmulatorBuilder {}
+
+ public static TxEmulatorBuilder builder() {
+ return new CustomEmulatorBuilder();
+ }
+
+ private static class CustomEmulatorBuilder extends TxEmulatorBuilder {
+ @Override
+ public TxEmulator build() {
+ String emulatorName;
+ Utils.OS os = Utils.getOS();
+ switch (os) {
+ case LINUX:
+ emulatorName = "libemulator-linux-x86-64.so";
+ break;
+ case LINUX_ARM:
+ emulatorName = "libemulator-linux-arm64.so";
+ break;
+ case WINDOWS:
+ emulatorName = "emulator.dll";
+ break;
+ case WINDOWS_ARM:
+ emulatorName = "emulator-arm.dll";
+ break;
+ case MAC:
+ emulatorName = "libemulator-mac-x86-64.dylib";
+ break;
+ case MAC_ARM64:
+ emulatorName = "libemulator-mac-arm64.dylib";
+ break;
+ case UNKNOWN:
+ throw new Error("Operating system is not supported!");
+ default:
+ throw new IllegalArgumentException("Unknown operating system: " + os);
+ }
+
+ if (isNull(super.pathToEmulatorSharedLib)) {
+ super.pathToEmulatorSharedLib = emulatorName;
+ }
+
+ super.txEmulatorI = Native.load(super.pathToEmulatorSharedLib, TxEmulatorI.class);
+ if (isNull(super.verbosityLevel)) {
+ super.verbosityLevel = TxVerbosityLevel.WITH_ALL_STACK_VALUES;
+ }
+ if (isNull(super.configBoc)) {
+ throw new Error("Config is not set");
+ }
+
+ String ss = super.txEmulatorI.emulator_version();
+ System.out.println("version = " + ss);
+
+ long s = super.txEmulator = super.txEmulatorI.emulator_config_create(super.configBoc);
+ System.out.println("s = " + s);
+
+ super.txEmulator =
+ super.txEmulatorI.transaction_emulator_create(
+ super.configBoc, super.verbosityLevel.ordinal());
+
+ if (super.txEmulator == 0) {
+ throw new Error("Can't create tx emulator instance");
+ }
+
+ log.info(
+ String.format(
+ "Java TON Tx Emulator configuration:\n" + "Location: %s\n" + "Verbosity level: %s",
+ super.pathToEmulatorSharedLib, super.verbosityLevel));
+ return super.build();
+ }
+ }
+
+ public void destroy() {
+ txEmulatorI.transaction_emulator_destroy(txEmulator);
+ }
+
+ /**
+ * Emulate transaction
+ *
+ * @param shardAccountBoc Base64 encoded BoC serialized ShardAccount
+ * @param messageBoc Base64 encoded BoC serialized inbound Message (internal or external)
+ * @return Json object with error: { "success": false, "error": "Error description",
+ * "external_not_accepted": false, // and optional fields "vm_exit_code", "vm_log",
+ * "elapsed_time" in case external message was not accepted. } Or success: { "success": true,
+ * "transaction": "Base64 encoded Transaction boc", "shard_account": "Base64 encoded new
+ * ShardAccount boc", "vm_log": "execute DUP...", "actions": "Base64 encoded compute phase
+ * actions boc (OutList n)", "elapsed_time": 0.02 }
+ */
+ public EmulateTransactionResult emulateTransaction(String shardAccountBoc, String messageBoc) {
+ String result =
+ txEmulatorI.transaction_emulator_emulate_transaction(
+ txEmulator, shardAccountBoc, messageBoc);
+ Gson gson = new GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.BIG_DECIMAL).create();
+ return gson.fromJson(result, EmulateTransactionResult.class);
+ }
+
+ /**
+ * Set global verbosity level of the library
+ *
+ * @param verbosityLevel New verbosity level (0 - never, 1 - error, 2 - warning, 3 - info, 4 -
+ * debug)
+ */
+ public void setVerbosityLevel(int verbosityLevel) {
+ txEmulatorI.emulator_set_verbosity_level(txEmulator, verbosityLevel);
+ }
+
+ /**
+ * Enable or disable TVM debug primitives
+ *
+ * @param debugEnabled Whether debug primitives should be enabled or not
+ * @return true in case of success, false in case of error
+ */
+ public boolean setDebugEnabled(boolean debugEnabled) {
+ return txEmulatorI.transaction_emulator_set_debug_enabled(txEmulator, debugEnabled);
+ }
+
+ /**
+ * Set libs for emulation
+ *
+ * @param libsBoc Base64 encoded BoC serialized shared libraries dictionary (HashmapE 256 ^Cell).
+ * @return true in case of success, false in case of error
+ */
+ public boolean setLibs(String libsBoc) {
+ return txEmulatorI.transaction_emulator_set_libs(txEmulator, libsBoc);
+ }
+
+ /**
+ * Set tuple of previous blocks (13th element of c7)
+ *
+ * @param infoBoc Base64 encoded BoC serialized TVM tuple (VmStackValue).
+ * @return true in case of success, false in case of error
+ */
+ public boolean setPrevBlockInfo(String infoBoc) {
+ return txEmulatorI.transaction_emulator_set_prev_blocks_info(txEmulator, infoBoc);
+ }
+
+ /**
+ * Set rand seed for emulation
+ *
+ * @param randSeedHex Hex string of length 64
+ * @return true in case of success, false in case of error
+ */
+ public boolean setRandSeed(String randSeedHex) {
+ return txEmulatorI.transaction_emulator_set_rand_seed(txEmulator, randSeedHex);
+ }
+
+ /**
+ * Set config for emulation
+ *
+ * @param configBoc Base64 encoded BoC serialized Config dictionary (Hashmap 32 ^Cell)
+ * @return true in case of success, false in case of error
+ */
+ public boolean setConfig(String configBoc) {
+ return txEmulatorI.transaction_emulator_set_config(txEmulator, configBoc);
+ }
+
+ /**
+ * Emulate tick-tock transaction
+ *
+ * @param shardAccountBoc Base64 encoded BoC serialized ShardAccount of special account
+ * @param isTock True for tock transactions, false for tick
+ * @return Json object with error: { "success": false, "error": "Error description",
+ * "external_not_accepted": false } Or success: { "success": true, "transaction": "Base64
+ * encoded Transaction boc", "shard_account": "Base64 encoded new ShardAccount boc", "vm_log":
+ * "execute DUP...", "actions": "Base64 encoded compute phase actions boc (OutList n)",
+ * "elapsed_time": 0.02 }
+ */
+ public EmulateTransactionResult emulateTickTockTransaction(
+ String shardAccountBoc, boolean isTock) {
+ String result =
+ txEmulatorI.transaction_emulator_emulate_tick_tock_transaction(
+ txEmulator, shardAccountBoc, isTock);
+ Gson gson = new GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.BIG_DECIMAL).create();
+ return gson.fromJson(result, EmulateTransactionResult.class);
+ }
+
+ /**
+ * Set lt for emulation
+ *
+ * @param lt Logical time
+ * @return true in case of success, false in case of error
+ */
+ public boolean setEmulatorLt(long lt) {
+ return txEmulatorI.transaction_emulator_set_lt(txEmulator, lt);
+ }
+
+ /**
+ * Set ignore_chksig flag for emulation
+ *
+ * @param ignoreChksig Whether emulation should always succeed on CHKSIG operation
+ * @return true in case of success, false in case of error
+ */
+ public boolean setIgnoreCheckSignature(boolean ignoreChksig) {
+ return txEmulatorI.transaction_emulator_set_ignore_chksig(txEmulator, ignoreChksig);
+ }
+}
diff --git a/emulator/src/main/java/org/ton/java/emulator/tx/TxEmulatorI.java b/emulator/src/main/java/org/ton/java/emulator/tx/TxEmulatorI.java
new file mode 100644
index 00000000..2ad86847
--- /dev/null
+++ b/emulator/src/main/java/org/ton/java/emulator/tx/TxEmulatorI.java
@@ -0,0 +1,159 @@
+package org.ton.java.emulator.tx;
+
+import com.sun.jna.Library;
+
+public interface TxEmulatorI extends Library {
+
+ /**
+ * @brief Creates Config object from base64 encoded BoC
+ * @param configParamBoc Base64 encoded BoC serialized Config dictionary (Hashmap 32 ^Cell)
+ * @return Pointer to Config object or nullptr in case of error
+ */
+ long emulator_config_create(String configParamBoc);
+
+ /**
+ * @brief Set config for TVM emulator
+ * @param tmvEmulator Pointer to TVM emulator
+ * @param config Pointer to Config object
+ * @return true in case of success, false in case of error
+ */
+ boolean tvm_emulator_set_config_object(long tmvEmulator, long config);
+
+ /**
+ * @brief Destroy Config object
+ * @param config Pointer to Config object
+ */
+ void emulator_config_destroy(long config);
+
+ /**
+ * @brief Get git commit hash and date of the library
+ */
+ String emulator_version();
+
+ /**
+ * @param configParamBoc Base64 encoded BoC serialized Config dictionary (Hashmap 32 ^Cell)
+ * @param verbosityLevel Verbosity level of VM log. 0 - log truncated to last 256 characters. 1 -
+ * unlimited length log. 2 - for each command prints its cell hash and offset. 3 - for each
+ * command log prints all stack values.
+ * @return Pointer to txEmulator or nullptr in case of error
+ */
+ long transaction_emulator_create(String configParamBoc, int verbosityLevel);
+
+ /**
+ * Destroy TransactionEmulator object
+ *
+ * @param txEmulator Pointer to TransactionEmulator object
+ */
+ void transaction_emulator_destroy(long txEmulator);
+
+ /**
+ * Emulate transaction
+ *
+ * @param txEmulator Pointer to TransactionEmulator object
+ * @param shardAccountBoc Base64 encoded BoC serialized ShardAccount
+ * @param messageBoc Base64 encoded BoC serialized inbound Message (internal or external)
+ * @return Json object with error: { "success": false, "error": "Error description",
+ * "external_not_accepted": false, // and optional fields "vm_exit_code", "vm_log",
+ * "elapsed_time" in case external message was not accepted. } Or success: { "success": true,
+ * "transaction": "Base64 encoded Transaction boc", "shard_account": "Base64 encoded new
+ * ShardAccount boc", "vm_log": "execute DUP...", "actions": "Base64 encoded compute phase
+ * actions boc (OutList n)", "elapsed_time": 0.02 }
+ */
+ String transaction_emulator_emulate_transaction(
+ long txEmulator, String shardAccountBoc, String messageBoc);
+
+ /**
+ * Set unixtime for emulation
+ *
+ * @param txEmulator Pointer to TransactionEmulator object
+ * @param unixtime Unix timestamp
+ * @return true in case of success, false in case of error
+ */
+ boolean transaction_emulator_set_unixtime(long txEmulator, long unixtime);
+
+ /**
+ * Set rand seed for emulation
+ *
+ * @param txEmulator Pointer to TransactionEmulator object
+ * @param randSeedHex Hex string of length 64
+ * @return true in case of success, false in case of error
+ */
+ boolean transaction_emulator_set_rand_seed(long txEmulator, String randSeedHex);
+
+ /**
+ * Set config for emulation
+ *
+ * @param txEmulator Pointer to TransactionEmulator object
+ * @param configBoc Base64 encoded BoC serialized Config dictionary (Hashmap 32 ^Cell)
+ * @return true in case of success, false in case of error
+ */
+ boolean transaction_emulator_set_config(long txEmulator, String configBoc);
+
+ /**
+ * Set libs for emulation
+ *
+ * @param txEmulator Pointer to TransactionEmulator object
+ * @param libsBoc Base64 encoded BoC serialized shared libraries dictionary (HashmapE 256 ^Cell).
+ * @return true in case of success, false in case of error
+ */
+ boolean transaction_emulator_set_libs(long txEmulator, String libsBoc);
+
+ /**
+ * Enable or disable TVM debug primitives
+ *
+ * @param txEmulator Pointer to TransactionEmulator object
+ * @param debugEnabled Whether debug primitives should be enabled or not
+ * @return true in case of success, false in case of error
+ */
+ boolean transaction_emulator_set_debug_enabled(long txEmulator, boolean debugEnabled);
+
+ /**
+ * Set tuple of previous blocks (13th element of c7)
+ *
+ * @param txEmulator Pointer to TransactionEmulator object
+ * @param infoBoc Base64 encoded BoC serialized TVM tuple (VmStackValue).
+ * @return true in case of success, false in case of error
+ */
+ boolean transaction_emulator_set_prev_blocks_info(long txEmulator, String infoBoc);
+
+ /**
+ * Emulate tick-tock transaction
+ *
+ * @param txEmulator Pointer to TransactionEmulator object
+ * @param shardAccountBoc Base64 encoded BoC serialized ShardAccount of special account
+ * @param isTock True for tock transactions, false for tick
+ * @return Json object with error: { "success": false, "error": "Error description",
+ * "external_not_accepted": false } Or success: { "success": true, "transaction": "Base64
+ * encoded Transaction boc", "shard_account": "Base64 encoded new ShardAccount boc", "vm_log":
+ * "execute DUP...", "actions": "Base64 encoded compute phase actions boc (OutList n)",
+ * "elapsed_time": 0.02 }
+ */
+ String transaction_emulator_emulate_tick_tock_transaction(
+ long txEmulator, String shardAccountBoc, boolean isTock);
+
+ /**
+ * Set global verbosity level of the library
+ *
+ * @param verbosityLevel New verbosity level (0 - never, 1 - error, 2 - warning, 3 - info, 4 -
+ * debug)
+ */
+ String emulator_set_verbosity_level(long txEmulator, int verbosityLevel);
+
+ /**
+ * Set lt for emulation
+ *
+ * @param txEmulator Pointer to TransactionEmulator object
+ * @param lt Logical time
+ * @return true in case of success, false in case of error
+ */
+ boolean transaction_emulator_set_lt(long txEmulator, long lt);
+
+ /**
+ * Set ignore_chksig flag for emulation
+ *
+ * @param txEmulator Pointer to TransactionEmulator object
+ * @param ignoreChksig Whether emulation should always succeed on CHKSIG operation
+ * @return true in case of success, false in case of error
+ */
+ boolean transaction_emulator_set_ignore_chksig(long txEmulator, boolean ignoreChksig);
+}
diff --git a/emulator/src/main/java/org/ton/java/emulator/tx/TxVerbosityLevel.java b/emulator/src/main/java/org/ton/java/emulator/tx/TxVerbosityLevel.java
new file mode 100644
index 00000000..f06a895a
--- /dev/null
+++ b/emulator/src/main/java/org/ton/java/emulator/tx/TxVerbosityLevel.java
@@ -0,0 +1,10 @@
+package org.ton.java.emulator.tx;
+
+import java.io.Serializable;
+
+public enum TxVerbosityLevel implements Serializable {
+ TRUNCATED,
+ UNLIMITED,
+ WITH_CELL_HASH_AND_OFFSET,
+ WITH_ALL_STACK_VALUES
+}
diff --git a/emulator/src/main/resources/config-all-mainnet.txt b/emulator/src/main/resources/config-all-mainnet.txt
new file mode 100644
index 00000000..e3014c0a
--- /dev/null
+++ b/emulator/src/main/resources/config-all-mainnet.txt
@@ -0,0 +1 @@
+te6cckIDCDYAAQAAATR8AAACASAAAQACAgLYAAMABAIC9QAFAAYCASAABwAIAgFiAAkACgEDpDMACwEDp3MADAIBIAANAA4CAUgADwAQAQH8ABECASAAEgATAEDLudEGKVRDmoOpHyeDX7nS4+eYkQNWZQw8STyUYjRkaAGB3STEofK4j4twU1E7XMbFoxvESypy3LTYwDOK8PDTfsUrV4RD7BD+j/C+Xsu8FBO9BOOOwISjNPbBC8tcq688GcAIHAIBIAAUABUCASAAFgAXAgFIABgAGQIBagAaABsBwd0kxKHyuI+LcFNRO1zGxaMbxEsqcty02MAzivDw037FO5u/0K1TOLlwDwgzOA7hfUY+UcGuZx7m8IkBveiZsgKAAAAAAAAAAAAAAAAsFsOVDYSn4keu8Y6dufls3yPveMAIHAEB1AAcAQH0AB0CASAAHgAfAgEgACAAIQIBIAAiACMCASAAJAAlAQFIACYBAUgAJwEBIAAoAQEgACkBwU1cAhCzXa3aohn6xFnboP3vsfrk6XoNB5dzn+BQ1pTKDr1/+cpw4G6eIqiSL1rnUhGp1qNKgJTo4Vh7YGvbtmKAAAAAAAAAAAAAAAA7U8vSzdFgu5NEtLtb2bo9/o6RB8AIHALFAbUl61s8X25tzWBr7nugeg7IMDUhKEm34FWUmcD2utVNIR8VdL9iPRR4dwjF/dVl4ymiWr+kkJXphEJvGbzwSXSAAAAAAAAAAAAAAAAAWZG0lbam3LV4+pciTNFehvbNeeLAACoAKwIBIAAsAC0CASAALgAvAgEgADAAMQIBIAAyADMCASAANAA1AgEgADYANwIBSAA4ADkCASAAOgA7ASsSZv5PCGb/TwgBkABkD////////zfAADwBKxJm/08IZwBPCAF9AGQP////////T8AAPQELALW9PrBAAD4BA8DAAD8CASAAQABBADBDuaygBDuaygA3oSAD5OHAQF9eEAOYloACASAAQgBDAQFIAEQCASAARQBGAQFYAEcCASAASABJAgEgAEoASwIBIABMAE0CASAATgBPAgEgAFAAUQEBSABSAgEgAFMAVAIBIABVAFYBASAAVwEBIABYAgEgAFkAWgEBWABbAgLHAFwAXQICxwBeAF8CASAAYABhAFWgESjR4FjxyuEAXHMvOQot+HG+D9TtSQavwKbeV09n3G9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
\ No newline at end of file
diff --git a/emulator/src/main/resources/config-all-testnet.txt b/emulator/src/main/resources/config-all-testnet.txt
new file mode 100644
index 00000000..61665cad
--- /dev/null
+++ b/emulator/src/main/resources/config-all-testnet.txt
@@ -0,0 +1 @@
+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
\ No newline at end of file
diff --git a/emulator/src/main/resources/slim-config.txt b/emulator/src/main/resources/slim-config.txt
new file mode 100644
index 00000000..52053a71
--- /dev/null
+++ b/emulator/src/main/resources/slim-config.txt
@@ -0,0 +1 @@
+te6cckECeAEABZwAAgPNwC8BAgEgGwICASAWAwIBIBEEAQFYBQEBwAYCASAIBwBDv+6SYlD5XEfFuCmona5jYtGN4iWVOW5abGAZxXh4ab9iwAIBIAoJAEK/jVwCELNdrdqiGfrEWdug/e+x+uTpeg0Hl3Of4FDWlMoCASAOCwIBWA0MAEG+3N3+hWqZxcuAeEGZwHcL6jHyjg1zOPc3hEgN70TNkBQAQb7ZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZnAIBSBAPAEG+9ev/zlOHA3TxFUSRetc6kI1OtRpUBKdHCsPbA17dsxQAA99wAgEgFBIBASATAErZAQMAAAfQAAA+gAAAAAMAAAAIAAAABAAgAAAAIAAAAAQAACcQAQEgFQAkwgEAAAD6AAAA+gAAA+gAAAAXAgFIGRcBASAYAELqAAAAAAAGGoAAAAAAAZAAAAAAAACcQAAAAAGAAFVVVVUBASAaAELqAAAAAACYloAAAAAAJxAAAAAAAA9CQAAAAAGAAFVVVVUCASAnHAIBICIdAgEgIB4BASAfAFBdwwACAAAACAAAABAAAMMAHoSAAJiWgAExLQDDAAAD6AAAE4gAACcQAQEgIQBQXcMAAgAAAAgAAAAQAADDAAMNQAAPQkAAJiWgwwAAA+gAABOIAAAnEAIBICUjAQEgJACU0QAAAAAAAABkAAAAAAAAnEDeAAAAAAGQAAAAAAAAAA9CQAAAAAAAD0JAAAAAAAAAJxAAAAAAAJiWgAAAAAAF9eEAAAAAADuaygABASAmAJTRAAAAAAAAAGQAAAAAAA9CQN4AAAAAJxAAAAAAAAAAD0JAAAAAAAIWDsAAAAAAAAAnEAAAAAAAJiWgAAAAAAX14QAAAAAAO5rKAAIBICooAQFIKQBN0GYAAAAAAAAAAAAAAACAAAAAAAAA+gAAAAAAAAH0AAAAAAAD0JBAAgEgLSsBASAsADdwEQ2TFuwAByOG8m/BAACAEKdBpGJ4AAAAMAAIAQEgLgAMAZAAZABLAgEgZDACASA9MQIBIDcyAgEgNTMBASA0ACAAAQAAAACAAAAAIAAAAIAAAQEgNgAUa0ZVPxAEO5rKAAIBIDo4AQEgOQATGkO5rKABASAfSAEBIDsBAcA8ALfQUy7nTs8AAAJwACrYn7aHDoYaZOELB7fIx0lsFfzu58bxcmSlH++c6KojdwX2/yWZOw/Zr08OxAx1OQZWjQc9ppdrOeJEc5dIgaEAAAAAD/////gAAAAAAAAABAIBIE0+AgEgQz8BASBAAgKRQkEAKjYEBwMFAExLQAExLQAAAAACAAAD6AAqNgIGAgUAD0JAAJiWgAAAAAEAAAH0AQEgRAIBIEhFAgm3///wYEdGAAHcAAH8AgLZS0kCAWJKVAIBIF5eAgEgWUwCAc5hYQIBIGJOAQEgTwIDzUBRUAADqKACASBZUgIBIFZTAgEgVVQAAdQCAUhhYQIBIFhXAgEgXFwCASBcXgIBIGBaAgEgXVsCASBeXAIBIGFhAgEgX14AAUgAAVgCAdRhYQABIAEBIGMAGsQAAAAHAAAAAAAAAC4CASBwZQIBIGtmAQFYZwEBwGgCASBqaQAVv////7y9GpSiABAAFb4AAAO8s2cNwVVQAgEgbmwBASBtAFMB//////////////////////////////////////////+AAAAAgAAAAUABASBvAEDlZ1T4NCb2mwkme9h2rJfESCE0W34ma9lWp7+/uY3zXAIBIHNxAQFIcgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACASB2dAEBIHUAQDMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzAQEgdwBAVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVXQSp01
\ No newline at end of file
diff --git a/emulator/src/test/java/org/ton/java/emulator/TestTvmEmulator.java b/emulator/src/test/java/org/ton/java/emulator/TestTvmEmulator.java
index c01c0c3d..d6a7090a 100644
--- a/emulator/src/test/java/org/ton/java/emulator/TestTvmEmulator.java
+++ b/emulator/src/test/java/org/ton/java/emulator/TestTvmEmulator.java
@@ -1,10 +1,21 @@
package org.ton.java.emulator;
+import static java.util.Objects.isNull;
+import static java.util.Objects.nonNull;
+import static org.junit.Assert.*;
+import static org.ton.java.smartcontract.wallet.v4.WalletV4R2.createPluginDataCell;
+
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.ToNumberPolicy;
import com.iwebpp.crypto.TweetNaclFast;
import com.sun.jna.Native;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import lombok.extern.slf4j.Slf4j;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -15,6 +26,7 @@
import org.ton.java.cell.CellBuilder;
import org.ton.java.cell.CellSlice;
import org.ton.java.cell.TonHashMapE;
+import org.ton.java.emulator.tvm.*;
import org.ton.java.smartcontract.GenericSmartContract;
import org.ton.java.smartcontract.SmartContractCompiler;
import org.ton.java.smartcontract.types.NewPlugin;
@@ -28,833 +40,813 @@
import org.ton.java.tonlib.types.SmcLibraryResult;
import org.ton.java.utils.Utils;
-import java.io.IOException;
-import java.math.BigInteger;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.nio.file.Paths;
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-
-import static java.util.Objects.isNull;
-import static java.util.Objects.nonNull;
-import static org.junit.Assert.*;
-import static org.ton.java.smartcontract.wallet.v4.WalletV4R2.createPluginDataCell;
-
@Slf4j
@RunWith(JUnit4.class)
public class TestTvmEmulator {
- static TvmEmulator tvmEmulator;
- static Tonlib tonlib;
- private static final Gson gson = new GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.BIG_DECIMAL).create();
- static WalletV4R2 contract;
-
- @BeforeClass
- public static void setUpBeforeClass() {
- byte[] secretKey = Utils.hexToSignedBytes("F182111193F30D79D517F2339A1BA7C25FDF6C52142F0F2C1D960A1F1D65E1E4");
- TweetNaclFast.Signature.KeyPair keyPair = TweetNaclFast.Signature.keyPair_fromSeed(secretKey);
-
- log.info("pubKey {}", Utils.bytesToHex(keyPair.getPublicKey()));
- log.info("prvKey {}", Utils.bytesToHex(keyPair.getSecretKey()));
- tonlib = Tonlib.builder()
- .testnet(true)
- .ignoreCache(false)
- .build();
-
- contract = WalletV4R2.builder()
- .tonlib(tonlib)
- .keyPair(keyPair)
- .walletId(42)
- .build();
-
- Address walletAddress = contract.getAddress();
-
- String bounceableAddress = walletAddress.toBounceable();
- log.info("bounceableAddress: {}", bounceableAddress);
- log.info("rawAddress: {}", walletAddress.toRaw());
- log.info("pub-key {}", Utils.bytesToHex(contract.getKeyPair().getPublicKey()));
- log.info("prv-key {}", Utils.bytesToHex(contract.getKeyPair().getSecretKey()));
-
- Cell code = contract.getStateInit().getCode();
- Cell data = contract.getStateInit().getData();
-
- tvmEmulator = TvmEmulator.builder()
- .pathToEmulatorSharedLib("G:/libs/emulator.dll")
- .codeBoc(code.toBase64())
- .dataBoc(data.toBase64())
- .verbosityLevel(TvmVerbosityLevel.UNLIMITED)
- .build();
- tvmEmulator.setDebugEnabled(true);
- }
-
- @Test
- public void testInitTvmEmulator() {
- TvmEmulatorI tvmEmulatorI = Native.load("emulator.dll", TvmEmulatorI.class);
- long emulator = tvmEmulatorI.tvm_emulator_create(
- contract.getStateInit().getCode().toBase64(),
- contract.getStateInit().getData().toBase64(),
- TvmVerbosityLevel.UNLIMITED.ordinal());
- assertNotEquals(0, emulator);
- }
-
- @Test
- public void testTvmEmulatorSetDebugEnabled() {
- assertTrue(tvmEmulator.setDebugEnabled(true));
- }
-
- @Test
- public void testTvmEmulatorSetGasLimit() {
- assertTrue(tvmEmulator.setGasLimit(200000));
- }
-
- @Test
- public void testTvmEmulatorSetLibs() {
- Cell dictLibs = getLibs();
-
- log.info("TvmEmulator.setLibs() result {}", tvmEmulator.setLibs(dictLibs.toBase64()));
- }
-
- @Test
- public void testTvmEmulatorSetC7() {
- String address = contract.getAddress().toBounceable();
- String randSeedHex = Utils.sha256("ABC");
-
- Cell config = tonlib.getConfigAll(128); // 128 - all config
-
- assertTrue(tvmEmulator.setC7(address,
- Instant.now().getEpochSecond(),
- Utils.toNano(1).longValue(), // smc balance
- randSeedHex,
- config.toBase64() // optional
- ));
- }
-
- @Test
- public void testTvmEmulatorEmulateRunMethod() {
-
- VmStack stack = VmStack.builder()
+ static TvmEmulator tvmEmulator;
+ static Tonlib tonlib;
+ private static final Gson gson =
+ new GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.BIG_DECIMAL).create();
+ static WalletV4R2 walletV4R2;
+
+ @BeforeClass
+ public static void setUpBeforeClass() {
+ byte[] secretKey =
+ Utils.hexToSignedBytes("F182111193F30D79D517F2339A1BA7C25FDF6C52142F0F2C1D960A1F1D65E1E4");
+ TweetNaclFast.Signature.KeyPair keyPair = TweetNaclFast.Signature.keyPair_fromSeed(secretKey);
+
+ log.info("pubKey {}", Utils.bytesToHex(keyPair.getPublicKey()));
+ log.info("prvKey {}", Utils.bytesToHex(keyPair.getSecretKey()));
+ tonlib = Tonlib.builder().testnet(true).ignoreCache(false).build();
+
+ walletV4R2 = WalletV4R2.builder().tonlib(tonlib).keyPair(keyPair).walletId(42).build();
+
+ Address walletAddress = walletV4R2.getAddress();
+
+ String bounceableAddress = walletAddress.toBounceable();
+ log.info("bounceableAddress: {}", bounceableAddress);
+ log.info("rawAddress: {}", walletAddress.toRaw());
+ log.info("pub-key {}", Utils.bytesToHex(walletV4R2.getKeyPair().getPublicKey()));
+ log.info("prv-key {}", Utils.bytesToHex(walletV4R2.getKeyPair().getSecretKey()));
+
+ Cell code = walletV4R2.getStateInit().getCode();
+ Cell data = walletV4R2.getStateInit().getData();
+
+ tvmEmulator =
+ TvmEmulator.builder()
+ .pathToEmulatorSharedLib("G:/libs/emulator.dll")
+ .codeBoc(code.toBase64())
+ .dataBoc(data.toBase64())
+ .verbosityLevel(TvmVerbosityLevel.UNLIMITED)
+ .build();
+ tvmEmulator.setDebugEnabled(true);
+ }
+
+ @Test
+ public void testInitTvmEmulator() {
+ // TvmEmulatorI tvmEmulatorI = Native.load("emulator.dll", TvmEmulatorI.class);
+ TvmEmulatorI tvmEmulatorI = Native.load("G:/libs/emulator.dll", TvmEmulatorI.class);
+ long emulator =
+ tvmEmulatorI.tvm_emulator_create(
+ walletV4R2.getStateInit().getCode().toBase64(),
+ walletV4R2.getStateInit().getData().toBase64(),
+ TvmVerbosityLevel.UNLIMITED.ordinal());
+ assertNotEquals(0, emulator);
+ }
+
+ @Test
+ public void testTvmEmulatorSetDebugEnabled() {
+ assertTrue(tvmEmulator.setDebugEnabled(true));
+ }
+
+ @Test
+ public void testTvmEmulatorSetGasLimit() {
+ assertTrue(tvmEmulator.setGasLimit(200000));
+ }
+
+ @Test
+ public void testTvmEmulatorSetLibs() {
+ Cell dictLibs = getLibs();
+
+ log.info("TvmEmulator.setLibs() result {}", tvmEmulator.setLibs(dictLibs.toBase64()));
+ }
+
+ /**
+ * The “global variables” may be helpful in implementing some high-level smart-contract languages.
+ * They are in fact stored as components of the Tuple at c7: the k-th global variable simply is
+ * the k-th component of this Tuple, for 1 ≤ k ≤ 254. By convention, the 0-th component is used
+ * for the “configuration parameters” of A.11.4, so it is not available as a global variable.
+ *
+ * The pseudorandom number generator uses the random seed (parameter #6, cf. A.11.4), an
+ * unsigned 256-bit Integer, and other data kept in c7.
+ */
+ @Test
+ public void testTvmEmulatorSetC7() {
+ String address = walletV4R2.getAddress().toBounceable();
+ String randSeedHex = Utils.sha256("ABC");
+
+ Cell config = tonlib.getConfigAll(128); // 128 - all config
+
+ assertTrue(
+ tvmEmulator.setC7(
+ address,
+ Instant.now().getEpochSecond(),
+ Utils.toNano(1).longValue(), // smc balance
+ randSeedHex,
+ config.toBase64() // optional
+ ));
+ }
+
+ @Test
+ public void testTvmEmulatorEmulateRunMethod() {
+
+ VmStack stack =
+ VmStack.builder()
+ .depth(0)
+ .stack(VmStackList.builder().tos(Collections.emptyList()).build())
+ .build();
+
+ String paramsBocBase64 =
+ CellBuilder.beginCell()
+ .storeRef(walletV4R2.getStateInit().getCode())
+ .storeRef(walletV4R2.getStateInit().getData())
+ .storeRef(stack.toCell())
+ .storeRef(
+ CellBuilder.beginCell()
+ .storeRef(stack.toCell()) // c7 ^VmStack
+ .storeRef(getLibs()) // libs ^Cell
+ .endCell())
+ .storeUint(Utils.calculateMethodId("seqno"), 32) // method-id - seqno
+ .endCell()
+ .toBase64();
+
+ Cell c = CellBuilder.beginCell().fromBocBase64(paramsBocBase64).endCell();
+ log.info("cellPrint {}", c.print());
+ long gasLimit = Utils.toNano(1).longValue();
+ String result =
+ tvmEmulator.emulateRunMethod(
+ paramsBocBase64.length(), paramsBocBase64, gasLimit); // todo why null
+ log.info("result emulateRunMethod: {}", result);
+ }
+
+ @Test
+ public void testTvmEmulatorRunGetMethodGetSeqNo() {
+ GetMethodResult methodResult = tvmEmulator.runGetMethod(Utils.calculateMethodId("seqno"));
+ log.info("result runGetMethod: {}", methodResult);
+
+ log.info("methodResult stack: {}", methodResult.getStack());
+
+ // Cell cellResult =
+ // CellBuilder.beginCell().fromBocBase64(methodResult.getStack()).endCell();
+ // log.info("cellResult {}", cellResult);
+ VmStack stack = methodResult.getStack();
+ int depth = stack.getDepth();
+ log.info("vmStack depth: {}", depth);
+ VmStackList vmStackList = stack.getStack();
+ log.info("vmStackList: {}", vmStackList.getTos());
+ BigInteger seqno =
+ VmStackValueTinyInt.deserialize(CellSlice.beginParse(vmStackList.getTos().get(0).toCell()))
+ .getValue();
+ log.info("seqno value: {}", seqno);
+ }
+
+ @Test
+ public void testTvmEmulatorRunGetMethodGetSeqNoShortVersion() {
+ log.info("seqno value: {}", tvmEmulator.runGetSeqNo());
+ }
+
+ @Test
+ public void testTvmEmulatorRunGetMethodGetPubKey() {
+ GetMethodResult methodResult =
+ tvmEmulator.runGetMethod(
+ Utils.calculateMethodId("get_public_key"),
+ VmStack.builder()
.depth(0)
- .stack(VmStackList.builder()
- .tos(Collections.emptyList())
- .build())
- .build();
-
- String paramsBocBase64 = CellBuilder.beginCell()
- .storeRef(contract.getStateInit().getCode())
- .storeRef(contract.getStateInit().getData())
- .storeRef(stack.toCell())
- .storeRef(CellBuilder.beginCell()
- .storeRef(stack.toCell()) // c7 ^VmStack
- .storeRef(getLibs()) // libs ^Cell
- .endCell())
- .storeUint(85143, 32) // method-id - seqno
- .endCell()
- .toBase64();
-
-
- Cell c = CellBuilder.beginCell().fromBocBase64(paramsBocBase64).endCell();
- log.info("cellPrint {}", c.print());
- long gasLimit = Utils.toNano(1).longValue();
- String result = tvmEmulator.emulateRunMethod(paramsBocBase64.length(), paramsBocBase64, gasLimit); // todo why null
- log.info("result emulateRunMethod: {}", result);
- }
-
- @Test
- public void testTvmEmulatorRunGetMethodGetSeqNo() {
- String result = tvmEmulator.runGetMethod(
- Utils.calculateMethodId("seqno")
- );
- log.info("result runGetMethod: {}", result);
-
- GetMethodResult methodResult = gson.fromJson(result, GetMethodResult.class);
- log.info("methodResult: {}", methodResult);
- log.info("methodResult stack: {}", methodResult.getStack());
-
- Cell cellResult = CellBuilder.beginCell().fromBocBase64(methodResult.getStack()).endCell();
-// log.info("cellResult {}", cellResult);
- VmStack stack = VmStack.deserialize(CellSlice.beginParse(cellResult));
- int depth = stack.getDepth();
- log.info("vmStack depth: {}", depth);
- VmStackList vmStackList = stack.getStack();
- log.info("vmStackList: {}", vmStackList.getTos());
- BigInteger seqno = VmStackValueTinyInt.deserialize(CellSlice.beginParse(vmStackList.getTos().get(0).toCell())).getValue();
- log.info("seqno value: {}", seqno);
- }
-
- @Test
- public void testTvmEmulatorRunGetMethodGetSeqNoShortVersion() {
- log.info("seqno value: {}", tvmEmulator.runGetSeqNo());
- }
-
- @Test
- public void testTvmEmulatorRunGetMethodGetPubKey() {
- String result = tvmEmulator.runGetMethod(
- Utils.calculateMethodId("get_public_key"),
- VmStack.builder()
- .depth(0)
- .stack(VmStackList.builder()
- .tos(Collections.emptyList())
- .build())
- .build()
- .toCell().toBase64());
- log.info("result runGetMethod: {}", result);
-
- GetMethodResult methodResult = gson.fromJson(result, GetMethodResult.class);
- log.info("methodResult: {}", methodResult);
- log.info("methodResult stack: {}", methodResult.getStack());
-
- Cell cellResult = CellBuilder.beginCell().fromBocBase64(methodResult.getStack()).endCell();
- log.info("cellResult {}", cellResult);
- VmStack stack = VmStack.deserialize(CellSlice.beginParse(cellResult));
- int depth = stack.getDepth();
- log.info("vmStack depth: {}", depth);
- VmStackList vmStackList = stack.getStack();
- log.info("vmStackList: {}", vmStackList.getTos()); // ok
- VmStackValue stackValue = VmStackValue.deserialize(CellSlice.beginParse(vmStackList.getTos().get(0).toCell()));
- log.info("stackValue value: {}", stackValue);
- BigInteger pubKey = VmStackValueInt.deserialize(CellSlice.beginParse(stackValue.toCell())).getValue();
- log.info("vmStackList value: {}", pubKey.toString(16)); // pubkey
-
- }
-
- @Test
- public void testTvmEmulatorRunGetMethodGetPubKeyShortVersion() {
- log.info("contract's pubKey: {}", tvmEmulator.runGetPublicKey()); // pubkey
- }
-
- @Test
- public void testTvmEmulatorRunGetMethodGetPluginList() {
- String stackSerialized = VmStack.builder()
- .depth(0)
- .stack(VmStackList.builder()
- .tos(Collections.emptyList())
- .build())
- .build()
- .toCell().toBase64();
-
- String result = tvmEmulator.runGetMethod(
- Utils.calculateMethodId("get_plugin_list"),
- stackSerialized);
- log.info("result runGetMethod: {}", result);
-
- GetMethodResult methodResult = gson.fromJson(result, GetMethodResult.class);
- log.info("methodResult: {}", methodResult);
- log.info("methodResult stack: {}", methodResult.getStack());
-
- Cell cellResult = CellBuilder.beginCell().fromBocBase64(methodResult.getStack()).endCell();
- log.info("cellResult {}", cellResult.print());
- VmStackValueTuple tuple = VmStackValueTuple.deserialize(CellSlice.beginParse(cellResult));
- log.info("tuple {}", tuple);
- }
-
- @Test
- public void testTvmEmulatorRunGetMethodIsPluginInstalled() {
- String stackSerialized = VmStack.builder()
- .depth(0)
- .stack(VmStackList.builder()
- .tos(Arrays.asList(
- VmStackValueTinyInt.builder().value(BigInteger.ZERO).build(),
- VmStackValueTinyInt.builder().value(BigInteger.ZERO).build()))
- .build())
- .build()
- .toCell().toBase64();
-
- String result = tvmEmulator.runGetMethod(
- Utils.calculateMethodId("is_plugin_installed"),
- stackSerialized);
- log.info("result runGetMethod: {}", result);
-
- GetMethodResult methodResult = gson.fromJson(result, GetMethodResult.class);
- log.info("methodResult: {}", methodResult);
- log.info("methodResult stack: {}", methodResult.getStack());
-
- Cell cellResult = CellBuilder.beginCell().fromBocBase64(methodResult.getStack()).endCell();
- log.info("cellResult {}", cellResult.print());
- VmStackValueTuple tuple = VmStackValueTuple.deserialize(CellSlice.beginParse(cellResult));
- log.info("tuple {}", tuple);
- }
-
- @Test
- public void testTvmEmulatorSendExternalMessage() {
-
- String address = contract.getAddress().toBounceable();
- String randSeedHex = Utils.sha256("ABC");
-// Cell configAll = tonlib.getConfigAll(128);
-
- // optionally set C7
- assertTrue(tvmEmulator.setC7(address,
- Instant.now().getEpochSecond(),
- Utils.toNano(1).longValue(),
- randSeedHex
- , null
-// , configAll.toBase64()
- ));
-
- WalletV4R2Config config = WalletV4R2Config.builder()
- .operation(0)
- .walletId(42)
- .seqno(0)
- .destination(Address.of("0:258e549638a6980ae5d3c76382afd3f4f32e34482dafc3751e3358589c8de00d"))
- .amount(Utils.toNano(0.124))
- .build();
-
- assertTrue(tvmEmulator.setLibs(getLibs().toBase64()));
-
- Message msg = contract.prepareExternalMsg(config);
- String resultBoc = tvmEmulator.sendExternalMessage(msg.getBody().toBase64());
-
- SendExternalMessageResult result = gson.fromJson(resultBoc, SendExternalMessageResult.class);
- log.info("result sendExternalMessage, exitCode: {}", result.getVm_exit_code());
-// log.info("result sendExternalMessage, actions: {}", result.getActions());
- log.info("seqno value: {}", tvmEmulator.runGetSeqNo());
- OutList actions = OutList.deserialize(CellSlice.beginParse(
- CellBuilder.beginCell().fromBocBase64(result.getActions()).endCell()));
- log.info("parsed actions {}", actions);
-
- assertEquals(1, tvmEmulator.runGetSeqNo().longValue());
-
- // send one more time
- config = WalletV4R2Config.builder()
- .operation(0)
- .walletId(42)
- .seqno(1)
- .destination(Address.of("0:258e549638a6980ae5d3c76382afd3f4f32e34482dafc3751e3358589c8de00d"))
- .amount(Utils.toNano(0.123))
- .build();
-
- msg = contract.prepareExternalMsg(config);
- tvmEmulator.sendExternalMessage(msg.getBody().toBase64());
-
- assertEquals(2, tvmEmulator.runGetSeqNo().longValue());
- }
-
- @Test
- public void testTvmEmulatorSendExternalMessageCustom() throws IOException {
-
- SmartContractCompiler smcFunc = SmartContractCompiler.builder()
- .contractPath("G:/smartcontracts/new-wallet-v4r2.fc")
- .build();
-
- String codeCellHex = smcFunc.compile();
- Cell codeCell = CellBuilder.beginCell().fromBoc(codeCellHex).endCell();
-
- byte[] publicKey = Utils.hexToSignedBytes("82A0B2543D06FEC0AAC952E9EC738BE56AB1B6027FC0C1AA817AE14B4D1ED2FB");
- byte[] secretKey = Utils.hexToSignedBytes("F182111193F30D79D517F2339A1BA7C25FDF6C52142F0F2C1D960A1F1D65E1E4");
- TweetNaclFast.Signature.KeyPair keyPair = TweetNaclFast.Signature.keyPair_fromSeed(secretKey);
-
- Cell dataCell = CellBuilder.beginCell()
- .storeUint(0, 32) // seqno
- .storeUint(42, 32) // wallet id
- .storeBytes(keyPair.getPublicKey())
- .storeBit(false) //plugins dict empty
- .endCell();
-
- log.info("codeCellHex {}", codeCellHex);
- log.info("dataCellHex {}", dataCell.toHex());
-
- Address address = StateInit.builder().code(codeCell).data(dataCell).build().getAddress();
- log.info("addressRaw {}", address.toRaw());
- log.info("addressBounceable {}", address.toBounceable());
-
- tvmEmulator = TvmEmulator.builder()
- .pathToEmulatorSharedLib("G:/libs/emulator.dll")
- .codeBoc(codeCell.toBase64())
- .dataBoc(dataCell.toBase64())
- .verbosityLevel(TvmVerbosityLevel.UNLIMITED)
- .build();
-
- tvmEmulator.setDebugEnabled(true);
-
- // optionally set C7
-// String address = contract.getAddress().toBounceable();
-// String randSeedHex = Utils.sha256("ABC");
-//// Cell configAll = tonlib.getConfigAll(128);
-//
-// assertTrue(tvmEmulator.setC7(address,
-// Instant.now().getEpochSecond(),
-// Utils.toNano(3).longValue(),
-// randSeedHex
-// , null
-//// , configAll.toBase64()
-// ));
-
- GenericSmartContract smc = GenericSmartContract.builder()
- .tonlib(tonlib)
- .keyPair(keyPair)
- .code(codeCellHex)
- .data(dataCell.toHex())
- .build();
-
-
- WalletV4R2Config config = WalletV4R2Config.builder()
- .operation(0)
- .walletId(42)
- .seqno(0)
- .destination(Address.of("0:258e549638a6980ae5d3c76382afd3f4f32e34482dafc3751e3358589c8de00d"))
- .amount(Utils.toNano(0.331))
- .build();
-
- assertTrue(tvmEmulator.setLibs(getLibs().toBase64()));
-
- Cell transferBody = createTransferBody(config);
-
- Cell signedBody = CellBuilder.beginCell()
- .storeBytes(Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), transferBody.hash()))
- .storeCell(transferBody)
- .endCell();
- log.info("extMsg {}", signedBody.toHex());
-
- String resultBoc = tvmEmulator.sendExternalMessage(signedBody.toBase64());
-
- SendExternalMessageResult result = gson.fromJson(resultBoc, SendExternalMessageResult.class);
- log.info("result sendExternalMessage, exitCode: {}", result.getVm_exit_code());
-
- config = WalletV4R2Config.builder()
- .operation(0)
- .walletId(42)
- .seqno(1) // second transfer with seqno 0 fails with error code 33 - as expected
- .destination(Address.of("0:258e549638a6980ae5d3c76382afd3f4f32e34482dafc3751e3358589c8de00d"))
- .amount(Utils.toNano(0.332))
- .build();
-
- assertTrue(tvmEmulator.setLibs(getLibs().toBase64()));
-
- transferBody = createTransferBody(config);
- signedBody = CellBuilder.beginCell()
- .storeBytes(Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), transferBody.hash()))
- .storeCell(transferBody)
- .endCell();
- log.info("extMsg {}", signedBody.toHex());
-
- resultBoc = tvmEmulator.sendExternalMessage(signedBody.toBase64());
-
- result = gson.fromJson(resultBoc, SendExternalMessageResult.class);
- log.info("result sendExternalMessage, exitCode: {}", result.getVm_exit_code());
-
-
- // is plugin installed - answer no
- Address beneficiaryAddress = Address.of("kf_sPxv06KagKaRmOOKxeDQwApCx3i8IQOwv507XD51JOLka");
- log.info("beneficiaryAddress: {}", beneficiaryAddress.toBounceable());
- log.info("beneficiaryAddress (raw): {}", beneficiaryAddress.toRaw());
-
-
-// BigInteger addr = new BigInteger("106857336580611253476560029380260470526545417460249276654115413311849265711416");
-// log.info("ha {}", addr);
-// log.info("ha {}", beneficiaryAddress.toBigInteger());
- String stackSerialized = VmStack.builder()
- .depth(2)
- .stack(VmStackList.builder()
- .tos(Arrays.asList(
- VmStackValueTinyInt.builder().value(BigInteger.ZERO).build(),
- VmStackValueInt.builder().value(address.toBigInteger()).build()))
- .build())
+ .stack(VmStackList.builder().tos(Collections.emptyList()).build())
.build()
.toCell()
- .toBase64();
-
- // is_plugin_installed
- String resultStr = tvmEmulator.runGetMethod(
- Utils.calculateMethodId("is_plugin_installed"),
- stackSerialized);
- log.info("result runGetMethod (is_plugin_installed): {}", resultStr); // should be no
- GetMethodResult methodResult = gson.fromJson(resultStr, GetMethodResult.class);
-// log.info("methodResult: {}", methodResult);
- log.info("methodResult stack: {}", methodResult.getStack());
-
- Cell cellResult = CellBuilder.beginCell().fromBocBase64(methodResult.getStack()).endCell();
- log.info("cellResult {}", cellResult.print());
- VmStack stack = VmStack.deserialize(CellSlice.beginParse(cellResult));
- int depth = stack.getDepth();
- log.info("vmStack depth: {}", depth);
- VmStackList vmStackList = stack.getStack();
- log.info("vmStackList: {}", vmStackList.getTos()); // should be empty
-
-
- // get plugin list - first time - result - empty
- stackSerialized = VmStack.builder()
- .depth(0)
- .stack(VmStackList.builder()
- .tos(Collections.emptyList())
- .build())
- .build()
- .toCell().toBase64();
-
- String resultStr2 = tvmEmulator.runGetMethod(
- Utils.calculateMethodId("get_plugin_list"),
- stackSerialized);
- log.info("result runGetMethod: {}", resultStr2);
-
- methodResult = gson.fromJson(resultStr2, GetMethodResult.class);
- log.info("methodResult: {}", methodResult);
- log.info("methodResult stack: {}", methodResult.getStack());
-
- cellResult = CellBuilder.beginCell().fromBocBase64(methodResult.getStack()).endCell();
- log.info("cellResult {}", cellResult.print());
- VmStackValueTuple tuple = VmStackValueTuple.deserialize(CellSlice.beginParse(cellResult));
- log.info("get_plugin_list first result tuple {}", tuple); // no plugins yet, should be empty
-
-
- // install plugin
- log.info("installing plugin");
- SubscriptionInfo subscriptionInfo = SubscriptionInfo.builder()
- .beneficiary(beneficiaryAddress)
- .subscriptionFee(Utils.toNano(0.11))
- .period(60)
- .startTime(0)
- .timeOut(30)
- .lastPaymentTime(0)
- .lastRequestTime(0)
- .failedAttempts(0)
- .subscriptionId(12345)
- .build();
-
- //log.info("beneficiaryWallet balance {}", Utils.formatNanoValue(tonlib.getAccountBalance(beneficiaryAddress)));
-
- StateInit pluginStateInit = StateInit.builder()
- .code(CellBuilder.beginCell().fromBoc("B5EE9C7241020F01000262000114FF00F4A413F4BCF2C80B0102012002030201480405036AF230DB3C5335A127A904F82327A128A90401BC5135A0F823B913B0F29EF800725210BE945387F0078E855386DB3CA4E2F82302DB3C0B0C0D0202CD06070121A0D0C9B67813F488DE0411F488DE0410130B048FD6D9E05E8698198FD201829846382C74E2F841999E98F9841083239BA395D497803F018B841083AB735BBED9E702984E382D9C74688462F863841083AB735BBED9E70156BA4E09040B0A0A080269F10FD22184093886D9E7C12C1083239BA39384008646582A803678B2801FD010A65B5658F89659FE4B9FD803FC1083239BA396D9E40E0A04F08E8D108C5F0C708210756E6B77DB3CE00AD31F308210706C7567831EB15210BA8F48305324A126A904F82326A127A904BEF27109FA4430A619F833D078D721D70B3F5260A11BBE8E923036F82370708210737562732759DB3C5077DE106910581047103645135042DB3CE0395F076C2232821064737472BA0A0A0D09011A8E897F821064737472DB3CE0300A006821B39982100400000072FB02DE70F8276F118010C8CB055005CF1621FA0214F40013CB6912CB1F830602948100A032DEC901FB000030ED44D0FA40FA40FA00D31FD31FD31FD31FD31FD307D31F30018021FA443020813A98DB3C01A619F833D078D721D70B3FA070F8258210706C7567228018C8CB055007CF165004FA0215CB6A12CB1F13CB3F01FA02CB00C973FB000E0040C8500ACF165008CF165006FA0214CB1F12CB1FCB1FCB1FCB1FCB07CB1FC9ED54005801A615F833D020D70B078100D1BA95810088D721DED307218100DDBA028100DEBA12B1F2E047D33F30A8AB0FE5855AB4").endCell())
- .data(
- createPluginDataCell(
- address,
- subscriptionInfo.getBeneficiary(),
- subscriptionInfo.getSubscriptionFee(),
- subscriptionInfo.getPeriod(),
- subscriptionInfo.getStartTime(),
- subscriptionInfo.getTimeOut(),
- subscriptionInfo.getLastPaymentTime(),
- subscriptionInfo.getLastRequestTime(),
- subscriptionInfo.getFailedAttempts(),
- subscriptionInfo.getSubscriptionId()))
- .build();
-
- log.info("plugin address Bounceable: {}", pluginStateInit.getAddress().toBounceable());
- log.info("plugin address Raw: {}", pluginStateInit.getAddress().toRaw());
-
- config = WalletV4R2Config.builder()
- .seqno(2)
- .operation(1) // deploy and install plugin
- .walletId(42)
- .newPlugin(NewPlugin.builder()
- .secretKey(keyPair.getSecretKey())
- .seqno(2)
- .pluginWc(address.wc) // reuse wc of the wallet
- .amount(Utils.toNano(0.1)) // initial plugin balance, will be taken from wallet-v4
- .stateInit(pluginStateInit.toCell())
- .body(CellBuilder.beginCell()
- .storeUint(new BigInteger("706c7567", 16).add(new BigInteger("80000000", 16)), 32) //OP
- .endCell())
- .build())
- .build();
-
- transferBody = createTransferBody(config);
- signedBody = CellBuilder.beginCell()
- .storeBytes(Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), transferBody.hash()))
- .storeCell(transferBody)
- .endCell();
- log.info("install plugin extMsg {}", signedBody.toHex());
-
- resultBoc = tvmEmulator.sendExternalMessage(signedBody.toBase64());
-
- result = gson.fromJson(resultBoc, SendExternalMessageResult.class);
- log.info("result deploy plugin sendExternalMessage, exitCode: {}", result.getVm_exit_code());
-
-
- // get plugin list - second time - result one entry
- stackSerialized = VmStack.builder()
- .depth(0)
- .stack(VmStackList.builder()
- .tos(Collections.emptyList())
- .build())
- .build()
- .toCell().toBase64();
-
- String resultStr3 = tvmEmulator.runGetMethod(
- Utils.calculateMethodId("get_plugin_list"),
- stackSerialized);
- log.info("result runGetMethod: {}", resultStr3);
-
- methodResult = gson.fromJson(resultStr3, GetMethodResult.class);
- log.info("get_plugin_list methodResult: {}", methodResult);
- log.info("get_plugin_list methodResult stack: {}", methodResult.getStack());
-
- cellResult = CellBuilder.beginCell().fromBocBase64(methodResult.getStack()).endCell();
- log.info("get_plugin_list second cellResult {}", cellResult.print());
- stack = VmStack.deserialize(CellSlice.beginParse(cellResult));
- depth = stack.getDepth();
- log.info("vmStack depth: {}", depth);
- vmStackList = stack.getStack();
- log.info("get_plugin_list second result vmStackList: {}", vmStackList.getTos()); // should be one entry with plugin address
- // plugin with address 38034472829642612572964913615375954737329097997866829358853605638742012097504
- //extract plugin addresses
-
- // is_plugin_installed - with parameters [] - answer yes
-
- stackSerialized = VmStack.builder()
- .depth(2)
- .stack(VmStackList.builder()
- .tos(Arrays.asList(
- VmStackValueInt.builder().value(BigInteger.ZERO).build(),
- VmStackValueInt.builder().value(new BigInteger("38034472829642612572964913615375954737329097997866829358853605638742012097504")).build()))
- .build())
- .build()
- .toCell()
- .toBase64();
-
- log.info("is installed ????");
- resultStr = tvmEmulator.runGetMethod(
- Utils.calculateMethodId("is_plugin_installed"),
- stackSerialized);
- log.info("result runGetMethod (is_plugin_installed) 2: {}", resultStr);
- methodResult = gson.fromJson(resultStr, GetMethodResult.class);
-// log.info("methodResult: {}", methodResult);
- log.info("methodResult stack: {}", methodResult.getStack());
-
- cellResult = CellBuilder.beginCell().fromBocBase64(methodResult.getStack()).endCell();
- log.info("cellResult {}", cellResult.print());
- stack = VmStack.deserialize(CellSlice.beginParse(cellResult));
- depth = stack.getDepth();
- log.info("vmStack depth: {}", depth);
- vmStackList = stack.getStack();
- log.info("vmStackList: {}", vmStackList.getTos());
+ .toBase64());
+
+ log.info("methodResult: {}", methodResult);
+ log.info("methodResult stack: {}", methodResult.getStack());
+
+ // Cell cellResult =
+ // CellBuilder.beginCell().fromBocBase64(methodResult.getStack()).endCell();
+ // log.info("cellResult {}", cellResult);
+ VmStack stack = methodResult.getStack();
+ int depth = stack.getDepth();
+ log.info("vmStack depth: {}", depth);
+ VmStackList vmStackList = stack.getStack();
+ log.info("vmStackList: {}", vmStackList.getTos()); // ok
+ VmStackValue stackValue =
+ VmStackValue.deserialize(CellSlice.beginParse(vmStackList.getTos().get(0).toCell()));
+ log.info("stackValue value: {}", stackValue);
+ BigInteger pubKey =
+ VmStackValueInt.deserialize(CellSlice.beginParse(stackValue.toCell())).getValue();
+ log.info("vmStackList value: {}", pubKey.toString(16)); // pubkey
+ }
+
+ @Test
+ public void testTvmEmulatorRunGetMethodGetPubKeyShortVersion() {
+ log.info("contract's pubKey: {}", tvmEmulator.runGetPublicKey()); // pubkey
+ }
+
+ @Test
+ public void testTvmEmulatorRunGetMethodGetPluginList() {
+ String stackSerialized =
+ VmStack.builder()
+ .depth(0)
+ .stack(VmStackList.builder().tos(Collections.emptyList()).build())
+ .build()
+ .toCell()
+ .toBase64();
+
+ GetMethodResult methodResult =
+ tvmEmulator.runGetMethod(Utils.calculateMethodId("get_plugin_list"), stackSerialized);
+ log.info("methodResult: {}", methodResult);
+ log.info("methodResult stack: {}", methodResult.getStack());
+
+ Cell cellResult = methodResult.getStack().toCell();
+ log.info("cellResult {}", cellResult.print());
+ VmStackValueTuple tuple = VmStackValueTuple.deserialize(CellSlice.beginParse(cellResult));
+ log.info("tuple {}", tuple);
+ }
+
+ @Test
+ public void testTvmEmulatorRunGetMethodIsPluginInstalled() {
+ String stackSerialized =
+ VmStack.builder()
+ .depth(0)
+ .stack(
+ VmStackList.builder()
+ .tos(
+ Arrays.asList(
+ VmStackValueTinyInt.builder().value(BigInteger.ZERO).build(),
+ VmStackValueTinyInt.builder().value(BigInteger.ZERO).build()))
+ .build())
+ .build()
+ .toCell()
+ .toBase64();
+
+ GetMethodResult methodResult =
+ tvmEmulator.runGetMethod(Utils.calculateMethodId("is_plugin_installed"), stackSerialized);
+ log.info("methodResult: {}", methodResult);
+ log.info("methodResult stack: {}", methodResult.getStack());
+
+ Cell cellResult = methodResult.getStack().toCell();
+ log.info("cellResult {}", cellResult.print());
+ VmStackValueTuple tuple = VmStackValueTuple.deserialize(CellSlice.beginParse(cellResult));
+ log.info("tuple {}", tuple);
+ }
+
+ @Test
+ public void testTvmEmulatorSendExternalMessage() {
+
+ String address = walletV4R2.getAddress().toBounceable();
+ String randSeedHex = Utils.sha256("ABC");
+ // Cell configAll = tonlib.getConfigAll(128);
+
+ // optionally set C7
+ assertTrue(
+ tvmEmulator.setC7(
+ address, Instant.now().getEpochSecond(), Utils.toNano(1).longValue(), randSeedHex, null
+ // , configAll.toBase64()
+ ));
+
+ WalletV4R2Config config =
+ WalletV4R2Config.builder()
+ .operation(0)
+ .walletId(42)
+ .seqno(0)
+ .destination(
+ Address.of("0:258e549638a6980ae5d3c76382afd3f4f32e34482dafc3751e3358589c8de00d"))
+ .amount(Utils.toNano(0.124))
+ .build();
+
+ // assertTrue(tvmEmulator.setLibs(getLibs().toBase64()));
+
+ Message msg = walletV4R2.prepareExternalMsg(config);
+ SendExternalMessageResult result = tvmEmulator.sendExternalMessage(msg.getBody().toBase64());
+
+ log.info("result sendExternalMessage, {}", result);
+ // log.info("result sendExternalMessage, actions: {}", result.getActions());
+ log.info("seqno value: {}", tvmEmulator.runGetSeqNo());
+ OutList actions = result.getActions();
+ log.info("compute phase actions {}", actions);
+ log.info("new code cell {}", result.getNewCodeCell().print());
+ log.info("new data cell {}", result.getNewDataCell().print());
+
+ assertEquals(1, tvmEmulator.runGetSeqNo().longValue());
+
+ // send one more time
+ config =
+ WalletV4R2Config.builder()
+ .operation(0)
+ .walletId(42)
+ .seqno(1)
+ .destination(
+ Address.of("0:258e549638a6980ae5d3c76382afd3f4f32e34482dafc3751e3358589c8de00d"))
+ .amount(Utils.toNano(0.123))
+ .build();
+
+ msg = walletV4R2.prepareExternalMsg(config);
+ tvmEmulator.sendExternalMessage(msg.getBody().toBase64());
+
+ assertEquals(2, tvmEmulator.runGetSeqNo().longValue());
+ }
+
+ @Test
+ public void testTvmEmulatorSendExternalMessageCustom() throws IOException {
+
+ SmartContractCompiler smcFunc =
+ SmartContractCompiler.builder()
+ .contractPath("G:/smartcontracts/new-wallet-v4r2.fc")
+ .build();
+
+ String codeCellHex = smcFunc.compile();
+ Cell codeCell = CellBuilder.beginCell().fromBoc(codeCellHex).endCell();
+
+ byte[] publicKey =
+ Utils.hexToSignedBytes("82A0B2543D06FEC0AAC952E9EC738BE56AB1B6027FC0C1AA817AE14B4D1ED2FB");
+ byte[] secretKey =
+ Utils.hexToSignedBytes("F182111193F30D79D517F2339A1BA7C25FDF6C52142F0F2C1D960A1F1D65E1E4");
+ TweetNaclFast.Signature.KeyPair keyPair = TweetNaclFast.Signature.keyPair_fromSeed(secretKey);
+
+ Cell dataCell =
+ CellBuilder.beginCell()
+ .storeUint(0, 32) // seqno
+ .storeUint(42, 32) // wallet id
+ .storeBytes(keyPair.getPublicKey())
+ .storeBit(false) // plugins dict empty
+ .endCell();
+
+ log.info("codeCellHex {}", codeCellHex);
+ log.info("dataCellHex {}", dataCell.toHex());
+
+ Address address = StateInit.builder().code(codeCell).data(dataCell).build().getAddress();
+ log.info("addressRaw {}", address.toRaw());
+ log.info("addressBounceable {}", address.toBounceable());
+
+ tvmEmulator =
+ TvmEmulator.builder()
+ .pathToEmulatorSharedLib("G:/libs/emulator.dll")
+ .codeBoc(codeCell.toBase64())
+ .dataBoc(dataCell.toBase64())
+ .verbosityLevel(TvmVerbosityLevel.UNLIMITED)
+ .build();
+
+ tvmEmulator.setDebugEnabled(true);
+
+ // optionally set C7
+ // String address = contract.getAddress().toBounceable();
+ // String randSeedHex = Utils.sha256("ABC");
+ //// Cell configAll = tonlib.getConfigAll(128);
+ //
+ // assertTrue(tvmEmulator.setC7(address,
+ // Instant.now().getEpochSecond(),
+ // Utils.toNano(3).longValue(),
+ // randSeedHex
+ // , null
+ //// , configAll.toBase64()
+ // ));
+
+ GenericSmartContract smc =
+ GenericSmartContract.builder()
+ .tonlib(tonlib)
+ .keyPair(keyPair)
+ .code(codeCellHex)
+ .data(dataCell.toHex())
+ .build();
+
+ WalletV4R2Config config =
+ WalletV4R2Config.builder()
+ .operation(0)
+ .walletId(42)
+ .seqno(0)
+ .destination(
+ Address.of("0:258e549638a6980ae5d3c76382afd3f4f32e34482dafc3751e3358589c8de00d"))
+ .amount(Utils.toNano(0.331))
+ .build();
+
+ // assertTrue(tvmEmulator.setLibs(getLibs().toBase64()));
+
+ Cell transferBody = createTransferBody(config);
+
+ Cell signedBody =
+ CellBuilder.beginCell()
+ .storeBytes(
+ Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), transferBody.hash()))
+ .storeCell(transferBody)
+ .endCell();
+ log.info("extMsg {}", signedBody.toHex());
+
+ SendExternalMessageResult resultBoc = tvmEmulator.sendExternalMessage(signedBody.toBase64());
+
+ log.info("result sendExternalMessage, {}", resultBoc);
+
+ config =
+ WalletV4R2Config.builder()
+ .operation(0)
+ .walletId(42)
+ .seqno(1) // second transfer with seqno 0 fails with error code 33 - as expected
+ .destination(
+ Address.of("0:258e549638a6980ae5d3c76382afd3f4f32e34482dafc3751e3358589c8de00d"))
+ .amount(Utils.toNano(0.332))
+ .build();
+
+ // assertTrue(tvmEmulator.setLibs(getLibs().toBase64()));
+
+ transferBody = createTransferBody(config);
+ signedBody =
+ CellBuilder.beginCell()
+ .storeBytes(
+ Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), transferBody.hash()))
+ .storeCell(transferBody)
+ .endCell();
+ log.info("extMsg {}", signedBody.toHex());
+
+ SendExternalMessageResult result = tvmEmulator.sendExternalMessage(signedBody.toBase64());
+
+ log.info("result sendExternalMessage, {}", result);
+
+ // is plugin installed - answer no
+ Address beneficiaryAddress = Address.of("kf_sPxv06KagKaRmOOKxeDQwApCx3i8IQOwv507XD51JOLka");
+ log.info("beneficiaryAddress: {}", beneficiaryAddress.toBounceable());
+ log.info("beneficiaryAddress (raw): {}", beneficiaryAddress.toRaw());
+
+ // BigInteger addr = new
+ // BigInteger("106857336580611253476560029380260470526545417460249276654115413311849265711416");
+ // log.info("ha {}", addr);
+ // log.info("ha {}", beneficiaryAddress.toBigInteger());
+ String stackSerialized =
+ VmStack.builder()
+ .depth(2)
+ .stack(
+ VmStackList.builder()
+ .tos(
+ Arrays.asList(
+ VmStackValueTinyInt.builder().value(BigInteger.ZERO).build(),
+ VmStackValueInt.builder().value(address.toBigInteger()).build()))
+ .build())
+ .build()
+ .toCell()
+ .toBase64();
+
+ // is_plugin_installed
+ GetMethodResult methodResult =
+ tvmEmulator.runGetMethod(Utils.calculateMethodId("is_plugin_installed"), stackSerialized);
+ log.info("methodResult stack: {}", methodResult.getStack());
+
+ // Cell cellResult =
+ // CellBuilder.beginCell().fromBocBase64(methodResult.getStack()).endCell();
+ // log.info("cellResult {}", cellResult.print());
+ VmStack stack = methodResult.getStack();
+ int depth = stack.getDepth();
+ log.info("vmStack depth: {}", depth);
+ VmStackList vmStackList = stack.getStack();
+ log.info("vmStackList: {}", vmStackList.getTos()); // should be empty
+
+ // get plugin list - first time - result - empty
+ stackSerialized =
+ VmStack.builder()
+ .depth(0)
+ .stack(VmStackList.builder().tos(Collections.emptyList()).build())
+ .build()
+ .toCell()
+ .toBase64();
+
+ methodResult =
+ tvmEmulator.runGetMethod(Utils.calculateMethodId("get_plugin_list"), stackSerialized);
+ log.info("methodResult: {}", methodResult);
+ log.info("methodResult stack: {}", methodResult.getStack());
+
+ Cell cellResult = methodResult.getStack().toCell();
+ log.info("cellResult {}", cellResult.print());
+ VmStackValueTuple tuple = VmStackValueTuple.deserialize(CellSlice.beginParse(cellResult));
+ log.info("get_plugin_list first result tuple {}", tuple); // no plugins yet, should be empty
+
+ // install plugin
+ log.info("installing plugin");
+ SubscriptionInfo subscriptionInfo =
+ SubscriptionInfo.builder()
+ .beneficiary(beneficiaryAddress)
+ .subscriptionFee(Utils.toNano(0.11))
+ .period(60)
+ .startTime(0)
+ .timeOut(30)
+ .lastPaymentTime(0)
+ .lastRequestTime(0)
+ .failedAttempts(0)
+ .subscriptionId(12345)
+ .build();
+
+ // log.info("beneficiaryWallet balance {}",
+ // Utils.formatNanoValue(tonlib.getAccountBalance(beneficiaryAddress)));
+
+ StateInit pluginStateInit =
+ StateInit.builder()
+ .code(
+ CellBuilder.beginCell()
+ .fromBoc(
+ "B5EE9C7241020F01000262000114FF00F4A413F4BCF2C80B0102012002030201480405036AF230DB3C5335A127A904F82327A128A90401BC5135A0F823B913B0F29EF800725210BE945387F0078E855386DB3CA4E2F82302DB3C0B0C0D0202CD06070121A0D0C9B67813F488DE0411F488DE0410130B048FD6D9E05E8698198FD201829846382C74E2F841999E98F9841083239BA395D497803F018B841083AB735BBED9E702984E382D9C74688462F863841083AB735BBED9E70156BA4E09040B0A0A080269F10FD22184093886D9E7C12C1083239BA39384008646582A803678B2801FD010A65B5658F89659FE4B9FD803FC1083239BA396D9E40E0A04F08E8D108C5F0C708210756E6B77DB3CE00AD31F308210706C7567831EB15210BA8F48305324A126A904F82326A127A904BEF27109FA4430A619F833D078D721D70B3F5260A11BBE8E923036F82370708210737562732759DB3C5077DE106910581047103645135042DB3CE0395F076C2232821064737472BA0A0A0D09011A8E897F821064737472DB3CE0300A006821B39982100400000072FB02DE70F8276F118010C8CB055005CF1621FA0214F40013CB6912CB1F830602948100A032DEC901FB000030ED44D0FA40FA40FA00D31FD31FD31FD31FD31FD307D31F30018021FA443020813A98DB3C01A619F833D078D721D70B3FA070F8258210706C7567228018C8CB055007CF165004FA0215CB6A12CB1F13CB3F01FA02CB00C973FB000E0040C8500ACF165008CF165006FA0214CB1F12CB1FCB1FCB1FCB1FCB07CB1FC9ED54005801A615F833D020D70B078100D1BA95810088D721DED307218100DDBA028100DEBA12B1F2E047D33F30A8AB0FE5855AB4")
+ .endCell())
+ .data(
+ createPluginDataCell(
+ address,
+ subscriptionInfo.getBeneficiary(),
+ subscriptionInfo.getSubscriptionFee(),
+ subscriptionInfo.getPeriod(),
+ subscriptionInfo.getStartTime(),
+ subscriptionInfo.getTimeOut(),
+ subscriptionInfo.getLastPaymentTime(),
+ subscriptionInfo.getLastRequestTime(),
+ subscriptionInfo.getFailedAttempts(),
+ subscriptionInfo.getSubscriptionId()))
+ .build();
+
+ log.info("plugin address Bounceable: {}", pluginStateInit.getAddress().toBounceable());
+ log.info("plugin address Raw: {}", pluginStateInit.getAddress().toRaw());
+
+ config =
+ WalletV4R2Config.builder()
+ .seqno(2)
+ .operation(1) // deploy and install plugin
+ .walletId(42)
+ .newPlugin(
+ NewPlugin.builder()
+ .secretKey(keyPair.getSecretKey())
+ .seqno(2)
+ .pluginWc(address.wc) // reuse wc of the wallet
+ .amount(
+ Utils.toNano(0.1)) // initial plugin balance, will be taken from wallet-v4
+ .stateInit(pluginStateInit.toCell())
+ .body(
+ CellBuilder.beginCell()
+ .storeUint(
+ new BigInteger("706c7567", 16).add(new BigInteger("80000000", 16)),
+ 32) // OP
+ .endCell())
+ .build())
+ .build();
+
+ transferBody = createTransferBody(config);
+ signedBody =
+ CellBuilder.beginCell()
+ .storeBytes(
+ Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), transferBody.hash()))
+ .storeCell(transferBody)
+ .endCell();
+ log.info("install plugin extMsg {}", signedBody.toHex());
+
+ result = tvmEmulator.sendExternalMessage(signedBody.toBase64());
+ log.info("result deploy plugin sendExternalMessage, {}", result);
+
+ // get plugin list - second time - result one entry
+ stackSerialized =
+ VmStack.builder()
+ .depth(0)
+ .stack(VmStackList.builder().tos(Collections.emptyList()).build())
+ .build()
+ .toCell()
+ .toBase64();
+
+ methodResult =
+ tvmEmulator.runGetMethod(Utils.calculateMethodId("get_plugin_list"), stackSerialized);
+
+ log.info("get_plugin_list methodResult: {}", methodResult);
+ log.info("get_plugin_list methodResult stack: {}", methodResult.getStack());
+
+ // cellResult = CellBuilder.beginCell().fromBocBase64(methodResult.getStack()).endCell();
+ // log.info("get_plugin_list second cellResult {}", cellResult.print());
+ stack = methodResult.getStack();
+ depth = stack.getDepth();
+ log.info("vmStack depth: {}", depth);
+ vmStackList = stack.getStack();
+ log.info(
+ "get_plugin_list second result vmStackList: {}",
+ vmStackList.getTos()); // should be one entry with plugin address
+ // plugin with address
+ // 38034472829642612572964913615375954737329097997866829358853605638742012097504
+ // extract plugin addresses
+
+ // is_plugin_installed - with parameters [] - answer yes
+
+ stackSerialized =
+ VmStack.builder()
+ .depth(2)
+ .stack(
+ VmStackList.builder()
+ .tos(
+ Arrays.asList(
+ VmStackValueInt.builder().value(BigInteger.ZERO).build(),
+ VmStackValueInt.builder()
+ .value(
+ new BigInteger(
+ "38034472829642612572964913615375954737329097997866829358853605638742012097504"))
+ .build()))
+ .build())
+ .build()
+ .toCell()
+ .toBase64();
+
+ log.info("is installed ????");
+ methodResult =
+ tvmEmulator.runGetMethod(Utils.calculateMethodId("is_plugin_installed"), stackSerialized);
+
+ log.info("methodResult stack: {}", methodResult.getStack());
+
+ stack = methodResult.getStack();
+ depth = stack.getDepth();
+ log.info("vmStack depth: {}", depth);
+ vmStackList = stack.getStack();
+ log.info("vmStackList: {}", vmStackList.getTos());
+ }
+
+ @Test
+ public void testTvmEmulatorSendInternalMessageCustomContract() throws IOException {
+ SmartContractCompiler smcFunc =
+ SmartContractCompiler.builder()
+ .contractPath("G:/smartcontracts/new-wallet-v4r2.fc")
+ .build();
+
+ String codeCellHex = smcFunc.compile();
+ Cell codeCell = CellBuilder.beginCell().fromBoc(codeCellHex).endCell();
+
+ TweetNaclFast.Signature.KeyPair keyPair = Utils.generateSignatureKeyPair();
+
+ Cell dataCell =
+ CellBuilder.beginCell()
+ .storeUint(0, 32) // seqno
+ .storeUint(42, 32) // wallet id
+ .storeBytes(keyPair.getPublicKey())
+ .storeUint(0, 1) // plugins dict empty
+ .endCell();
+
+ log.info("codeCellHex {}", codeCellHex);
+ log.info("dataCellHex {}", dataCell.toHex());
+
+ tvmEmulator =
+ TvmEmulator.builder()
+ .pathToEmulatorSharedLib("G:/libs/emulator.dll")
+ .codeBoc(codeCell.toBase64())
+ .dataBoc(dataCell.toBase64())
+ .verbosityLevel(TvmVerbosityLevel.UNLIMITED)
+ .build();
+
+ // optionally set C7
+ // assertTrue(tvmEmulator.setC7(address,
+ // Instant.now().getEpochSecond(),
+ // Utils.toNano(1).longValue(),
+ // randSeedHex
+ //// , null
+ // , configAll.toBase64()
+ // ));
+
+ // tvmEmulator.setGasLimit(Utils.toNano(10).longValue());
+ tvmEmulator.setDebugEnabled(true);
+
+ Cell body =
+ CellBuilder.beginCell()
+ .storeUint(0x706c7567, 32) // op request funds
+ .endCell();
+
+ SendInternalMessageResult result =
+ tvmEmulator.sendInternalMessage(body.toBase64(), Utils.toNano(0.11).longValue());
+
+ log.info("result sendInternalMessage, {}", result);
+ }
+
+ @Test
+ public void testTvmEmulatorSendInternalMessage() {
+ Cell body =
+ CellBuilder.beginCell()
+ .storeUint(0x706c7567, 32) // op request funds
+ .endCell();
+
+ tvmEmulator.setDebugEnabled(true);
+
+ SendInternalMessageResult result =
+ tvmEmulator.sendInternalMessage(body.toBase64(), Utils.toNano(0.11).longValue());
+
+ log.info("result sendInternalMessage, {}", result);
+
+ OutList actions = result.getActions();
+ log.info("compute phase actions {}", actions);
+ log.info("new code cell {}", result.getNewCodeCell().print());
+ log.info("new data cell {}", result.getNewDataCell().print());
+ }
+
+ @Test
+ public void testTvmEmulatorSetPrevBlockInfo() {
+ BlockIdExt lastBlock = tonlib.getLast().getLast();
+ log.info("lastBlockId: {}", lastBlock);
+
+ ArrayList stack = new ArrayList<>();
+ stack.add(
+ VmStackValueTinyInt.builder().value(BigInteger.valueOf(lastBlock.getWorkchain())).build());
+ stack.add(
+ VmStackValueTinyInt.builder().value(BigInteger.valueOf(lastBlock.getShard())).build());
+ stack.add(
+ VmStackValueTinyInt.builder().value(BigInteger.valueOf(lastBlock.getSeqno())).build());
+ stack.add(
+ VmStackValueInt.builder()
+ .value(new BigInteger(Utils.base64ToHexString(lastBlock.getRoot_hash()), 16))
+ .build());
+ stack.add(
+ VmStackValueInt.builder()
+ .value(new BigInteger(Utils.base64ToHexString(lastBlock.getFile_hash()), 16))
+ .build());
+
+ VmStackValueTuple vmStackValueTuple =
+ VmStackValueTuple.builder().data(VmTuple.builder().values(stack).build()).build();
+
+ Cell deserializedTuple =
+ CellBuilder.beginCell().fromBocBase64(vmStackValueTuple.toCell().toBase64()).endCell();
+ log.info("test deserialization: {}", deserializedTuple.print());
+
+ assertTrue(tvmEmulator.setPrevBlockInfo(vmStackValueTuple.toCell().toBase64()));
+ }
+
+ private static Cell getLibs() {
+ SmcLibraryResult result =
+ tonlib.getLibraries(
+ Collections.singletonList("wkUmK4wrzl6fzSPKM04dVfqW1M5pqigX3tcXzvy6P3M="));
+
+ TonHashMapE x = new TonHashMapE(256);
+
+ for (SmcLibraryEntry l : result.getResult()) {
+ String cellLibBoc = l.getData();
+ Cell lib = Cell.fromBocBase64(cellLibBoc);
+ // log.info("cell lib {}", lib.toHex());
+ x.elements.put(1L, lib);
}
- @Test
- public void testTvmEmulatorSendInternalMessageCustomContract() throws IOException {
- SmartContractCompiler smcFunc = SmartContractCompiler.builder()
- .contractPath("G:/smartcontracts/new-wallet-v4r2.fc")
- .build();
-
- String codeCellHex = smcFunc.compile();
- Cell codeCell = CellBuilder.beginCell().fromBoc(codeCellHex).endCell();
-
- TweetNaclFast.Signature.KeyPair keyPair = Utils.generateSignatureKeyPair();
-
- Cell dataCell = CellBuilder.beginCell()
- .storeUint(0, 32) // seqno
- .storeUint(42, 32) // wallet id
- .storeBytes(keyPair.getPublicKey())
- .storeUint(0, 1) //plugins dict empty
- .endCell();
-
- log.info("codeCellHex {}", codeCellHex);
- log.info("dataCellHex {}", dataCell.toHex());
-
-
- tvmEmulator = TvmEmulator.builder()
- .pathToEmulatorSharedLib("G:/libs/emulator.dll")
- .codeBoc(codeCell.toBase64())
- .dataBoc(dataCell.toBase64())
- .verbosityLevel(TvmVerbosityLevel.UNLIMITED)
- .build();
-
- String address = contract.getAddress().toBounceable();
- String randSeedHex = Utils.sha256("ABC");
- Cell configAll = tonlib.getConfigAll(128);
-
- assertTrue(tvmEmulator.setLibs(getLibs().toBase64()));
-
- // optionally set C7
-// assertTrue(tvmEmulator.setC7(address,
-// Instant.now().getEpochSecond(),
-// Utils.toNano(1).longValue(),
-// randSeedHex
-//// , null
-// , configAll.toBase64()
-// ));
-
-// tvmEmulator.setGasLimit(Utils.toNano(10).longValue());
- tvmEmulator.setDebugEnabled(true);
-
- Cell body = CellBuilder.beginCell()
- .storeUint(0x706c7567, 32) // op request funds
- .endCell();
-
- String resultBoc = tvmEmulator.sendInternalMessage(body.toBase64(), Utils.toNano(0.11).longValue());
- log.info("resultBoc {}", resultBoc);
- SendExternalMessageResult result = gson.fromJson(resultBoc, SendExternalMessageResult.class);
- log.info("result sendInternalMessage, exitCode: {}", result.getVm_exit_code());
+ return x.serialize(
+ k -> CellBuilder.beginCell().storeUint((Long) k, 256).endCell().getBits(),
+ v -> CellBuilder.beginCell().storeRef((Cell) v).endCell());
+ }
+
+ private Cell createTransferBody(WalletV4R2Config config) {
+
+ CellBuilder message = CellBuilder.beginCell();
+
+ message.storeUint(config.getWalletId(), 32);
+
+ message.storeUint(
+ (config.getValidUntil() == 0)
+ ? Instant.now().getEpochSecond() + 60
+ : config.getValidUntil(),
+ 32);
+
+ message.storeUint(config.getSeqno(), 32); // msg_seqno
+
+ if (config.getOperation() == 0) {
+ Cell order =
+ Message.builder()
+ .info(
+ InternalMessageInfo.builder()
+ .bounce(config.isBounce())
+ .dstAddr(
+ MsgAddressIntStd.builder()
+ .workchainId(config.getDestination().wc)
+ .address(config.getDestination().toBigInteger())
+ .build())
+ .value(CurrencyCollection.builder().coins(config.getAmount()).build())
+ .build())
+ .init(config.getStateInit())
+ .body(
+ (isNull(config.getBody()) && nonNull(config.getComment()))
+ ? CellBuilder.beginCell()
+ .storeUint(0, 32)
+ .storeString(config.getComment())
+ .endCell()
+ : config.getBody())
+ .build()
+ .toCell();
+
+ message.storeUint(BigInteger.ZERO, 8); // op simple send
+ message.storeUint(config.getMode(), 8);
+ message.storeRef(order);
+ } else if (config.getOperation() == 1) {
+ message.storeUint(1, 8); // deploy and install plugin
+ message.storeUint(BigInteger.valueOf(config.getNewPlugin().getPluginWc()), 8);
+ message.storeCoins(config.getNewPlugin().getAmount()); // plugin balance
+ message.storeRef(config.getNewPlugin().getStateInit());
+ message.storeRef(config.getNewPlugin().getBody());
}
-
- @Test
- public void testTvmEmulatorSendInternalMessage() {
- Cell body = CellBuilder.beginCell()
- .storeUint(0x706c7567, 32) // op request funds
- .endCell();
-
- assertTrue(tvmEmulator.setLibs(getLibs().toBase64()));
- tvmEmulator.setDebugEnabled(true);
-
- String resultBoc = tvmEmulator.sendInternalMessage(body.toBase64(), Utils.toNano(0.11).longValue());
-
- SendExternalMessageResult result = gson.fromJson(resultBoc, SendExternalMessageResult.class);
- log.info("result sendInternalMessage, exitCode: {}", result.getVm_exit_code());
+ if (config.getOperation() == 2) {
+ message.storeUint(2, 8); // install plugin
+ message.storeUint(BigInteger.valueOf(config.getDeployedPlugin().getPluginAddress().wc), 8);
+ message.storeBytes(config.getDeployedPlugin().getPluginAddress().hashPart);
+ message.storeCoins(BigInteger.valueOf(config.getDeployedPlugin().getAmount().longValue()));
+ message.storeUint(BigInteger.valueOf(config.getDeployedPlugin().getQueryId()), 64);
+ message.endCell();
}
-
- @Test
- public void testTvmEmulatorSetPrevBlockInfo() {
- BlockIdExt lastBlock = tonlib.getLast().getLast();
- log.info("lastBlockId: {}", lastBlock);
-
- ArrayList stack = new ArrayList<>();
- stack.add(VmStackValueTinyInt.builder().value(BigInteger.valueOf(lastBlock.getWorkchain())).build());
- stack.add(VmStackValueTinyInt.builder().value(BigInteger.valueOf(lastBlock.getShard())).build());
- stack.add(VmStackValueTinyInt.builder().value(BigInteger.valueOf(lastBlock.getSeqno())).build());
- stack.add(VmStackValueInt.builder().value(new BigInteger(Utils.base64ToHexString(lastBlock.getRoot_hash()), 16)).build());
- stack.add(VmStackValueInt.builder().value(new BigInteger(Utils.base64ToHexString(lastBlock.getFile_hash()), 16)).build());
-
- VmStackValueTuple vmStackValueTuple = VmStackValueTuple.builder()
- .data(VmTuple.builder()
- .values(stack)
- .build())
- .build();
-
- Cell deserializedTuple = CellBuilder.beginCell().fromBocBase64(vmStackValueTuple.toCell().toBase64()).endCell();
- log.info("test deserialization: {}", deserializedTuple.print());
-
- assertTrue(tvmEmulator.setPrevBlockInfo(vmStackValueTuple.toCell().toBase64()));
+ if (config.getOperation() == 3) {
+ message.storeUint(3, 8); // remove plugin
+ message.storeUint(BigInteger.valueOf(config.getDeployedPlugin().getPluginAddress().wc), 8);
+ message.storeBytes(config.getDeployedPlugin().getPluginAddress().hashPart);
+ message.storeCoins(BigInteger.valueOf(config.getDeployedPlugin().getAmount().longValue()));
+ message.storeUint(BigInteger.valueOf(config.getDeployedPlugin().getQueryId()), 64);
+ message.endCell();
}
+ return message.endCell();
+ }
- private static Cell getLibs() {
- SmcLibraryResult result = tonlib.getLibraries(
- Collections.singletonList("wkUmK4wrzl6fzSPKM04dVfqW1M5pqigX3tcXzvy6P3M="));
+ @Test
+ public void testTvmEmulatorParsePluginListResultWithOneEntry() {
- TonHashMapE x = new TonHashMapE(256);
-
- for (SmcLibraryEntry l : result.getResult()) {
- String cellLibBoc = l.getData();
- Cell lib = Cell.fromBocBase64(cellLibBoc);
- log.info("cell lib {}", lib.toHex());
- x.elements.put(1L, lib);
- }
-
- return x.serialize(
- k -> CellBuilder.beginCell().storeUint((Long) k, 256).endCell().getBits(),
- v -> CellBuilder.beginCell().storeRef((Cell) v).endCell()
- );
- }
-
- private Cell createTransferBody(WalletV4R2Config config) {
-
- CellBuilder message = CellBuilder.beginCell();
-
- message.storeUint(config.getWalletId(), 32);
-
- message.storeUint((config.getValidUntil() == 0) ? Instant.now().getEpochSecond() + 60 : config.getValidUntil(), 32);
-
- message.storeUint(config.getSeqno(), 32);// msg_seqno
-
- if (config.getOperation() == 0) {
- Cell order = Message.builder()
- .info(InternalMessageInfo.builder()
- .bounce(config.isBounce())
- .dstAddr(MsgAddressIntStd.builder()
- .workchainId(config.getDestination().wc)
- .address(config.getDestination().toBigInteger())
- .build())
- .value(CurrencyCollection.builder().coins(config.getAmount()).build())
- .build())
- .init(config.getStateInit())
- .body((isNull(config.getBody()) && nonNull(config.getComment())) ?
- CellBuilder.beginCell()
- .storeUint(0, 32)
- .storeString(config.getComment())
- .endCell()
- : config.getBody())
- .build().toCell();
-
- message.storeUint(BigInteger.ZERO, 8); // op simple send
- message.storeUint(config.getMode(), 8);
- message.storeRef(order);
- } else if (config.getOperation() == 1) {
- message.storeUint(1, 8); // deploy and install plugin
- message.storeUint(BigInteger.valueOf(config.getNewPlugin().getPluginWc()), 8);
- message.storeCoins(config.getNewPlugin().getAmount()); // plugin balance
- message.storeRef(config.getNewPlugin().getStateInit());
- message.storeRef(config.getNewPlugin().getBody());
- }
- if (config.getOperation() == 2) {
- message.storeUint(2, 8); // install plugin
- message.storeUint(BigInteger.valueOf(config.getDeployedPlugin().getPluginAddress().wc), 8);
- message.storeBytes(config.getDeployedPlugin().getPluginAddress().hashPart);
- message.storeCoins(BigInteger.valueOf(config.getDeployedPlugin().getAmount().longValue()));
- message.storeUint(BigInteger.valueOf(config.getDeployedPlugin().getQueryId()), 64);
- message.endCell();
- }
- if (config.getOperation() == 3) {
- message.storeUint(3, 8); // remove plugin
- message.storeUint(BigInteger.valueOf(config.getDeployedPlugin().getPluginAddress().wc), 8);
- message.storeBytes(config.getDeployedPlugin().getPluginAddress().hashPart);
- message.storeCoins(BigInteger.valueOf(config.getDeployedPlugin().getAmount().longValue()));
- message.storeUint(BigInteger.valueOf(config.getDeployedPlugin().getQueryId()), 64);
- message.endCell();
- }
-
- return message.endCell();
- }
-
- @Test
- public void testTvmEmulatorParsePluginListResultWithOneEntry() {
-
- String bocBase64 = "te6cckEBBgEARgADDAAAAQcAAgECAwAAAgYHAAIEBQACAAASAQAAAAAAAAAAAEQCAFQWv62UIb68RxRkPHIBa4xGgl2dhv3r6zAHZjygzHPgkqH6lg";
- Cell cell = CellBuilder.beginCell().fromBocBase64(bocBase64).endCell();
- log.info("cell print: {}", cell.print());
- log.info("cell boc: {}", cell.toHex());
-
- VmStack stack = VmStack.deserialize(CellSlice.beginParse(cell));
- log.info("vmStack depth: {}", stack.getDepth());
- VmStackList vmStackList = stack.getStack();
- log.info("vmStackList: {}", vmStackList.getTos());
- }
+ String bocBase64 =
+ "te6cckEBBgEARgADDAAAAQcAAgECAwAAAgYHAAIEBQACAAASAQAAAAAAAAAAAEQCAFQWv62UIb68RxRkPHIBa4xGgl2dhv3r6zAHZjygzHPgkqH6lg";
+ Cell cell = CellBuilder.beginCell().fromBocBase64(bocBase64).endCell();
+ log.info("cell print: {}", cell.print());
+ log.info("cell boc: {}", cell.toHex());
- @Test
- public void testTvmEmulatorWalletV5() throws IOException, URISyntaxException {
-
- URL resource = SmartContractCompiler.class.getResource("/contracts/wallets/new-wallet-v5.fc");
- String contractAbsolutePath = Paths.get(resource.toURI()).toFile().getAbsolutePath();
- SmartContractCompiler smcFunc = SmartContractCompiler.builder()
- .contractPath(contractAbsolutePath)
- .build();
-
- String codeCellHex = smcFunc.compile();
- Cell codeCell = CellBuilder.beginCell().fromBoc(codeCellHex).endCell();
-
- byte[] publicKey = Utils.hexToSignedBytes("82A0B2543D06FEC0AAC952E9EC738BE56AB1B6027FC0C1AA817AE14B4D1ED2FB");
- byte[] secretKey = Utils.hexToSignedBytes("F182111193F30D79D517F2339A1BA7C25FDF6C52142F0F2C1D960A1F1D65E1E4");
- TweetNaclFast.Signature.KeyPair keyPair = TweetNaclFast.Signature.keyPair_fromSeed(secretKey);
-
- Cell dataCell = CellBuilder.beginCell()
- .storeBit(true)
- .storeUint(0, 32)
- .storeUint(42, 32)
- .storeBytes(keyPair.getPublicKey())
- .storeBit(false)
- .endCell();
-
- log.info("codeCellHex {}", codeCellHex);
- log.info("dataCellHex {}", dataCell.toHex());
-
- Address address = StateInit.builder().code(codeCell).data(dataCell).build().getAddress();
- log.info("addressRaw {}", address.toRaw());
- log.info("addressBounceable {}", address.toBounceable());
-
- tvmEmulator = TvmEmulator.builder()
- .pathToEmulatorSharedLib("G:/libs/emulator.dll")
- .codeBoc(codeCell.toBase64())
- .dataBoc(dataCell.toBase64())
- .verbosityLevel(TvmVerbosityLevel.UNLIMITED)
- .build();
-
- tvmEmulator.setDebugEnabled(true);
-
- assertTrue(tvmEmulator.setLibs(getLibs().toBase64()));
-
- // todo
- // String resultBoc = tvmEmulator.sendExternalMessage(signedBody.toBase64());
-
-// SendExternalMessageResult result = gson.fromJson(resultBoc, SendExternalMessageResult.class);
-// log.info("result sendExternalMessage, exitCode: {}", result.getVm_exit_code());
- }
+ VmStack stack = VmStack.deserialize(CellSlice.beginParse(cell));
+ log.info("vmStack depth: {}", stack.getDepth());
+ VmStackList vmStackList = stack.getStack();
+ log.info("vmStackList: {}", vmStackList.getTos());
+ }
}
diff --git a/emulator/src/test/java/org/ton/java/emulator/TestTxEmulator.java b/emulator/src/test/java/org/ton/java/emulator/TestTxEmulator.java
index 659606d5..7cd75c5e 100644
--- a/emulator/src/test/java/org/ton/java/emulator/TestTxEmulator.java
+++ b/emulator/src/test/java/org/ton/java/emulator/TestTxEmulator.java
@@ -1,159 +1,532 @@
package org.ton.java.emulator;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.iwebpp.crypto.TweetNaclFast;
import com.sun.jna.Native;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.IOUtils;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.ton.java.address.Address;
import org.ton.java.cell.Cell;
import org.ton.java.cell.CellBuilder;
import org.ton.java.cell.TonHashMapE;
+import org.ton.java.emulator.tx.TxEmulator;
+import org.ton.java.emulator.tx.TxEmulatorI;
+import org.ton.java.emulator.tx.TxVerbosityLevel;
import org.ton.java.liteclient.LiteClient;
+import org.ton.java.smartcontract.SmartContractCompiler;
+import org.ton.java.smartcontract.types.Destination;
+import org.ton.java.smartcontract.types.WalletV5Config;
+import org.ton.java.smartcontract.wallet.v5.WalletV5;
import org.ton.java.tlb.types.*;
import org.ton.java.tonlib.Tonlib;
import org.ton.java.tonlib.types.SmcLibraryEntry;
import org.ton.java.tonlib.types.SmcLibraryResult;
import org.ton.java.utils.Utils;
-import java.math.BigInteger;
-import java.util.Collections;
-
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
-
@Slf4j
@RunWith(JUnit4.class)
public class TestTxEmulator {
- static TxEmulator txEmulator;
- static Tonlib tonlib;
- static Cell config;
- static LiteClient liteClient;
-
- @BeforeClass
- public static void setUpBeforeClass() {
- liteClient = LiteClient.builder()
- .pathToLiteClientBinary("G:/Git_Projects/ton4j/emulator/lite-client.exe")
- .build();
- tonlib = Tonlib.builder()
- .testnet(true)
- .ignoreCache(false)
- .build();
- config = tonlib.getConfigAll(128);
- txEmulator = TxEmulator.builder()
- .configBoc(config.toBase64())
- .build();
- }
+ static TxEmulator txEmulator;
+ static Tonlib tonlib;
+ static Cell config;
+ static LiteClient liteClient;
- @Test
- public void testInitTxEmulator() {
- TxEmulatorI txEmulatorI = Native.load("emulator.dll", TxEmulatorI.class);
- long emulator = txEmulatorI.transaction_emulator_create(config.toBase64(), 2);
- assertNotEquals(0, emulator);
- }
+ static Account testAccount;
- @Test
- public void testSetVerbosityLevel() {
- txEmulator.setVerbosityLevel(4);
- }
+ @BeforeClass
+ public static void setUpBeforeClass() throws IOException {
+ liteClient =
+ LiteClient.builder()
+ .pathToLiteClientBinary("G:/Git_Projects/ton4j/emulator/lite-client.exe")
+ .build();
+ tonlib = Tonlib.builder().testnet(true).ignoreCache(false).build();
- @Test
- public void testTxEmulatorIgnoreCheckSignature() {
- assertTrue(txEmulator.setIgnoreCheckSignature(true));
- }
+ config = tonlib.getConfigAll(128);
- @Test
- public void testTxEmulatorSetLt() {
- assertTrue(txEmulator.setEmulatorLt(200000));
- }
+ // all configs taken as of 04.10.2024
+ String configAllMainnet =
+ IOUtils.toString(
+ Objects.requireNonNull(
+ TestTxEmulator.class.getResourceAsStream("/config-all-mainnet.txt")),
+ StandardCharsets.UTF_8);
- @Test
- public void testTxEmulatorSetLibs() {
- Cell dictLibs = getLibs();
+ // String configAllTestnet =
+ // IOUtils.toString(
+ // Objects.requireNonNull(
+ // TestTxEmulator.class.getResourceAsStream("/config-all-testnet.txt")),
+ // StandardCharsets.UTF_8);
+ //
+ // String slimConfig =
+ // IOUtils.toString(
+ //
+ // Objects.requireNonNull(TestTxEmulator.class.getResourceAsStream("/slim-config.txt")),
+ // StandardCharsets.UTF_8);
- log.info("txEmulator.setLibs() result {}", txEmulator.setLibs(dictLibs.toBase64()));
- }
+ txEmulator =
+ TxEmulator.builder()
+ .configBoc(configAllMainnet)
+ // .pathToEmulatorSharedLib("G:/libs/emulator.dll")
+ .pathToEmulatorSharedLib(
+ "G:\\Git_Projects\\ton-blockchain\\build\\emulator\\emulator.dll")
+ .verbosityLevel(TxVerbosityLevel.UNLIMITED)
+ .build();
+ // txEmulator.setVerbosityLevel(TxVerbosityLevel.WITH_ALL_STACK_VALUES.ordinal());
- @Test
- public void testTxEmulatorEmulateTickTockTx() {
-// Cell dictLibs = getLibs();
-// txEmulator.setLibs(dictLibs.toBase64());
-
-// ResultLastBlock lightBlock = LiteClientParser.parseLast(liteClient.executeLast());
-// Block block = LiteClientParser.parseDumpblock(liteClient.executeDumpblock(lightBlock), true, true);
-// log.info("block: {}", block);
-
- ShardAccount shardAccount = ShardAccount.builder()
- .account(
- Account.builder()
- .isNone(false)
- .address(MsgAddressIntStd.builder()
- .workchainId((byte) -1)
- .address(new BigInteger("000000000000000000000000000000000000000000000000000000000000000", 16))
-// .address(new BigInteger("333333333333333333333333333333333333333333333333333333333333333", 16))
-// .address(new BigInteger("555555555555555555555555555555555555555555555555555555555555555", 16))
- .build())
- .storageInfo(StorageInfo.builder()
- .storageUsed(StorageUsed.builder()
- .cellsUsed(BigInteger.ZERO)
- .bitsUsed(BigInteger.ZERO)
- .publicCellsUsed(BigInteger.ZERO)
- .build())
- .lastPaid(123654)
- .duePayment(Utils.toNano(2))
- .build())
- .accountStorage(AccountStorage.builder()
-// .lastTransactionLt(BigInteger.TWO)
- .balance(CurrencyCollection.builder()
- .coins(Utils.toNano(2))
- .build())
- .accountState(AccountStateActive.builder()
- .stateInit(StateInit.builder()
-// .depth(BigInteger.valueOf(1))
-// .tickTock(TickTock.builder()
-// .tick(false)
-// .tock(true)
-// .build())
- .code(CellBuilder.beginCell().fromBoc("b5ee9c7241010101004e000098ff0020dd2082014c97ba9730ed44d0d70b1fe0a4f260810200d71820d70b1fed44d0d31fd3ffd15112baf2a122f901541044f910f2a2f80001d31f31d307d4d101fb00a4c8cb1fcbffc9ed5470102286").endCell())
-// .data(CellBuilder.beginCell().storeBit(true).endCell())
- .build())
- .build())
- .accountStatus("ACTIVE")
- .build())
- .build()
- )
-// .lastTransLt(BigInteger.ONE)
- .lastTransHash(BigInteger.valueOf(2))
- .build();
-
- log.info("shardAccount: {}", shardAccount);
- String shardAccountBocBase64 = shardAccount.toCell().toBase64();
- log.info("shardAccountCellBocBase64: {}", shardAccountBocBase64);
- String result = txEmulator.emulateTickTockTransaction(shardAccountBocBase64, false);
- log.info("result {}", result);
- }
+ testAccount =
+ Account.builder()
+ .isNone(false)
+ .address(
+ MsgAddressIntStd.of(
+ "-1:0000000000000000000000000000000000000000000000000000000000000000"))
+ .storageInfo(
+ StorageInfo.builder()
+ .storageUsed(
+ StorageUsed.builder()
+ .cellsUsed(BigInteger.ZERO)
+ .bitsUsed(BigInteger.ZERO)
+ .publicCellsUsed(BigInteger.ZERO)
+ .build())
+ .lastPaid(123654)
+ .duePayment(Utils.toNano(2))
+ .build())
+ .accountStorage(
+ AccountStorage.builder()
+ //
+ // .lastTransactionLt(BigInteger.TWO)
+ .balance(CurrencyCollection.builder().coins(Utils.toNano(2)).build())
+ .accountState(
+ AccountStateActive.builder()
+ .stateInit(
+ StateInit.builder()
+ //
+ // .depth(BigInteger.valueOf(1))
+ //
+ // .tickTock(TickTock.builder()
+ //
+ // .tick(false)
+ //
+ // .tock(true)
+ //
+ // .build())
+ .code(
+ CellBuilder.beginCell()
+ .fromBoc(
+ "b5ee9c7241010101004e000098ff0020dd2082014c97ba9730ed44d0d70b1fe0a4f260810200d71820d70b1fed44d0d31fd3ffd15112baf2a122f901541044f910f2a2f80001d31f31d307d4d101fb00a4c8cb1fcbffc9ed5470102286")
+ .endCell())
+ //
+ //
+ // .data(CellBuilder.beginCell().storeBit(true).endCell())
+ .build())
+ .build())
+ .accountStatus("ACTIVE")
+ .build())
+ .build();
+ }
+
+ @Test
+ public void testInitTxEmulator() {
+ TxEmulatorI txEmulatorI = Native.load("emulator.dll", TxEmulatorI.class);
+ long emulator = txEmulatorI.transaction_emulator_create(config.toBase64(), 2);
+ assertNotEquals(0, emulator);
+ }
+
+ @Test
+ public void testSetVerbosityLevel() {
+ txEmulator.setVerbosityLevel(4);
+ }
+
+ @Test
+ public void testTxEmulatorIgnoreCheckSignature() {
+ assertTrue(txEmulator.setIgnoreCheckSignature(true));
+ }
+
+ @Test
+ public void testTxEmulatorSetLt() {
+ assertTrue(txEmulator.setEmulatorLt(200000));
+ }
+
+ @Test
+ public void testTxEmulatorSetLibs() {
+ Cell dictLibs = getLibs();
+
+ log.info("txEmulator.setLibs() result {}", txEmulator.setLibs(dictLibs.toBase64()));
+ }
+
+ @Test
+ public void testTxEmulatorEmulateTickTockTx() {
+ // Cell dictLibs = getLibs();
+ // txEmulator.setLibs(dictLibs.toBase64());
+
+ // ResultLastBlock lightBlock = LiteClientParser.parseLast(liteClient.executeLast());
+ // Block block = LiteClientParser.parseDumpblock(liteClient.executeDumpblock(lightBlock),
+ // true, true);
+ // log.info("block: {}", block);
+
+ ShardAccount shardAccount =
+ ShardAccount.builder()
+ .account(testAccount)
+ .lastTransHash(BigInteger.valueOf(2))
+ .lastTransLt(BigInteger.ZERO)
+ .build();
+
+ log.info("shardAccount: {}", shardAccount);
+ String shardAccountBocBase64 = shardAccount.toCell().toBase64();
+ log.info("shardAccountCellBocBase64: {}", shardAccountBocBase64);
+ EmulateTransactionResult result =
+ txEmulator.emulateTickTockTransaction(shardAccountBocBase64, false);
+ log.info("result {}", result);
+ }
+
+ @Test
+ public void testTxEmulatorEmulateTxWithEmptyAccount() {
+
+ ShardAccount shardAccount =
+ ShardAccount.builder()
+ .account(Account.builder().isNone(true).build())
+ .lastTransHash(BigInteger.ZERO)
+ .lastTransLt(BigInteger.ZERO)
+ .build();
+ String shardAccountBocBase64 = shardAccount.toCell().toBase64();
+
+ Message internalMsg =
+ Message.builder()
+ .info(
+ InternalMessageInfo.builder()
+ .srcAddr(
+ MsgAddressIntStd.builder()
+ .workchainId((byte) 0)
+ .address(BigInteger.ZERO)
+ .build())
+ .dstAddr(
+ MsgAddressIntStd.builder()
+ .workchainId((byte) 0)
+ .address(BigInteger.ZERO)
+ .build())
+ .value(CurrencyCollection.builder().coins(Utils.toNano(1)).build())
+ .bounce(false)
+ .createdAt(0)
+ .build())
+ .init(null)
+ .body(null)
+ .build();
+ String internalMsgBocBase64 = internalMsg.toCell().toBase64();
+ EmulateTransactionResult result =
+ txEmulator.emulateTransaction(shardAccountBocBase64, internalMsgBocBase64);
+ log.info("result {}", result);
+ assertThat(result.isSuccess()).isTrue();
+ }
+
+ @Test
+ public void testTxEmulatorEmulateTxWithAccount() {
+
+ ShardAccount shardAccount =
+ ShardAccount.builder()
+ .account(testAccount)
+ .lastTransHash(BigInteger.ZERO)
+ .lastTransLt(BigInteger.ZERO)
+ .build();
+ String shardAccountBocBase64 = shardAccount.toCell().toBase64();
+
+ Message internalMsg =
+ Message.builder()
+ .info(
+ InternalMessageInfo.builder()
+ .srcAddr(
+ MsgAddressIntStd.builder()
+ .workchainId((byte) 0)
+ .address(BigInteger.ZERO)
+ .build())
+ .dstAddr(
+ MsgAddressIntStd.builder()
+ .workchainId((byte) 0)
+ .address(BigInteger.ZERO)
+ .build())
+ .value(CurrencyCollection.builder().coins(Utils.toNano(1)).build())
+ .bounce(false)
+ .createdAt(0)
+ .build())
+ .init(null)
+ .body(null)
+ .build();
+ String internalMsgBocBase64 = internalMsg.toCell().toBase64();
+ EmulateTransactionResult result =
+ txEmulator.emulateTransaction(shardAccountBocBase64, internalMsgBocBase64);
+ log.info("result {}", result);
+ assertThat(result.isSuccess()).isTrue();
+ log.info("new shardAccount {}", result.getNewShardAccount());
+ log.info("new transaction {}", result.getTransaction());
+ log.info("new actions {}", result.getActions());
+ }
+
+ @Test
+ public void testTxEmulatorWalletV5ExternalMsg() throws IOException, URISyntaxException {
- private static Cell getLibs() {
- SmcLibraryResult result = tonlib.getLibraries(
- Collections.singletonList("wkUmK4wrzl6fzSPKM04dVfqW1M5pqigX3tcXzvy6P3M="));
- log.info("result: {}", result);
-
- TonHashMapE x = new TonHashMapE(256);
-
- for (SmcLibraryEntry l : result.getResult()) {
- String cellLibBoc = l.getData();
- Cell lib = Cell.fromBocBase64(cellLibBoc);
- log.info("cell lib {}", lib.toHex());
- x.elements.put(1L, lib);
- x.elements.put(2L, lib); // 2nd because of the bug in hashmap/e
- }
-
- Cell dictLibs = x.serialize(
- k -> CellBuilder.beginCell().storeUint((Long) k, 256).endCell().getBits(),
- v -> CellBuilder.beginCell().storeRef((Cell) v).endCell()
- );
- return dictLibs;
+ URL resource = SmartContractCompiler.class.getResource("/contracts/wallets/new-wallet-v5.fc");
+ String contractAbsolutePath = Paths.get(resource.toURI()).toFile().getAbsolutePath();
+ SmartContractCompiler smcFunc =
+ SmartContractCompiler.builder().contractPath(contractAbsolutePath).build();
+
+ String codeCellHex = smcFunc.compile();
+ Cell codeCell = CellBuilder.beginCell().fromBoc(codeCellHex).endCell();
+
+ byte[] publicKey =
+ Utils.hexToSignedBytes("82A0B2543D06FEC0AAC952E9EC738BE56AB1B6027FC0C1AA817AE14B4D1ED2FB");
+ byte[] secretKey =
+ Utils.hexToSignedBytes("F182111193F30D79D517F2339A1BA7C25FDF6C52142F0F2C1D960A1F1D65E1E4");
+ TweetNaclFast.Signature.KeyPair keyPair = TweetNaclFast.Signature.keyPair_fromSeed(secretKey);
+
+ WalletV5 walletV5 =
+ WalletV5.builder()
+ .keyPair(keyPair)
+ .isSigAuthAllowed(false)
+ .initialSeqno(0)
+ .walletId(42)
+ .build();
+
+ Cell dataCell = walletV5.createDataCell();
+
+ log.info("codeCellHex {}", codeCellHex);
+ log.info("dataCellHex {}", dataCell.toHex());
+
+ Address address = StateInit.builder().code(codeCell).data(dataCell).build().getAddress();
+ log.info("addressRaw {}", address.toRaw());
+ log.info("addressBounceable {}", address.toBounceable());
+
+ Account walletV5Account =
+ Account.builder()
+ .isNone(false)
+ .address(MsgAddressIntStd.of(address))
+ .storageInfo(
+ StorageInfo.builder()
+ .storageUsed(
+ StorageUsed.builder()
+ .cellsUsed(BigInteger.ZERO)
+ .bitsUsed(BigInteger.ZERO)
+ .publicCellsUsed(BigInteger.ZERO)
+ .build())
+ .lastPaid(System.currentTimeMillis() / 1000)
+ .duePayment(Utils.toNano(22))
+ .build())
+ .accountStorage(
+ AccountStorage.builder()
+ .lastTransactionLt(BigInteger.ZERO)
+ .balance(
+ CurrencyCollection.builder()
+ .coins(Utils.toNano(2)) // initial balance
+ .build())
+ .accountState(
+ AccountStateActive.builder()
+ .stateInit(StateInit.builder().code(codeCell).data(dataCell).build())
+ .build())
+ // .accountStatus("ACTIVE")
+ .build())
+ .build();
+
+ ShardAccount shardAccount =
+ ShardAccount.builder()
+ .account(walletV5Account)
+ .lastTransHash(BigInteger.ZERO)
+ .lastTransLt(BigInteger.ZERO)
+ .build();
+ String shardAccountBocBase64 = shardAccount.toCell().toBase64();
+
+ txEmulator.setDebugEnabled(true);
+
+ // assertTrue(txEmulator.setLibs(getLibs().toBase64()));
+
+ String rawDummyDestinationAddress =
+ "0:258e549638a6980ae5d3c76382afd3f4f32e34482dafc3751e3358589c8de00d";
+
+ WalletV5Config walletV5Config =
+ WalletV5Config.builder()
+ .seqno(1)
+ .walletId(42)
+ .body(
+ walletV5
+ .createBulkTransfer(
+ Collections.singletonList(
+ Destination.builder()
+ .bounce(false)
+ .address(rawDummyDestinationAddress)
+ .amount(Utils.toNano(0.001))
+ .build()))
+ .toCell())
+ .build();
+
+ // Message extMsg = walletV5.prepareExternalMsg(walletV5Config);
+ Cell extBodyCell = walletV5.createExternalTransferBody(walletV5Config);
+
+ // Cell transferBody = walletV5.createExternalTransferBody(walletV5Config);
+ //
+ // Cell signedBody =
+ // CellBuilder.beginCell()
+ // .storeBytes(
+ // Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(),
+ // transferBody.hash()))
+ // .storeCell(transferBody)
+ // .endCell();
+ // log.info("extMsg {}", signedBody.toHex());
+
+ EmulateTransactionResult result =
+ txEmulator.emulateTransaction(shardAccountBocBase64, extBodyCell.toBase64());
+ // EmulateTransactionResult result =
+ // txEmulator.emulateTransaction(shardAccountBocBase64, signedBody.toBase64());
+ // txEmulator.emulateTransaction(shardAccountBocBase64, extMsg.toCell().toBase64());
+
+ log.info("result sendExternalMessage, exitCode: {}", result);
+ }
+
+ @Test
+ public void testTvmEmulatorWalletV5InternalMsg() throws IOException, URISyntaxException {
+
+ testAccount =
+ Account.builder()
+ .isNone(false)
+ .address(
+ MsgAddressIntStd.of(
+ "-1:0000000000000000000000000000000000000000000000000000000000000000"))
+ .storageInfo(
+ StorageInfo.builder()
+ .storageUsed(
+ StorageUsed.builder()
+ .cellsUsed(BigInteger.ZERO)
+ .bitsUsed(BigInteger.ZERO)
+ .publicCellsUsed(BigInteger.ZERO)
+ .build())
+ .lastPaid(123654)
+ .duePayment(Utils.toNano(2))
+ .build())
+ .accountStorage(
+ AccountStorage.builder()
+ //
+ // .lastTransactionLt(BigInteger.TWO)
+ .balance(CurrencyCollection.builder().coins(Utils.toNano(2)).build())
+ .accountState(
+ AccountStateActive.builder()
+ .stateInit(
+ StateInit.builder()
+ //
+ // .depth(BigInteger.valueOf(1))
+ //
+ // .tickTock(TickTock.builder()
+ //
+ // .tick(false)
+ //
+ // .tock(true)
+ //
+ // .build())
+ .code(
+ CellBuilder.beginCell()
+ .fromBoc(
+ "b5ee9c7241010101004e000098ff0020dd2082014c97ba9730ed44d0d70b1fe0a4f260810200d71820d70b1fed44d0d31fd3ffd15112baf2a122f901541044f910f2a2f80001d31f31d307d4d101fb00a4c8cb1fcbffc9ed5470102286")
+ .endCell())
+ //
+ //
+ // .data(CellBuilder.beginCell().storeBit(true).endCell())
+ .build())
+ .build())
+ .accountStatus("ACTIVE")
+ .build())
+ .build();
+
+ ShardAccount shardAccount =
+ ShardAccount.builder()
+ .account(testAccount)
+ .lastTransHash(BigInteger.ZERO)
+ .lastTransLt(BigInteger.ZERO)
+ .build();
+ String shardAccountBocBase64 = shardAccount.toCell().toBase64();
+
+ URL resource = SmartContractCompiler.class.getResource("/contracts/wallets/new-wallet-v5.fc");
+ String contractAbsolutePath = Paths.get(resource.toURI()).toFile().getAbsolutePath();
+ SmartContractCompiler smcFunc =
+ SmartContractCompiler.builder().contractPath(contractAbsolutePath).build();
+
+ String codeCellHex = smcFunc.compile();
+ Cell codeCell = CellBuilder.beginCell().fromBoc(codeCellHex).endCell();
+
+ byte[] publicKey =
+ Utils.hexToSignedBytes("82A0B2543D06FEC0AAC952E9EC738BE56AB1B6027FC0C1AA817AE14B4D1ED2FB");
+ byte[] secretKey =
+ Utils.hexToSignedBytes("F182111193F30D79D517F2339A1BA7C25FDF6C52142F0F2C1D960A1F1D65E1E4");
+ TweetNaclFast.Signature.KeyPair keyPair = TweetNaclFast.Signature.keyPair_fromSeed(secretKey);
+
+ WalletV5 walletV5 =
+ WalletV5.builder()
+ .keyPair(keyPair)
+ .isSigAuthAllowed(false)
+ .initialSeqno(0)
+ .walletId(42)
+ .build();
+
+ Cell dataCell = walletV5.createDataCell();
+
+ log.info("codeCellHex {}", codeCellHex);
+ log.info("dataCellHex {}", dataCell.toHex());
+
+ Address address = StateInit.builder().code(codeCell).data(dataCell).build().getAddress();
+ log.info("addressRaw {}", address.toRaw());
+ log.info("addressBounceable {}", address.toBounceable());
+
+ txEmulator.setDebugEnabled(true);
+
+ assertTrue(txEmulator.setLibs(getLibs().toBase64()));
+
+ Cell internalBodyCell =
+ walletV5
+ .createBulkTransfer(
+ Collections.singletonList(
+ Destination.builder()
+ .bounce(false)
+ .address(
+ "0:258e549638a6980ae5d3c76382afd3f4f32e34482dafc3751e3358589c8de00d")
+ .amount(Utils.toNano(0.0001))
+ .build()))
+ .toCell();
+
+ EmulateTransactionResult result =
+ txEmulator.emulateTransaction(shardAccountBocBase64, internalBodyCell.toBase64());
+
+ log.info("result emulateTransaction: {}", result);
+ }
+
+ private static Cell getLibs() {
+ SmcLibraryResult result =
+ tonlib.getLibraries(
+ Collections.singletonList("wkUmK4wrzl6fzSPKM04dVfqW1M5pqigX3tcXzvy6P3M="));
+ log.info("result: {}", result);
+
+ TonHashMapE x = new TonHashMapE(256);
+
+ for (SmcLibraryEntry l : result.getResult()) {
+ String cellLibBoc = l.getData();
+ Cell lib = Cell.fromBocBase64(cellLibBoc);
+ log.info("cell lib {}", lib.toHex());
+ x.elements.put(1L, lib);
+ x.elements.put(2L, lib); // 2nd because of the bug in hashmap/e
}
+
+ Cell dictLibs =
+ x.serialize(
+ k -> CellBuilder.beginCell().storeUint((Long) k, 256).endCell().getBits(),
+ v -> CellBuilder.beginCell().storeRef((Cell) v).endCell());
+ return dictLibs;
+ }
}
diff --git a/emulator/src/test/java/org/ton/java/emulator/TvmEmulator.java b/emulator/src/test/java/org/ton/java/emulator/TvmEmulator.java
deleted file mode 100644
index 3b651550..00000000
--- a/emulator/src/test/java/org/ton/java/emulator/TvmEmulator.java
+++ /dev/null
@@ -1,338 +0,0 @@
-package org.ton.java.emulator;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.ToNumberPolicy;
-import com.sun.jna.Native;
-import lombok.Builder;
-import lombok.extern.java.Log;
-import org.ton.java.cell.Cell;
-import org.ton.java.cell.CellBuilder;
-import org.ton.java.cell.CellSlice;
-import org.ton.java.tlb.types.VmStack;
-import org.ton.java.tlb.types.VmStackList;
-import org.ton.java.tlb.types.VmStackValueInt;
-import org.ton.java.tlb.types.VmStackValueTinyInt;
-import org.ton.java.utils.Utils;
-
-import java.math.BigInteger;
-import java.util.Collections;
-
-import static java.util.Objects.isNull;
-
-@Log
-@Builder
-public class TvmEmulator {
-
- /**
- * If not specified then emulator shared library must be located in:
- *
- * jna.library.path
User-customizable path
- * jna.platform.library.path
Platform-specific paths
- * - On OSX, ~/Library/Frameworks, /Library/Frameworks, and /System/Library/Frameworks will be searched for a framework with a name corresponding to that requested. Absolute paths to frameworks are also accepted, either ending at the framework name (sans ".framework") or the full path to the framework shared library (e.g. CoreServices.framework/CoreServices).
- * - Context class loader classpath. Deployed native libraries may be installed on the classpath under ${os-prefix}/LIBRARY_FILENAME, where ${os-prefix} is the OS/Arch prefix returned by Platform.getNativeLibraryResourcePrefix(). If bundled in a jar file, the resource will be extracted to jna.tmpdir for loading, and later removed.
- *
- *
- * Java Tonlib looking for following filenames in above locations:
- *
- * - libemulator-linux-x86_64.so and libemulator-linux-arm64.so
- * - emulator.dll and emulator-arm.dll
- * - libemulator-mac-x86-64.dylib and libemulator-mac-arm64.dylib
- *
- */
- private String pathToEmulatorSharedLib;
- private final TvmEmulatorI tvmEmulatorI;
- private final long tvmEmulator;
-
- private String codeBoc;
- private String dataBoc;
- private TvmVerbosityLevel verbosityLevel;
-
- public static class TvmEmulatorBuilder {
- }
-
- public static TvmEmulatorBuilder builder() {
- return new CustomTvmEmulatorBuilder();
- }
-
- private static class CustomTvmEmulatorBuilder extends TvmEmulatorBuilder {
- @Override
- public TvmEmulator build() {
- String emulatorName;
- Utils.OS os = Utils.getOS();
- switch (os) {
- case LINUX:
- emulatorName = "libemulator-linux-x86_64.so";
- break;
- case LINUX_ARM:
- emulatorName = "libemulator-linux-arm64.so";
- break;
- case WINDOWS:
- emulatorName = "emulator.dll";
- break;
- case WINDOWS_ARM:
- emulatorName = "emulator-arm.dll";
- break;
- case MAC:
- emulatorName = "libemulator-mac-x86-64.dylib";
- break;
- case MAC_ARM64:
- emulatorName = "libemulator-mac-arm64.dylib";
- break;
- case UNKNOWN:
- throw new Error("Operating system is not supported!");
- default:
- throw new IllegalArgumentException("Unknown operating system: " + os);
- }
-
- if (isNull(super.pathToEmulatorSharedLib)) {
- super.pathToEmulatorSharedLib = emulatorName;
- }
-
- super.tvmEmulatorI = Native.load(super.pathToEmulatorSharedLib, TvmEmulatorI.class);
- if (isNull(super.verbosityLevel)) {
- super.verbosityLevel = TvmVerbosityLevel.WITH_ALL_STACK_VALUES;
- }
- if (isNull(super.codeBoc)) {
- throw new Error("codeBoc is not set");
- }
- if (isNull(super.dataBoc)) {
- throw new Error("dataBoc is not set");
- }
- super.tvmEmulator = super.tvmEmulatorI.tvm_emulator_create(super.codeBoc, super.dataBoc, super.verbosityLevel.ordinal());
-
- if (super.tvmEmulator == 0) {
- throw new Error("Can't create emulator instance");
- }
-
- System.out.printf("Java TON TVM Emulator configuration:\n" +
- "Location: %s\n" +
- "Verbosity level: %s\n",
- super.pathToEmulatorSharedLib,
- super.verbosityLevel);
- return super.build();
- }
- }
-
- public void destroy() {
- tvmEmulatorI.tvm_emulator_destroy(tvmEmulator);
- }
-
- /**
- * Set libs for emulation
- *
- * @param libsBoc Base64 encoded BoC serialized shared libraries dictionary (HashmapE 256 ^Cell).
- * @return true in case of success, false in case of error
- */
- public boolean setLibs(String libsBoc) {
- return tvmEmulatorI.tvm_emulator_set_libraries(tvmEmulator, libsBoc);
- }
-
- /**
- * Prepares the c7 tuple (virtual machine context) for a compute phase of a transaction.
- *
- * C7 tlb-scheme FYI:
- *
- * smc_info#076ef1ea
- * actions:uint16
- * msgs_sent:uint16
- * unixtime:uint32
- * block_lt:uint64
- * trans_lt:uint64
- * rand_seed:bits256
- * balance_remaining:CurrencyCollection
- * myself:MsgAddressInt
- * global_config:(Maybe Cell) = SmartContractInfo;
- *
- * Set c7 parameters
- *
- * @param address Address of smart contract
- * @param unixTime Unix timestamp
- * @param balance Smart contract balance
- * @param randSeedHex Random seed as hex string of length 64
- * @param config Base64 encoded BoC serialized Config dictionary (Hashmap 32 ^Cell). Optional.
- * @return true in case of success, false in case of error
- */
- public boolean setC7(String address, long unixTime, long balance, String randSeedHex, String config) {
- return tvmEmulatorI.tvm_emulator_set_c7(tvmEmulator, address, unixTime, balance, randSeedHex, config);
- }
-
- /**
- * Set tuple of previous blocks (13th element of c7)
- *
- * @param infoBoc Base64 encoded BoC serialized TVM tuple (VmStackValue).
- * @return true in case of success, false in case of error
- */
- public boolean setPrevBlockInfo(String infoBoc) {
- return tvmEmulatorI.tvm_emulator_set_prev_blocks_info(tvmEmulator, infoBoc);
- }
-
- /**
- * Set TVM gas limit
- *
- * @param gasLimit Gas limit
- * @return true in case of success, false in case of error
- */
- public boolean setGasLimit(long gasLimit) {
- return tvmEmulatorI.tvm_emulator_set_gas_limit(tvmEmulator, gasLimit);
- }
-
- /**
- * Enable or disable TVM debug primitives
- *
- * @param debugEnabled Whether debug primitives should be enabled or not
- * @return true in case of success, false in case of error
- */
- public boolean setDebugEnabled(boolean debugEnabled) {
- return tvmEmulatorI.tvm_emulator_set_debug_enabled(tvmEmulator, debugEnabled);
- }
-
-
- /**
- * Run get method
- *
- * @param methodId Integer method id
- * @param stackBoc Base64 encoded BoC serialized stack (VmStack)
- * @return Json object with error:
- * {
- * "success": false,
- * "error": "Error description"
- * }
- * Or success:
- * {
- * "success": true
- * "vm_log": "...",
- * "vm_exit_code": 0,
- * "stack": "Base64 encoded BoC serialized stack (VmStack)",
- * "missing_library": null,
- * "gas_used": 1212
- * }
- */
- public String runGetMethod(int methodId, String stackBoc) {
- return tvmEmulatorI.tvm_emulator_run_get_method(tvmEmulator, methodId, stackBoc);
- }
-
- /**
- * Run get method with empty input stack
- *
- * @param methodId Integer method id
- * @return Json object with error:
- * {
- * "success": false,
- * "error": "Error description"
- * }
- * Or success:
- * {
- * "success": true
- * "vm_log": "...",
- * "vm_exit_code": 0,
- * "stack": "Base64 encoded BoC serialized stack (VmStack)",
- * "missing_library": null,
- * "gas_used": 1212
- * }
- */
- public String runGetMethod(int methodId) {
- return tvmEmulatorI.tvm_emulator_run_get_method(tvmEmulator, methodId,
- VmStack.builder()
- .depth(0)
- .stack(VmStackList.builder()
- .tos(Collections.emptyList())
- .build())
- .build()
- .toCell().toBase64());
- }
-
- public BigInteger runGetSeqNo() {
- String seqNoResult = runGetMethod(Utils.calculateMethodId("seqno"));
- Gson gson = new GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.BIG_DECIMAL).create();
- GetMethodResult methodResult = gson.fromJson(seqNoResult, GetMethodResult.class);
-
- Cell cellResult = CellBuilder.beginCell().fromBocBase64(methodResult.getStack()).endCell();
- VmStack stack = VmStack.deserialize(CellSlice.beginParse(cellResult));
- VmStackList vmStackList = stack.getStack();
- return VmStackValueTinyInt.deserialize(CellSlice.beginParse(vmStackList.getTos().get(0).toCell())).getValue();
- }
-
- public String runGetPublicKey() {
- String pubKeyResult = runGetMethod(Utils.calculateMethodId("get_public_key"));
- Gson gson = new GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.BIG_DECIMAL).create();
- GetMethodResult methodResult = gson.fromJson(pubKeyResult, GetMethodResult.class);
-
- Cell cellResult = CellBuilder.beginCell().fromBocBase64(methodResult.getStack()).endCell();
- VmStack stack = VmStack.deserialize(CellSlice.beginParse(cellResult));
- int depth = stack.getDepth();
- VmStackList vmStackList = stack.getStack();
- BigInteger pubKey = VmStackValueInt.deserialize(CellSlice.beginParse(vmStackList.getTos().get(0).toCell())).getValue();
- return pubKey.toString(16);
- }
-
- /**
- * Optimized version of "run get method" with all passed parameters in a single call
- *
- * @param len Length of params_boc buffer
- * @param paramsBoc BoC serialized parameters, scheme:
- * code:^Cell data:^Cell stack:^VmStack params:^[c7:^VmStack libs:^Cell]
- * method_id:(## 32)
- * @param gasLimit Gas limit
- * @return String with first 4 bytes defining length, and the rest BoC serialized result
- * Scheme: result$_ exit_code:(## 32) gas_used:(## 32) stack:^VmStack
- */
- public String emulateRunMethod(int len, String paramsBoc, long gasLimit) {
- return tvmEmulatorI.tvm_emulator_emulate_run_method(len, paramsBoc, gasLimit);
- }
-
- /**
- * Send external message
- *
- * @param messageBodyBoc Base64 encoded BoC serialized message body cell.
- * @return Json object with error:
- * {
- * "success": false,
- * "error": "Error description"
- * }
- * Or success:
- * {
- * "success": true,
- * "new_code": "Base64 boc decoded new code cell",
- * "new_data": "Base64 boc decoded new data cell",
- * "accepted": true,
- * "vm_exit_code": 0,
- * "vm_log": "...",
- * "missing_library": null,
- * "gas_used": 1212,
- * "actions": "Base64 boc decoded actions cell of type (OutList n)"
- * }
- */
- public String sendExternalMessage(String messageBodyBoc) {
- return tvmEmulatorI.tvm_emulator_send_external_message(tvmEmulator, messageBodyBoc);
- }
-
- /**
- * Send internal message
- *
- * @param messageBodyBoc Base64 encoded BoC serialized message body cell.
- * @param amount Amount of nanograms attached with internal message.
- * @return Json object with error:
- * {
- * "success": false,
- * "error": "Error description"
- * }
- * Or success:
- * {
- * "success": true,
- * "new_code": "Base64 boc decoded new code cell",
- * "new_data": "Base64 boc decoded new data cell",
- * "accepted": true,
- * "vm_exit_code": 0,
- * "vm_log": "...",
- * "missing_library": null,
- * "gas_used": 1212,
- * "actions": "Base64 boc decoded actions cell of type (OutList n)"
- * }
- */
- public String sendInternalMessage(String messageBodyBoc, long amount) {
- return tvmEmulatorI.tvm_emulator_send_internal_message(tvmEmulator, messageBodyBoc, amount);
- }
-}
-
-
diff --git a/smartcontract/src/main/java/org/ton/java/smartcontract/wallet/v5/WalletV5.java b/smartcontract/src/main/java/org/ton/java/smartcontract/wallet/v5/WalletV5.java
index e65211d4..228756f9 100644
--- a/smartcontract/src/main/java/org/ton/java/smartcontract/wallet/v5/WalletV5.java
+++ b/smartcontract/src/main/java/org/ton/java/smartcontract/wallet/v5/WalletV5.java
@@ -26,355 +26,352 @@
@Getter
public class WalletV5 implements Contract {
- private static final int SIZE_BOOL = 1;
- private static final int SIZE_SEQNO = 32;
- private static final int SIZE_WALLET_ID = 32;
- private static final int SIZE_VALID_UNTIL = 32;
+ private static final int SIZE_BOOL = 1;
+ private static final int SIZE_SEQNO = 32;
+ private static final int SIZE_WALLET_ID = 32;
+ private static final int SIZE_VALID_UNTIL = 32;
- private static final int PREFIX_SIGNED_EXTERNAL = 0x7369676E;
- private static final int PREFIX_SIGNED_INTERNAL = 0x73696E74;
- private static final int PREFIX_EXTENSION_ACTION = 0x6578746e;
+ private static final int PREFIX_SIGNED_EXTERNAL = 0x7369676E;
+ private static final int PREFIX_SIGNED_INTERNAL = 0x73696E74;
+ private static final int PREFIX_EXTENSION_ACTION = 0x6578746e;
- TweetNaclFast.Signature.KeyPair keyPair;
- long initialSeqno;
- long walletId;
+ TweetNaclFast.Signature.KeyPair keyPair;
+ long initialSeqno;
+ long walletId;
- long validUntil;
- TonHashMapE extensions;
- boolean isSigAuthAllowed;
+ long validUntil;
+ TonHashMapE extensions;
+ boolean isSigAuthAllowed;
- private Tonlib tonlib;
- private long wc;
+ private Tonlib tonlib;
+ private long wc;
- private boolean deployAsLibrary;
+ private boolean deployAsLibrary;
- public static class WalletV5Builder {
- }
-
- public static WalletV5Builder builder() {
- return new CustomWalletV5Builder();
- }
-
- private static class CustomWalletV5Builder extends WalletV5Builder {
- @Override
- public WalletV5 build() {
- if (isNull(super.keyPair)) {
- super.keyPair = Utils.generateSignatureKeyPair();
- }
- return super.build();
- }
- }
-
- @Override
- public Tonlib getTonlib() {
- return tonlib;
- }
-
- @Override
- public long getWorkchain() {
- return wc;
- }
-
- @Override
- public String getName() {
- return "V5";
- }
+ public static class WalletV5Builder {}
- /**
- *
- * contract_state$_
- * is_signature_allowed:(## 1)
- * seqno:# wallet_id:(## 32)
- * public_key:(## 256)
- * extensions_dict:(HashmapE 256 int1)
- * = ContractState;
- *
- */
- @Override
- public Cell createDataCell() {
- if (isNull(extensions)) {
- return CellBuilder.beginCell()
- .storeBit(isSigAuthAllowed)
- .storeUint(initialSeqno, 32)
- .storeUint(walletId, 32)
- .storeBytes(keyPair.getPublicKey())
- .storeBit(false) // empty extensions dict
- .endCell();
- } else {
- return CellBuilder.beginCell()
- .storeBit(isSigAuthAllowed)
- .storeUint(initialSeqno, 32)
- .storeUint(walletId, 32)
- .storeBytes(keyPair.getPublicKey())
- .storeDict(extensions.serialize(
- k -> CellBuilder.beginCell().storeUint((BigInteger) k, 256).endCell().getBits(),
- v -> CellBuilder.beginCell().storeBit((Boolean) v).endCell()))
- .endCell();
- }
- }
+ public static WalletV5Builder builder() {
+ return new CustomWalletV5Builder();
+ }
+ private static class CustomWalletV5Builder extends WalletV5Builder {
@Override
- public Cell createCodeCell() {
- if (!deployAsLibrary) {
- return CellBuilder.beginCell()
- .fromBoc(WalletCodes.V5R1.getValue())
- .endCell();
- } else {
- return CellBuilder.beginCell()
- .storeUint(2, 8)
- .storeBytes(CellBuilder.beginCell()
- .fromBoc(WalletCodes.V5R1.getValue())
- .endCell().getHash())
- .setExotic(true)
- .cellType(CellType.LIBRARY)
- .endCell();
- }
- }
-
- @Override
- public StateInit getStateInit() {
- return StateInit.builder()
- .code(createCodeCell())
- .data(createDataCell())
-// .lib(createLibraryCell())
- .build();
- }
-
- public ExtMessageInfo send(WalletV5Config config) {
- return tonlib.sendRawMessage(prepareExternalMsg(config).toCell().toBase64());
- }
-
- /**
- * Deploy wallet without any extensions.
- * One can be installed later into the wallet.
- */
-
- public ExtMessageInfo deploy() {
- return tonlib.sendRawMessage(prepareDeployMsg().toCell().toBase64());
- }
-
- public Message prepareDeployMsg() {
- Cell body = createDeployMsg();
- byte[] signature = Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), body.hash());
-
- return Message.builder()
- .info(ExternalMessageInfo.builder()
- .dstAddr(getAddressIntStd())
- .build())
- .init(getStateInit())
- .body(CellBuilder.beginCell()
- .storeCell(body)
- .storeBytes(signature)
- .endCell())
- .build();
- }
-
- public Message prepareExternalMsg(WalletV5Config config) {
- Cell body = createExternalTransferBody(config);
- byte[] signature = Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), body.hash());
-
- return Message.builder()
- .info(ExternalMessageInfo.builder()
- .dstAddr(getAddressIntStd())
- .build())
- .init(getStateInit())
- .body(CellBuilder.beginCell()
- .storeCell(body)
- .storeBytes(signature)
- .endCell())
- .build();
- }
-
- /**
- *
- * signed_request$_ // 32 (opcode from outer)
- * wallet_id: # // 32
- * valid_until: # // 32
- * msg_seqno: # // 32
- * inner: InnerRequest //
- * signature: bits512 // 512
- * = SignedRequest;
- *
- */
- private Cell createDeployMsg() {
- if (isNull(extensions)) {
- return CellBuilder.beginCell()
- .storeUint(PREFIX_SIGNED_EXTERNAL, 32)
- .storeUint(walletId, SIZE_WALLET_ID)
- .storeUint((validUntil == 0) ? Instant.now().getEpochSecond() + 60 : validUntil, SIZE_VALID_UNTIL)
- .storeUint(0, SIZE_SEQNO)
- .storeBit(false) // empty extensions dict
- .endCell();
- } else {
- return CellBuilder.beginCell()
- .storeUint(PREFIX_SIGNED_EXTERNAL, 32)
- .storeUint(walletId, SIZE_WALLET_ID)
- .storeUint((validUntil == 0) ? Instant.now().getEpochSecond() + 60 : validUntil, SIZE_VALID_UNTIL)
- .storeUint(0, SIZE_SEQNO)
- .storeDict(extensions.serialize(
- k -> CellBuilder.beginCell().storeUint((BigInteger) k, 256).endCell().getBits(),
- v -> CellBuilder.beginCell().storeBit((Boolean) v).endCell()))
- .endCell();
- }
+ public WalletV5 build() {
+ if (isNull(super.keyPair)) {
+ super.keyPair = Utils.generateSignatureKeyPair();
+ }
+ return super.build();
}
-
- private Cell createExternalTransferBody(WalletV5Config config) {
- return CellBuilder.beginCell()
- .storeUint(PREFIX_SIGNED_EXTERNAL, 32)
- .storeUint(config.getWalletId(), SIZE_WALLET_ID)
- .storeUint((config.getValidUntil() == 0) ? Instant.now().getEpochSecond() + 60 : config.getValidUntil(), SIZE_VALID_UNTIL)
- .storeUint(config.getSeqno(), SIZE_SEQNO)
- .storeCell(config.getBody()) // innerRequest
- .endCell();
+ }
+
+ @Override
+ public Tonlib getTonlib() {
+ return tonlib;
+ }
+
+ @Override
+ public long getWorkchain() {
+ return wc;
+ }
+
+ @Override
+ public String getName() {
+ return "V5";
+ }
+
+ /**
+ *
+ *
+ *
+ * contract_state$_
+ * is_signature_allowed:(## 1)
+ * seqno:# wallet_id:(## 32)
+ * public_key:(## 256)
+ * extensions_dict:(HashmapE 256 int1)
+ * = ContractState;
+ *
+ */
+ @Override
+ public Cell createDataCell() {
+ if (isNull(extensions)) {
+ return CellBuilder.beginCell()
+ .storeBit(isSigAuthAllowed)
+ .storeUint(initialSeqno, 32)
+ .storeUint(walletId, 32)
+ .storeBytes(keyPair.getPublicKey())
+ .storeBit(false) // empty extensions dict
+ .endCell();
+ } else {
+ return CellBuilder.beginCell()
+ .storeBit(isSigAuthAllowed)
+ .storeUint(initialSeqno, 32)
+ .storeUint(walletId, 32)
+ .storeBytes(keyPair.getPublicKey())
+ .storeDict(
+ extensions.serialize(
+ k -> CellBuilder.beginCell().storeUint((BigInteger) k, 256).endCell().getBits(),
+ v -> CellBuilder.beginCell().storeBit((Boolean) v).endCell()))
+ .endCell();
}
-
- public Cell createInternalTransferBody(WalletV5Config config) {
- return CellBuilder.beginCell()
- .storeUint(PREFIX_SIGNED_INTERNAL, 32)
- .storeUint(config.getWalletId(), SIZE_WALLET_ID)
- .storeUint((config.getValidUntil() == 0) ? Instant.now().getEpochSecond() + 60 : config.getValidUntil(), SIZE_VALID_UNTIL)
- .storeUint(config.getSeqno(), SIZE_SEQNO)
- .storeCell(config.getBody()) // innerRequest
- .endCell();
+ }
+
+ @Override
+ public Cell createCodeCell() {
+ if (!deployAsLibrary) {
+ return CellBuilder.beginCell().fromBoc(WalletCodes.V5R1.getValue()).endCell();
+ } else {
+ return CellBuilder.beginCell()
+ .storeUint(2, 8)
+ .storeBytes(
+ CellBuilder.beginCell().fromBoc(WalletCodes.V5R1.getValue()).endCell().getHash())
+ .setExotic(true)
+ .cellType(CellType.LIBRARY)
+ .endCell();
}
-
- public Cell createInternalSignedBody(WalletV5Config config) {
- Cell body = createInternalTransferBody(config);
- byte[] signature = Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), body.hash());
-
- return CellBuilder.beginCell().storeCell(body).storeBytes(signature).endCell();
+ }
+
+ @Override
+ public StateInit getStateInit() {
+ return StateInit.builder()
+ .code(createCodeCell())
+ .data(createDataCell())
+ // .lib(createLibraryCell())
+ .build();
+ }
+
+ public ExtMessageInfo send(WalletV5Config config) {
+ return tonlib.sendRawMessage(prepareExternalMsg(config).toCell().toBase64());
+ }
+
+ /** Deploy wallet without any extensions. One can be installed later into the wallet. */
+ public ExtMessageInfo deploy() {
+ return tonlib.sendRawMessage(prepareDeployMsg().toCell().toBase64());
+ }
+
+ public Message prepareDeployMsg() {
+ Cell body = createDeployMsg();
+ byte[] signature = Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), body.hash());
+
+ return Message.builder()
+ .info(ExternalMessageInfo.builder().dstAddr(getAddressIntStd()).build())
+ .init(getStateInit())
+ .body(CellBuilder.beginCell().storeCell(body).storeBytes(signature).endCell())
+ .build();
+ }
+
+ public Message prepareExternalMsg(WalletV5Config config) {
+ Cell body = createExternalTransferBody(config);
+ byte[] signature = Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), body.hash());
+
+ return Message.builder()
+ .info(ExternalMessageInfo.builder().dstAddr(getAddressIntStd()).build())
+ .init(getStateInit())
+ .body(CellBuilder.beginCell().storeCell(body).storeBytes(signature).endCell())
+ .build();
+ }
+
+ /**
+ *
+ *
+ *
+ * signed_request$_ // 32 (opcode from outer)
+ * wallet_id: # // 32
+ * valid_until: # // 32
+ * msg_seqno: # // 32
+ * inner: InnerRequest //
+ * signature: bits512 // 512
+ * = SignedRequest;
+ *
+ */
+ private Cell createDeployMsg() {
+ if (isNull(extensions)) {
+ return CellBuilder.beginCell()
+ .storeUint(PREFIX_SIGNED_EXTERNAL, 32)
+ .storeUint(walletId, SIZE_WALLET_ID)
+ .storeUint(
+ (validUntil == 0) ? Instant.now().getEpochSecond() + 60 : validUntil,
+ SIZE_VALID_UNTIL)
+ .storeUint(0, SIZE_SEQNO)
+ .storeBit(false) // empty extensions dict
+ .endCell();
+ } else {
+ return CellBuilder.beginCell()
+ .storeUint(PREFIX_SIGNED_EXTERNAL, 32)
+ .storeUint(walletId, SIZE_WALLET_ID)
+ .storeUint(
+ (validUntil == 0) ? Instant.now().getEpochSecond() + 60 : validUntil,
+ SIZE_VALID_UNTIL)
+ .storeUint(0, SIZE_SEQNO)
+ .storeDict(
+ extensions.serialize(
+ k -> CellBuilder.beginCell().storeUint((BigInteger) k, 256).endCell().getBits(),
+ v -> CellBuilder.beginCell().storeBit((Boolean) v).endCell()))
+ .endCell();
}
-
- public Cell createInternalExtensionTransferBody(BigInteger queryId, Cell body) {
- return CellBuilder.beginCell()
- .storeUint(PREFIX_EXTENSION_ACTION, 32)
- .storeUint(queryId, 64)
- .storeCell(body) // innerRequest
- .endCell();
+ }
+
+ public Cell createExternalTransferBody(WalletV5Config config) {
+ return CellBuilder.beginCell()
+ .storeUint(PREFIX_SIGNED_EXTERNAL, 32)
+ .storeUint(config.getWalletId(), SIZE_WALLET_ID)
+ .storeUint(
+ (config.getValidUntil() == 0)
+ ? Instant.now().getEpochSecond() + 60
+ : config.getValidUntil(),
+ SIZE_VALID_UNTIL)
+ .storeUint(config.getSeqno(), SIZE_SEQNO)
+ .storeCell(config.getBody()) // innerRequest
+ .endCell();
+ }
+
+ public Cell createInternalTransferBody(WalletV5Config config) {
+ return CellBuilder.beginCell()
+ .storeUint(PREFIX_SIGNED_INTERNAL, 32)
+ .storeUint(config.getWalletId(), SIZE_WALLET_ID)
+ .storeUint(
+ (config.getValidUntil() == 0)
+ ? Instant.now().getEpochSecond() + 60
+ : config.getValidUntil(),
+ SIZE_VALID_UNTIL)
+ .storeUint(config.getSeqno(), SIZE_SEQNO)
+ .storeCell(config.getBody()) // innerRequest
+ .endCell();
+ }
+
+ public Cell createInternalSignedBody(WalletV5Config config) {
+ Cell body = createInternalTransferBody(config);
+ byte[] signature = Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), body.hash());
+
+ return CellBuilder.beginCell().storeCell(body).storeBytes(signature).endCell();
+ }
+
+ public Cell createInternalExtensionTransferBody(BigInteger queryId, Cell body) {
+ return CellBuilder.beginCell()
+ .storeUint(PREFIX_EXTENSION_ACTION, 32)
+ .storeUint(queryId, 64)
+ .storeCell(body) // innerRequest
+ .endCell();
+ }
+
+ public Cell createInternalExtensionSignedlBody(BigInteger queryId, Cell body) {
+ Cell body1 = createInternalExtensionTransferBody(queryId, body);
+ byte[] signature = Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), body1.hash());
+
+ return CellBuilder.beginCell().storeCell(body).storeBytes(signature).endCell();
+ }
+
+ public WalletV5InnerRequest manageExtensions(ActionList actionList) {
+
+ return WalletV5InnerRequest.builder()
+ .outActions(OutList.builder().build())
+ .hasOtherActions(true)
+ .otherActions(actionList)
+ .build();
+ }
+
+ public WalletV5InnerRequest createBulkTransfer(List recipients) {
+ if (recipients.size() > 255) {
+ throw new IllegalArgumentException("Maximum number of recipients should be less than 255");
}
- public Cell createInternalExtensionSignedlBody(BigInteger queryId, Cell body) {
- Cell body1 = createInternalExtensionTransferBody(queryId, body);
- byte[] signature = Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), body1.hash());
-
- return CellBuilder.beginCell().storeCell(body).storeBytes(signature).endCell();
+ List messages = new ArrayList<>();
+ for (Destination recipient : recipients) {
+ messages.add(convertDestinationToOutAction(recipient));
}
- public WalletV5InnerRequest manageExtensions(ActionList actionList) {
+ return WalletV5InnerRequest.builder()
+ .outActions(OutList.builder().actions(messages).build())
+ .hasOtherActions(false)
+ .build();
+ }
- return WalletV5InnerRequest.builder()
- .outActions(OutList.builder().build())
- .hasOtherActions(true)
- .otherActions(actionList)
- .build();
+ public WalletV5InnerRequest createBulkTransferAndManageExtensions(
+ List recipients, ActionList actionList) {
+ if (recipients.size() > 255) {
+ throw new IllegalArgumentException("Maximum number of recipients should be less than 255");
}
- public WalletV5InnerRequest createBulkTransfer(List recipients) {
- if (recipients.size() > 255) {
- throw new IllegalArgumentException("Maximum number of recipients should be less than 255");
- }
-
- List messages = new ArrayList<>();
- for (Destination recipient : recipients) {
- messages.add(convertDestinationToOutAction(recipient));
- }
-
- return WalletV5InnerRequest.builder()
- .outActions(OutList.builder()
- .actions(messages)
- .build())
- .hasOtherActions(false)
- .build();
+ List messages = new ArrayList<>();
+ for (Destination recipient : recipients) {
+ messages.add(convertDestinationToOutAction(recipient));
}
- public WalletV5InnerRequest createBulkTransferAndManageExtensions(List recipients, ActionList actionList) {
- if (recipients.size() > 255) {
- throw new IllegalArgumentException("Maximum number of recipients should be less than 255");
- }
-
- List messages = new ArrayList<>();
- for (Destination recipient : recipients) {
- messages.add(convertDestinationToOutAction(recipient));
- }
-
- if (actionList.getActions().size() == 0) {
-
- return WalletV5InnerRequest.builder()
- .outActions(OutList.builder()
- .actions(messages)
- .build())
- .hasOtherActions(false)
- .build();
- } else {
- return WalletV5InnerRequest.builder()
- .outActions(OutList.builder()
- .actions(messages)
- .build())
- .hasOtherActions(true)
- .otherActions(actionList)
- .build();
- }
+ if (actionList.getActions().size() == 0) {
+
+ return WalletV5InnerRequest.builder()
+ .outActions(OutList.builder().actions(messages).build())
+ .hasOtherActions(false)
+ .build();
+ } else {
+ return WalletV5InnerRequest.builder()
+ .outActions(OutList.builder().actions(messages).build())
+ .hasOtherActions(true)
+ .otherActions(actionList)
+ .build();
}
-
- private OutAction convertDestinationToOutAction(Destination destination) {
- Address dstAddress = Address.of(destination.getAddress());
- return ActionSendMsg.builder()
- .mode((destination.getMode() == 0) ? 3 : destination.getMode())
- .outMsg(MessageRelaxed.builder()
- .info(InternalMessageInfoRelaxed.builder()
- .bounce(destination.isBounce())
- .dstAddr(MsgAddressIntStd.builder()
- .workchainId(dstAddress.wc)
- .address(dstAddress.toBigInteger())
- .build())
- .value(CurrencyCollection.builder()
- .coins(destination.getAmount())
- .build())
+ }
+
+ private OutAction convertDestinationToOutAction(Destination destination) {
+ Address dstAddress = Address.of(destination.getAddress());
+ return ActionSendMsg.builder()
+ .mode((destination.getMode() == 0) ? 3 : destination.getMode())
+ .outMsg(
+ MessageRelaxed.builder()
+ .info(
+ InternalMessageInfoRelaxed.builder()
+ .bounce(destination.isBounce())
+ .dstAddr(
+ MsgAddressIntStd.builder()
+ .workchainId(dstAddress.wc)
+ .address(dstAddress.toBigInteger())
.build())
- .init(getStateInit())
- .body((isNull(destination.getBody()) && StringUtils.isNotEmpty(destination.getComment())) ?
- CellBuilder.beginCell()
- .storeUint(0, 32) // 0 opcode means we have a comment
- .storeString(destination.getComment())
- .endCell() :
- destination.getBody())
+ .value(CurrencyCollection.builder().coins(destination.getAmount()).build())
.build())
- .build();
- }
-
-// Get Methods
-// --------------------------------------------------------------------------------------------------
-
- public long getWalletId() {
- RunResult result = tonlib.runMethod(getAddress(), Utils.calculateMethodId("get_subwallet_id"));
- TvmStackEntryNumber subWalletId = (TvmStackEntryNumber) result.getStack().get(0);
- return subWalletId.getNumber().longValue();
- }
-
- public byte[] getPublicKey() {
- RunResult result = tonlib.runMethod(getAddress(), Utils.calculateMethodId("get_public_key"));
- TvmStackEntryNumber pubKey = (TvmStackEntryNumber) result.getStack().get(0);
- return pubKey.getNumber().toByteArray();
- }
-
- public boolean getIsSignatureAuthAllowed() {
- RunResult result = tonlib.runMethod(getAddress(), Utils.calculateMethodId("is_signature_allowed"));
- TvmStackEntryNumber signatureAllowed = (TvmStackEntryNumber) result.getStack().get(0);
- return signatureAllowed.getNumber().longValue() != 0;
+ .init(getStateInit())
+ .body(
+ (isNull(destination.getBody())
+ && StringUtils.isNotEmpty(destination.getComment()))
+ ? CellBuilder.beginCell()
+ .storeUint(0, 32) // 0 opcode means we have a comment
+ .storeString(destination.getComment())
+ .endCell()
+ : destination.getBody())
+ .build())
+ .build();
+ }
+
+ // Get Methods
+ // --------------------------------------------------------------------------------------------------
+
+ public long getWalletId() {
+ RunResult result = tonlib.runMethod(getAddress(), Utils.calculateMethodId("get_subwallet_id"));
+ TvmStackEntryNumber subWalletId = (TvmStackEntryNumber) result.getStack().get(0);
+ return subWalletId.getNumber().longValue();
+ }
+
+ public byte[] getPublicKey() {
+ RunResult result = tonlib.runMethod(getAddress(), Utils.calculateMethodId("get_public_key"));
+ TvmStackEntryNumber pubKey = (TvmStackEntryNumber) result.getStack().get(0);
+ return pubKey.getNumber().toByteArray();
+ }
+
+ public boolean getIsSignatureAuthAllowed() {
+ RunResult result =
+ tonlib.runMethod(getAddress(), Utils.calculateMethodId("is_signature_allowed"));
+ TvmStackEntryNumber signatureAllowed = (TvmStackEntryNumber) result.getStack().get(0);
+ return signatureAllowed.getNumber().longValue() != 0;
+ }
+
+ public TonHashMap getRawExtensions() {
+ RunResult result = tonlib.runMethod(getAddress(), Utils.calculateMethodId("get_extensions"));
+ if (result.getStack().get(0) instanceof TvmStackEntryList) {
+ return new TonHashMap(256);
}
+ TvmStackEntryCell tvmStackEntryCell = (TvmStackEntryCell) result.getStack().get(0);
- public TonHashMap getRawExtensions() {
- RunResult result = tonlib.runMethod(getAddress(), Utils.calculateMethodId("get_extensions"));
- if (result.getStack().get(0) instanceof TvmStackEntryList) {
- return new TonHashMap(256);
- }
- TvmStackEntryCell tvmStackEntryCell = (TvmStackEntryCell) result.getStack().get(0);
-
- String base64Msg = tvmStackEntryCell.getCell().getBytes();
- CellSlice cs = CellSlice.beginParse(Cell.fromBocBase64(base64Msg));
+ String base64Msg = tvmStackEntryCell.getCell().getBytes();
+ CellSlice cs = CellSlice.beginParse(Cell.fromBocBase64(base64Msg));
- return cs.loadDict(256,
- k -> k.readUint(256),
- v -> v);
- }
-}
\ No newline at end of file
+ return cs.loadDict(256, k -> k.readUint(256), v -> v);
+ }
+}