diff --git a/.github/badges/jacoco.svg b/.github/badges/jacoco.svg index c4a4781..b489198 100644 --- a/.github/badges/jacoco.svg +++ b/.github/badges/jacoco.svg @@ -1 +1 @@ -coverage71.6% \ No newline at end of file +coverage72.4% \ No newline at end of file diff --git a/src/integrationTest/java/io/sui/JsonRpcTransactionBuilderIntTests.java b/src/integrationTest/java/io/sui/JsonRpcTransactionBuilderIntTests.java index ad02fa7..ebe61de 100644 --- a/src/integrationTest/java/io/sui/JsonRpcTransactionBuilderIntTests.java +++ b/src/integrationTest/java/io/sui/JsonRpcTransactionBuilderIntTests.java @@ -28,7 +28,9 @@ import io.sui.models.transactions.RPCTransactionRequestParams.MoveCallRequestParams; import io.sui.models.transactions.RPCTransactionRequestParams.TransferObjectParams; import io.sui.models.transactions.RPCTransactionRequestParams.TransferObjectRequestParams; +import io.sui.models.transactions.StructTag; import io.sui.models.transactions.TransactionBytes; +import io.sui.models.transactions.TypeTag; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import org.junit.jupiter.api.BeforeAll; @@ -324,4 +326,41 @@ void batchTransaction() throws ExecutionException, InterruptedException { }); System.out.println(future.get()); } + + /** + * Move call. + * + * @throws ExecutionException the execution exception + * @throws InterruptedException the interrupted exception + */ + @Test + @DisplayName("Test moveCall.") + void moveCall() throws ExecutionException, InterruptedException { + final TypeTag.StructType structType = new TypeTag.StructType(); + StructTag structTag = new StructTag(); + structTag.setAddress("0x2"); + structTag.setModule("sui"); + structTag.setName("SUI"); + structType.setStructTag(structTag); + CompletableFuture res = + transactionBuilder.moveCall( + "0xea79464d86786b7a7a63e3f13f798f29f5e65947", + "0x0000000000000000000000000000000000000002", + "pay", + "split", + Lists.newArrayList(structType), + Lists.newArrayList("0x05f71eb5dc69224ef8e3a4c13917c799190237d9", 10000L), + null, + 1000L); + CompletableFuture future = new CompletableFuture<>(); + res.whenComplete( + (transactionResponse, throwable) -> { + if (throwable != null) { + future.complete(throwable); + } else { + future.complete(transactionResponse); + } + }); + System.out.println(future.get()); + } } diff --git a/src/main/java/io/sui/Sui.java b/src/main/java/io/sui/Sui.java index 381b4aa..54397e1 100644 --- a/src/main/java/io/sui/Sui.java +++ b/src/main/java/io/sui/Sui.java @@ -109,7 +109,6 @@ public CompletableFuture transferSui( future.completeExceptionally(new SuiApiException(e)); return future; } - System.out.println(signature); return executionClient.executeTransaction( txBytes, signatureScheme, signature, publicKey, requestType); }); diff --git a/src/main/java/io/sui/clients/JsonRpcTransactionBuilder.java b/src/main/java/io/sui/clients/JsonRpcTransactionBuilder.java index b460f11..df38631 100644 --- a/src/main/java/io/sui/clients/JsonRpcTransactionBuilder.java +++ b/src/main/java/io/sui/clients/JsonRpcTransactionBuilder.java @@ -23,6 +23,7 @@ import io.sui.jsonrpc.JsonRpcClientProvider; import io.sui.models.transactions.RPCTransactionRequestParams; import io.sui.models.transactions.TransactionBytes; +import io.sui.models.transactions.TypeTag; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -147,4 +148,30 @@ public CompletableFuture batchTransaction( return this.jsonRpcClientProvider.callAndUnwrapResponse( "/sui_batchTransaction", request, new TypeToken() {}.getType()); } + + @Override + public CompletableFuture moveCall( + String signer, + String packageObjectId, + String module, + String function, + List typeArguments, + List arguments, + String gas, + long gasBudget) { + final JsonRpc20Request request = + this.jsonRpcClientProvider.createJsonRpc20Request( + "sui_moveCall", + Lists.newArrayList( + signer, + packageObjectId, + module, + function, + typeArguments, + arguments, + gas, + gasBudget)); + return this.jsonRpcClientProvider.callAndUnwrapResponse( + "/sui_moveCall", request, new TypeToken() {}.getType()); + } } diff --git a/src/main/java/io/sui/clients/TransactionBuilder.java b/src/main/java/io/sui/clients/TransactionBuilder.java index b5fd134..a645ba6 100644 --- a/src/main/java/io/sui/clients/TransactionBuilder.java +++ b/src/main/java/io/sui/clients/TransactionBuilder.java @@ -19,6 +19,7 @@ import io.sui.models.transactions.RPCTransactionRequestParams; import io.sui.models.transactions.TransactionBytes; +import io.sui.models.transactions.TypeTag; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -157,4 +158,27 @@ CompletableFuture batchTransaction( List batchTransactionParams, String gas, long gasBudget); + + /** + * Move call completable future. + * + * @param signer the signer + * @param packageObjectId the package object id + * @param module the module + * @param function the function + * @param typeArguments the type arguments + * @param arguments the arguments + * @param gas the gas + * @param gasBudget the gas budget + * @return the completable future + */ + CompletableFuture moveCall( + String signer, + String packageObjectId, + String module, + String function, + List typeArguments, + List arguments, + String gas, + long gasBudget); } diff --git a/src/main/java/io/sui/jsonrpc/GsonJsonHandler.java b/src/main/java/io/sui/jsonrpc/GsonJsonHandler.java index 98bd490..5504a7d 100644 --- a/src/main/java/io/sui/jsonrpc/GsonJsonHandler.java +++ b/src/main/java/io/sui/jsonrpc/GsonJsonHandler.java @@ -70,6 +70,9 @@ import io.sui.models.transactions.ParsedTransactionResponseKind.ParsedSplitCoinResponseKind; import io.sui.models.transactions.TransactionKind; import io.sui.models.transactions.TransactionQuery; +import io.sui.models.transactions.TypeTag; +import io.sui.models.transactions.TypeTag.StructType; +import io.sui.models.transactions.TypeTag.VectorType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; @@ -513,6 +516,15 @@ public JsonElement serialize( } } + /** The type Type tag serializer. */ + public static class TypeTagSerializer implements JsonSerializer { + + @Override + public JsonElement serialize(TypeTag src, Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive(src.toString()); + } + } + /** The type Execute transaction response deserializer. */ public class ExecuteTransactionResponseDeserializer implements JsonDeserializer { @@ -571,6 +583,9 @@ AuthorityQuorumSignInfo.class, new AuthorityQuorumSignInfoDeserializer()) .registerTypeAdapter(MoveFunction.class, new MoveFunctionSerializer()) .registerTypeAdapter( ExecuteTransactionResponse.class, new ExecuteTransactionResponseDeserializer()) + .registerTypeAdapter(StructType.class, new TypeTagSerializer()) + .registerTypeAdapter(VectorType.class, new TypeTagSerializer()) + .registerTypeAdapter(TypeTag.class, new TypeTagSerializer()) .create(); } diff --git a/src/main/java/io/sui/models/transactions/StructTag.java b/src/main/java/io/sui/models/transactions/StructTag.java new file mode 100644 index 0000000..517f4ee --- /dev/null +++ b/src/main/java/io/sui/models/transactions/StructTag.java @@ -0,0 +1,150 @@ +/* + * Copyright 2022 281165273grape@gmail.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package io.sui.models.transactions; + + +import java.util.List; +import java.util.Objects; + +/** + * The type Struct tag. + * + * @author grapebaba + * @since 2022.11 + */ +public class StructTag { + + private String address; + + private String module; + + private String name; + + private List typeParams; + + /** + * Gets address. + * + * @return the address + */ + public String getAddress() { + return address; + } + + /** + * Sets address. + * + * @param address the address + */ + public void setAddress(String address) { + this.address = address; + } + + /** + * Gets module. + * + * @return the module + */ + public String getModule() { + return module; + } + + /** + * Sets module. + * + * @param module the module + */ + public void setModule(String module) { + this.module = module; + } + + /** + * Gets name. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * Sets name. + * + * @param name the name + */ + public void setName(String name) { + this.name = name; + } + + /** + * Gets type params. + * + * @return the type params + */ + public List getTypeParams() { + return typeParams; + } + + /** + * Sets type params. + * + * @param typeParams the type params + */ + public void setTypeParams(List typeParams) { + this.typeParams = typeParams; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof StructTag)) { + return false; + } + StructTag structTag = (StructTag) o; + return address.equals(structTag.address) + && module.equals(structTag.module) + && name.equals(structTag.name) + && typeParams.equals(structTag.typeParams); + } + + @Override + public int hashCode() { + return Objects.hash(address, module, name, typeParams); + } + + @Override + public String toString() { + StringBuilder typeParamsBuilder = new StringBuilder(); + if (typeParams != null) { + for (int i = 0; i < typeParams.size(); i++) { + if (i == 0) { + typeParamsBuilder.append("<"); + typeParamsBuilder.append(String.format("%s", typeParams.get(i))); + } else { + typeParamsBuilder.append(String.format(", %s", typeParams.get(i))); + if (i == typeParams.size() - 1) { + typeParamsBuilder.append(">"); + } + } + } + } + + return String.format("%s::%s::%s%s", address, module, name, typeParamsBuilder); + } +} diff --git a/src/main/java/io/sui/models/transactions/TypeTag.java b/src/main/java/io/sui/models/transactions/TypeTag.java new file mode 100644 index 0000000..21faae7 --- /dev/null +++ b/src/main/java/io/sui/models/transactions/TypeTag.java @@ -0,0 +1,145 @@ +/* + * Copyright 2022 281165273grape@gmail.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package io.sui.models.transactions; + + +import java.util.Objects; + +/** + * The interface Type tag. + * + * @author grapebaba + * @since 2022.11 + */ +public interface TypeTag { + + String toString(); + + /** The enum Simple type. */ + enum SimpleType implements TypeTag { + /** Bool simple type. */ + bool, + /** U8 simple type. */ + u8, + /** U16 simple type. */ + u16, + /** U32 simple type. */ + u32, + /** U64 simple type. */ + u64, + /** U128 simple type. */ + u128, + /** U256 simple type. */ + u256, + /** Address simple type. */ + address, + /** Signer simple type. */ + signer + } + + /** The type Vector type. */ + class VectorType implements TypeTag { + + private TypeTag typeTag; + + /** + * Gets type tag. + * + * @return the type tag + */ + public TypeTag getTypeTag() { + return typeTag; + } + + /** + * Sets type tag. + * + * @param typeTag the type tag + */ + public void setTypeTag(TypeTag typeTag) { + this.typeTag = typeTag; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof VectorType)) { + return false; + } + VectorType that = (VectorType) o; + return typeTag.equals(that.typeTag); + } + + @Override + public int hashCode() { + return Objects.hash(typeTag); + } + + @Override + public String toString() { + return String.format("vector<%s>", typeTag.toString()); + } + } + + /** The type Struct type. */ + class StructType implements TypeTag { + + private StructTag structTag; + + /** + * Gets struct tag. + * + * @return the struct tag + */ + public StructTag getStructTag() { + return structTag; + } + + /** + * Sets struct tag. + * + * @param structTag the struct tag + */ + public void setStructTag(StructTag structTag) { + this.structTag = structTag; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof StructType)) { + return false; + } + StructType that = (StructType) o; + return structTag.equals(that.structTag); + } + + @Override + public int hashCode() { + return Objects.hash(structTag); + } + + @Override + public String toString() { + return structTag.toString(); + } + } +} diff --git a/src/test/java/io/sui/clients/JsonRpcTransactionBuilderTests.java b/src/test/java/io/sui/clients/JsonRpcTransactionBuilderTests.java index e9549f6..2da31c1 100644 --- a/src/test/java/io/sui/clients/JsonRpcTransactionBuilderTests.java +++ b/src/test/java/io/sui/clients/JsonRpcTransactionBuilderTests.java @@ -30,7 +30,9 @@ import io.sui.models.transactions.RPCTransactionRequestParams.MoveCallRequestParams; import io.sui.models.transactions.RPCTransactionRequestParams.TransferObjectParams; import io.sui.models.transactions.RPCTransactionRequestParams.TransferObjectRequestParams; +import io.sui.models.transactions.StructTag; import io.sui.models.transactions.TransactionBytes; +import io.sui.models.transactions.TypeTag; import java.io.IOException; import java.net.URL; import java.nio.charset.StandardCharsets; @@ -111,6 +113,10 @@ public MockResponse dispatch(RecordedRequest request) { return getMockResponse("mockdata/batchTransaction.json"); } + if ("/sui_moveCall".equals(request.getPath())) { + return getMockResponse("mockdata/moveCall.json"); + } + return new MockResponse().setResponseCode(404); } }; @@ -388,4 +394,38 @@ void batchTransaction() throws ExecutionException, InterruptedException { .getImmOrOwnedMoveObject() .getDigest()); } + + /** + * Move call. + * + * @throws ExecutionException the execution exception + * @throws InterruptedException the interrupted exception + */ + @Test + @DisplayName("Test moveCall.") + void moveCall() throws ExecutionException, InterruptedException { + final TypeTag.StructType structType = new TypeTag.StructType(); + StructTag structTag = new StructTag(); + structTag.setAddress("0x2"); + structTag.setModule("sui"); + structTag.setName("SUI"); + structType.setStructTag(structTag); + CompletableFuture res = + transactionBuilder.moveCall( + "0xea79464d86786b7a7a63e3f13f798f29f5e65947", + "0x0000000000000000000000000000000000000002", + "pay", + "split", + Lists.newArrayList(structType), + Lists.newArrayList("0x05f71eb5dc69224ef8e3a4c13917c799190237d9", 10000L), + null, + 1000L); + System.out.println(res.get()); + assertEquals("QXXmgG+hHAubzXbL3QhpLPJfakHqNLMp6DZAVyO00c8=", res.get().getGas().getDigest()); + assertEquals( + "QXXmgG+hHAubzXbL3QhpLPJfakHqNLMp6DZAVyO00c8=", + ((ImmOrOwnedMoveObjectKind) res.get().getInputObjects().get(2)) + .getImmOrOwnedMoveObject() + .getDigest()); + } } diff --git a/src/test/java/io/sui/models/transactions/TypeTagTest.java b/src/test/java/io/sui/models/transactions/TypeTagTest.java new file mode 100644 index 0000000..f117bb9 --- /dev/null +++ b/src/test/java/io/sui/models/transactions/TypeTagTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2022 281165273grape@gmail.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package io.sui.models.transactions; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.google.common.collect.Lists; +import io.sui.models.transactions.TypeTag.SimpleType; +import io.sui.models.transactions.TypeTag.StructType; +import io.sui.models.transactions.TypeTag.VectorType; +import org.junit.jupiter.api.Test; + +/** + * The type Type tag test. + * + * @author grapebaba + * @since 2022.11 + */ +class TypeTagTest { + + /** Type tag. */ + @Test + void typeTag() { + StructTag structTag = new StructTag(); + structTag.setAddress("0x2"); + structTag.setModule("sui"); + structTag.setName("Sui"); + structTag.setTypeParams(Lists.newArrayList(SimpleType.bool, SimpleType.u16)); + VectorType vectorType = new TypeTag.VectorType(); + StructType structType = new StructType(); + structType.setStructTag(structTag); + vectorType.setTypeTag(structType); + System.out.println(vectorType); + assertEquals("vector<0x2::sui::Sui>", vectorType.toString()); + + StructTag structTag1 = new StructTag(); + structTag1.setAddress("0x2"); + structTag1.setModule("test"); + structTag1.setName("Test"); + structTag1.setTypeParams(Lists.newArrayList(SimpleType.u128, vectorType)); + + VectorType vectorType1 = new TypeTag.VectorType(); + StructType structType1 = new StructType(); + structType1.setStructTag(structTag1); + vectorType1.setTypeTag(structType1); + System.out.println(vectorType1); + assertEquals( + "vector<0x2::test::Test>>>", vectorType1.toString()); + } +} diff --git a/src/test/resources/mockdata/moveCall.json b/src/test/resources/mockdata/moveCall.json new file mode 100644 index 0000000..2106dda --- /dev/null +++ b/src/test/resources/mockdata/moveCall.json @@ -0,0 +1,31 @@ +{ + "jsonrpc": "2.0", + "result": { + "txBytes": "VHJhbnNhY3Rpb25EYXRhOjoAAgAAAAAAAAAAAAAAAAAAAAAAAAACAQAAAAAAAAAgqfVhcEKs/dHDNNRZjotHPp50jauePdlz6dUbjdvSY5sDcGF5BXNwbGl0AQcAAAAAAAAAAAAAAAAAAAAAAAAAAgNzdWkDU1VJAAIBAAX3HrXcaSJO+OOkwTkXx5kZAjfZAAAAAAAAAAAgXpJDVPOW3OjFJJ9iDhU3GZjJWmDt4NX3XF4H4uA53+0ACBAnAAAAAAAA6nlGTYZ4a3p6Y+PxP3mPKfXmWUdjkWUHiBBuh2ZcVJntCeLO8oA+3wAAAAAAAAAAIEF15oBvoRwLm812y90IaSzyX2pB6jSzKeg2QFcjtNHPAQAAAAAAAADoAwAAAAAAAA==", + "gas": { + "objectId": "0x6391650788106e87665c5499ed09e2cef2803edf", + "version": 0, + "digest": "QXXmgG+hHAubzXbL3QhpLPJfakHqNLMp6DZAVyO00c8=" + }, + "inputObjects": [ + { + "ImmOrOwnedMoveObject": { + "objectId": "0x05f71eb5dc69224ef8e3a4c13917c799190237d9", + "version": 0, + "digest": "XpJDVPOW3OjFJJ9iDhU3GZjJWmDt4NX3XF4H4uA53+0=" + } + }, + { + "MovePackage": "0x0000000000000000000000000000000000000002" + }, + { + "ImmOrOwnedMoveObject": { + "objectId": "0x6391650788106e87665c5499ed09e2cef2803edf", + "version": 0, + "digest": "QXXmgG+hHAubzXbL3QhpLPJfakHqNLMp6DZAVyO00c8=" + } + } + ] + }, + "id": 1 +} \ No newline at end of file