gasfree_sdk 0.1.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,16 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
+ # GasFree SDK Basic Usage Example
5
+ # ===============================
6
+ # This example demonstrates the basic usage of the GasFree SDK with TRON testnet.
7
+ #
8
+ # Note: This demo uses placeholder TRON addresses and mock signatures for demonstration.
9
+ # In a production application, you would need:
10
+ # 1. Proper TRON key generation and address derivation
11
+ # 2. Proper TRON transaction signing using TRON-specific libraries
12
+ # 3. Real API credentials from GasFree.io
13
+
4
14
  require "bundler/setup"
5
15
  require "gasfree_sdk"
6
16
  require "eth"
@@ -9,7 +19,8 @@ require "eth"
9
19
  GasfreeSdk.configure do |config|
10
20
  config.api_key = ENV["GASFREE_API_KEY"] || "your-api-key"
11
21
  config.api_secret = ENV["GASFREE_API_SECRET"] || "your-api-secret"
12
- config.api_endpoint = ENV["GASFREE_API_ENDPOINT"] || "https://open.gasfree.io/tron/"
22
+ # Use the correct endpoint from the error - this appears to be the TRON testnet (Nile) endpoint
23
+ config.api_endpoint = ENV["GASFREE_API_ENDPOINT"] || "https://open-test.gasfree.io/nile/"
13
24
  end
14
25
 
15
26
  # Check if we have real API credentials
@@ -40,15 +51,17 @@ providers.each do |provider|
40
51
  puts " Default Deadline: #{provider.config.default_deadline_duration}s"
41
52
  end
42
53
 
43
- # Create a new key pair for testing
44
- key = Eth::Key.new
54
+ # For TRON testnet, we need to use a TRON address format (starts with T)
55
+ # Since we don't have a TRON-specific library, we'll use a valid TRON address for testing
56
+ user_address = "TZ3oPnE1SdAUL1YRd9GJQHenxrXjy4paAn" # Valid TRON testnet address
45
57
  puts "\nTest Account:"
46
- puts " Address: #{key.address}"
58
+ puts " TRON Address: #{user_address}"
59
+ puts " Note: Using a sample TRON address since API expects TRON format"
47
60
 
48
61
  # Get GasFree account info
49
62
  puts "\nGasFree Account Info:"
50
63
  begin
51
- account = client.address(key.address)
64
+ account = client.address(user_address)
52
65
  puts " GasFree Address: #{account.gas_free_address}"
53
66
  puts " Active: #{account.active}"
54
67
  puts " Nonce: #{account.nonce}"
@@ -70,8 +83,8 @@ begin
70
83
  message = {
71
84
  token: token.token_address,
72
85
  service_provider: provider.address,
73
- user: key.address,
74
- receiver: "0x1234567890123456789012345678901234567890",
86
+ user: user_address,
87
+ receiver: "TX554G9uKsEv1U6TBQnNPC7dkhbvBFhgrD",
75
88
  value: "1000000",
76
89
  max_fee: token.transfer_fee,
77
90
  deadline: Time.now.to_i + provider.config.default_deadline_duration,
@@ -80,7 +93,10 @@ begin
80
93
  }
81
94
 
82
95
  # Sign the message
83
- sig = key.sign(Eth::Util.keccak256(message.to_json))
96
+ # Note: In a real TRON application, you would use TRON-specific signing
97
+ # For this demo, we'll use a mock signature since we don't have TRON signing libraries
98
+ # sig = key.sign(Eth::Util.keccak256(message.to_json)) # This was for Ethereum
99
+ sig = "0x#{"a" * 130}" # Mock signature for demo purposes
84
100
 
85
101
  # Create and submit transfer request
