diff --git a/CHANGELOG.md b/CHANGELOG.md index 84b00b442..3f7c1c7ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ # Changelog -## 12.1.0 - +## Unreleased +- Added `MintTokenOperation` implementing protocol level token mint +- Added protocol level token mint example, see `MintToken` in `concordium-sdk-examples` - Added deserialization for the `ConfigureDelegation` payload - Fixed incorrect deserialization of the `UpdateContract` payload parameter diff --git a/concordium-android-sdk/pom.xml b/concordium-android-sdk/pom.xml index 24351a1a9..a1644335c 100644 --- a/concordium-android-sdk/pom.xml +++ b/concordium-android-sdk/pom.xml @@ -5,7 +5,7 @@ com.concordium.sdk concordium-sdk-base - 12.1.0-alpha.1 + 12.1.0-alpha.2 concordium-android-sdk diff --git a/concordium-sdk-examples/pom.xml b/concordium-sdk-examples/pom.xml index 52858e30e..677ff5396 100644 --- a/concordium-sdk-examples/pom.xml +++ b/concordium-sdk-examples/pom.xml @@ -23,7 +23,7 @@ com.concordium.sdk concordium-sdk - 12.0.0 + 12.1.0-alpha.2 org.projectlombok diff --git a/concordium-sdk-examples/src/main/java/com/concordium/sdk/examples/MintToken.java b/concordium-sdk-examples/src/main/java/com/concordium/sdk/examples/MintToken.java new file mode 100644 index 000000000..ada895734 --- /dev/null +++ b/concordium-sdk-examples/src/main/java/com/concordium/sdk/examples/MintToken.java @@ -0,0 +1,95 @@ +package com.concordium.sdk.examples; + +import com.concordium.sdk.ClientV2; +import com.concordium.sdk.Connection; +import com.concordium.sdk.crypto.ed25519.ED25519SecretKey; +import com.concordium.sdk.exceptions.ClientInitializationException; +import com.concordium.sdk.requests.AccountQuery; +import com.concordium.sdk.requests.BlockQuery; +import com.concordium.sdk.responses.blockitemstatus.FinalizedBlockItem; +import com.concordium.sdk.transactions.*; +import com.concordium.sdk.transactions.tokens.TokenOperationAmount; +import com.concordium.sdk.transactions.tokens.MintTokenOperation; +import com.concordium.sdk.types.AccountAddress; +import lombok.var; +import picocli.CommandLine; +import picocli.CommandLine.Command; +import picocli.CommandLine.Option; + +import java.math.BigDecimal; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Optional; +import java.util.concurrent.Callable; + +@Command(name = "MintToken", mixinStandardHelpOptions = true) +public class MintToken implements Callable { + @Option( + names = {"--endpoint"}, + description = "GRPC interface of the node.", + defaultValue = "https://127.0.0.1:7000") + private String endpoint; + + @Option( + names = {"--timeout"}, + description = "GRPC request timeout in milliseconds.", + defaultValue = "100000") + private int timeout; + + @Override + public Integer call() throws MalformedURLException, ClientInitializationException { + var endpointUrl = new URL(this.endpoint); + + Connection connection = Connection.newBuilder() + .host(endpointUrl.getHost()) + .port(endpointUrl.getPort()) + //.useTLS(TLSConfig.auto()) //update this as necessary if using tls or not + .build(); + + String tokenSymbol = "RRR10"; // Replace this with the appropriate token symbol in your node + TokenOperationAmount amount = new TokenOperationAmount( + new BigDecimal("1"), + 6 //ensure the decimal precision here matches the value of the decimal during token creation + ); + + //use an address valid in the node being used + AccountAddress sender = AccountAddress.from("4FbFhx5C5XaSUKdnTdrRVbtNW6rtgYYdKRJtggYGBSiktiymsX"); + Expiry expiry = Expiry.createNew().addMinutes(5); + + //replace with a valid sign key value from the accounts of the node being used + TransactionSigner signer = TransactionSigner.from( + SignerEntry.from(Index.from(0), Index.from(0), + ED25519SecretKey + .from("b4cef1510079ba946c093826d3cf9cdd3132fa9dd8aaaf9c01442bf12d6614fd"))); + + var client = ClientV2.from(connection); + var senderInfo = client.getAccountInfo(BlockQuery.BEST, AccountQuery.from(sender)); + var nonce = senderInfo.getNonce(); + var txnHash = client.sendTransaction( + TransactionFactory + .newTokenUpdate( TokenUpdate + .builder() + .tokenSymbol(tokenSymbol) + .operation( + MintTokenOperation + .builder() + .amount(amount) + .build() + ).build() + ) + .nonce(nonce) + .expiry(expiry) + .sender(sender) + .sign(signer) + ); + System.out.println(txnHash); + Optional finalizedBlockItem = client.waitUntilFinalized(txnHash, this.timeout); + System.out.println(finalizedBlockItem); + return 0; + } + + public static void main(String[] args) { + int exitCode = new CommandLine(new MintToken()).execute(args); + System.exit(exitCode); + } +} diff --git a/concordium-sdk/pom.xml b/concordium-sdk/pom.xml index e41d807ec..64208ad9c 100644 --- a/concordium-sdk/pom.xml +++ b/concordium-sdk/pom.xml @@ -7,7 +7,7 @@ com.concordium.sdk concordium-sdk-base - 12.1.0-alpha.1 + 12.1.0-alpha.2 concordium-sdk diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/transactions/tokens/MintTokenOperation.java b/concordium-sdk/src/main/java/com/concordium/sdk/transactions/tokens/MintTokenOperation.java new file mode 100644 index 000000000..9c47d24eb --- /dev/null +++ b/concordium-sdk/src/main/java/com/concordium/sdk/transactions/tokens/MintTokenOperation.java @@ -0,0 +1,39 @@ +package com.concordium.sdk.transactions.tokens; + +import com.concordium.sdk.types.UInt64; +import lombok.*; +import lombok.extern.jackson.Jacksonized; + +import java.util.Optional; + +/** + * Mint Token + * @see CBOR Schema + */ +@Getter +@Builder +@EqualsAndHashCode +@ToString +// This is for CBOR serialization to use the generated builder. +@Jacksonized +public class MintTokenOperation implements TokenOperation { + + /** + * Amount to be transferred. + * It very important that the decimals in it match the actual value of the token. + */ + @NonNull + private final TokenOperationAmount amount; + + @Override + public UInt64 getBaseCost() { + return UInt64.from(50); + } + + @Override + public String getType() { + return TYPE; + } + + public static final String TYPE = "mint"; +} diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/transactions/tokens/TokenOperation.java b/concordium-sdk/src/main/java/com/concordium/sdk/transactions/tokens/TokenOperation.java index 3dd20dc12..6061cc3a7 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/transactions/tokens/TokenOperation.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/transactions/tokens/TokenOperation.java @@ -33,6 +33,10 @@ @JsonSubTypes.Type( value = TransferTokenOperation.class, name = TransferTokenOperation.TYPE + ), + @JsonSubTypes.Type( + value = MintTokenOperation.class, + name = MintTokenOperation.TYPE ) }) public interface TokenOperation { diff --git a/concordium-sdk/src/test/java/com/concordium/sdk/tokens/MintTokenOperationTest.java b/concordium-sdk/src/test/java/com/concordium/sdk/tokens/MintTokenOperationTest.java new file mode 100644 index 000000000..310a26d8e --- /dev/null +++ b/concordium-sdk/src/test/java/com/concordium/sdk/tokens/MintTokenOperationTest.java @@ -0,0 +1,37 @@ +package com.concordium.sdk.tokens; + +import com.concordium.sdk.serializing.CborMapper; +import com.concordium.sdk.transactions.tokens.*; +import com.concordium.sdk.types.AccountAddress; +import com.concordium.sdk.types.UInt64; +import lombok.SneakyThrows; +import lombok.val; +import org.bouncycastle.util.encoders.Hex; +import org.junit.Assert; +import org.junit.Test; + +import java.math.BigDecimal; + +public class MintTokenOperationTest { + + @Test + @SneakyThrows + public void testMintTokenOperationSerialization() { + val operation = MintTokenOperation + .builder() + .amount(new TokenOperationAmount(UInt64.from("15"), 6)) + .build(); + val expectedHex = "bf646d696e74bf66616d6f756e74c482250fffff"; + Assert.assertEquals( + expectedHex, + Hex.toHexString(CborMapper.INSTANCE.writeValueAsBytes(operation)) + ); + Assert.assertEquals( + operation, + CborMapper.INSTANCE.readValue( + Hex.decode(expectedHex), + TokenOperation.class + ) + ); + } +} diff --git a/concordium-sdk/src/test/java/com/concordium/sdk/transactions/TokenUpdateTest.java b/concordium-sdk/src/test/java/com/concordium/sdk/transactions/TokenUpdateTest.java index b7f7106b0..360f03d6a 100644 --- a/concordium-sdk/src/test/java/com/concordium/sdk/transactions/TokenUpdateTest.java +++ b/concordium-sdk/src/test/java/com/concordium/sdk/transactions/TokenUpdateTest.java @@ -1,9 +1,6 @@ package com.concordium.sdk.transactions; -import com.concordium.sdk.transactions.tokens.CborMemo; -import com.concordium.sdk.transactions.tokens.TaggedTokenHolderAccount; -import com.concordium.sdk.transactions.tokens.TokenOperationAmount; -import com.concordium.sdk.transactions.tokens.TransferTokenOperation; +import com.concordium.sdk.transactions.tokens.*; import com.concordium.sdk.types.AccountAddress; import com.concordium.sdk.types.Nonce; import com.concordium.sdk.types.UInt64; @@ -230,4 +227,38 @@ public void testTokenUpdatePayloadSerialization() { TokenUpdate.fromBytes(ByteBuffer.wrap(Hex.decode(expectedHex))) ); } + + + @Test + @SneakyThrows + public void testTokenUpdateMintTransactionEnergy() { + Assert.assertEquals( + UInt64.from("642"), + TransactionFactory + .newTokenUpdate( + TokenUpdate + .builder() + .tokenSymbol("TEST") + .operation( + MintTokenOperation + .builder() + .amount( + new TokenOperationAmount( + new BigDecimal("1.5"), + 2 + ) + ) + .build() + ) + .build() + ) + .sender(AccountAddress.from("3JwD2Wm3nMbsowCwb1iGEpnt47UQgdrtnq2qT6opJc3z2AgCrc")) + .nonce(Nonce.from(78910)) + .expiry(Expiry.from(123456)) + .sign(TransactionTestHelper.getValidSigner()) + .getHeader() + .getMaxEnergyCost() + ); + } + } diff --git a/pom.xml b/pom.xml index 6909f722b..4ba46ec0b 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.concordium.sdk concordium-sdk-base - 12.1.0-alpha.1 + 12.1.0-alpha.2 pom https://github.com/Concordium/concordium-java-sdk