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.
- checksums.yaml +4 -4
- data/.rubocop.yml +28 -3
- data/CHANGELOG.md +58 -3
- data/LICENSE.txt +119 -21
- data/README.md +211 -56
- data/examples/basic_usage.rb +26 -10
- data/examples/demo.rb +12 -10
- data/examples/simple_usage_example.rb +107 -0
- data/examples/test_tron_signer.rb +122 -0
- data/lib/gasfree_sdk/base58.rb +65 -0
- data/lib/gasfree_sdk/client.rb +184 -14
- data/lib/gasfree_sdk/crypto.rb +111 -0
- data/lib/gasfree_sdk/models/token.rb +4 -4
- data/lib/gasfree_sdk/models/transfer_response.rb +19 -19
- data/lib/gasfree_sdk/tron_eip712_signer.rb +260 -0
- data/lib/gasfree_sdk/types.rb +25 -2
- data/lib/gasfree_sdk/version.rb +1 -1
- data/lib/gasfree_sdk.rb +3 -0
- metadata +21 -2
data/examples/basic_usage.rb
CHANGED
@@ -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
|
-
|
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
|
-
#
|
44
|
-
|
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: #{
|
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(
|
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:
|
74
|
-
receiver: "
|
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
|
-
|
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
|
-
|
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
|
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: "
|
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: "
|
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: "
|
80
|
-
receiver: "
|
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: "
|
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
|