86
102
  request = GasfreeSdk::Models::TransferRequest.new(
@@ -96,13 +112,13 @@ begin
96
112
 
97
113
  # Monitor transfer status
98
114
  puts "\nMonitoring Transfer Status:"
99
- 5.times do
115
+ 7.times do
100
116
  status = client.transfer_status(response.id)
101
117
  puts " State: #{status.state}"
102
118
  puts " Transaction Hash: #{status.txn_hash}" if status.txn_hash
103
119
  break if %w[SUCCEED FAILED].include?(status.state)
104
120
 
105
- sleep 2
121
+ sleep 5
106
122
  end
107
123
  rescue GasfreeSdk::APIError => e
108
124
  puts " Error (#{e.code}): #{e.message}"
data/examples/demo.rb CHANGED
@@ -34,9 +34,9 @@ puts "==============="
34
34
 
35
35
  # Token model
36
36
  token = GasfreeSdk::Models::Token.new(
37
- token_address: "0x1234567890123456789012345678901234567890",
38
- created_at: "2024-01-01T00:00:00Z",
39
- updated_at: "2024-01-01T00:00:00Z",
37
+ token_address: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
38
+ created_at: Time.parse("2024-01-01T00:00:00Z"),
39
+ updated_at: Time.parse("2024-01-01T00:00:00Z"),
40
40
  activate_fee: "1000000",
41
41
  transfer_fee: "500000",
42
42
  supported: true,
@@ -53,7 +53,7 @@ puts ""
53
53
 
54
54
  # Provider model
55
55
  provider = GasfreeSdk::Models::Provider.new(
56
- address: "0x1234567890123456789012345678901234567890",
56
+ address: "TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp",
57
57
  name: "Demo Provider",
58
58
  icon: "",
59
59
  website: "https://demo.provider.com",
@@ -76,8 +76,8 @@ puts ""
76
76
  transfer_request = GasfreeSdk::Models::TransferRequest.new(
77
77
  token: token.token_address,
78
78
  service_provider: provider.address,
79
- user: "0x1111111111111111111111111111111111111111",
80
- receiver: "0x2222222222222222222222222222222222222222",
79
+ user: "TZ3oPnE1SdAUL1YRd9GJQHenxrXjy4paAn",
80
+ receiver: "TX554G9uKsEv1U6TBQnNPC7dkhbvBFhgrD",
81
81
  value: "1000000",
82
82
  max_fee: "100000",
83
83
  deadline: Time.now.to_i + 180,
@@ -100,10 +100,10 @@ puts ""
100
100
  # Transfer response model
101
101
  transfer_response = GasfreeSdk::Models::TransferResponse.new(
102
102
  id: "demo-transfer-id",
103
- created_at: "2024-01-01T00:00:00Z",
104
- updated_at: "2024-01-01T00:00:00Z",
103
+ created_at: Time.parse("2024-01-01T00:00:00Z").to_i * 1000, # milliseconds
104
+ updated_at: Time.parse("2024-01-01T00:00:00Z").to_i * 1000, # milliseconds
105
105
  account_address: transfer_request.user,
106
- gas_free_address: "0x3333333333333333333333333333333333333333",
106
+ gas_free_address: "TGxDyymFq4cSvNjvqGstCxaoG2JWW3x5Mg",
107
107
  provider_address: provider.address,
108
108
  target_address: transfer_request.receiver,
109
109
  token_address: token.token_address,
@@ -111,7 +111,7 @@ transfer_response = GasfreeSdk::Models::TransferResponse.new(
111
111
  max_fee: transfer_request.max_fee,
112
112
  signature: transfer_request.sig,
113
113
  nonce: transfer_request.nonce,
114
- expired_at: "2024-01-01T00:03:00Z",
114
+ expired_at: Time.parse("2024-01-01T00:03:00Z").to_i * 1000, # milliseconds
115
115
  state: "WAITING"
116
116
  )
117
117
 
@@ -119,6 +119,8 @@ puts "Transfer Response:"
119
119
  puts " ID: #{transfer_response.id}"
120
120
  puts " State: #{transfer_response.state}"
121
121
  puts " Amount: #{transfer_response.amount}"
122
+ puts " Created At: #{transfer_response.created_at}"
123
+ puts " Updated At: #{transfer_response.updated_at}"
122
124
  puts " Expires At: #{transfer_response.expired_at}"
123
125
  puts ""
124
126
 
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # GasFree SDK Simple Usage Example with TronEIP712Signer
5
+ # =====================================================
6
+ # This example demonstrates how to use the TronEIP712Signer module
7
+ # to sign EIP-712 messages for TRON GasFree transfers.
8
+
9
+ require "bundler/setup"
10
+ require "gasfree_sdk"
11
+
12
+ # Configure the SDK
13
+ GasfreeSdk.configure do |config|
14
+ config.api_key = ENV["GASFREE_API_KEY"] || "your-api-key"
15
+ config.api_secret = ENV["GASFREE_API_SECRET"] || "your-api-secret"
16
+ config.api_endpoint = ENV["GASFREE_API_ENDPOINT"] || "https://open.gasfree.io/tron/"
17
+ end
18
+
19
+ puts "GasFree SDK with TronEIP712Signer Example"
20
+ puts "=" * 50
21
+
22
+ # Example private key and address (for demonstration only)
23
+ private_key = "1b3d1201039f2c91d2dac01a218967981d594a4bfa004478e7fed19a12a9fc31"
24
+ user_address = "TZ3oPnE1SdAUL1YRd9GJQHenxrXjy4paAn"
25
+
26
+ puts "Using example key pair:"
27
+ puts " Private Key: #{private_key}"
28
+ puts " TRON Address: #{user_address}"
29
+ puts
30
+
31
+ # Example message data for signing
32
+ message_data = {
33
+ token: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", # USDT TRC-20
34
+ serviceProvider: "TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp",
35
+ user: user_address,
36
+ receiver: "TX554G9uKsEv1U6TBQnNPC7dkhbvBFhgrD",
37
+ value: "3000000", # 3 USDT (6 decimals)
38
+ maxFee: "2000000", # 2 USDT max fee
39
+ deadline: (Time.now.to_i + 300).to_s, # 5 minutes from now
40
+ version: 1,
41
+ nonce: 0
42
+ }
43
+
44
+ puts "Message to sign:"
45
+ message_data.each do |key, value|
46
+ puts " #{key}: #{value}"
47
+ end
48
+ puts
49
+
50
+ # Sign for testnet
51
+ puts "Signing for TRON Testnet (Nile):"
52
+ testnet_signature = GasfreeSdk::TronEIP712Signer.sign_typed_data_testnet(private_key, message_data)
53
+ puts " Signature: #{testnet_signature}"
54
+ puts " Length: #{testnet_signature.length} characters"
55
+ puts
56
+
57
+ # Sign for mainnet
58
+ puts "Signing for TRON Mainnet:"
59
+ mainnet_signature = GasfreeSdk::TronEIP712Signer.sign_typed_data_mainnet(private_key, message_data)
60
+ puts " Signature: #{mainnet_signature}"
61
+ puts " Length: #{mainnet_signature.length} characters"
62
+ puts
63
+
64
+ # Show domain information
65
+ puts "Domain Information:"
66
+ puts " Testnet Domain:"
67
+ GasfreeSdk::TronEIP712Signer::DOMAIN_TESTNET.each do |key, value|
68
+ puts " #{key}: #{value}"
69
+ end
70
+ puts
71
+ puts " Mainnet Domain:"
72
+ GasfreeSdk::TronEIP712Signer::DOMAIN_MAINNET.each do |key, value|
73
+ puts " #{key}: #{value}"
74
+ end
75
+ puts
76
+
77
+ # Example of using with GasFree SDK client
78
+ if GasfreeSdk.config.api_key == "your-api-key"
79
+ puts "Set GASFREE_API_KEY and GASFREE_API_SECRET to test with real API"
80
+ else
81
+ puts "Creating transfer request with signed message:"
82
+
83
+ begin
84
+ GasfreeSdk.client
85
+
86
+ # Create transfer request with the signature
87
+ GasfreeSdk::Models::TransferRequest.new(
88
+ token: message_data[:token],
89
+ service_provider: message_data[:serviceProvider],
90
+ user: message_data[:user],
91
+ receiver: message_data[:receiver],
92
+ value: message_data[:value],
93
+ max_fee: message_data[:maxFee],
94
+ deadline: message_data[:deadline].to_i,
95
+ version: message_data[:version],
96
+ nonce: message_data[:nonce],
97
+ sig: testnet_signature
98
+ )
99
+
100
+ puts " Transfer request created successfully!"
101
+ puts " Ready to submit to GasFree API"
102
+ rescue StandardError => e
103
+ puts " Error creating request: #{e.message}"
104
+ end
105
+ end
106
+
107
+ puts "\nExample completed!"
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Test script for TronEIP712Signer module
5
+ # This script tests the signature functionality without making API calls
6
+
7
+ require "bundler/setup"
8
+ require "gasfree_sdk"
9
+
10
+ puts "Testing TronEIP712Signer Module"
11
+ puts "=" * 40
12
+
13
+ # Test data
14
+ private_key = "1b3d1201039f2c91d2dac01a218967981d594a4bfa004478e7fed19a12a9fc31"
15
+ user_address = "TZ3oPnE1SdAUL1YRd9GJQHenxrXjy4paAn"
16
+
17
+ message_data = {
18
+ token: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
19
+ serviceProvider: "TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp",
20
+ user: user_address,
21
+ receiver: "TX554G9uKsEv1U6TBQnNPC7dkhbvBFhgrD",
22
+ value: "3000000",
23
+ maxFee: "2000000",
24
+ deadline: "1749371692",
25
+ version: 1,
26
+ nonce: 0
27
+ }
28
+
29
+ puts "Test Data:"
30
+ puts " Private Key: #{private_key}"
31
+ puts " User Address: #{user_address}"
32
+ puts " Message Data: #{message_data}"
33
+ puts
34
+
35
+ # Test 1: Basic signature generation
36
+ puts "Test 1: Basic Signature Generation"
37
+ begin
38
+ testnet_sig = GasfreeSdk::TronEIP712Signer.sign_typed_data_testnet(private_key, message_data)
39
+ puts " ✅ Testnet signature: #{testnet_sig[0..20]}...#{testnet_sig[-20..]}"
40
+ puts " ✅ Signature length: #{testnet_sig.length} characters"
41
+ rescue StandardError => e
42
+ puts " ❌ Error: #{e.message}"
43
+ end
44
+
45
+ # Test 2: Mainnet signature
46
+ puts "\nTest 2: Mainnet Signature Generation"
47
+ begin
48
+ mainnet_sig = GasfreeSdk::TronEIP712Signer.sign_typed_data_mainnet(private_key, message_data)
49
+ puts " ✅ Mainnet signature: #{mainnet_sig[0..20]}...#{mainnet_sig[-20..]}"
50
+ puts " ✅ Signature length: #{mainnet_sig.length} characters"
51
+ rescue StandardError => e
52
+ puts " ❌ Error: #{e.message}"
53
+ end
54
+
55
+ # Test 3: Domain constants
56
+ puts "\nTest 3: Domain Constants"
57
+ begin
58
+ testnet_domain = GasfreeSdk::TronEIP712Signer::DOMAIN_TESTNET
59
+ mainnet_domain = GasfreeSdk::TronEIP712Signer::DOMAIN_MAINNET
60
+
61
+ puts " ✅ Testnet domain: #{testnet_domain[:name]} v#{testnet_domain[:version]}"
62
+ puts " Chain ID: #{testnet_domain[:chainId]}"
63
+ puts " Contract: #{testnet_domain[:verifyingContract]}"
64
+
65
+ puts " ✅ Mainnet domain: #{mainnet_domain[:name]} v#{mainnet_domain[:version]}"
66
+ puts " Chain ID: #{mainnet_domain[:chainId]}"
67
+ puts " Contract: #{mainnet_domain[:verifyingContract]}"
68
+ rescue StandardError => e
69
+ puts " ❌ Error: #{e.message}"
70
+ end
71
+
72
+ # Test 4: Cryptographic utilities
73
+ puts "\nTest 4: Cryptographic Utilities"
74
+ begin
75
+ test_data = "Hello, TRON!"
76
+ hash = GasfreeSdk::TronEIP712Signer.keccac256(test_data)
77
+ hex_hash = GasfreeSdk::TronEIP712Signer.keccac256_hex(test_data)
78
+
79
+ puts " ✅ Keccac256 hash length: #{hash.length} bytes"
80
+ puts " ✅ Keccac256 hex hash: #{hex_hash[0..20]}...#{hex_hash[-20..]}"
81
+ rescue StandardError => e
82
+ puts " ❌ Error: #{e.message}"
83
+ end
84
+
85
+ # Test 5: Base58 utilities
86
+ puts "\nTest 5: Base58 Utilities"
87
+ begin
88
+ binary_data = GasfreeSdk::Base58.base58_to_binary(user_address)
89
+ restored_address = GasfreeSdk::Base58.binary_to_base58(binary_data)
90
+
91
+ puts " ✅ Address conversion: #{user_address} -> binary -> #{restored_address}"
92
+ puts " ✅ Conversion successful: #{user_address == restored_address}"
93
+ rescue StandardError => e
94
+ puts " ❌ Error: #{e.message}"
95
+ end
96
+
97
+ # Test 6: Type encoding
98
+ puts "\nTest 6: EIP-712 Type Encoding"
99
+ begin
100
+ encoded_type = GasfreeSdk::TronEIP712Signer.encode_type(:PermitTransfer)
101
+ puts " ✅ Encoded PermitTransfer type:"
102
+ puts " #{encoded_type[0..80]}..."
103
+ rescue StandardError => e
104
+ puts " ❌ Error: #{e.message}"
105
+ end
106
+
107
+ # Test 7: Signature consistency
108
+ puts "\nTest 7: Signature Consistency"
109
+ begin
110
+ sig1 = GasfreeSdk::TronEIP712Signer.sign_typed_data_testnet(private_key, message_data)
111
+ sig2 = GasfreeSdk::TronEIP712Signer.sign_typed_data_testnet(private_key, message_data)
112
+
113
+ puts " ✅ Signature 1: #{sig1[0..20]}...#{sig1[-20..]}"
114
+ puts " ✅ Signature 2: #{sig2[0..20]}...#{sig2[-20..]}"
115
+ puts " ✅ Signatures are identical: #{sig1 == sig2}"
116
+ rescue StandardError => e
117
+ puts " ❌ Error: #{e.message}"
118
+ end
119
+
120
+ puts "\n#{"=" * 40}"
121
+ puts "All tests completed!"
122
+ puts "TronEIP712Signer module is working correctly ✅"
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GasfreeSdk
4
+ # Base58 implementation for TRON address encoding/decoding
5
+ module Base58
6
+ ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
7
+
8
+ class << self
9
+ # Convert Base58 string to binary data
10
+ # @param s [String] Base58 encoded string
11
+ # @return [String] Binary data
12
+ def base58_to_binary(string)
13
+ int_val = 0
14
+ base = ALPHABET.size
15
+ string.each_char do |char|
16
+ int_val = (int_val * base) + ALPHABET.index(char)
17
+ end
18
+
19
+ # Convert to bytes
20
+ bytes = []
21
+ while int_val.positive?
22
+ bytes.unshift(int_val & 0xff)
23
+ int_val >>= 8
24
+ end
25
+
26
+ # Handle leading zeros
27
+ string.each_char do |char|
28
+ break if char != "1"
29
+
30
+ bytes.unshift(0)
31
+ end
32
+
33
+ bytes.pack("C*")
34
+ end
35
+
36
+ # Convert binary data to Base58 string
37
+ # @param bytes [String] Binary data
38
+ # @return [String] Base58 encoded string
39
+ def binary_to_base58(bytes)
40
+ # Convert bytes to integer
41
+ int_val = 0
42
+ bytes.each_byte do |byte|
43
+ int_val = (int_val << 8) + byte
44
+ end
45
+
46
+ # Convert to base58
47
+ result = ""
48
+ base = ALPHABET.size
49
+ while int_val.positive?
50
+ int_val, remainder = int_val.divmod(base)
51
+ result = ALPHABET[remainder] + result
52
+ end
53
+
54
+ # Handle leading zeros
55
+ bytes.each_byte do |byte|
56
+ break if byte != 0
57
+
58
+ result = "1#{result}"
59
+ end
60
+
61
+ result.empty? ? "1" : result
62
+ end
63
+ end
64
+ end
65
+ end