Skip to content

Commit 0c1c859

Browse files
committed
feat(gasfree): support Ledger for gasfree
1 parent d138810 commit 0c1c859

File tree

12 files changed

+150
-101
lines changed

12 files changed

+150
-101
lines changed

README.md

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ For more information on a specific command, just type the command on terminal wh
105105
| [ImportWalletByKeystore](#export-import-wallet-keystore) | [ImportWalletByLedger](#import-wallet-by-ledger) | [LoginAll](#login-all) |
106106
| [Lock](#lock) | [Unlock](#unlock) | [ResetWallet](#reset-wallet) |
107107
| [CreateAccount](#create-account) | [SwitchWallet](#switch-wallet) | [SwitchNetwork](#switch-network) |
108-
| [CurrentNetwork](#current-network) | [GasFreeAddress](#gas-free-address) | [GasFreeTransfer](#gas-free-transfer) |
108+
| [CurrentNetwork](#current-network) | [GasFreeInfo](#gas-free-info) | [GasFreeTransfer](#gas-free-transfer) |
109109
| [GasFreeTrace](#gas-free-trace) | | |
110110

111111

@@ -1645,6 +1645,7 @@ unlock successful !!!
16451645
## switch network
16461646
> SwitchNetwork
16471647
>This command allows for flexible network switching at any time. Unlocking can specify parameters in seconds.
1648+
>`switchnetwork local` will switch to the network configured in local config.conf.
16481649
16491650
Example:
16501651
```console
@@ -1654,10 +1655,18 @@ Please select network:
16541655
2. NILE
16551656
3. SHASTA
16561657
Enter numbers to select a network (1-3):1
1658+
Now, current network is : MAIN
16571659
SwitchNetwork successful !!!
16581660
```
16591661
```console
16601662
wallet> switchnetwork main
1663+
Now, current network is : MAIN
1664+
SwitchNetwork successful !!!
1665+
```
1666+
1667+
```console
1668+
wallet> switchnetwork empty localhost:50052
1669+
Now, current network is : CUSTOM
16611670
SwitchNetwork successful !!!
16621671
```
16631672

@@ -1671,14 +1680,43 @@ wallet> currentnetwork
16711680
currentNetwork: NILE
16721681
```
16731682

1674-
## gas free address
1675-
> GasFreeAddress
1676-
>Get the gas-free address of the current address.
1683+
```console
1684+
wallet> currentnetwork
1685+
current network: CUSTOM
1686+
fullNode: EMPTY, solidityNode: localhost:50052
1687+
```
1688+
1689+
## gas free info
1690+
> GasFreeInfo
1691+
>Get gasfree info of the current address.
16771692
16781693
Example:
16791694
```console
1680-
wallet> gasfreeaddress TUUSMd58eC3fKx3fn7whxJyr1FR56tgaP8
1681-
gas free address : TNER12mMVWruqopsW9FQtKxCGfZcEtb3ER
1695+
wallet> gasfreeinfo
1696+
balanceOf(address):70a08231
1697+
{
1698+
"gasFreeAddress":"TCtSt8fCkZcVdrGpaVHUr6P8EmdjysswMF",
1699+
"active":true,
1700+
"tokenBalance":998696000,
1701+
"activateFee":0,
1702+
"transferFee":2000,
1703+
"maxTransferValue":998694000
1704+
}
1705+
gasFreeInfo: successful !!
1706+
```
1707+
1708+
```console
1709+
wallet> gasfreeinfo TRvVXgqddDGYRMx3FWf2tpVxXQQXDZxJQe
1710+
balanceOf(address):70a08231
1711+
{
1712+
"gasFreeAddress":"TCtSt8fCkZcVdrGpaVHUr6P8EmdjysswMF",
1713+
"active":true,
1714+
"tokenBalance":998696000,
1715+
"activateFee":0,
1716+
"transferFee":2000,
1717+
"maxTransferValue":998694000
1718+
}
1719+
gasFreeInfo: successful !!
16821720
```
16831721

16841722
## gas free transfer

src/main/java/org/tron/common/crypto/ECKey.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ public ECKey(SecureRandom secureRandom) {
179179
* <p>All private key operations will use the provider.
180180
*/
181181

182-
// isPrivateKey true 私钥 其他公钥
182+
// isPrivateKey true
183183
public ECKey(byte[] key, boolean isPrivateKey) {
184184
if (isPrivateKey) {
185185
BigInteger pk = new BigInteger(1, key);

src/main/java/org/tron/common/utils/DomainValidator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,6 @@ public static boolean isDomain(String input) {
3636
public static boolean isDomainOrIP(String input) {
3737
if (input == null || input.isEmpty()) return false;
3838
if ("localhost".equalsIgnoreCase(input)) return true;
39-
return isIPv4(input) || isIPv6(input) || isDomain(input);
39+
return isIPv4(input) || isDomain(input);
4040
}
4141
}

src/main/java/org/tron/common/utils/HttpUtils.java

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import java.util.Map;
88
import java.util.Optional;
99
import java.util.concurrent.TimeUnit;
10-
import okhttp3.FormBody;
1110
import okhttp3.MediaType;
1211
import okhttp3.OkHttpClient;
1312
import okhttp3.Request;
@@ -25,7 +24,6 @@ public class HttpUtils {
2524
.build();
2625

2726
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
28-
private static final MediaType FORM = MediaType.parse("application/x-www-form-urlencoded; charset=utf-8");
2927

3028
public static String get(String url, Map<String, String> headers) throws IOException {
3129
Request.Builder builder = new Request.Builder().url(url).get();
@@ -54,27 +52,6 @@ public static String postJson(String url, String jsonBody) throws IOException {
5452
return postJson(url, jsonBody, null);
5553
}
5654

57-
// POST 请求 - 表单格式
58-
public static String postForm(String url, Map<String, String> formParams, Map<String, String> headers) throws IOException {
59-
FormBody.Builder formBuilder = new FormBody.Builder();
60-
if (formParams != null) {
61-
formParams.forEach(formBuilder::add);
62-
}
63-
64-
Request.Builder builder = new Request.Builder()
65-
.url(url)
66-
.post(formBuilder.build());
67-
68-
if (headers != null) {
69-
headers.forEach(builder::addHeader);
70-
}
71-
72-
Request request = builder.build();
73-
try (Response response = client.newCall(request).execute()) {
74-
return responseBodyToString(response);
75-
}
76-
}
77-
7855
private static String responseBodyToString(Response response) throws IOException {
7956
if (!response.isSuccessful()) {
8057
String msg = response.message();

src/main/java/org/tron/gasfree/GasFreeApi.java

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import org.tron.gasfree.request.GasFreeSubmitRequest;
3232
import org.web3j.abi.FunctionEncoder;
3333
import org.web3j.abi.datatypes.Address;
34-
import org.web3j.abi.datatypes.DynamicBytes;
3534
import org.web3j.abi.datatypes.Function;
3635
import org.web3j.abi.datatypes.Type;
3736
import org.web3j.abi.datatypes.generated.Bytes32;
@@ -43,7 +42,6 @@
4342
import org.web3j.utils.Numeric;
4443

4544
public class GasFreeApi {
46-
public static final String CREATION_CODE_STR = "0x60a06040526040516105ac3803806105ac83398101604081905261002291610382565b61002c828261003e565b506001600160a01b0316608052610471565b610047826100fb565b6040516001600160a01b038316907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e905f90a28051156100ef576100ea826001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100e4919061043d565b82610209565b505050565b6100f761027c565b5050565b806001600160a01b03163b5f0361013557604051631933b43b60e21b81526001600160a01b03821660048201526024015b60405180910390fd5b807fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5080546001600160a01b0319166001600160a01b0392831617905560408051635c60da1b60e01b815290515f92841691635c60da1b9160048083019260209291908290030181865afa1580156101ae573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101d2919061043d565b9050806001600160a01b03163b5f036100f757604051634c9c8ce360e01b81526001600160a01b038216600482015260240161012c565b60605f80846001600160a01b0316846040516102259190610456565b5f60405180830381855af49150503d805f811461025d576040519150601f19603f3d011682016040523d82523d5f602084013e610262565b606091505b50909250905061027385838361029d565b95945050505050565b341561029b5760405163b398979f60e01b815260040160405180910390fd5b565b6060826102b2576102ad826102fc565b6102f5565b81511580156102c957506001600160a01b0384163b155b156102f257604051639996b31560e01b81526001600160a01b038516600482015260240161012c565b50805b9392505050565b80511561030c5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b80515f906001600160a81b038116811461033d575f80fd5b6001600160a01b031692915050565b634e487b7160e01b5f52604160045260245ffd5b5f5b8381101561037a578181015183820152602001610362565b50505f910152565b5f8060408385031215610393575f80fd5b61039c83610325565b60208401519092506001600160401b03808211156103b8575f80fd5b818501915085601f8301126103cb575f80fd5b8151818111156103dd576103dd61034c565b604051601f8201601f19908116603f011681019083821181831017156104055761040561034c565b8160405282815288602084870101111561041d575f80fd5b61042e836020830160208801610360565b80955050505050509250929050565b5f6020828403121561044d575f80fd5b6102f582610325565b5f8251610467818460208701610360565b9190910192915050565b6080516101246104885f395f601d01526101245ff3fe6080604052600a600c565b005b60186014601a565b609d565b565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156076573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906098919060ba565b905090565b365f80375f80365f845af43d5f803e80801560b6573d5ff35b3d5ffd5b5f6020828403121560c9575f80fd5b81516001600160a81b038116811460de575f80fd5b6001600160a01b0316939250505056fea26474726f6e582212201a19cd1340c744d4f2dd20c2563b0a588f92859265dff6c1fd5750b22eef473f64736f6c63430008140033";
4745
public static final String DOMAIN_TYPE_STRING = "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)";
4846
public static final String PERMIT_TRANSFER_TYPE_STRING = "PermitTransfer(address token,address serviceProvider,address user,address receiver,uint256 value,uint256 maxFee,uint256 deadline,uint256 version,uint256 nonce)";
4947
private static final String API_PATH_TOKEN_ALL = "/api/v1/config/token/all";
@@ -106,16 +104,6 @@ public static byte[] concat(byte[]... arrays) {
106104
return result;
107105
}
108106

109-
public static byte[] bytecodeHash(String user, String beacon) {
110-
byte[] creationCode = Numeric.hexStringToByteArray(CREATION_CODE_STR);
111-
String userHex = Numeric.toHexString(tronBase58ToBytes32(user));
112-
String beaconHex = Numeric.toHexString(tronBase58ToBytes32(beacon));
113-
byte[] encodedCall = abiEncodeCall("initialize", new Address(userHex));
114-
byte[] encodedOuter = abiEncode(new Address(beaconHex), new DynamicBytes(encodedCall));
115-
byte[] packed = abiEncodePacked(creationCode, encodedOuter);
116-
return Hash.sha3(packed);
117-
}
118-
119107
private static String buildApiPath(NetType netType, String apiPath) {
120108
String prefix = netType.getGasFree().getApiPrefix();
121109
return prefix + apiPath;
@@ -274,29 +262,39 @@ public static byte[] getMessage(NetType netType, GasFreeSubmitRequest gasFreeSub
274262
JSONObject root = JSON.parseObject(resp);
275263
JSONObject data = root.getJSONObject("data");
276264
JSONArray tokens = data.getJSONArray("tokens");
277-
String tokenAddress = EMPTY;
278-
long maxFee = 0;
279-
long activateFee = 0;
280-
long transferFee = 0;
281-
if (tokens != null && !tokens.isEmpty()) {
282-
JSONObject token = tokens.getJSONObject(0);
283-
tokenAddress = token.getString("tokenAddress");
284-
activateFee = token.getLongValue("activateFee");
285-
transferFee = token.getLongValue("transferFee");
286-
maxFee = activateFee + transferFee;
265+
if (tokens == null || tokens.isEmpty()) {
266+
System.out.println("Failed to get tokens information.");
267+
return new byte[0];
287268
}
269+
String tokenAddress;
270+
long maxFee;
271+
long activateFee;
272+
long transferFee;
273+
JSONObject tokensJSONObject = tokens.getJSONObject(0);
274+
tokenAddress = tokensJSONObject.getString("tokenAddress");
275+
activateFee = tokensJSONObject.getLongValue("activateFee");
276+
transferFee = tokensJSONObject.getLongValue("transferFee");
277+
maxFee = activateFee + transferFee;
288278
gasFreeSubmitRequest.setToken(tokenAddress);
289279
gasFreeSubmitRequest.setMaxFee(maxFee);
290280

291281
String providerAll = providerAll(netType);
292282
JSONObject root1 = JSON.parseObject(providerAll);
293283
JSONObject data1 = root1.getJSONObject("data");
294284
JSONArray providers = data1.getJSONArray("providers");
295-
String providerAddress = EMPTY;
296-
if (providers != null && !providers.isEmpty()) {
297-
JSONObject provider = providers.getJSONObject(0);
298-
providerAddress = provider.getString("address");
285+
if (providers == null || providers.isEmpty()) {
286+
System.out.println("Failed to get providers information.");
287+
return new byte[0];
288+
}
289+
String providerAddress;
290+
long defaultDeadlineDuration;
291+
JSONObject provider = providers.getJSONObject(0);
292+
providerAddress = provider.getString("address");
293+
JSONObject config = provider.getJSONObject("config");
294+
if (config == null) {
295+
return new byte[0];
299296
}
297+
defaultDeadlineDuration = config.getLongValue("defaultDeadlineDuration");
300298
gasFreeSubmitRequest.setServiceProvider(providerAddress);
301299

302300
String addressResp = address(netType, gasFreeSubmitRequest.getUser());
@@ -307,7 +305,7 @@ public static byte[] getMessage(NetType netType, GasFreeSubmitRequest gasFreeSub
307305
System.out.println("Activate Fee: " + (active ? 0 : activateFee));
308306
System.out.println("Transfer Fee: " + transferFee);
309307
gasFreeSubmitRequest.setNonce(nonce);
310-
gasFreeSubmitRequest.setDeadline((System.currentTimeMillis() / 1000) + 300);
308+
gasFreeSubmitRequest.setDeadline((System.currentTimeMillis() / 1000) + defaultDeadlineDuration);
311309

312310
Address token = new Address(Numeric.toHexString(tronBase58ToBytes32(gasFreeSubmitRequest.getToken())));
313311
Address serviceProvider = new Address(Numeric.toHexString(tronBase58ToBytes32(gasFreeSubmitRequest.getServiceProvider())));

src/main/java/org/tron/ledger/LedgerSignUtil.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818

1919
public class LedgerSignUtil {
2020

21-
public static boolean requestLedgerSignLogic(Protocol.Transaction transaction, String path, String address) {
21+
public static boolean requestLedgerSignLogic(Protocol.Transaction transaction, String path, String address, boolean gasfree) {
2222
try {
23-
if (!ContractTypeChecker.canUseLedgerSign(
23+
if (!gasfree && !ContractTypeChecker.canUseLedgerSign(
2424
transaction.getRawData().getContract(0).getType().toString())) {
2525
return false;
2626
}
@@ -70,7 +70,7 @@ public static boolean requestLedgerSignLogic(Protocol.Transaction transaction, S
7070
if (hidDevice.isClosed()) {
7171
hidDevice.open();
7272
}
73-
ret = LedgerEventListener.getInstance().executeSignListen(hidDevice, transaction, path);
73+
ret = LedgerEventListener.getInstance().executeSignListen(hidDevice, transaction, path, gasfree);
7474
} catch (IllegalStateException e) {
7575
System.out.println(ANSI_RED + e.getMessage() + ANSI_RESET);
7676
if (DebugConfig.isDebugEnabled()) {

src/main/java/org/tron/ledger/listener/LedgerEventListener.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,10 @@ private synchronized void shutdownHidServices() {
7777
}
7878

7979

80-
public boolean executeSignListen(HidDevice hidDevice, Transaction transaction, String path) {
80+
public boolean executeSignListen(HidDevice hidDevice, Transaction transaction, String path, boolean gasfree) {
8181
boolean ret = false;
8282
try {
83-
byte[] sendResult = handleTransSign(hidDevice, transaction, path);
83+
byte[] sendResult = handleTransSign(hidDevice, transaction, path, gasfree);
8484
if (sendResult == null) {
8585
System.out.println("Transaction sign request is sent to Ledger");
8686
TransactionSignManager.getInstance().setHidDevice(hidDevice);
@@ -103,7 +103,7 @@ public boolean executeSignListen(HidDevice hidDevice, Transaction transaction, S
103103
/**
104104
* @param path example "m/44'/195'/0'/0/0"
105105
*/
106-
public byte[] handleTransSign(HidDevice hidDevice, Transaction transaction, String path) {
106+
public byte[] handleTransSign(HidDevice hidDevice, Transaction transaction, String path, boolean gasfree) {
107107
final int TIMEOUT_MILLIS = 1000;
108108
final int MAX_WAIT_TIME_MILLIS = 1000; // 1.5 seconds
109109
final int BYTE_LENGTH_THRESHOLD = 255;
@@ -115,12 +115,15 @@ public byte[] handleTransSign(HidDevice hidDevice, Transaction transaction, Stri
115115
String ins;
116116
String p1;
117117
String p2 = "00";
118-
if (rawBytes.length < BYTE_LENGTH_THRESHOLD) {
118+
if (rawBytes.length < BYTE_LENGTH_THRESHOLD && !gasfree) {
119119
transactionRaw = bytesToHex(rawBytes);
120120
ins = "04";
121121
p1 = "10";
122122
} else {
123123
transactionRaw = bytesToHex(getTransactionId(transaction).getBytes());
124+
if (gasfree) {
125+
transactionRaw = bytesToHex(transaction.getRawData().getData().toByteArray());
126+
}
124127
ins = "05";
125128
p1 = "00";
126129
}
@@ -190,6 +193,7 @@ public void hidDataReceived(HidServicesEvent event) {
190193
if (DebugConfig.isDebugEnabled()) {
191194
System.out.println("Signature: " + CommonUtil.bytesToHex(signature));
192195
}
196+
TransactionSignManager.getInstance().generateGasFreeSignature(signature);
193197
TransactionSignManager.getInstance().addTransactionSign(signature);
194198
LedgerSignResult.updateState(
195199
TransactionSignManager.getInstance().getHidDevice().getPath()

src/main/java/org/tron/ledger/listener/TransactionSignManager.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package org.tron.ledger.listener;
22

33
import com.google.protobuf.ByteString;
4+
import org.bouncycastle.util.encoders.Hex;
45
import org.hid4java.HidDevice;
56
import org.tron.protos.Protocol;
67

78
public class TransactionSignManager {
89
private Protocol.Transaction transaction;
910
private HidDevice hidDevice;
11+
private String gasfreeSignature;
1012

1113
private TransactionSignManager() {
1214

@@ -24,6 +26,10 @@ public synchronized void setTransaction(Protocol.Transaction newTransaction) {
2426
this.transaction = newTransaction;
2527
}
2628

29+
public synchronized void setGasfreeSignature(String gasfreeSignature) {
30+
this.gasfreeSignature = gasfreeSignature;
31+
}
32+
2733
public synchronized void setHidDevice(HidDevice hidDevice) {
2834
this.hidDevice = hidDevice;
2935
}
@@ -33,6 +39,10 @@ public synchronized Protocol.Transaction getTransaction() {
3339
return this.transaction;
3440
}
3541

42+
public synchronized String getGasfreeSignature() {
43+
return this.gasfreeSignature;
44+
}
45+
3646
public synchronized HidDevice getHidDevice() {
3747
return this.hidDevice;
3848
}
@@ -43,4 +53,8 @@ public synchronized void addTransactionSign(byte[] signByteArr) {
4353
transactionBuilderSigned.addSignature(bsSign);
4454
transaction = transactionBuilderSigned.build();
4555
}
56+
57+
public synchronized void generateGasFreeSignature(byte[] signedHash) {
58+
this.gasfreeSignature = Hex.toHexString(signedHash);
59+
}
4660
}

src/main/java/org/tron/walletcli/Client.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5627,6 +5627,11 @@ private void gasFreeTrace(String[] parameters) throws IOException, NoSuchAlgorit
56275627
private void currentNetwork() {
56285628
NetType currentNet = WalletApi.getCurrentNetwork();
56295629
Pair<String, String> customNodes = WalletApi.getCustomNodes();
5630+
if (customNodes == null || (org.apache.commons.lang3.StringUtils.isEmpty(customNodes.getLeft())
5631+
&& org.apache.commons.lang3.StringUtils.isEmpty(customNodes.getRight()))) {
5632+
System.out.println("The configuration of both fullnode and solidity cannot be empty at the same time.");
5633+
return;
5634+
}
56305635
String fullNode = customNodes.getLeft();
56315636
String solidityNode = customNodes.getRight();
56325637
System.out.println("current network: " + blueBoldHighlight(currentNet.name()));

0 commit comments

Comments
 (0)