diff --git a/emulator/src/main/java/org/ton/java/emulator/SendExternalMessageResult.java b/emulator/src/main/java/org/ton/java/emulator/SendExternalMessageResult.java new file mode 100644 index 00000000..2766bd5f --- /dev/null +++ b/emulator/src/main/java/org/ton/java/emulator/SendExternalMessageResult.java @@ -0,0 +1,26 @@ +package org.ton.java.emulator; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +import java.io.Serializable; + +@Builder +@Setter +@Getter +@ToString +public class SendExternalMessageResult implements Serializable { + boolean success; + String new_code; // Base64 boc decoded new code cell + String new_data; // Base64 boc decoded new data cell + String error; + String vm_log; + int vm_exit_code; + String stack; // Base64 encoded BoC serialized stack (VmStack) + String missing_library; + int gas_used; + String actions; // Base64 boc decoded actions cell of type (OutList n) +} + diff --git a/emulator/src/main/java/org/ton/java/emulator/TvmEmulator.java b/emulator/src/main/java/org/ton/java/emulator/TvmEmulator.java index f0e1c12f..a24d9b56 100644 --- a/emulator/src/main/java/org/ton/java/emulator/TvmEmulator.java +++ b/emulator/src/main/java/org/ton/java/emulator/TvmEmulator.java @@ -5,8 +5,6 @@ import lombok.extern.java.Log; import org.ton.java.utils.Utils; -import java.math.BigInteger; - import static java.util.Objects.isNull; @Log @@ -96,7 +94,7 @@ public TvmEmulator build() { System.out.printf("Java TON TVM Emulator configuration:\n" + "Location: %s\n" + - "Verbosity level: %s", + "Verbosity level: %s\n", super.pathToEmulatorSharedLib, super.verbosityLevel); return super.build(); @@ -118,6 +116,19 @@ public boolean setLibs(String libsBoc) { } /** + * C7 tlb-scheme: + *

+ * 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 @@ -251,7 +262,7 @@ public String sendExternalMessage(String messageBodyBoc) { * "actions": "Base64 boc decoded actions cell of type (OutList n)" * } */ - public String sendInternalMessage(String messageBodyBoc, BigInteger amount) { + public String sendInternalMessage(String messageBodyBoc, long amount) { return tvmEmulatorI.tvm_emulator_send_internal_message(tvmEmulator, messageBodyBoc, amount); } diff --git a/emulator/src/main/java/org/ton/java/emulator/TvmEmulatorI.java b/emulator/src/main/java/org/ton/java/emulator/TvmEmulatorI.java index 2501a5b7..3aa90069 100644 --- a/emulator/src/main/java/org/ton/java/emulator/TvmEmulatorI.java +++ b/emulator/src/main/java/org/ton/java/emulator/TvmEmulatorI.java @@ -2,8 +2,6 @@ import com.sun.jna.Library; -import java.math.BigInteger; - public interface TvmEmulatorI extends Library { /** @@ -161,5 +159,5 @@ public interface TvmEmulatorI extends Library { * "actions": "Base64 boc decoded actions cell of type (OutList n)" * } */ - String tvm_emulator_send_internal_message(long tvmEmulator, String messageBodyBoc, BigInteger amount); + String tvm_emulator_send_internal_message(long tvmEmulator, String messageBodyBoc, long amount); } 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 a4b95537..1baa256e 100644 --- a/emulator/src/test/java/org/ton/java/emulator/TestTvmEmulator.java +++ b/emulator/src/test/java/org/ton/java/emulator/TestTvmEmulator.java @@ -11,14 +11,15 @@ 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.CellSlice; import org.ton.java.cell.TonHashMapE; -import org.ton.java.smartcontract.wallet.v3.WalletV3R2; -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.smartcontract.types.WalletV4R2Config; +import org.ton.java.smartcontract.utils.MsgUtils; +import org.ton.java.smartcontract.wallet.v4.WalletV4R2; +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; @@ -38,8 +39,7 @@ public class TestTvmEmulator { static TvmEmulator tvmEmulator; static Tonlib tonlib; private static final Gson gson = new GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.BIG_DECIMAL).create(); - - static WalletV3R2 contract; + static WalletV4R2 contract; @BeforeClass public static void setUpBeforeClass() { @@ -50,7 +50,7 @@ public static void setUpBeforeClass() { .ignoreCache(false) .build(); - contract = WalletV3R2.builder() + contract = WalletV4R2.builder() .tonlib(tonlib) .keyPair(keyPair) .walletId(42) @@ -140,9 +140,37 @@ public void testTvmEmulatorEmulateRunMethod() { } @Test - public void testTvmEmulatorRunGetMethod() { + public void testTvmEmulatorRunGetMethodGetSeqNo() { + String result = tvmEmulator.runGetMethod( + 85143, // seqno + VmStack.builder() + .depth(0) + .stack(VmStackList.builder() + .tos(Lists.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()); + BigInteger seqno = VmStackValueTinyInt.deserialize(CellSlice.beginParse(vmStackList.getTos().get(0).toCell())).getValue(); + log.info("seqno value: {}", seqno); // pubkey + } + + @Test + public void testTvmEmulatorRunGetMethodGetPubKey() { String result = tvmEmulator.runGetMethod( - 78748, // 78748 - get_public_key + 78748, // get_public_key VmStack.builder() .depth(0) .stack(VmStackList.builder() @@ -169,12 +197,47 @@ public void testTvmEmulatorRunGetMethod() { @Test public void testTvmEmulatorSendExternalMessage() { -// String result = tvmEmulator.sendExternalMessage(); + +// String address = contract.getAddress().toBounceable(); +// String randSeedHex = Utils.sha256("ABC"); +//// Cell configAll = tonlib.getConfigAll(128); +// +// assertTrue(tvmEmulator.setC7(address, +// Instant.now().getEpochSecond() - 300, +// 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.331)) + .build(); + + Message msg = contract.prepareExternalMsg(config); + String resultBoc = tvmEmulator.sendExternalMessage(msg.toCell().toBase64()); + + SendExternalMessageResult result = gson.fromJson(resultBoc, SendExternalMessageResult.class); + log.info("result sendExternalMessage: {}", result); } @Test public void testTvmEmulatorSendInternalMessage() { -// String result = tvmEmulator.sendInternalMessage(); + Cell body = CellBuilder.beginCell() + .storeUint(0x706c7567, 32) // op request funds + .endCell(); + Message msg = MsgUtils.createInternalMessage( + Address.of("0:258e549638a6980ae5d3c76382afd3f4f32e34482dafc3751e3358589c8de00d") + , Utils.toNano(0.1), null, body, true); + + String resultBoc = tvmEmulator.sendInternalMessage(msg.toCell().toBase64(), Utils.toNano(0.11).longValue()); + + SendExternalMessageResult result = gson.fromJson(resultBoc, SendExternalMessageResult.class); + log.info("result sendInternalMessage: {}", result); } @Test diff --git a/smartcontract/src/main/java/org/ton/java/smartcontract/types/WalletV4R1Config.java b/smartcontract/src/main/java/org/ton/java/smartcontract/types/WalletV4R2Config.java similarity index 92% rename from smartcontract/src/main/java/org/ton/java/smartcontract/types/WalletV4R1Config.java rename to smartcontract/src/main/java/org/ton/java/smartcontract/types/WalletV4R2Config.java index 91c55a11..72f05252 100644 --- a/smartcontract/src/main/java/org/ton/java/smartcontract/types/WalletV4R1Config.java +++ b/smartcontract/src/main/java/org/ton/java/smartcontract/types/WalletV4R2Config.java @@ -14,7 +14,7 @@ @Getter @Setter @ToString -public class WalletV4R1Config implements WalletConfig { +public class WalletV4R2Config implements WalletConfig { long walletId; long seqno; int mode; diff --git a/smartcontract/src/main/java/org/ton/java/smartcontract/wallet/v4/WalletV4R2.java b/smartcontract/src/main/java/org/ton/java/smartcontract/wallet/v4/WalletV4R2.java index 01109858..a4c0aaca 100644 --- a/smartcontract/src/main/java/org/ton/java/smartcontract/wallet/v4/WalletV4R2.java +++ b/smartcontract/src/main/java/org/ton/java/smartcontract/wallet/v4/WalletV4R2.java @@ -7,7 +7,7 @@ import org.ton.java.cell.Cell; import org.ton.java.cell.CellBuilder; import org.ton.java.smartcontract.types.WalletCodes; -import org.ton.java.smartcontract.types.WalletV4R1Config; +import org.ton.java.smartcontract.types.WalletV4R2Config; import org.ton.java.smartcontract.utils.MsgUtils; import org.ton.java.smartcontract.wallet.Contract; import org.ton.java.tlb.types.ExternalMessageInfo; @@ -95,7 +95,7 @@ public Cell createDeployMessage() { .endCell(); } - public Cell createTransferBody(WalletV4R1Config config) { + public Cell createTransferBody(WalletV4R2Config config) { CellBuilder message = CellBuilder.beginCell(); @@ -139,12 +139,20 @@ public Cell createTransferBody(WalletV4R1Config config) { * Deploy wallet without any plugins. * One can also deploy plugin separately and later install into the wallet. See installPlugin(). */ - + public ExtMessageInfo deploy() { + return tonlib.sendRawMessage(prepareDeployMsg().toCell().toBase64()); + } + + /** + * Deploy wallet without any plugins. + * One can also deploy plugin separately and later install into the wallet. See installPlugin(). + */ + public Message prepareDeployMsg() { Cell body = createDeployMessage(); - Message externalMessage = Message.builder() + return Message.builder() .info(ExternalMessageInfo.builder() .dstAddr(getAddressIntStd()) .build()) @@ -154,10 +162,9 @@ public ExtMessageInfo deploy() { .storeCell(body) .endCell()) .build(); - - return tonlib.sendRawMessage(externalMessage.toCell().toBase64()); } + public Cell createPluginStateInit(SubscriptionInfo subscriptionInfo) { // code = boc in hex format, result of fift commands: // "subscription-plugin-code.fif" include @@ -194,7 +201,7 @@ public Cell createPluginSelfDestructBody() { .endCell(); } - public ExtMessageInfo installPlugin(Tonlib tonlib, WalletV4R1Config config) { + public ExtMessageInfo installPlugin(Tonlib tonlib, WalletV4R2Config config) { Address ownAddress = getAddress(); config.setOperation(2); @@ -204,7 +211,7 @@ public ExtMessageInfo installPlugin(Tonlib tonlib, WalletV4R1Config config) { return tonlib.sendRawMessage(extMsg.toBase64()); } - public ExtMessageInfo uninstallPlugin(WalletV4R1Config config) { + public ExtMessageInfo uninstallPlugin(WalletV4R2Config config) { Address ownAddress = getAddress(); config.setOperation(3); @@ -350,25 +357,15 @@ private SubscriptionInfo parseSubscriptionData(List subscriptionData) { /** * Sends amount of nano toncoins to destination address using auto-fetched seqno without the body and default send-mode 3 * - * @param config WalletV4R1Config + * @param config WalletV4R2Config */ - public ExtMessageInfo send(WalletV4R1Config config) { + public ExtMessageInfo send(WalletV4R2Config config) { + return tonlib.sendRawMessage(prepareExternalMsg(config).toCell().toBase64()); + } + public Message prepareExternalMsg(WalletV4R2Config config) { Cell body = createTransferBody(config); - - Message externalMessage = Message.builder() - .info(ExternalMessageInfo.builder() - .dstAddr(getAddressIntStd()) - .build()) - .init(getStateInit()) - .body(CellBuilder.beginCell() - .storeBytes(Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), body.hash())) - .storeCell(body) - .endCell()) - .build(); - - return tonlib.sendRawMessage(externalMessage.toCell().toBase64()); - + return MsgUtils.createExternalMessageWithSignedBody(keyPair, getAddress(), null, body); } } diff --git a/smartcontract/src/test/java/org/ton/java/smartcontract/integrationtests/TestWalletV4R2Plugins.java b/smartcontract/src/test/java/org/ton/java/smartcontract/integrationtests/TestWalletV4R2Plugins.java index da3328ce..36a876b7 100644 --- a/smartcontract/src/test/java/org/ton/java/smartcontract/integrationtests/TestWalletV4R2Plugins.java +++ b/smartcontract/src/test/java/org/ton/java/smartcontract/integrationtests/TestWalletV4R2Plugins.java @@ -10,7 +10,7 @@ import org.ton.java.smartcontract.TestFaucet; import org.ton.java.smartcontract.types.DeployedPlugin; import org.ton.java.smartcontract.types.NewPlugin; -import org.ton.java.smartcontract.types.WalletV4R1Config; +import org.ton.java.smartcontract.types.WalletV4R2Config; import org.ton.java.smartcontract.utils.MsgUtils; import org.ton.java.smartcontract.wallet.ContractUtils; import org.ton.java.smartcontract.wallet.v4.SubscriptionInfo; @@ -85,7 +85,7 @@ public void testPlugins() throws InterruptedException { log.info("beneficiaryWallet balance {}", Utils.formatNanoValue(ContractUtils.getBalance(tonlib, beneficiaryAddress))); - WalletV4R1Config config = WalletV4R1Config.builder() + WalletV4R2Config config = WalletV4R2Config.builder() .seqno(contract.getSeqno()) .operation(1) // deploy and install plugin .walletId(42) @@ -123,7 +123,7 @@ public void testPlugins() throws InterruptedException { log.info("plugin {} installed {}", pluginAddress, contract.isPluginInstalled(pluginAddress)); - // Collect fee - first time + log.info("collect fee - first time"); Cell extMessage = MsgUtils.createExternalMessageWithSignedBody(contract.getKeyPair(), pluginAddress, null, null).toCell(); extMessageInfo = tonlib.sendRawMessage(extMessage.toBase64()); @@ -142,7 +142,7 @@ public void testPlugins() throws InterruptedException { assertThat(subscriptionInfo.getLastPaymentTime()).isNotEqualTo(0); - // collect fee - second time + log.info("collect fee - second time"); Utils.sleep(180, "wait for timeout"); @@ -168,7 +168,7 @@ public void testPlugins() throws InterruptedException { walletCurrentSeqno = contract.getSeqno(); - config = WalletV4R1Config.builder() + config = WalletV4R2Config.builder() .seqno(contract.getSeqno()) .walletId(config.getWalletId()) .operation(3) // uninstall plugin @@ -192,7 +192,7 @@ public void testPlugins() throws InterruptedException { log.info("pluginsList: {}", list); assertThat(list.isEmpty()).isTrue(); - config = WalletV4R1Config.builder() + config = WalletV4R2Config.builder() .operation(0) .walletId(contract.getWalletId()) .seqno(contract.getSeqno()) @@ -203,4 +203,50 @@ public void testPlugins() throws InterruptedException { Utils.sleep(30, "sent toncoins"); assertThat(extMessageInfo.getError().getCode()).isZero(); } + + @Test + public void testSimpleSend() throws InterruptedException { + + TweetNaclFast.Signature.KeyPair keyPair = Utils.generateSignatureKeyPair(); + + WalletV4R2 contract = WalletV4R2.builder() + .tonlib(tonlib) + .keyPair(keyPair) + .walletId(42) + .build(); + + Address walletAddress = contract.getAddress(); + + String nonBounceableAddress = walletAddress.toNonBounceable(); + String bounceableAddress = walletAddress.toBounceable(); + log.info("bounceableAddress: {}", bounceableAddress); + log.info("pub-key {}", Utils.bytesToHex(contract.getKeyPair().getPublicKey())); + log.info("prv-key {}", Utils.bytesToHex(contract.getKeyPair().getSecretKey())); + + BigInteger balance = TestFaucet.topUpContract(tonlib, Address.of(nonBounceableAddress), Utils.toNano(7)); + log.info("new wallet {} balance: {}", contract.getName(), Utils.formatNanoValue(balance)); + + // deploy wallet-v4 + ExtMessageInfo extMessageInfo = contract.deploy(); + assertThat(extMessageInfo.getError().getCode()).isZero(); + + contract.waitForDeployment(30); + + long walletCurrentSeqno = contract.getSeqno(); + log.info("walletV4 balance: {}", Utils.formatNanoValue(contract.getBalance())); + log.info("seqno: {}", walletCurrentSeqno); + log.info("walletId: {}", contract.getWalletId()); + log.info("pubKey: {}", Utils.bytesToHex(contract.getPublicKey())); + log.info("pluginsList: {}", contract.getPluginsList()); + log.info("pluginsList: {}", contract.getPluginsList()); + + WalletV4R2Config config = WalletV4R2Config.builder() + .operation(0) + .walletId(contract.getWalletId()) + .seqno(contract.getSeqno()) + .destination(Address.of(FAUCET_ADDRESS_RAW)) + .amount(Utils.toNano(0.331)).build(); + + contract.send(config); + } }