Skip to content

Commit

Permalink
make Faucet contracts available in development;
Browse files Browse the repository at this point in the history
add toBounceableTestnet() and toNonBounceableTestnet() to Address;
  • Loading branch information
neodix42 committed Oct 10, 2024
1 parent 43eb07f commit ca05314
Show file tree
Hide file tree
Showing 35 changed files with 3,451 additions and 3,207 deletions.
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ found [here](https://github.com/ton-blockchain/ton/actions).
## Maven [![Maven Central][maven-central-svg]][maven-central]

```xml

<dependency>
<groupId>io.github.neodix42</groupId>
<artifactId>smartcontract</artifactId>
Expand All @@ -21,6 +22,7 @@ found [here](https://github.com/ton-blockchain/ton/actions).
## Jitpack [![JitPack][jitpack-svg]][jitpack]

```xml

<repositories>
<repository>
<id>jitpack.io</id>
Expand All @@ -30,6 +32,7 @@ found [here](https://github.com/ton-blockchain/ton/actions).
```

```xml

<dependency>
<groupId>io.github.neodix42</groupId>
<artifactId>ton4j</artifactId>
Expand Down Expand Up @@ -60,16 +63,20 @@ You can use each submodule individually. Click the module below to get more deta
* ✅ Cell builder and cell slicer (reader)
* ✅ Tonlib wrapper
* ✅ Lite-client wrapper
* ✅ Fift wrapper
* ✅ Func wrapper
* ✅ TVM emulator wrapper
* ✅ Transaction emulator wrapper
* ✅ TonConnect
* ✅ Support num, cell and slice as arguments for runMethod
* ✅ Render List, Tuple, Slice, Cell and Number results from runMethod
* ✅ Generate or import private key, sign, encrypt and decrypt using Tonlib
* ✅ Encrypt/decrypt with mnemonic
* ✅ Send external message
* ✅ Get block transactions
* ✅ Deploy contracts and send external messages using Tonlib
* ✅ Wallets - Simple (V1), V2, V3, V4 (plugins), Lockup, Highload/Highload-V3, DNS, Jetton, StableCoin, NFT,
Payment-channels,
Multisig V1
* ✅ Wallets - Simple (V1), V2, V3, V4 (plugins), V5, Lockup, Highload/Highload-V3, DNS, Jetton, StableCoin, NFT,
Payment-channels, Multisig V1
* ✅ HashMap, HashMapE, PfxHashMap, PfxHashMapE, HashMapAug, HashMapAugE serialization / deserialization

## Support ton4j development
Expand Down
13 changes: 10 additions & 3 deletions address/src/main/java/org/ton/java/address/Address.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package org.ton.java.address;

import org.ton.java.utils.Utils;
import static java.util.Objects.isNull;

import java.io.IOException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;

import static java.util.Objects.isNull;
import org.ton.java.utils.Utils;

public class Address {

Expand Down Expand Up @@ -191,6 +190,10 @@ public String toBounceable() {
return toString(true, true, true, false);
}

public String toBounceableTestnet() {
return toString(true, true, true, true);
}

public String toRaw() {
return toString(false, true, true, false);
}
Expand All @@ -199,6 +202,10 @@ public String toNonBounceable() {
return toString(true, true, false, false);
}

public String toNonBounceableTestnet() {
return toString(true, true, false, true);
}

public String toString(boolean isUserFriendly,
boolean isUrlSafe,
boolean isBounceable,
Expand Down
66 changes: 33 additions & 33 deletions smartcontract/highload-v3-example.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,63 +3,63 @@
### Example of usage of Highload Wallet V3

```java
HighloadWalletV3 contract = HighloadWalletV3.builder()
HighloadWalletV3 contract=HighloadWalletV3.builder()
.tonlib(tonlib)
.walletId(42)
.build();

String nonBounceableAddress = contract.getAddress().toNonBounceable();
String bounceableAddress = contract.getAddress().toBounceable();
String rawAddress = contract.getAddress().toRaw();
String nonBounceableAddress=contract.getAddress().toNonBounceable();
String bounceableAddress=contract.getAddress().toBounceable();
String rawAddress=contract.getAddress().toRaw();

log.info("non-bounceable address {}", nonBounceableAddress);
log.info(" bounceable address {}", bounceableAddress);
log.info(" raw address {}", rawAddress);
log.info("pub-key {}", Utils.bytesToHex(contract.getKeyPair().getPublicKey()));
log.info("prv-key {}", Utils.bytesToHex(contract.getKeyPair().getSecretKey()));
log.info("non-bounceable address {}",nonBounceableAddress);
log.info(" bounceable address {}",bounceableAddress);
log.info(" raw address {}",rawAddress);
log.info("pub-key {}",Utils.bytesToHex(contract.getKeyPair().getPublicKey()));
log.info("prv-key {}",Utils.bytesToHex(contract.getKeyPair().getSecretKey()));

// top up new wallet using test-faucet-wallet
BigInteger balance = TestFaucet.topUpContract(tonlib, Address.of(nonBounceableAddress), Utils.toNano(12));
Utils.sleep(30, "topping up...");
log.info("new wallet {} balance: {}", contract.getName(), Utils.formatNanoValue(balance));
BigInteger balance=TestnetFaucet.topUpContract(tonlib,Address.of(nonBounceableAddress),Utils.toNano(12));
Utils.sleep(30,"topping up...");
log.info("new wallet {} balance: {}",contract.getName(),Utils.formatNanoValue(balance));

HighloadV3Config config = HighloadV3Config.builder()
HighloadV3Config config=HighloadV3Config.builder()
.walletId(42)
.queryId(HighloadQueryId.fromSeqno(0).getQueryId())
.build();

ExtMessageInfo extMessageInfo = contract.deploy(config);
assertThat(extMessageInfo.getError().getCode()).isZero();
ExtMessageInfo extMessageInfo=contract.deploy(config);
assertThat(extMessageInfo.getError().getCode()).isZero();

contract.waitForDeployment(45);
contract.waitForDeployment(45);

config = HighloadV3Config.builder()
config=HighloadV3Config.builder()
.walletId(42)
.queryId(HighloadQueryId.fromSeqno(1).getQueryId())
.body(contract.createBulkTransfer(
createDummyDestinations(300),
BigInteger.valueOf(HighloadQueryId.fromSeqno(1).getQueryId())))
createDummyDestinations(300),
BigInteger.valueOf(HighloadQueryId.fromSeqno(1).getQueryId())))
.build();

extMessageInfo = contract.send(config);
assertThat(extMessageInfo.getError().getCode()).isZero();
log.info("sent 1000 messages");
extMessageInfo=contract.send(config);
assertThat(extMessageInfo.getError().getCode()).isZero();
log.info("sent 1000 messages");

// help method
List<Destination> createDummyDestinations(int count) throws NoSuchAlgorithmException {
List<Destination> result = new ArrayList<>();
for (int i = 0; i < count; i++) {
String dstDummyAddress = "0:" + Utils.bytesToHex(MessageDigest.getInstance("SHA-256").digest(UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8)));
List<Destination> createDummyDestinations(int count)throws NoSuchAlgorithmException{
List<Destination> result=new ArrayList<>();
for(int i=0;i<count; i++){
String dstDummyAddress="0:"+Utils.bytesToHex(MessageDigest.getInstance("SHA-256").digest(UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8)));

result.add(Destination.builder()
.bounce(false)
.address(dstDummyAddress)
.amount(Utils.toNano(0.01))
.bounce(false)
.address(dstDummyAddress)
.amount(Utils.toNano(0.01))
// .comment("comment-" + i)
.build());
}
return result;
}
.build());
}
return result;
}
```

![Class Diagram](http://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/neodix42/ton4j/highload-v3-tests/smartcontract/highload-v3.puml)
Expand Down
2 changes: 1 addition & 1 deletion smartcontract/plugin-example.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ 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));
BigInteger balance = TestnetFaucet.topUpContract(tonlib, Address.of(nonBounceableAddress), Utils.toNano(7));
log.info("new wallet {} balance: {}", contract.getName(), Utils.formatNanoValue(balance));

// deploy wallet-v4
Expand Down
2 changes: 1 addition & 1 deletion smartcontract/sample-smc-example.md
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ Address address = exampleContract.getAddress();
log.info("contract address {}", address);

// top up new wallet using test-faucet-wallet
BigInteger balance = TestFaucet.topUpContract(tonlib, Address.of(address.toString(true)), Utils.toNano(0.1));
BigInteger balance = TestnetFaucet.topUpContract(tonlib, Address.of(address.toString(true)), Utils.toNano(0.1));
log.info("new wallet {} balance: {}", address.toString(true), Utils.formatNanoValue(balance));

ExtMessageInfo extMessageInfo = exampleContract.deploy();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package org.ton.java.smartcontract.faucet;

import static java.util.Objects.isNull;

import com.iwebpp.crypto.TweetNaclFast;
import java.math.BigInteger;
import org.ton.java.address.Address;
import org.ton.java.smartcontract.types.WalletV1R3Config;
import org.ton.java.smartcontract.wallet.ContractUtils;
import org.ton.java.smartcontract.wallet.v1.WalletV1R3;
import org.ton.java.tonlib.Tonlib;
import org.ton.java.tonlib.types.ExtMessageInfo;
import org.ton.java.utils.Utils;

public class TestnetFaucet {

public static String PUBLIC_KEY =
"c02ece00eceb299066597ccc7a8ac0b2d08f0ad425f28c0ea92e74e2064f41f0";
static String SECRET_KEY =
"46aab91daaaa375d40588384fdf7e36c62d0c0f38c46adfea7f9c904c5973d97c02ece00eceb299066597ccc7a8ac0b2d08f0ad425f28c0ea92e74e2064f41f0";
public static String FAUCET_ADDRESS_RAW =
"0:b52a16ba3735501df19997550e7ed4c41754ee501ded8a841088ce4278b66de4";
public static String NON_BOUNCEABLE = "0QC1Kha6NzVQHfGZl1UOftTEF1TuUB3tioQQiM5CeLZt5FIA";
public static String BOUNCEABLE = "kQC1Kha6NzVQHfGZl1UOftTEF1TuUB3tioQQiM5CeLZt5A_F";

public static BigInteger topUpContract(
Tonlib tonlib, Address destinationAddress, BigInteger amount) throws InterruptedException {

if (amount.compareTo(Utils.toNano(20)) > 0) {
throw new Error(
"Too many TONs requested from the TestnetFaucet, maximum amount per request is 20.");
}

TweetNaclFast.Signature.KeyPair keyPair =
TweetNaclFast.Signature.keyPair_fromSeed(Utils.hexToSignedBytes(SECRET_KEY));

WalletV1R3 faucet = WalletV1R3.builder().tonlib(tonlib).keyPair(keyPair).build();

BigInteger faucetBalance = null;
int i = 0;
do {
try {
if (i++ > 10) {
throw new Error("Cannot get faucet balance. Restart.");
}

faucetBalance = faucet.getBalance();
System.out.println(
"Faucet address "
+ faucet.getAddress().toBounceable()
+ ", balance "
+ Utils.formatNanoValue(faucetBalance));
if (faucetBalance.compareTo(amount) < 0) {
throw new Error(
"Faucet does not have that much toncoins. faucet balance "
+ Utils.formatNanoValue(faucetBalance)
+ ", requested "
+ Utils.formatNanoValue(amount));
}
} catch (Exception e) {
System.out.println("Cannot get faucet balance. Restarting...");
Utils.sleep(5, "Waiting for faucet balance");
}
} while (isNull(faucetBalance));

WalletV1R3Config config =
WalletV1R3Config.builder()
.bounce(false)
.seqno(faucet.getSeqno())
.destination(destinationAddress)
.amount(amount)
.comment("top-up from ton4j faucet")
.build();

ExtMessageInfo extMessageInfo = faucet.send(config);

if (extMessageInfo.getError().getCode() != 0) {
throw new Error(extMessageInfo.getError().getMessage());
}

ContractUtils.waitForBalanceChange(tonlib, destinationAddress, 120);

return tonlib.getAccountBalance(destinationAddress);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package org.ton.java.smartcontract.faucet;

import com.iwebpp.crypto.TweetNaclFast;
import java.math.BigInteger;
import org.ton.java.address.Address;
import org.ton.java.smartcontract.token.ft.JettonMinter;
import org.ton.java.smartcontract.token.ft.JettonWallet;
import org.ton.java.smartcontract.types.WalletV3Config;
import org.ton.java.smartcontract.utils.MsgUtils;
import org.ton.java.smartcontract.wallet.ContractUtils;
import org.ton.java.smartcontract.wallet.v3.WalletV3R2;
import org.ton.java.tonlib.Tonlib;
import org.ton.java.tonlib.types.ExtMessageInfo;
import org.ton.java.utils.Utils;

/** Faucet for NEOJ jettons. */
public class TestnetJettonFaucet {

public static String ADMIN_WALLET_PUBLIC_KEY =
"d1d4515b2635b81de98d58f65502f2c242bb0e63615520341b83a12dd4d0f516";
static String ADMIN_WALLET_SECRET_KEY =
"be0bbb1725807ec0df984702a32a143864418400d797a48e267a120c3dc5f8d0d1d4515b2635b81de98d58f65502f2c242bb0e63615520341b83a12dd4d0f516";
public static String ADMIN_WALLET_ADDRESS =
"0:98972d1ab4b86f6be34ad03d64bb5e2cb369f0d7b5e53f13348664672b893010";
public static String ADMIN_WALLET_BOUNCEABLE_ADDRESS =
"EQCYly0atLhva-NK0D1ku14ss2nw17XlPxM0hmRnK4kwEO86";
public static String FAUCET_MASTER_ADDRESS = "kQAN6TAGauShFKDQvZCwNb_EeTUIjQDwRZ9t6GOn4FBzfg9Y";

public static BigInteger topUpContractWithNeoj(
Tonlib tonlib, Address destinationAddress, BigInteger jettonsAmount) {

if (jettonsAmount.compareTo(Utils.toNano(100)) > 0) {
throw new Error(
"Too many NEOJ jettons requested from the TestnetJettonFaucet, maximum amount per request is 100.");
}

TweetNaclFast.Signature.KeyPair keyPair =
TweetNaclFast.Signature.keyPair_fromSeed(Utils.hexToSignedBytes(ADMIN_WALLET_SECRET_KEY));

WalletV3R2 adminWallet =
WalletV3R2.builder().tonlib(tonlib).walletId(42).keyPair(keyPair).build();

JettonMinter jettonMinterWallet =
JettonMinter.builder()
.tonlib(tonlib)
.customAddress(Address.of(FAUCET_MASTER_ADDRESS))
.build();

JettonWallet adminJettonWallet = jettonMinterWallet.getJettonWallet(adminWallet.getAddress());

WalletV3Config walletV3Config =
WalletV3Config.builder()
.walletId(42)
.seqno(adminWallet.getSeqno())
.destination(adminJettonWallet.getAddress())
.amount(Utils.toNano(0.06))
.body(
JettonWallet.createTransferBody(
0,
jettonsAmount,
destinationAddress, // recipient
adminWallet.getAddress(), // response address
null, // custom payload
BigInteger.ONE, // forward amount
MsgUtils.createTextMessageBody(
"jetton top up from ton4j faucet") // forward payload
))
.build();
ExtMessageInfo extMessageInfo = adminWallet.send(walletV3Config);

if (extMessageInfo.getError().getCode() != 0) {
throw new Error(extMessageInfo.getError().getMessage());
}

ContractUtils.waitForJettonBalanceChange(
tonlib, Address.of(FAUCET_MASTER_ADDRESS), adminWallet.getAddress(), 60);
Utils.sleep(10);
return ContractUtils.getJettonBalance(
tonlib, Address.of(FAUCET_MASTER_ADDRESS), destinationAddress);
}
}
Loading

0 comments on commit ca05314

Please sign in to comment.